feat: Add dynamic Hide/Unhide toggle for channels#38873
feat: Add dynamic Hide/Unhide toggle for channels#38873satyansh911 wants to merge 5 commits intoRocketChat:developfrom
Conversation
- Add useUnhideRoomAction hook to unhide channels - Update Room Info panel to show Hide/Unhide based on channel state - Update sidebar context menu with dynamic Hide/Unhide option - Update Teams info panel with Hide/Unhide toggle - Add translation keys for Unhide functionality - Fix error toast when clicking Hide on already-hidden channel Fixes inconsistent hide behavior and missing UI affordances
|
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 |
🦋 Changeset detectedLatest commit: 80536ee The changes in this PR will be included in the next version bump. This PR includes changesets to release 42 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughAdds an Unhide action and UI toggle for hidden rooms and teams. Introduces a new Changes
Sequence DiagramsequenceDiagram
participant User as User (UI)
participant Menu as Menu Component
participant Hook as useUnhideRoomAction
participant Mutation as useMutation
participant API as Open Room API
participant Sub as Subscription Store
participant Toast as Toast Service
User->>Menu: Click "Unhide"
Menu->>Hook: call handleUnhide(rid, type)
Hook->>Mutation: trigger mutation
Mutation->>Sub: onMutate → optimistic update (subscription.open = true)
Mutation->>API: POST to resolved endpoint (open/unhide)
alt Success
API-->>Mutation: 200 OK
Mutation->>Toast: show "Room unhidden successfully"
else Error
API-->>Mutation: error
Mutation->>Sub: rollback subscription.open to previous value
Mutation->>Toast: show error toast
end
Toast-->>User: display feedback
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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 |
There was a problem hiding this comment.
Pull request overview
This PR adds dynamic Hide/Unhide functionality for channels, eliminating the error toast that previously appeared when trying to hide an already-hidden channel. The implementation adds a new useUnhideRoomAction hook and updates three key areas (Room Info panel, Teams info panel, and sidebar context menu) to conditionally display "Hide" or "Unhide" based on the subscription's open state.
Changes:
- Introduced
useUnhideRoomActionhook to handle unhiding channels via type-specific API endpoints - Modified three action menus to dynamically toggle between Hide/Unhide options based on
subscription?.open === false - Added translation keys "Unhide" and "Room_unhidden_successfully" for user feedback
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/i18n/src/locales/en.i18n.json | Added translation keys for "Unhide" and success message |
| apps/meteor/client/hooks/useUnhideRoomAction.tsx | New hook implementing unhide functionality with optimistic updates and error handling |
| apps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.ts | Updated Room Info panel to show dynamic Hide/Unhide toggle based on subscription state |
| apps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts | Updated Teams info panel with conditional Hide/Unhide display |
| apps/meteor/client/hooks/useRoomMenuActions.ts | Updated sidebar context menu with dynamic Hide/Unhide option |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
apps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.ts (1)
36-41: Add room-type guard for consistency with useRoomMenuActions — Hide/Unhide action is unconditionally included.In
useRoomMenuActions.ts(line 65), the hide/unhide action is guarded with!isOmnichannelRoom. Here it's always included, though the Info UI itself is restricted to channels/groups viauseChannelSettingsRoomAction. For defensive programming and consistency, consider adding the same room-type guard:room.t !== 'l' && { id: isRoomHidden ? 'unhide' : 'hide', content: isRoomHidden ? t('Unhide') : t('Hide'), icon: isRoomHidden ? ('eye' as const) : ('eye-off' as const), onClick: isRoomHidden ? handleUnhide : handleHide, },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.ts` around lines 36 - 41, Add the same omnichannel room-type guard used in useRoomMenuActions to the hide/unhide action in useRoomActions.ts: only include the action when room.t !== 'l' (i.e., not an omnichannel/live chat room). Locate the action object that references isRoomHidden, handleHide and handleUnhide and wrap it with the guard so the hide/unhide menu entry is omitted for omnichannel rooms, preserving the existing content, id, icon and onClick behavior.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/meteor/client/hooks/useRoomMenuActions.tsapps/meteor/client/hooks/useUnhideRoomAction.tsxapps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.tsapps/meteor/client/views/teams/contextualBar/info/useTeamActions.tspackages/i18n/src/locales/en.i18n.json
🧰 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/hooks/useRoomMenuActions.tsapps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.tsapps/meteor/client/views/teams/contextualBar/info/useTeamActions.tsapps/meteor/client/hooks/useUnhideRoomAction.tsx
🧠 Learnings (6)
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.
Applied to files:
apps/meteor/client/hooks/useRoomMenuActions.tsapps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.tsapps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.
Applied to files:
apps/meteor/client/hooks/useRoomMenuActions.tsapps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.tsapps/meteor/client/views/teams/contextualBar/info/useTeamActions.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/hooks/useRoomMenuActions.tsapps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.tsapps/meteor/client/views/teams/contextualBar/info/useTeamActions.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/contextualBar/Info/hooks/useRoomActions.tsapps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts
📚 Learning: 2025-11-19T12:32:29.696Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.696Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.
Applied to files:
packages/i18n/src/locales/en.i18n.json
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Applied to files:
apps/meteor/client/hooks/useUnhideRoomAction.tsx
🧬 Code graph analysis (4)
apps/meteor/client/hooks/useRoomMenuActions.ts (1)
apps/meteor/client/hooks/useUnhideRoomAction.tsx (1)
useUnhideRoomAction(21-53)
apps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.ts (3)
packages/ui-contexts/src/index.ts (1)
useUserSubscription(88-88)apps/meteor/client/views/room/contextualBar/Info/hooks/actions/useRoomLeave.tsx (1)
useRoomLeave(12-51)apps/meteor/client/hooks/useUnhideRoomAction.tsx (1)
useUnhideRoomAction(21-53)
apps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts (2)
packages/ui-contexts/src/index.ts (1)
useUserSubscription(88-88)apps/meteor/client/hooks/useUnhideRoomAction.tsx (1)
useUnhideRoomAction(21-53)
apps/meteor/client/hooks/useUnhideRoomAction.tsx (2)
packages/apps-engine/src/definition/rooms/index.ts (1)
RoomType(14-14)packages/ui-contexts/src/index.ts (4)
useTranslation(81-81)useToastMessageDispatch(78-78)useUserId(85-85)useEndpoint(34-34)
⏰ 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: Agent
- GitHub Check: cubic · AI code reviewer
🔇 Additional comments (5)
packages/i18n/src/locales/en.i18n.json (1)
2501-2502: LGTM — new i18n keys added in the correct file.
These additions match the repo’s i18n workflow and look good.Based on learnings: “In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English.”
apps/meteor/client/hooks/useUnhideRoomAction.tsx (1)
28-46: Optimistic update and rollback pattern looks solid.The
onMutate→ optimistic update →onErrorrollback flow follows the standardreact-querypattern correctly. The rollback properly restores the previousopenstate from the context returned byonMutate.apps/meteor/client/hooks/useRoomMenuActions.ts (1)
37-37: Clean implementation of the Hide/Unhide toggle.The
subscription?.open === falsecheck is safely strict (won't trigger forundefinedsubscription), and the omnichannel guard on Line 65 already prevents this action for livechat rooms. The icon semantics (eyefor Unhide,eye-offfor Hide) are intuitive.Also applies to: 66-69
apps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.ts (1)
108-120: Dependency array is complete.All variables referenced inside the
useMemocallback are properly included in the dependency array, including the newhandleUnhideandisRoomHidden.apps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts (1)
18-22: Consistent implementation with the other action hooks.The subscription-based
isRoomHiddenderivation, dynamic toggle, and dependency tracking all follow the same pattern used inuseRoomMenuActionsanduseRoomActions. Since teams map toporcroom types, the endpoint lookup inuseUnhideRoomActionwill resolve correctly.Also applies to: 31-34
🤖 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/hooks/useUnhideRoomAction.tsx`:
- Around line 14-19: Remove the inline comments inside the
OPEN_ENDPOINTS_BY_ROOM_TYPE constant so the object contains only the mapping
entries (e.g., p: '/v1/groups.open', c: '/v1/channels.open', d: '/v1/im.open',
l: '/v1/channels.open'); locate the constant named OPEN_ENDPOINTS_BY_ROOM_TYPE
and delete the trailing "// private", "// channel", "// direct message", and "//
livechat" comments, keeping the rest of the mapping intact and unchanged.
---
Nitpick comments:
In `@apps/meteor/client/views/room/contextualBar/Info/hooks/useRoomActions.ts`:
- Around line 36-41: Add the same omnichannel room-type guard used in
useRoomMenuActions to the hide/unhide action in useRoomActions.ts: only include
the action when room.t !== 'l' (i.e., not an omnichannel/live chat room). Locate
the action object that references isRoomHidden, handleHide and handleUnhide and
wrap it with the guard so the hide/unhide menu entry is omitted for omnichannel
rooms, preserving the existing content, id, icon and onClick behavior.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ns.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts (1)
28-34: Gate the hide/unhide item onsubscriptionexistence to match the pattern used for all other conditional actions.The hide/unhide item is unconditionally inserted into the action list, while every other action (edit, leave, convert, delete) uses the conditional spread pattern
...(condition ? [item] : []). When a non-member admin views the team info panel wheresubscriptionisundefined, the "Hide" option is rendered and clickable, butuseHideRoomActionhas no guard against a missing subscription—it directly invokes the endpoint.♻️ Suggested implementation
- { - id: isRoomHidden ? 'unhide' : 'hide', - content: isRoomHidden ? t('Unhide') : t('Hide'), - icon: isRoomHidden ? ('eye' as const) : ('eye-off' as const), - onClick: isRoomHidden ? unhideTeam : hideTeam, - }, + ...(subscription + ? [ + { + id: isRoomHidden ? 'unhide' : 'hide', + content: isRoomHidden ? t('Unhide') : t('Hide'), + icon: isRoomHidden ? ('eye' as const) : ('eye-off' as const), + onClick: isRoomHidden ? unhideTeam : hideTeam, + }, + ] + : []),Also add
subscriptionto theuseMemodependency array:- [t, hideTeam, unhideTeam, isRoomHidden, leaveTeam, onClickEdit, handleDelete, canDeleteRoom, convertToChannel], + [t, hideTeam, unhideTeam, isRoomHidden, subscription, leaveTeam, onClickEdit, handleDelete, canDeleteRoom, convertToChannel],🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts` around lines 28 - 34, The hide/unhide menu item is always pushed into items even when subscription is undefined, causing hideTeam/unhideTeam (from useHideRoomAction) to be called without a subscription; gate the item the same way as other conditional actions by changing the items array to use the spread pattern ...(subscription ? [{ id: isRoomHidden ? 'unhide' : 'hide', content: isRoomHidden ? t('Unhide') : t('Hide'), icon: isRoomHidden ? ('eye' as const) : ('eye-off' as const), onClick: isRoomHidden ? unhideTeam : hideTeam }] : []) and add subscription to the useMemo dependency array so the menu updates correctly when subscription changes.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/meteor/client/hooks/useUnhideRoomAction.tsxapps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/meteor/client/hooks/useUnhideRoomAction.tsx
🧰 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/teams/contextualBar/info/useTeamActions.ts
🧠 Learnings (4)
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.
Applied to files:
apps/meteor/client/views/teams/contextualBar/info/useTeamActions.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/teams/contextualBar/info/useTeamActions.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.
Applied to files:
apps/meteor/client/views/teams/contextualBar/info/useTeamActions.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/teams/contextualBar/info/useTeamActions.ts
🧬 Code graph analysis (1)
apps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts (2)
packages/ui-contexts/src/index.ts (1)
useUserSubscription(88-88)apps/meteor/client/hooks/useUnhideRoomAction.tsx (1)
useUnhideRoomAction(14-46)
🔇 Additional comments (2)
apps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts (2)
18-19: LGTM —isRoomHiddenlogic is sound.
ISubscription.openis a non-optionalbooleanused by clients to determine whether the room is visible in the user's sidebar. The optional-chain default (undefined?.open === false→false) correctly treats a missing subscription as "not hidden", so the fallback to the Hide action is safe.
21-21:⚠️ Potential issue | 🟡 MinorRemove unused
typeparameter fromuseUnhideRoomActionor mark intent if needed.The hook destructures
typein its signature (line 14 ofapps/meteor/client/hooks/useUnhideRoomAction.tsx) but never references it in the function body. Either removetypefromUnhideRoomPropsto keep the API minimal, or add// eslint-disable-next-linewith a comment if it's planned for future use (analytics, logging, etc.).⛔ Skipped due to learnings
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 **/*.{ts,tsx,js} : Avoid code comments in the implementationLearnt from: Dnouv Repo: RocketChat/Rocket.Chat PR: 37057 File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27 Timestamp: 2025-09-25T09:59:26.461Z Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@apps/meteor/client/views/teams/contextualBar/info/useTeamActions.ts`:
- Around line 28-34: The hide/unhide menu item is always pushed into items even
when subscription is undefined, causing hideTeam/unhideTeam (from
useHideRoomAction) to be called without a subscription; gate the item the same
way as other conditional actions by changing the items array to use the spread
pattern ...(subscription ? [{ id: isRoomHidden ? 'unhide' : 'hide', content:
isRoomHidden ? t('Unhide') : t('Hide'), icon: isRoomHidden ? ('eye' as const) :
('eye-off' as const), onClick: isRoomHidden ? unhideTeam : hideTeam }] : []) and
add subscription to the useMemo dependency array so the menu updates correctly
when subscription changes.
Description
Adds a dynamic Hide/Unhide button for channels that eliminates the error toast when trying to hide an already-hidden channel.
Changes Made
useUnhideRoomActionhook to handle unhiding channelsUnhideandRoom_unhidden_successfullyScreenshots
Testing
Before:
After:
Steps to Test:
Related Issues
Fixes: #38838
Closes #38838
Summary by CodeRabbit
New Features
Bug Fixes