poc: Virtua message list#40105
Conversation
|
Looks like this PR is not ready to merge, because of the following issues:
Please fix the issues and try again If you have any trouble, please check the PR guidelines |
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization 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:
WalkthroughReplaces DOM-based message list scrolling with a virtualized VList, removes ref-based jump-to-message plumbing, centralizes deep-link handling into new hooks that fetch/scroll/highlight messages, and shifts scroll/load state management to ref-driven and virtualizer-driven APIs across room and thread UIs. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Router
participant TryJumpHook as useTryToJumpToMessage
participant ReactQuery
participant RoomHistory
participant Virtualizer as MessageList(VList)
participant HighlightMgr as HighlightManager
User->>Router: Navigate with ?msg=messageId
Router->>TryJumpHook: effect triggered (msg param present)
TryJumpHook->>ReactQuery: GET /v1/chat.getMessage(messageId)
ReactQuery-->>TryJumpHook: API message payload
alt Message in messages[]
TryJumpHook->>Virtualizer: scrollToIndex(foundIndex, center)
else Message not present
TryJumpHook->>RoomHistory: loadSurroundingMessages(messageId)
RoomHistory-->>Virtualizer: messages loaded into list
TryJumpHook->>Virtualizer: scrollToIndex(foundIndex, center)
end
TryJumpHook->>HighlightMgr: setHighlightMessage(messageId)
Note over HighlightMgr: Highlight cleared after timeout
TryJumpHook->>Router: replace URL without ?msg
sequenceDiagram
participant User
participant Virtualizer as VList
participant MessageList
participant useGetMore
participant RoomHistoryManager
User->>Virtualizer: Scroll near start (top)
Virtualizer->>MessageList: onScroll/topIndex changed
MessageList->>useGetMore: request previous page
useGetMore->>RoomHistoryManager: getMorePrevious(rid)
RoomHistoryManager-->>useGetMore: messages loaded
useGetMore->>MessageList: update internal ref/viewport
MessageList->>Virtualizer: re-render (prepend shift)
User->>Virtualizer: Scroll near end (bottom)
Virtualizer->>MessageList: onScroll + isAtBottom check
MessageList->>useGetMore: request next page
useGetMore->>RoomHistoryManager: getMoreNext(rid)
Note over RoomHistoryManager: no longer mutates external atBottomRef
RoomHistoryManager-->>useGetMore: messages loaded
useGetMore->>MessageList: update internal ref/viewport
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 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. 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 |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #40105 +/- ##
===========================================
+ Coverage 69.83% 69.85% +0.01%
===========================================
Files 3296 3298 +2
Lines 119173 119228 +55
Branches 21475 21468 -7
===========================================
+ Hits 83221 83282 +61
- Misses 32645 32651 +6
+ Partials 3307 3295 -12
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
c6d1200 to
d893bb3
Compare
remove shift
819b667 to
6e60799
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts (1)
22-31:⚠️ Potential issue | 🟡 MinorReset shared refs between tests to avoid order-dependent behavior.
Line 22 and Line 23 define mutable refs once for the whole suite, but they are never reset in
beforeEach. Because tests mutate these refs (e.g., Line 191), later tests can inherit stale state.Proposed fix
beforeEach(() => { jest.clearAllMocks(); + isAtBottom.current = true; + shouldJumpToBottom.current = false; clientCallbacks.remove('streamNewMessage', rid); clientCallbacks.remove('afterSaveMessage', rid); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts` around lines 22 - 31, Tests define shared mutable refs isAtBottom and shouldJumpToBottom at suite scope but never reinitialize them between tests; update the beforeEach in useHasNewMessages.spec.ts to reset isAtBottom.current = true and shouldJumpToBottom.current = false (or recreate the objects) so each test starts with fresh refs, ensuring tests that mutate these refs (e.g., later assertions around shouldJumpToBottom) are isolated.
🧹 Nitpick comments (3)
packages/ui-client/src/components/CustomScrollbars/CustomVirtuaScrollbars.tsx (1)
18-21: Remove the inline implementation comment.As per coding guidelines, keep implementation comments out of the component; the overflow-style assignments are already self-explanatory.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ui-client/src/components/CustomScrollbars/CustomVirtuaScrollbars.tsx` around lines 18 - 21, Remove the unnecessary implementation comment in CustomVirtuaScrollbars.tsx: delete the line containing "// force overflow styles" directly above the block that accesses osInstance.elements() and assigns viewport.style.overflowX and viewport.style.overflowY so the code remains self-explanatory while leaving the osInstance.elements() call and viewport.style assignments intact.apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts (1)
36-39: Remove inline REVIEW/TODO comments from hook implementation.Move these notes to a tracked issue/PR note and keep runtime code comment-free.
As per coding guidelines "
**/*.{ts,tsx,js}: ... Avoid code comments in the implementation".Also applies to: 82-82
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts` around lines 36 - 39, Remove the inline REVIEW/TODO comments inside the useTryToJumpToMessage hook implementation (e.g., the block mentioning onScroll and context about jump-to-message behavior) and relocate that text into a tracked issue or PR note; update the hook file to contain no runtime-facing REVIEW/TODO comments while preserving any necessary context in the external issue/PR so the behavior is documented outside the code.apps/meteor/client/views/room/MessageList/MessageList.tsx (1)
65-67: Remove inline TODO/REVIEW comments from runtime implementation.Please track these as issues/PR notes instead of embedding them in component code.
As per coding guidelines "
**/*.{ts,tsx,js}: ... Avoid code comments in the implementation".Also applies to: 80-83, 99-100, 134-135
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/client/views/room/MessageList/MessageList.tsx` around lines 65 - 67, Remove inline TODO/REVIEW comments from the runtime component code in MessageList.tsx: delete the comment blocks that precede/annotate the isPrepend useRef declaration and any other inline review/TODO comments in this file (the ones near the isPrepend declaration and the other comment blocks around the message list logic), and instead track these items as issues or PR notes in your tracker; keep the isPrepend = useRef<boolean>(false) statement unchanged but remove any explanatory review comments from the implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts`:
- Around line 57-59: The test "should NOT show new messages button when user
sends own message during race condition (not at bottom)" sets isAtBottom true,
so it never exercises the "not at bottom" branch; update the test that calls
renderHook(() => useHasNewMessages(rid, uid, shouldJumpToBottom, isAtBottom), {
wrapper: ... }) to pass isAtBottom as false (or use the existing variable set to
false) so the hook runs the not-at-bottom race-condition path for self-sent
messages; ensure the variables referenced (rid, uid, shouldJumpToBottom,
isAtBottom) and the renderHook call are adjusted accordingly.
In `@apps/meteor/client/views/room/body/hooks/useStoreScrollPosition.ts`:
- Around line 13-21: The debounced callback in useStoreScrollPosition can
overwrite the last valid scroll with 0 if virtualizerRef.current is gone when
the timer fires; change the callback in useStoreScrollPosition to bail out if
virtualizerRef.current is null/undefined instead of using the "?? 0" fallback,
and only call RoomManager.getStore(rid)?.update(...) when virtualizerRef.current
exists (use its scrollOffset) and preserve using isAtBottom.current for the
atBottom field; this prevents detaching the viewport from writing a bogus
top-of-list position.
In
`@apps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx`:
- Around line 126-131: The current call to router.navigate with only pathname
wipes all query params; instead, preserve existing query params and remove only
the msg key before navigating. Read the current search/query (via
router.getLocationSearch or the router/location object available in
ThreadMessageList), create a URLSearchParams from it, delete('msg'), then call
router.navigate with pathname: router.getLocationPathname() and search:
`?${params.toString()}` (or omit search if empty), keeping { replace: true } to
avoid replacing unrelated query state.
In `@apps/meteor/client/views/room/hooks/useDateScroll.ts`:
- Around line 97-107: The fallback date-bubble style in useDateScroll.ts sets an
invalid CSS key "to" which prevents the position from applying; find the code
path where matched is assigned when (matched.length === 0 && topMessage) and
replace the "to" property in the style object with "top" (keeping the same value
`${margin}px`) so the absolute positioning for the fallback bubble works as
intended (refer to the matched assignment and topMessage usage).
- Around line 113-118: The state update in useDateScroll.ts clears date to ''
every run, which causes flicker; instead only overwrite date when the new date
value is present. Update the setBubbleDate(...) call (the setter used in
useDateScroll.ts) to avoid setting date: '' unconditionally—keep the existing
current.date when date is falsy and only spread in { date } when date is truthy,
while still updating show using Boolean(date).
In `@apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts`:
- Around line 54-67: The isJumpingToMessage.current flag is set too early
causing it to remain true on early returns; move the assignment or ensure it's
cleared on all aborted paths: either set isJumpingToMessage.current = true only
after the RoomHistoryManager.isLoading(rid) check and after confirming
loadedMessage exists, or add explicit resets (isJumpingToMessage.current =
false) before each early return in the current block (references:
isJumpingToMessage.current, RoomHistoryManager.isLoading(rid), messages.find(...
_id === messageJumpParam),
RoomHistoryManager.getSurroundingChannelMessages(message)).
In `@apps/meteor/client/views/room/MessageList/MessageList.tsx`:
- Around line 46-47: lastViewportSize is defined as a constant (const
lastViewportSize = 0) so the subsequent comparison never tracks previous
viewport height; replace it with a persistent mutable value (e.g., a React ref
via useRef<number>(0) or component state) inside the MessageList component,
update references in the resize/viewport-checking logic to read/write
lastViewportSize.current (or the state setter) instead of the constant, and set
it after you perform the comparison so future renders see the previous viewport
size (update usages where the code compares and assigns around the existing
comparison block that references lastViewportSize).
- Around line 155-175: Reset unreadMarkIndex.current to null at the start of
each render so stale index values can't be used by visibility checks: add
unreadMarkIndex.current = null near the top of the MessageList component before
any logic that searches for the divider (the code paths that set unreadMarkIndex
when a divider is found), and do the same reset in the other block that mirrors
this logic (the block around the second occurrence at lines 227-235). This
ensures isUnreadMarkVisible (which reads unreadMarkIndex.current), the
divider-finding code that updates unreadMarkIndex, and uses of virtualizerRef
and canPreview always operate on a fresh value rather than a stale ref.
In
`@packages/ui-client/src/components/CustomScrollbars/CustomVirtuaScrollbars.tsx`:
- Around line 23-27: The forwarded ref assigned in CustomVirtuaScrollbars (the
block that sets ref(viewport) or ref.current = viewport) must be cleared on
unmount to avoid leaving a dangling reference; update the component's effect or
cleanup where the viewport is assigned so the cleanup function resets the
forwarded ref back to null (call ref(null) for function refs or set ref.current
= null for RefObjects) and ensure this logic runs when the overlay/component
unmounts or viewport changes.
---
Outside diff comments:
In `@apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts`:
- Around line 22-31: Tests define shared mutable refs isAtBottom and
shouldJumpToBottom at suite scope but never reinitialize them between tests;
update the beforeEach in useHasNewMessages.spec.ts to reset isAtBottom.current =
true and shouldJumpToBottom.current = false (or recreate the objects) so each
test starts with fresh refs, ensuring tests that mutate these refs (e.g., later
assertions around shouldJumpToBottom) are isolated.
---
Nitpick comments:
In `@apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts`:
- Around line 36-39: Remove the inline REVIEW/TODO comments inside the
useTryToJumpToMessage hook implementation (e.g., the block mentioning onScroll
and context about jump-to-message behavior) and relocate that text into a
tracked issue or PR note; update the hook file to contain no runtime-facing
REVIEW/TODO comments while preserving any necessary context in the external
issue/PR so the behavior is documented outside the code.
In `@apps/meteor/client/views/room/MessageList/MessageList.tsx`:
- Around line 65-67: Remove inline TODO/REVIEW comments from the runtime
component code in MessageList.tsx: delete the comment blocks that
precede/annotate the isPrepend useRef declaration and any other inline
review/TODO comments in this file (the ones near the isPrepend declaration and
the other comment blocks around the message list logic), and instead track these
items as issues or PR notes in your tracker; keep the isPrepend =
useRef<boolean>(false) statement unchanged but remove any explanatory review
comments from the implementation.
In
`@packages/ui-client/src/components/CustomScrollbars/CustomVirtuaScrollbars.tsx`:
- Around line 18-21: Remove the unnecessary implementation comment in
CustomVirtuaScrollbars.tsx: delete the line containing "// force overflow
styles" directly above the block that accesses osInstance.elements() and assigns
viewport.style.overflowX and viewport.style.overflowY so the code remains
self-explanatory while leaving the osInstance.elements() call and viewport.style
assignments intact.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e0052fd9-bbed-423c-b36b-ec29e2545d7d
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (30)
apps/meteor/app/ui-utils/client/lib/RoomHistoryManager.tsapps/meteor/client/components/message/list/MessageListContext.tsxapps/meteor/client/components/message/variants/RoomMessage.tsxapps/meteor/client/components/message/variants/ThreadMessage.tsxapps/meteor/client/lib/chats/readStateManager.tsapps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/views/room/MessageList/MessageList.tsxapps/meteor/client/views/room/MessageList/MessageListItem.tsxapps/meteor/client/views/room/MessageList/hooks/useJumpToMessage.tsapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.spec.tsapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.tsapps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsxapps/meteor/client/views/room/body/RoomBody.tsxapps/meteor/client/views/room/body/hooks/useGetMore.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.tsapps/meteor/client/views/room/body/hooks/useListIsAtBottom.tsapps/meteor/client/views/room/body/hooks/useRestoreScrollPosition.spec.tsxapps/meteor/client/views/room/body/hooks/useRestoreScrollPosition.tsapps/meteor/client/views/room/body/hooks/useStoreScrollPosition.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsxapps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageListScrolling.tsapps/meteor/client/views/room/hooks/useDateScroll.tsapps/meteor/client/views/room/hooks/useRetentionPolicy.tsapps/meteor/package.jsonpackages/ui-client/src/components/CustomScrollbars/CustomVirtuaScrollbars.tsxpackages/ui-client/src/components/CustomScrollbars/index.ts
💤 Files with no reviewable changes (8)
- apps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.spec.ts
- apps/meteor/client/components/message/variants/ThreadMessage.tsx
- apps/meteor/client/components/message/variants/RoomMessage.tsx
- apps/meteor/client/views/room/body/hooks/useRestoreScrollPosition.spec.tsx
- apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageListScrolling.ts
- apps/meteor/client/views/room/MessageList/hooks/useJumpToMessage.ts
- apps/meteor/client/views/room/body/hooks/useRestoreScrollPosition.ts
- apps/meteor/client/views/room/body/hooks/useListIsAtBottom.ts
📜 Review details
⏰ 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). (2)
- GitHub Check: 📦 Build Packages
- GitHub Check: CodeQL-Build
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
packages/ui-client/src/components/CustomScrollbars/index.tsapps/meteor/client/views/room/MessageList/MessageListItem.tsxapps/meteor/client/views/room/body/hooks/useStoreScrollPosition.tsapps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsxapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/client/components/message/list/MessageListContext.tsxapps/meteor/client/views/room/hooks/useRetentionPolicy.tsapps/meteor/app/ui-utils/client/lib/RoomHistoryManager.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.tsapps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/lib/chats/readStateManager.tspackages/ui-client/src/components/CustomScrollbars/CustomVirtuaScrollbars.tsxapps/meteor/client/views/room/body/hooks/useGetMore.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.tsapps/meteor/client/views/room/hooks/useDateScroll.tsapps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsxapps/meteor/client/views/room/body/RoomBody.tsxapps/meteor/client/views/room/MessageList/MessageList.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.ts
**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use.spec.tsextension for test files (e.g.,login.spec.ts)
Files:
apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
🧠 Learnings (32)
📓 Common learnings
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 38623
File: apps/meteor/app/lib/server/functions/cleanRoomHistory.ts:146-149
Timestamp: 2026-04-18T12:32:53.425Z
Learning: In `apps/meteor/app/lib/server/functions/cleanRoomHistory.ts` (PR `#38623`), the read-receipt cleanup (both `ReadReceipts.removeByMessageIds` and `ReadReceiptsArchive.removeByMessageIds`) is intentionally only performed in the limited prune path (`limit && selectedMessageIds`). The unlimited/delete-all path (`limit === 0`) deliberately skips cleaning up orphaned read receipts in both hot and cold storage — this is by design. Do not flag this as a bug or missing cleanup in future reviews.
📚 Learning: 2026-04-14T23:23:18.990Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 40159
File: packages/apps-engine/turbo.json:6-6
Timestamp: 2026-04-14T23:23:18.990Z
Learning: In RocketChat/Rocket.Chat's Turborepo setup, the workspace-root `package.json` is part of Turbo's global hash and does not need to be explicitly listed in a package-level turbo.json task's `inputs` array. Changes to the root `package.json` already bust the cache for all tasks via the global hash. Do not flag the absence of `$TURBO_ROOT$/package.json` in task-level inputs as a cache-invalidation issue.
Applied to files:
apps/meteor/package.json
📚 Learning: 2026-03-17T16:08:37.572Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 39690
File: packages/ui-voip/package.json:11-11
Timestamp: 2026-03-17T16:08:37.572Z
Learning: In `packages/ui-voip/package.json` (RocketChat/Rocket.Chat), the team deliberately chose to use `rm -rf dist` directly in the `"build"` script instead of `rimraf`, as they decided against introducing the `rimraf` dependency for this package. Do not flag `rm -rf dist` in the ui-voip build script as a cross-platform issue requiring rimraf.
Applied to files:
apps/meteor/package.json
📚 Learning: 2026-02-25T20:10:16.987Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38913
File: packages/ddp-client/src/legacy/types/SDKLegacy.ts:34-34
Timestamp: 2026-02-25T20:10:16.987Z
Learning: In the RocketChat/Rocket.Chat monorepo, packages/ddp-client and apps/meteor do not use TypeScript project references. Module augmentations in apps/meteor (e.g., declare module 'rocket.chat/rest-typings') are not visible when compiling packages/ddp-client in isolation, which is why legacy SDK methods that depend on OperationResult types for OpenAPI-migrated endpoints must remain commented out.
Applied to files:
apps/meteor/package.jsonapps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsxapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.
Applied to files:
packages/ui-client/src/components/CustomScrollbars/index.tsapps/meteor/client/views/room/body/hooks/useStoreScrollPosition.tsapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/client/views/room/hooks/useRetentionPolicy.tsapps/meteor/app/ui-utils/client/lib/RoomHistoryManager.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.tsapps/meteor/client/lib/chats/readStateManager.tsapps/meteor/client/views/room/body/hooks/useGetMore.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.tsapps/meteor/client/views/room/hooks/useDateScroll.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.
Applied to files:
packages/ui-client/src/components/CustomScrollbars/index.tsapps/meteor/client/views/room/body/hooks/useStoreScrollPosition.tsapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/client/views/room/hooks/useRetentionPolicy.tsapps/meteor/app/ui-utils/client/lib/RoomHistoryManager.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.tsapps/meteor/client/lib/chats/readStateManager.tsapps/meteor/client/views/room/body/hooks/useGetMore.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.tsapps/meteor/client/views/room/hooks/useDateScroll.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.ts
📚 Learning: 2026-03-11T22:04:20.529Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 39545
File: apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts:59-61
Timestamp: 2026-03-11T22:04:20.529Z
Learning: In `apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts`, the `msg.u._id === uid` early-return in the `streamNewMessage` handler is intentional: the "New messages" indicator is designed to notify about messages from other users only. Self-sent messages — including those sent from a different session/device — are always skipped, by design. Do not flag this as a multi-session regression.
Applied to files:
apps/meteor/client/views/room/MessageList/MessageListItem.tsxapps/meteor/client/views/room/body/hooks/useStoreScrollPosition.tsapps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsxapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/client/views/room/hooks/useRetentionPolicy.tsapps/meteor/app/ui-utils/client/lib/RoomHistoryManager.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.tsapps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/lib/chats/readStateManager.tsapps/meteor/client/views/room/body/hooks/useGetMore.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.tsapps/meteor/client/views/room/hooks/useDateScroll.tsapps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsxapps/meteor/client/views/room/body/RoomBody.tsxapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-02-24T19:36:55.089Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/page-objects/fragments/home-content.ts:60-82
Timestamp: 2026-02-24T19:36:55.089Z
Learning: In RocketChat/Rocket.Chat e2e tests (apps/meteor/tests/e2e/page-objects/fragments/home-content.ts), thread message preview listitems do not have aria-roledescription="message", so lastThreadMessagePreview locator cannot be scoped to messageListItems (which filters for aria-roledescription="message"). It should remain scoped to page.getByRole('listitem') or mainMessageList.getByRole('listitem').
Applied to files:
apps/meteor/client/views/room/MessageList/MessageListItem.tsxapps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsxapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.tsapps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.tsapps/meteor/client/views/room/hooks/useDateScroll.tsapps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsxapps/meteor/client/views/room/body/RoomBody.tsxapps/meteor/client/views/room/MessageList/MessageList.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.ts
📚 Learning: 2026-03-27T14:52:56.865Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39892
File: apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx:150-155
Timestamp: 2026-03-27T14:52:56.865Z
Learning: In Rocket.Chat, there are two different `ModalBackdrop` components with different prop APIs. During review, confirm the import source: (1) `rocket.chat/fuselage` `ModalBackdrop` uses `ModalBackdropProps` based on `BoxProps` (so it supports `onClick` and other Box/DOM props) and does not have an `onDismiss` prop; (2) `rocket.chat/ui-client` `ModalBackdrop` uses a narrower props interface like `{ children?: ReactNode; onDismiss?: () => void }` and handles Escape keypress and outside mouse-up, and it does not forward arbitrary DOM props such as `onClick`. Flag mismatched props (e.g., `onDismiss` passed to the fuselage component or `onClick` passed to the ui-client component) and ensure the usage matches the correct component being imported.
Applied to files:
apps/meteor/client/views/room/MessageList/MessageListItem.tsxapps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsxapps/meteor/client/components/message/list/MessageListContext.tsxapps/meteor/client/views/room/MessageList/MessageList.spec.tsxpackages/ui-client/src/components/CustomScrollbars/CustomVirtuaScrollbars.tsxapps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsxapps/meteor/client/views/room/body/RoomBody.tsxapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-04-13T16:40:55.864Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 40100
File: apps/meteor/client/views/root/MainLayout/EmbeddedPreload.tsx:18-35
Timestamp: 2026-04-13T16:40:55.864Z
Learning: In Rocket.Chat's embedded mode (`?layout=embedded`), route changes are driven by the parent frame reloading the iframe URL, which causes a full remount of the React tree (including `EmbeddedPreload` at `apps/meteor/client/views/root/MainLayout/EmbeddedPreload.tsx`). The component never survives a navigation, so `roomParams` (computed via `useMemo`) is always fresh on mount. A `[router]` singleton as the sole `useMemo` dependency is therefore correct and intentional — do not flag it as a stale-dependency bug in this component.
Applied to files:
apps/meteor/client/views/room/body/hooks/useStoreScrollPosition.tsapps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsxapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/app/ui-utils/client/lib/RoomHistoryManager.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.tsapps/meteor/client/views/room/body/hooks/useGetMore.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/body/RoomBody.tsx
📚 Learning: 2026-02-10T16:32:42.586Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38528
File: apps/meteor/client/startup/roles.ts:14-14
Timestamp: 2026-02-10T16:32:42.586Z
Learning: In Rocket.Chat's Meteor client code, DDP streams use EJSON and Date fields arrive as Date objects; do not manually construct new Date() in stream handlers (for example, in sdk.stream()). Only REST API responses return plain JSON where dates are strings, so implement explicit conversion there if needed. Apply this guidance to all TypeScript files under apps/meteor/client to ensure consistent date handling in DDP streams and REST responses.
Applied to files:
apps/meteor/client/views/room/body/hooks/useStoreScrollPosition.tsapps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/client/views/room/hooks/useRetentionPolicy.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.tsapps/meteor/client/lib/chats/readStateManager.tsapps/meteor/client/views/room/body/hooks/useGetMore.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.tsapps/meteor/client/views/room/hooks/useDateScroll.tsapps/meteor/client/views/room/body/hooks/useHasNewMessages.ts
📚 Learning: 2026-04-14T21:10:36.233Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 36292
File: apps/meteor/client/hooks/useHasValidLocationHash.ts:7-12
Timestamp: 2026-04-14T21:10:36.233Z
Learning: In the RocketChat/Rocket.Chat repository, adding JSDoc-style comments to React hooks (e.g., files under apps/meteor/client/hooks/) is considered a good pattern and should not be flagged as a violation of the "avoid code comments in the implementation" guideline. The guideline against code comments does not apply to JSDoc documentation on exported hooks.
Applied to files:
apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsxapps/meteor/client/components/message/list/MessageListContext.tsxapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx
📚 Learning: 2025-11-19T18:20:07.720Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.720Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.
Applied to files:
apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx
📚 Learning: 2026-04-18T12:32:53.425Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 38623
File: apps/meteor/app/lib/server/functions/cleanRoomHistory.ts:146-149
Timestamp: 2026-04-18T12:32:53.425Z
Learning: In `apps/meteor/app/lib/server/functions/cleanRoomHistory.ts` (PR `#38623`), the read-receipt cleanup (both `ReadReceipts.removeByMessageIds` and `ReadReceiptsArchive.removeByMessageIds`) is intentionally only performed in the limited prune path (`limit && selectedMessageIds`). The unlimited/delete-all path (`limit === 0`) deliberately skips cleaning up orphaned read receipts in both hot and cold storage — this is by design. Do not flag this as a bug or missing cleanup in future reviews.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.tsapps/meteor/client/views/room/hooks/useRetentionPolicy.tsapps/meteor/app/ui-utils/client/lib/RoomHistoryManager.tsapps/meteor/client/lib/chats/readStateManager.tsapps/meteor/client/views/room/body/hooks/useGetMore.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/hooks/useDateScroll.tsapps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsxapps/meteor/client/views/room/body/RoomBody.tsxapps/meteor/client/views/room/MessageList/MessageList.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.ts
📚 Learning: 2026-01-19T18:08:13.423Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38169
File: packages/ui-client/src/hooks/useGoToDirectMessage.ts:20-27
Timestamp: 2026-01-19T18:08:13.423Z
Learning: In React hooks, including custom hooks like useUserSubscriptionByName, must always be called unconditionally and in the same order on every render, per the Rules of Hooks. Passing empty strings or fallback values to hooks is the correct approach when dealing with potentially undefined values, rather than conditionally calling the hook based on whether the value exists.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.ts
📚 Learning: 2026-03-04T14:16:49.202Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39304
File: packages/ui-contexts/src/ActionManagerContext.ts:26-26
Timestamp: 2026-03-04T14:16:49.202Z
Learning: In `packages/ui-contexts/src/ActionManagerContext.ts` (TypeScript, RocketChat/Rocket.Chat), the `disposeView` method in `IActionManager` uses an intentionally explicit union `UiKit.ModalView['id'] | UiKit.BannerView['viewId'] | UiKit.ContextualBarView['id']` to document which view types are accepted, even though all constituents resolve to the same primitive. The inline `// eslint-disable-next-line typescript-eslint/no-duplicate-type-constituents` comment is intentional and should not be flagged or removed.
Applied to files:
apps/meteor/client/components/message/list/MessageListContext.tsx
📚 Learning: 2026-04-17T17:38:15.994Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 39858
File: packages/ui-kit/src/interactions/UserInteraction.ts:33-33
Timestamp: 2026-04-17T17:38:15.994Z
Learning: In RocketChat/Rocket.Chat (`packages/ui-kit/src/interactions/UserInteraction.ts`), `ViewSubmitUserInteraction` and `ViewClosedUserInteraction` intentionally do NOT include `rid` when the interaction originates from a **modal** surface. Modals are not scoped to a room, so no room id is available in that context. The `rid?: string` field is optional to support the contextual bar surface (where room context exists) while remaining absent for modals. Do not flag the absence of `rid` in modal viewSubmit/viewClosed interactions as a missing-context bug.
Applied to files:
apps/meteor/client/views/room/hooks/useRetentionPolicy.tsapps/meteor/app/ui-utils/client/lib/RoomHistoryManager.tsapps/meteor/client/views/room/body/hooks/useGetMore.tsapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/body/hooks/useUnreadMessages.tsapps/meteor/client/views/room/MessageList/MessageList.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.ts
📚 Learning: 2026-04-17T18:33:27.211Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 39858
File: apps/meteor/tests/e2e/apps/uikit-interactions.spec.ts:123-151
Timestamp: 2026-04-17T18:33:27.211Z
Learning: In RocketChat/Rocket.Chat (`apps/meteor/tests/e2e/apps/uikit-interactions.spec.ts`), `executeBlockActionHandler` invocations originating from a **modal** surface intentionally do NOT include a `block_action_room` (room property) in the interaction payload. Modals are not scoped to a room, so no room id is available in that context. Do not flag the absence of a room assertion in the modal block-action test as a missing coverage bug; instead, document it explicitly with a `test.step` asserting the room entry is `undefined`.
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Prefer web-first assertions (`toBeVisible`, `toHaveText`, etc.) in Playwright tests
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,spec.ts} : Follow Page Object Model pattern consistently in Playwright tests
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.spec.tsxapps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests
Applied to files:
apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Maintain test isolation between test cases in Playwright tests
Applied to files:
apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests
Applied to files:
apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2026-02-24T19:22:48.358Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/omnichannel/omnichannel-send-pdf-transcript.spec.ts:66-67
Timestamp: 2026-02-24T19:22:48.358Z
Learning: In Playwright end-to-end tests (e.g., under apps/meteor/tests/e2e/...), prefer locating elements by translated text (getByText) and ARIA roles (getByRole) over data-qa attributes. If translation values change, update the corresponding test locators accordingly. Never use data-qa locators. This guideline applies to all Playwright e2e test specs in the repository and helps keep tests robust to UI text changes and accessible semantics.
Applied to files:
apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts
📚 Learning: 2026-03-11T18:17:53.972Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39425
File: apps/meteor/client/lib/chats/flows/processMessageUploads.ts:112-119
Timestamp: 2026-03-11T18:17:53.972Z
Learning: In `apps/meteor/client/lib/chats/flows/processMessageUploads.ts`, when sending multiple file uploads, each file is confirmed via its own `/rooms.mediaConfirm/${rid}/${fileId}` call and produces a separate message. Only the first file's confirm payload carries the composed message text (`msg`); all subsequent files receive `msg: ''`. This one-message-per-file behavior is intentional by design — do not flag it as a bug or suggest batching into a single message.
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-03-11T22:04:16.136Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 39545
File: apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts:59-61
Timestamp: 2026-03-11T22:04:16.136Z
Learning: In apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts, the early-return condition that checks msg.u._id === uid in the streamNewMessage handler is intentional. The New messages indicator should notify only about messages from other users; self-sent messages (including those from a different session/device) are intentionally skipped. Do not flag this as a multi-session regression for this file.
Applied to files:
apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts
🔇 Additional comments (11)
apps/meteor/client/views/room/MessageList/MessageListItem.tsx (1)
5-6: Import cleanup only.This reorder doesn't change behavior; it just groups the message-list helpers together.
apps/meteor/client/components/message/list/MessageListContext.tsx (1)
2-2: Type import matches the hook signature.
KeyboardEvent | MouseEventis the right shape foruseOpenEmojiPicker, so this update looks good.apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx (1)
26-26: Provider API cleanup looks consistent.Dropping the provider-level
messageListRefpassthrough matches the newuseMessageListNavigation/Virtua wiring.apps/meteor/client/views/room/hooks/useRetentionPolicy.ts (1)
87-122: Type alias makes the hook contract clearer.The exported
RetentionPolicytype matches the existing returned shape, and theundefinedreturn for a missing room is consistent with the hook's usage.packages/ui-client/src/components/CustomScrollbars/index.ts (1)
6-6: Barrel export looks good.Re-exporting
CustomVirtuaScrollbarshere keeps the new scroll wrapper available through the existing public entrypoint.apps/meteor/package.json (1)
307-307: Dependency addition matches the virtualization rollout.Adding
virtuahere is consistent with the newVList-based message list and thread list components.apps/meteor/app/ui-utils/client/lib/RoomHistoryManager.ts (1)
218-218: AllgetMoreNextusages have been correctly updated to the new one-argument signature. The function definition at line 218 accepts onlyrid, and the single call site inuseGetMore.ts:61passes exactly one argument. No unmigrated two-argument call patterns exist in the codebase.apps/meteor/client/views/room/MessageList/MessageList.spec.tsx (1)
140-201: Good targeted coverage for virtualizer scroll state behavior.These cases validate the critical restore/update paths introduced by the virtualization refactor.
apps/meteor/client/views/room/body/hooks/useGetMore.ts (1)
27-62: Jump-aware short-circuiting and cleanup look solid here.The fetch/restore flow is correctly guarded during jump-to-message and keeps observer/listener teardown intact.
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToThreadMessage.ts (1)
35-64: Thread deep-link routing flow looks consistent.The guard clauses and navigation branching are clean and match the intended thread-only handling.
apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts (1)
83-95: Ref-based debounced clearing integrates well with the new scroll model.The returned
debouncedClearNewMessagesOnScrollcleanly supports virtualizer-driven scroll updates.
| it('should NOT show new messages button when user sends own message during race condition (not at bottom)', () => { | ||
| const scrollBehavior = { | ||
| ...mockScrollBehavior, | ||
| isAtBottom: jest.fn(() => false), | ||
| }; | ||
|
|
||
| const { result } = renderHook(() => useHasNewMessages(rid, uid, atBottomRef, scrollBehavior), { wrapper: mockAppRoot().build() }); | ||
| const { result } = renderHook(() => useHasNewMessages(rid, uid, shouldJumpToBottom, isAtBottom), { wrapper: mockAppRoot().build() }); | ||
|
|
There was a problem hiding this comment.
The "not at bottom" precondition is not actually set in this test.
Line 57 says this covers the "not at bottom" race, but Line 58 passes isAtBottom (initialized true). This test currently validates only the self-message branch, not the intended scroll-state branch.
Proposed fix
-const { result } = renderHook(() => useHasNewMessages(rid, uid, shouldJumpToBottom, isAtBottom), { wrapper: mockAppRoot().build() });
+const { result } = renderHook(() => useHasNewMessages(rid, uid, shouldJumpToBottom, { current: false }), {
+ wrapper: mockAppRoot().build(),
+});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| it('should NOT show new messages button when user sends own message during race condition (not at bottom)', () => { | |
| const scrollBehavior = { | |
| ...mockScrollBehavior, | |
| isAtBottom: jest.fn(() => false), | |
| }; | |
| const { result } = renderHook(() => useHasNewMessages(rid, uid, atBottomRef, scrollBehavior), { wrapper: mockAppRoot().build() }); | |
| const { result } = renderHook(() => useHasNewMessages(rid, uid, shouldJumpToBottom, isAtBottom), { wrapper: mockAppRoot().build() }); | |
| it('should NOT show new messages button when user sends own message during race condition (not at bottom)', () => { | |
| const { result } = renderHook(() => useHasNewMessages(rid, uid, shouldJumpToBottom, { current: false }), { | |
| wrapper: mockAppRoot().build(), | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/client/views/room/body/hooks/useHasNewMessages.spec.ts` around
lines 57 - 59, The test "should NOT show new messages button when user sends own
message during race condition (not at bottom)" sets isAtBottom true, so it never
exercises the "not at bottom" branch; update the test that calls renderHook(()
=> useHasNewMessages(rid, uid, shouldJumpToBottom, isAtBottom), { wrapper: ...
}) to pass isAtBottom as false (or use the existing variable set to false) so
the hook runs the not-at-bottom race-condition path for self-sent messages;
ensure the variables referenced (rid, uid, shouldJumpToBottom, isAtBottom) and
the renderHook call are adjusted accordingly.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/meteor/client/views/room/MessageList/MessageList.tsx (1)
46-47:⚠️ Potential issue | 🟠 MajorModule-level mutable state causes cross-instance pollution.
lastViewportSizeis declared at module scope, meaning it's shared across allMessageListinstances. If multiple rooms are open (e.g., in different tabs or panels), they'll interfere with each other's viewport tracking.🔧 Proposed fix: Convert to ref inside component
-let lastViewportSize = 0; - export const MessageList = function MessageList({ // ...props }: MessageListProps) { + const lastViewportSizeRef = useRef(0); // ... - if (isAtBottom.current && lastViewportSize !== handle?.viewportSize) { - lastViewportSize = handle?.viewportSize ?? 0; + if (isAtBottom.current && lastViewportSizeRef.current !== handle?.viewportSize) { + lastViewportSizeRef.current = handle?.viewportSize ?? 0; handle?.scrollToIndex(lastItemIndex + 1, { align: 'end', }); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/client/views/room/MessageList/MessageList.tsx` around lines 46 - 47, lastViewportSize is a module-level mutable variable shared across all MessageList instances causing cross-instance interference; move this state into the MessageList component as an instance-scoped ref (e.g., useRef) so each component keeps its own viewport value, update any reads/writes to reference the ref (current) inside the MessageList render/effects, and remove the module-level declaration to prevent global pollution.
🧹 Nitpick comments (1)
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts (1)
89-89: Unusedrouterin dependency array.
routeris included in theuseEffectdependency array but is not used in the effect body. The query parameter is already cleared viasetMessageJumpQueryStringParameter(null)at line 88.🔧 Proposed fix
- }, [messageJumpParam, virtualizerRef, isJumpingToMessage, rid, messages, router, message]); + }, [messageJumpParam, virtualizerRef, isJumpingToMessage, rid, messages, message]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts` at line 89, In the useEffect inside useTryToJumpToMessage (the effect with dependencies [messageJumpParam, virtualizerRef, isJumpingToMessage, rid, messages, router, message]), remove the unused router from the dependency array (or alternatively reference router in the effect if you intended to use it); update the dependency list to [messageJumpParam, virtualizerRef, isJumpingToMessage, rid, messages, message] so it only contains variables actually used in the effect body (ensure ESLint/React hooks rules remain satisfied).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/meteor/client/views/room/MessageList/MessageList.tsx`:
- Around line 234-239: The unread mark is being nulled inside the per-message
mapping which causes later messages to overwrite the found index; before
iterating, reset unreadMarkIndex.current = null once, and inside the loop only
set unreadMarkIndex.current = index when showUnreadDivider is true (remove the
else branch that clears it). Update the logic around the map that computes
showUnreadDivider/unreadMarkIndex (referencing unreadMarkIndex,
showUnreadDivider and isUnreadMarkVisible) so the index is initialized once
before the loop and only assigned when the divider is encountered.
- Line 147: The effect's dependency array incorrectly uses ref `.current` values
(shouldJumpToBottom.current, isJumpingToMessage.current) which don't trigger
reruns; update the dependency array to either remove those `.current` entries
entirely if the effect doesn't need to rerun on ref mutations, or replace them
with the ref objects (shouldJumpToBottom, isJumpingToMessage) so React sees
stable refs (but still won't rerun on .current changes) and the effect can read
latest values inside its body; adjust the useEffect dependency list where it's
declared to reference shouldJumpToBottom and isJumpingToMessage (or omit them)
along with the existing messages, rid, isAtBottom, firstUnreadMessageId.
---
Duplicate comments:
In `@apps/meteor/client/views/room/MessageList/MessageList.tsx`:
- Around line 46-47: lastViewportSize is a module-level mutable variable shared
across all MessageList instances causing cross-instance interference; move this
state into the MessageList component as an instance-scoped ref (e.g., useRef) so
each component keeps its own viewport value, update any reads/writes to
reference the ref (current) inside the MessageList render/effects, and remove
the module-level declaration to prevent global pollution.
---
Nitpick comments:
In `@apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts`:
- Line 89: In the useEffect inside useTryToJumpToMessage (the effect with
dependencies [messageJumpParam, virtualizerRef, isJumpingToMessage, rid,
messages, router, message]), remove the unused router from the dependency array
(or alternatively reference router in the effect if you intended to use it);
update the dependency list to [messageJumpParam, virtualizerRef,
isJumpingToMessage, rid, messages, message] so it only contains variables
actually used in the effect body (ensure ESLint/React hooks rules remain
satisfied).
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c1f2746e-014d-4308-8301-056f4cb86635
📒 Files selected for processing (6)
apps/meteor/client/views/room/MessageList/MessageList.tsxapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/body/hooks/useGetMore.spec.tsxapps/meteor/client/views/room/body/hooks/useStoreScrollPosition.tsapps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsxapps/meteor/client/views/room/hooks/useDateScroll.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/meteor/client/views/room/body/hooks/useStoreScrollPosition.ts
- apps/meteor/client/views/room/hooks/useDateScroll.ts
- apps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx
📜 Review details
⏰ 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). (2)
- GitHub Check: 📦 Build Packages
- GitHub Check: CodeQL-Build
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)
**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation
Files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsxapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/MessageList.tsx
🧠 Learnings (33)
📓 Common learnings
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:18.785Z
Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers.
Learnt from: smirk-dev
Repo: RocketChat/Rocket.Chat PR: 39625
File: apps/meteor/app/api/server/v1/push.ts:85-97
Timestamp: 2026-03-14T14:58:58.834Z
Learning: In RocketChat/Rocket.Chat, the `push.token` POST/DELETE endpoints in `apps/meteor/app/api/server/v1/push.ts` were already migrated to the chained router API pattern on `develop` prior to PR `#39625`. `cleanTokenResult` (which strips `authToken` and returns `PushTokenResult`) and `isPushTokenPOSTProps`/`isPushTokenDELETEProps` validators already exist on `develop`. PR `#39625` only migrates `push.get` and `push.info` to the chained pattern. Do not flag `cleanTokenResult` or `PushTokenResult` as newly introduced behavior-breaking changes when reviewing this PR.
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/page-objects/fragments/home-content.ts:60-82
Timestamp: 2026-02-24T19:36:55.089Z
Learning: In RocketChat/Rocket.Chat e2e tests (apps/meteor/tests/e2e/page-objects/fragments/home-content.ts), thread message preview listitems do not have aria-roledescription="message", so lastThreadMessagePreview locator cannot be scoped to messageListItems (which filters for aria-roledescription="message"). It should remain scoped to page.getByRole('listitem') or mainMessageList.getByRole('listitem').
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx
📚 Learning: 2026-04-17T18:33:27.211Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 39858
File: apps/meteor/tests/e2e/apps/uikit-interactions.spec.ts:123-151
Timestamp: 2026-04-17T18:33:27.211Z
Learning: In RocketChat/Rocket.Chat (`apps/meteor/tests/e2e/apps/uikit-interactions.spec.ts`), `executeBlockActionHandler` invocations originating from a **modal** surface intentionally do NOT include a `block_action_room` (room property) in the interaction payload. Modals are not scoped to a room, so no room id is available in that context. Do not flag the absence of a room assertion in the modal block-action test as a missing coverage bug; instead, document it explicitly with a `test.step` asserting the room entry is `undefined`.
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx
📚 Learning: 2026-03-11T22:04:20.529Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 39545
File: apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts:59-61
Timestamp: 2026-03-11T22:04:20.529Z
Learning: In `apps/meteor/client/views/room/body/hooks/useHasNewMessages.ts`, the `msg.u._id === uid` early-return in the `streamNewMessage` handler is intentional: the "New messages" indicator is designed to notify about messages from other users only. Self-sent messages — including those sent from a different session/device — are always skipped, by design. Do not flag this as a multi-session regression.
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsxapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Prefer web-first assertions (`toBeVisible`, `toHaveText`, etc.) in Playwright tests
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx
📚 Learning: 2025-12-16T17:29:45.163Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37834
File: apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-emoji.ts:12-22
Timestamp: 2025-12-16T17:29:45.163Z
Learning: In page object files under `apps/meteor/tests/e2e/page-objects/`, always import `expect` from `../../utils/test` (Playwright's async expect), not from Jest. Jest's `expect` has a synchronous signature and will cause TypeScript errors when used with web-first assertions like `toBeVisible()`.
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx
📚 Learning: 2026-04-18T12:32:53.425Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 38623
File: apps/meteor/app/lib/server/functions/cleanRoomHistory.ts:146-149
Timestamp: 2026-04-18T12:32:53.425Z
Learning: In `apps/meteor/app/lib/server/functions/cleanRoomHistory.ts` (PR `#38623`), the read-receipt cleanup (both `ReadReceipts.removeByMessageIds` and `ReadReceiptsArchive.removeByMessageIds`) is intentionally only performed in the limited prune path (`limit && selectedMessageIds`). The unlimited/delete-all path (`limit === 0`) deliberately skips cleaning up orphaned read receipts in both hot and cold storage — this is by design. Do not flag this as a bug or missing cleanup in future reviews.
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsxapps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx
📚 Learning: 2026-03-27T14:52:56.865Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39892
File: apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx:150-155
Timestamp: 2026-03-27T14:52:56.865Z
Learning: In Rocket.Chat, there are two different `ModalBackdrop` components with different prop APIs. During review, confirm the import source: (1) `rocket.chat/fuselage` `ModalBackdrop` uses `ModalBackdropProps` based on `BoxProps` (so it supports `onClick` and other Box/DOM props) and does not have an `onDismiss` prop; (2) `rocket.chat/ui-client` `ModalBackdrop` uses a narrower props interface like `{ children?: ReactNode; onDismiss?: () => void }` and handles Escape keypress and outside mouse-up, and it does not forward arbitrary DOM props such as `onClick`. Flag mismatched props (e.g., `onDismiss` passed to the fuselage component or `onClick` passed to the ui-client component) and ensure the usage matches the correct component being imported.
Applied to files:
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsxapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-04-28T14:08:43.140Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 40105
File: apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts:54-67
Timestamp: 2026-04-28T14:08:43.140Z
Learning: In `apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts`, setting `isJumpingToMessage.current = true` before the guard clauses (RoomHistoryManager.isLoading check, message not found check) is intentional. The flag means "a jump is pending/in progress" and must stay `true` through all intermediate early-return paths (loading, unresolved message, etc.) so that downstream scroll and load behavior is suppressed while waiting for the jump conditions to be satisfied. Do not flag this as a "flag stuck true" bug.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-02-24T19:36:55.089Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/page-objects/fragments/home-content.ts:60-82
Timestamp: 2026-02-24T19:36:55.089Z
Learning: In RocketChat/Rocket.Chat e2e tests (apps/meteor/tests/e2e/page-objects/fragments/home-content.ts), thread message preview listitems do not have aria-roledescription="message", so lastThreadMessagePreview locator cannot be scoped to messageListItems (which filters for aria-roledescription="message"). It should remain scoped to page.getByRole('listitem') or mainMessageList.getByRole('listitem').
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-04-17T17:38:15.994Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 39858
File: packages/ui-kit/src/interactions/UserInteraction.ts:33-33
Timestamp: 2026-04-17T17:38:15.994Z
Learning: In RocketChat/Rocket.Chat (`packages/ui-kit/src/interactions/UserInteraction.ts`), `ViewSubmitUserInteraction` and `ViewClosedUserInteraction` intentionally do NOT include `rid` when the interaction originates from a **modal** surface. Modals are not scoped to a room, so no room id is available in that context. The `rid?: string` field is optional to support the contextual bar surface (where room context exists) while remaining absent for modals. Do not flag the absence of `rid` in modal viewSubmit/viewClosed interactions as a missing-context bug.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-04-13T16:40:55.864Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 40100
File: apps/meteor/client/views/root/MainLayout/EmbeddedPreload.tsx:18-35
Timestamp: 2026-04-13T16:40:55.864Z
Learning: In Rocket.Chat's embedded mode (`?layout=embedded`), route changes are driven by the parent frame reloading the iframe URL, which causes a full remount of the React tree (including `EmbeddedPreload` at `apps/meteor/client/views/root/MainLayout/EmbeddedPreload.tsx`). The component never survives a navigation, so `roomParams` (computed via `useMemo`) is always fresh on mount. A `[router]` singleton as the sole `useMemo` dependency is therefore correct and intentional — do not flag it as a stale-dependency bug in this component.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-04-17T23:32:07.223Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 38357
File: apps/meteor/app/apps/server/converters/messages.ts:348-352
Timestamp: 2026-04-17T23:32:07.223Z
Learning: In `apps/meteor/app/apps/server/converters/messages.ts`, the `timestamp` handler inside `_convertAttachmentsToApp` uses a non-null assertion (`attachment.ts!`) intentionally. The `ts` property on `MessageAttachment` is optional only to accommodate MessageAttachment creation-time scenarios; by the time `_convertAttachmentsToApp` is called, the message has already been stored and the attachment is guaranteed to have a `ts` value. Do not flag this non-null assertion as unsafe during code review.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-02-24T19:16:35.307Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 39003
File: apps/meteor/client/lib/chats/flows/sendMessage.ts:39-45
Timestamp: 2026-02-24T19:16:35.307Z
Learning: In apps/meteor/client/lib/chats/flows/sendMessage.ts, when sdk.call('sendMessage', ...) throws an error, the message is intentionally left with temp: true (not deleted or cleaned up) to support a future retry UI feature. This allows users to retry sending failed messages rather than losing them.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-04-20T17:11:59.452Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 40225
File: apps/meteor/ee/server/apps/communication/endpoints/appLogsHandler.ts:55-71
Timestamp: 2026-04-20T17:11:59.452Z
Learning: In `apps/meteor/ee/server/apps/communication/endpoints/appLogsHandler.ts`, the concern about an empty `?appId=` query param bypassing the truthy check and overriding the path `appId` in the `makeAppLogsQuery` spread is not relevant. The AJV query schema (`isAppLogsProps`) validates and rejects invalid/empty `appId` values before the action handler is reached, making the in-handler guard sufficient as-is. Do not flag this pattern as a vulnerability in future reviews of this file.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-03-16T22:56:54.500Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 39677
File: packages/models/src/helpers/omnichannel/agentStatus.ts:10-29
Timestamp: 2026-03-16T22:56:54.500Z
Learning: In `packages/models/src/helpers/omnichannel/agentStatus.ts` (PR `#39677`), the `queryStatusAgentOnline` function intentionally omits the `$or` offline-status guard for non-bot agents when `isLivechatEnabledWhenAgentIdle === true`. This is by design: the setting `Livechat_enabled_when_agent_idle` (`accept_chats_when_agent_idle`) means agents should receive chats even when idle/offline, so the offline filter must be removed in that path. Bots are always status-agnostic and are always included regardless of their online/offline status. Do not flag this as a bug.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-03-20T13:51:23.302Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 39553
File: apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts:179-181
Timestamp: 2026-03-20T13:51:23.302Z
Learning: In `apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts`, the truthiness guards `...(integration.avatar && { avatar })`, `...(integration.emoji && { emoji })`, `...(integration.alias && { alias })`, and `...(integration.script && { script })` in the `$set` payload of `updateIncomingIntegration` are intentional. Empty-string values for these fields should NOT overwrite the stored value — only truthy values are persisted. Do not flag these as bugs preventing explicit clears.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.tsapps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-03-10T08:13:52.153Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39414
File: apps/meteor/app/api/server/v1/rooms.ts:1241-1297
Timestamp: 2026-03-10T08:13:52.153Z
Learning: In the RocketChat/Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1/rooms.ts, the pattern `ajv.compile<void>({...})` is intentionally used for the 200 response schema even when the endpoint returns `{ success: true }`. This is an established convention across all migrated endpoints (rooms.leave, rooms.favorite, rooms.delete, rooms.muteUser, rooms.unmuteUser). Do not flag this as a type mismatch during reviews of these migration PRs.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-04-14T21:10:36.233Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 36292
File: apps/meteor/client/hooks/useHasValidLocationHash.ts:7-12
Timestamp: 2026-04-14T21:10:36.233Z
Learning: In the RocketChat/Rocket.Chat repository, adding JSDoc-style comments to React hooks (e.g., files under apps/meteor/client/hooks/) is considered a good pattern and should not be flagged as a violation of the "avoid code comments in the implementation" guideline. The guideline against code comments does not apply to JSDoc documentation on exported hooks.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-02-23T17:53:18.785Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:18.785Z
Learning: In Rocket.Chat PR reviews, maintain strict scope boundaries—when a PR is focused on a specific endpoint (e.g., rooms.favorite), avoid reviewing or suggesting changes to other endpoints that were incidentally refactored (e.g., rooms.invite) unless explicitly requested by maintainers.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-03-06T18:10:23.330Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:23.330Z
Learning: In the RocketChat/Rocket.Chat `packages/gazzodown` package and more broadly, the HTML `<code>` element has an implicit ARIA role of `code` per WAI-ARIA 1.3, and `testing-library/dom` / jsdom supports it. Therefore, `screen.getByRole('code')` / `screen.findByRole('code')` correctly locates `<code>` elements without needing an explicit `role="code"` attribute. Do NOT flag `findByRole('code')` as invalid in future reviews.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-02-10T16:32:42.586Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38528
File: apps/meteor/client/startup/roles.ts:14-14
Timestamp: 2026-02-10T16:32:42.586Z
Learning: In Rocket.Chat's Meteor client code, DDP streams use EJSON and Date fields arrive as Date objects; do not manually construct new Date() in stream handlers (for example, in sdk.stream()). Only REST API responses return plain JSON where dates are strings, so implement explicit conversion there if needed. Apply this guidance to all TypeScript files under apps/meteor/client to ensure consistent date handling in DDP streams and REST responses.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.
Applied to files:
apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts
📚 Learning: 2026-04-10T22:42:05.539Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 40075
File: apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx:69-71
Timestamp: 2026-04-10T22:42:05.539Z
Learning: In `apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx`, the submit handler converts an empty/whitespace-only description to `undefined` (`description?.trim() || undefined`) intentionally. All downstream image-rendering components (`AttachmentImage`, `ImagePreview`, `ImageItem`, `ImageGallery`) default `undefined` alt to `''`, so the `<img alt="">` attribute is always present. Do not flag this `undefined` conversion as a bug preventing alt text from being cleared.
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.tsx
📚 Learning: 2026-03-04T14:16:49.202Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39304
File: packages/ui-contexts/src/ActionManagerContext.ts:26-26
Timestamp: 2026-03-04T14:16:49.202Z
Learning: In `packages/ui-contexts/src/ActionManagerContext.ts` (TypeScript, RocketChat/Rocket.Chat), the `disposeView` method in `IActionManager` uses an intentionally explicit union `UiKit.ModalView['id'] | UiKit.BannerView['viewId'] | UiKit.ContextualBarView['id']` to document which view types are accepted, even though all constituents resolve to the same primitive. The inline `// eslint-disable-next-line typescript-eslint/no-duplicate-type-constituents` comment is intentional and should not be flagged or removed.
Applied to files:
apps/meteor/client/views/room/MessageList/MessageList.tsx
🔇 Additional comments (5)
apps/meteor/client/views/room/body/hooks/useGetMore.spec.tsx (1)
94-94: LGTM!The updated assertion correctly matches the
RoomHistoryManager.getMoreNext(rid)signature, which now accepts only a singleridargument. This aligns with the implementation inRoomHistoryManager.ts.apps/meteor/client/views/room/MessageList/hooks/useTryToJumpToMessage.ts (1)
21-35: LGTM!The React Query setup correctly fetches the message only when
messageJumpParamis present. ThemapMessageFromApitransformation properly converts API date fields to Date objects, matching the internalIMessageshape.apps/meteor/client/views/room/MessageList/MessageList.tsx (3)
115-127: LGTM on scroll restoration logic.The scroll restoration correctly handles both cases: converting stored scroll offset to an item index via
findItemIndex()for index-based scrolling, and falling back to directscrollTo()for offset-based scrolling when the index lookup fails.
78-93: LGTM on prepend handling and bottom detection.The
handlePrependcallback correctly:
- Enables shift mode when scrolled near top (
offset < 200) for smooth prepending- Calculates
isAtBottombased on scroll position relative to scroll size and viewport- Resets
shouldJumpToBottomwhen the user is at the bottom
159-176: LGTM on unread mark visibility detection.The
isUnreadMarkVisiblecallback correctly accounts for the leading preview row offset and computes the visible viewport range usingfindItemIndex(). The min/max comparison handles both scroll directions.
| align: 'end', | ||
| }); | ||
| } | ||
| }, [isAtBottom, messages, shouldJumpToBottom.current, isJumpingToMessage.current, rid, firstUnreadMessageId]); |
There was a problem hiding this comment.
Ref .current values in dependency array don't trigger effect re-runs.
shouldJumpToBottom.current and isJumpingToMessage.current are ref values. React's useEffect doesn't track ref mutations, so the effect won't re-run when these values change. The effect only runs when messages or rid change.
If the intent is to read the latest ref values during each effect run (not to trigger re-runs), remove .current from the dependencies and keep only the refs themselves, or remove them entirely since refs are stable:
🔧 Proposed fix
- }, [isAtBottom, messages, shouldJumpToBottom.current, isJumpingToMessage.current, rid, firstUnreadMessageId]);
+ }, [isAtBottom, messages, shouldJumpToBottom, isJumpingToMessage, rid, firstUnreadMessageId]);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| }, [isAtBottom, messages, shouldJumpToBottom.current, isJumpingToMessage.current, rid, firstUnreadMessageId]); | |
| }, [isAtBottom, messages, shouldJumpToBottom, isJumpingToMessage, rid, firstUnreadMessageId]); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/client/views/room/MessageList/MessageList.tsx` at line 147, The
effect's dependency array incorrectly uses ref `.current` values
(shouldJumpToBottom.current, isJumpingToMessage.current) which don't trigger
reruns; update the dependency array to either remove those `.current` entries
entirely if the effect doesn't need to rerun on ref mutations, or replace them
with the ref objects (shouldJumpToBottom, isJumpingToMessage) so React sees
stable refs (but still won't rerun on .current changes) and the effect can read
latest values inside its body; adjust the useEffect dependency list where it's
declared to reference shouldJumpToBottom and isJumpingToMessage (or omit them)
along with the existing messages, rid, isAtBottom, firstUnreadMessageId.
| if (showUnreadDivider) { | ||
| unreadMarkIndex.current = index; | ||
| } else { | ||
| // Manually unsets the unread mark index when the divider is not visible to avoid stale state | ||
| unreadMarkIndex.current = null; | ||
| } |
There was a problem hiding this comment.
Unread mark index is incorrectly reset by subsequent messages.
The else branch (line 238) resets unreadMarkIndex.current = null for every message that doesn't show the divider. Since this runs inside the .map() loop, messages after the unread divider will overwrite the index with null.
For example, if the divider is at message index 5 out of 10, messages 6-9 will each set it back to null, and isUnreadMarkVisible() will always return false.
🔧 Proposed fix: Reset once before the loop, set only when divider found
+ // Reset before rendering messages
+ unreadMarkIndex.current = null;
+
{messages.map((message, index, { [index - 1]: previous }) => {
const sequential = isMessageSequential(message, previous, messageGroupingPeriod);
const showUnreadDivider = firstUnreadMessageId === message._id;
const system = MessageTypes.isSystemMessage(message);
const visible = !isThreadMessage(message) && !system;
if (showUnreadDivider) {
unreadMarkIndex.current = index;
- } else {
- // Manually unsets the unread mark index when the divider is not visible to avoid stale state
- unreadMarkIndex.current = null;
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/meteor/client/views/room/MessageList/MessageList.tsx` around lines 234 -
239, The unread mark is being nulled inside the per-message mapping which causes
later messages to overwrite the found index; before iterating, reset
unreadMarkIndex.current = null once, and inside the loop only set
unreadMarkIndex.current = index when showUnreadDivider is true (remove the else
branch that clears it). Update the logic around the map that computes
showUnreadDivider/unreadMarkIndex (referencing unreadMarkIndex,
showUnreadDivider and isUnreadMarkVisible) so the index is initialized once
before the loop and only assigned when the divider is encountered.
bbcaa92 to
ea7d275
Compare
Proposed changes (including videos or screenshots)
Migrates the main message list to a virtualized solution to improve performance
I'm using this storybook as an example/guide https://inokawa.github.io/virtua/?path=/story/advanced-chat--default
TODO:
Possible next steps:
Existing issues (that will not be fixed on this PR):
Issue(s)
Summary by CodeRabbit
New Features
Bug Fixes
Tests