Skip to content

fix: close thread sidebar when main message is not found or already deleted#40042

Open
adwait50 wants to merge 2 commits intoRocketChat:developfrom
adwait50:fix/thread-stuck-on-deleted-message
Open

fix: close thread sidebar when main message is not found or already deleted#40042
adwait50 wants to merge 2 commits intoRocketChat:developfrom
adwait50:fix/thread-stuck-on-deleted-message

Conversation

@adwait50
Copy link
Copy Markdown

@adwait50 adwait50 commented Apr 3, 2026

Problem

When a user clicks on a "Message removed" placeholder that was part of a thread, the thread sidebar opens but becomes completely stuck:

  • The close (X) button does not work
  • Clicking "View Thread" on other valid messages does not update the sidebar
  • The only recovery is a full page reload (F5)

Root Cause

useThreadMainMessageQuery throws 'Invalid main message' when the thread's main message no longer exists (already deleted). This puts the query into an isError state.

The Thread component only handled isLoading and isSuccess states — the isError state was never accounted for, so the sidebar rendered with no content and no way to close or recover without a page reload.

Fix

Added a useEffect in Thread.tsx that calls closeTab() whenever the query enters an error state. This ensures the sidebar closes immediately and cleanly if the thread main message cannot be found, instead of getting stuck.

Steps to Test

  1. Go to any channel where a message has been deleted (showing "Message removed")
  2. Click on the "Message removed" placeholder
  3. Before fix: Thread sidebar opens and gets stuck — X button unresponsive
  4. After fix: Thread sidebar does not open / closes immediately

Related

Closes #40036

Summary by CodeRabbit

  • Chores
    • Minor internal code update with no user-facing changes.

…eleted

When a user clicks on a 'Message removed' placeholder that was part of a
thread, the thread sidebar would open but become stuck — the close button
would not work and switching to other threads would fail.

This happened because useThreadMainMessageQuery throws 'Invalid main message'
when the message no longer exists, putting the query in an error state. The
component only handled isLoading and isSuccess states, never isError, so the
sidebar rendered with no content and no cleanup.

Fix: add a useEffect that calls closeTab() when the query enters an error
state, ensuring the sidebar closes immediately if the thread main message
cannot be found.

Fixes RocketChat#40036
@adwait50 adwait50 requested a review from a team as a code owner April 3, 2026 19:49
@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot bot commented Apr 3, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 3, 2026

⚠️ No Changeset found

Latest commit: 2eebc21

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

Walkthrough

A single line import was added to the Thread component to enable proper state management for handling thread UI transitions, particularly addressing state persistence when interacting with deleted messages.

Changes

Cohort / File(s) Summary
Thread Component Import
apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx
Added useEffect import from React to manage component lifecycle and state transitions when switching between threads.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

Suggested labels

type: bug

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title clearly summarizes the main fix: closing the thread sidebar when the main message is not found or deleted, which directly addresses the bug described in the changeset.
Linked Issues check ✅ Passed PR addresses the core objective from #40036 by adding a useEffect to handle the error state when the thread's main message cannot be found, closing the sidebar automatically as expected.
Out of Scope Changes check ✅ Passed The single change (adding useEffect import) is directly scoped to implementing the fix for the stuck thread sidebar issue, with no unrelated modifications present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

Copy link
Copy Markdown
Contributor

@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

🤖 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/contextualBar/Threads/Thread.tsx`:
- Line 23: Add a useEffect inside the Thread component that watches
mainMessageQueryResult.isError and calls closeTab() when it becomes true; locate
the Thread component (where mainMessageQueryResult and closeTab are
defined/used) and after the existing hooks add: useEffect(() => { if
(mainMessageQueryResult?.isError) closeTab(); },
[mainMessageQueryResult?.isError, closeTab]); to ensure the sidebar closes when
the main message query errors out.
🪄 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: 6d5cf5de-baf7-4bd3-a96b-edefd79eafee

📥 Commits

Reviewing files that changed from the base of the PR and between 8ebf44b and 2eebc21.

📒 Files selected for processing (1)
  • apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx
📜 Review details
🧰 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/contextualBar/Threads/Thread.tsx
🧠 Learnings (3)
📓 Common learnings
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: 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/contextualBar/Threads/Thread.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/contextualBar/Threads/Thread.tsx

useRoomToolbox,
} from '@rocket.chat/ui-contexts';
import { createPortal } from 'react-dom';
import { useEffect } from 'react';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: useEffect imported but never used; the PR's stated fix is not implemented.

The import is added but there is no corresponding useEffect hook in the component. According to the PR description, the fix should add a useEffect that monitors mainMessageQueryResult.isError and calls closeTab() to prevent the stuck sidebar when the thread's main message is deleted. However, this logic is completely missing from the implementation.

Currently, the component only handles isLoading and isSuccess states (lines 114-116, 135-141), leaving the isError state unhandled—which is the root cause of the bug this PR claims to fix.

🔧 Implement the missing error handling

Add the useEffect hook after line 45 to close the sidebar when the query fails:

 	const mainMessageQueryResult = useThreadMainMessageQuery(tmid, {
 		onDelete: () => {
 			closeTab();
 		},
 	});
+
+	useEffect(() => {
+		if (mainMessageQueryResult.isError) {
+			closeTab();
+		}
+	}, [mainMessageQueryResult.isError, closeTab]);
 
 	const t = useTranslation();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx` at line 23,
Add a useEffect inside the Thread component that watches
mainMessageQueryResult.isError and calls closeTab() when it becomes true; locate
the Thread component (where mainMessageQueryResult and closeTab are
defined/used) and after the existing hooks add: useEffect(() => { if
(mainMessageQueryResult?.isError) closeTab(); },
[mainMessageQueryResult?.isError, closeTab]); to ensure the sidebar closes when
the main message query errors out.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sticky Thread UI Bug on Deleted Messages

1 participant