From 0f2c84193801f9502b944ad5d213baa77941d497 Mon Sep 17 00:00:00 2001
From: Tasso Evangelista <tasso.evangelista@rocket.chat>
Date: Mon, 31 Jul 2023 10:01:04 -0300
Subject: [PATCH] refactor: Room toolbox quirks (#29959)

---
 .../app/reactions/client/{init.js => init.ts} |   6 +-
 .../app/ui-utils/client/lib/MessageAction.ts  | 152 ++++--------------
 .../client/lib/messageActionDefault.ts        |   5 +-
 .../app/lib/CommonRoomTemplateInstance.ts     |  12 --
 ...boxHolder.tsx => MessageToolboxHolder.tsx} |  25 +--
 .../{Toolbox.tsx => MessageToolbox.tsx}       |  36 ++---
 .../message/variants/RoomMessage.tsx          |   4 +-
 .../message/variants/ThreadMessage.tsx        |   4 +-
 apps/meteor/client/lib/getPermaLink.ts        |  39 +++++
 .../client/lib/utils/legacyJumpToMessage.ts   |   4 -
 .../meteor/client/lib/utils/prependReplies.ts |   4 +-
 .../startup/actionButtons/permalinkPinned.ts  |   3 +-
 .../startup/actionButtons/permalinkStar.ts    |   3 +-
 .../moderation/ModerationConsolePage.tsx      |   4 +-
 .../contactHistory/ContactHistory.tsx         |   8 +-
 .../contextualBar/CallsContextualBarRoom.tsx  |   7 +-
 .../contextualBar/ChatsContextualBar.tsx      |   2 +-
 .../contextualBar/ContactsContextualBar.tsx   |   2 +-
 .../outlookCalendar/OutlookEventsRoute.tsx    |   2 +-
 .../Omnichannel/OmnichannelRoomHeader.tsx     |  17 +-
 .../Header/Omnichannel/VoipRoomHeader.tsx     |  17 +-
 .../room/Header/RoomToolbox/RoomToolbox.tsx   |  81 +++++-----
 .../client/views/room/MemberListRouter.js     |   5 +-
 apps/meteor/client/views/room/Room/Room.tsx   |  11 +-
 .../views/room/components/body/RoomBody.tsx   |   9 +-
 .../contextualBar/MessageListTab.tsx          |   2 +-
 .../views/room/contexts/RoomAPIContext.ts     |   5 -
 .../views/room/contexts/RoomToolboxContext.ts |  25 +++
 .../views/room/contexts/ToolboxContext.ts     |  35 ----
 .../room/contextualBar/Apps/AppsWithData.tsx  |   2 +-
 .../AutoTranslate/AutoTranslateWithData.tsx   |   2 +-
 .../Discussions/DiscussionsListContextBar.tsx |   2 +-
 .../ExportMessages/ExportMessages.tsx         |   2 +-
 .../Info/EditRoomInfo/EditChannelWithData.js  |   2 +-
 .../contextualBar/Info/RoomInfoRouter.tsx     |   2 +-
 .../KeyboardShortcuts.stories.tsx             |   2 +-
 .../KeyboardShortcutsWithData.tsx             |   9 +-
 .../MessageSearchTab/MessageSearchTab.tsx     |  11 +-
 .../NotificationPreferencesWithData.tsx       |   2 +-
 .../room/contextualBar/OTR/OTRWithData.tsx    |   2 +-
 .../PruneMessages/PruneMessagesWithData.tsx   |  19 +--
 .../RoomFiles/RoomFilesWithData.js            |   2 +-
 .../RoomMembers/AddUsers/AddUsersWithData.tsx |   2 +-
 .../InviteUsers/InviteUsersWithData.tsx       |   2 +-
 .../RoomMembers/RoomMembersWithData.tsx       |   2 +-
 .../room/contextualBar/Threads/Thread.tsx     |   2 +-
 .../room/contextualBar/Threads/ThreadList.tsx |   2 +-
 .../room/contextualBar/Threads/Threads.tsx    |   4 +-
 .../Threads/components/ThreadChat.tsx         |   2 +-
 .../VideoConfList/VideoConfListWithData.tsx   |   2 +-
 .../client/views/room/lib/Toolbox/index.tsx   |  46 ++----
 .../views/room/providers/RoomProvider.tsx     |  15 +-
 .../room/providers/RoomToolboxProvider.tsx    | 101 ++++++------
 .../views/room/providers/VirtualAction.tsx    |  56 -------
 .../providers/hooks/useCoreRoomActions.ts     |   6 +-
 .../views/room/providers/hooks/useUserCard.ts |   2 +-
 .../contextualBar/channels/TeamsChannels.tsx  |   2 +-
 .../contextualBar/info/TeamsInfoWithData.js   |   2 +-
 .../ee/client/apps/gameCenter/GameCenter.tsx  |   2 +-
 .../CannedResponse/CannedResponseList.tsx     |   4 +-
 .../contextualBar/CannedResponse/index.tsx    |   8 +-
 .../views/room/MessageList/Message.spec.tsx   |   2 +-
 62 files changed, 320 insertions(+), 532 deletions(-)
 rename apps/meteor/app/reactions/client/{init.js => init.ts} (83%)
 delete mode 100644 apps/meteor/app/ui/client/views/app/lib/CommonRoomTemplateInstance.ts
 rename apps/meteor/client/components/message/{ToolboxHolder.tsx => MessageToolboxHolder.tsx} (64%)
 rename apps/meteor/client/components/message/toolbox/{Toolbox.tsx => MessageToolbox.tsx} (82%)
 create mode 100644 apps/meteor/client/lib/getPermaLink.ts
 delete mode 100644 apps/meteor/client/views/room/contexts/RoomAPIContext.ts
 create mode 100644 apps/meteor/client/views/room/contexts/RoomToolboxContext.ts
 delete mode 100644 apps/meteor/client/views/room/contexts/ToolboxContext.ts
 delete mode 100644 apps/meteor/client/views/room/providers/VirtualAction.tsx

diff --git a/apps/meteor/app/reactions/client/init.js b/apps/meteor/app/reactions/client/init.ts
similarity index 83%
rename from apps/meteor/app/reactions/client/init.js
rename to apps/meteor/app/reactions/client/init.ts
index de690b66810..b670b5c6d41 100644
--- a/apps/meteor/app/reactions/client/init.js
+++ b/apps/meteor/app/reactions/client/init.ts
@@ -12,9 +12,9 @@ Meteor.startup(() => {
 		label: 'Add_Reaction',
 		context: ['message', 'message-mobile', 'threads', 'federated'],
 		action(event, props) {
-			event.stopPropagation();
 			const { message = messageArgs(this).msg, chat } = props;
-			chat?.emojiPicker.open(event.currentTarget, (emoji) => sdk.call('setReaction', `:${emoji}:`, message._id));
+			event.stopPropagation();
+			chat?.emojiPicker.open(event.currentTarget! as Element, (emoji) => sdk.call('setReaction', `:${emoji}:`, message._id));
 		},
 		condition({ message, user, room, subscription }) {
 			if (!room) {
@@ -29,7 +29,7 @@ Meteor.startup(() => {
 				return false;
 			}
 
-			if (roomCoordinator.readOnly(room._id, user) && !room.reactWhenReadOnly) {
+			if (roomCoordinator.readOnly(room._id, user!) && !room.reactWhenReadOnly) {
 				return false;
 			}
 			const isLivechatRoom = roomCoordinator.isLivechatRoom(room.t);
diff --git a/apps/meteor/app/ui-utils/client/lib/MessageAction.ts b/apps/meteor/app/ui-utils/client/lib/MessageAction.ts
index 18687dae44c..a0a350adc77 100644
--- a/apps/meteor/app/ui-utils/client/lib/MessageAction.ts
+++ b/apps/meteor/app/ui-utils/client/lib/MessageAction.ts
@@ -1,29 +1,15 @@
-import type { IMessage, IUser, ISubscription, IRoom, SettingValue, Serialized, ITranslatedMessage } from '@rocket.chat/core-typings';
+import type { IMessage, IUser, ISubscription, IRoom, SettingValue, ITranslatedMessage } from '@rocket.chat/core-typings';
 import type { Keys as IconName } from '@rocket.chat/icons';
 import type { TranslationKey } from '@rocket.chat/ui-contexts';
 import mem from 'mem';
-import { Meteor } from 'meteor/meteor';
-import { ReactiveVar } from 'meteor/reactive-var';
-import { Tracker } from 'meteor/tracker';
 import type { ContextType } from 'react';
 
-import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator';
 import type { AutoTranslateOptions } from '../../../../client/views/room/MessageList/hooks/useAutoTranslate';
 import type { ChatContext } from '../../../../client/views/room/contexts/ChatContext';
-import type { ToolboxContextValue } from '../../../../client/views/room/contexts/ToolboxContext';
-import { Messages, ChatRoom, Subscriptions } from '../../../models/client';
-import { sdk } from '../../../utils/client/lib/SDKClient';
-
-const getMessage = async (msgId: string): Promise<Serialized<IMessage> | null> => {
-	try {
-		const { message } = await sdk.rest.get('/v1/chat.getMessage', { msgId });
-		return message;
-	} catch {
-		return null;
-	}
-};
+import type { RoomToolboxContextValue } from '../../../../client/views/room/contexts/RoomToolboxContext';
 
 type MessageActionGroup = 'message' | 'menu';
+
 export type MessageActionContext =
 	| 'message'
 	| 'threads'
@@ -58,7 +44,8 @@ export type MessageActionConfig = {
 	group?: MessageActionGroup | MessageActionGroup[];
 	context?: MessageActionContext[];
 	action: (
-		e: Pick<Event, 'preventDefault' | 'stopPropagation'>,
+		this: any,
+		e: Pick<Event, 'preventDefault' | 'stopPropagation' | 'currentTarget'>,
 		{
 			message,
 			tabbar,
@@ -67,7 +54,7 @@ export type MessageActionConfig = {
 			autoTranslateOptions,
 		}: {
 			message: IMessage & Partial<ITranslatedMessage>;
-			tabbar: ToolboxContextValue;
+			tabbar: RoomToolboxContextValue;
 			room?: IRoom;
 			chat: ContextType<typeof ChatContext>;
 			autoTranslateOptions?: AutoTranslateOptions;
@@ -76,23 +63,10 @@ export type MessageActionConfig = {
 	condition?: (props: MessageActionConditionProps) => Promise<boolean> | boolean;
 };
 
-type MessageActionConfigList = MessageActionConfig[];
-
-export const MessageAction = new (class {
-	/*
-  	config expects the following keys (only id is mandatory):
-  		id (mandatory)
-  		icon: string
-  		label: string
-  		action: function(event, instance)
-  		condition: function(message)
-			order: integer
-			group: string (message or menu)
-   */
+class MessageAction {
+	public buttons: Record<MessageActionConfig['id'], MessageActionConfig> = {};
 
-	buttons = new ReactiveVar<Record<string, MessageActionConfig>>({});
-
-	addButton(config: MessageActionConfig): void {
+	public addButton(config: MessageActionConfig): void {
 		if (!config?.id) {
 			return;
 		}
@@ -105,106 +79,34 @@ export const MessageAction = new (class {
 			config.condition = mem(config.condition, { maxAge: 1000, cacheKey: JSON.stringify });
 		}
 
-		return Tracker.nonreactive(() => {
-			const btns = this.buttons.get();
-			btns[config.id] = config;
-			mem.clear(this._getButtons);
-			mem.clear(this.getButtonsByGroup);
-			return this.buttons.set(btns);
-		});
-	}
-
-	removeButton(id: MessageActionConfig['id']): void {
-		return Tracker.nonreactive(() => {
-			const btns = this.buttons.get();
-			delete btns[id];
-			return this.buttons.set(btns);
-		});
+		this.buttons[config.id] = config;
 	}
 
-	updateButton(id: MessageActionConfig['id'], config: MessageActionConfig): void {
-		return Tracker.nonreactive(() => {
-			const btns = this.buttons.get();
-			if (btns[id]) {
-				btns[id] = Object.assign(btns[id], config);
-				return this.buttons.set(btns);
-			}
-		});
+	public removeButton(id: MessageActionConfig['id']): void {
+		delete this.buttons[id];
 	}
 
-	getButtonById(id: MessageActionConfig['id']): MessageActionConfig | undefined {
-		const allButtons = this.buttons.get();
-		return allButtons[id];
-	}
-
-	_getButtons = mem((): MessageActionConfigList => Object.values(this.buttons.get()).sort((a, b) => (a.order ?? 0) - (b.order ?? 0)), {
-		maxAge: 1000,
-	});
-
-	async getButtonsByCondition(
-		prop: MessageActionConditionProps,
-		arr: MessageActionConfigList = MessageAction._getButtons(),
-	): Promise<MessageActionConfigList> {
+	public async getAll(
+		props: MessageActionConditionProps,
+		context: MessageActionContext,
+		group: MessageActionGroup,
+	): Promise<MessageActionConfig[]> {
 		return (
 			await Promise.all(
-				arr.map(async (button) => {
-					return [button, !button.condition || (await button.condition(prop))] as const;
-				}),
+				Object.values(this.buttons)
+					.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
+					.filter((button) => !button.group || (Array.isArray(button.group) ? button.group.includes(group) : button.group === group))
+					.filter((button) => !button.context || button.context.includes(context))
+					.map(async (button) => {
+						return [button, !button.condition || (await button.condition({ ...props, context }))] as const;
+					}),
 			)
 		)
 			.filter(([, condition]) => condition)
 			.map(([button]) => button);
 	}
+}
 
-	getButtonsByGroup = mem(
-		(group: MessageActionGroup, arr: MessageActionConfigList = MessageAction._getButtons()): MessageActionConfigList => {
-			return arr.filter((button) => !button.group || (Array.isArray(button.group) ? button.group.includes(group) : button.group === group));
-		},
-		{ maxAge: 1000 },
-	);
-
-	getButtonsByContext(context: MessageActionContext, arr: MessageActionConfigList): MessageActionConfigList {
-		return !context ? arr : arr.filter((button) => !button.context || button.context.includes(context));
-	}
+const instance = new MessageAction();
 
-	async getButtons(
-		props: MessageActionConditionProps,
-		context: MessageActionContext,
-		group: MessageActionGroup,
-	): Promise<MessageActionConfigList> {
-		const allButtons = group ? this.getButtonsByGroup(group) : MessageAction._getButtons();
-
-		if (props.message) {
-			return this.getButtonsByCondition({ ...props, context }, this.getButtonsByContext(context, allButtons));
-		}
-		return allButtons;
-	}
-
-	resetButtons(): void {
-		mem.clear(this._getButtons);
-		mem.clear(this.getButtonsByGroup);
-		return this.buttons.set({});
-	}
-
-	async getPermaLink(msgId: string): Promise<string> {
-		if (!msgId) {
-			throw new Error('invalid-parameter');
-		}
-
-		const msg = Messages.findOne(msgId) || (await getMessage(msgId));
-		if (!msg) {
-			throw new Error('message-not-found');
-		}
-		const roomData = ChatRoom.findOne({
-			_id: msg.rid,
-		});
-
-		if (!roomData) {
-			throw new Error('room-not-found');
-		}
-
-		const subData = Subscriptions.findOne({ 'rid': roomData._id, 'u._id': Meteor.userId() });
-		const roomURL = roomCoordinator.getURL(roomData.t, { ...(subData || roomData), tab: '' });
-		return `${roomURL}?msg=${msgId}`;
-	}
-})();
+export { instance as MessageAction };
diff --git a/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts b/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts
index f7cd1c482e3..e2c216bc5f3 100644
--- a/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts
+++ b/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts
@@ -3,6 +3,7 @@ import { isRoomFederated } from '@rocket.chat/core-typings';
 import { Meteor } from 'meteor/meteor';
 import moment from 'moment';
 
+import { getPermaLink } from '../../../../client/lib/getPermaLink';
 import { imperativeModal } from '../../../../client/lib/imperativeModal';
 import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator';
 import { dispatchToastMessage } from '../../../../client/lib/toast';
@@ -70,7 +71,7 @@ Meteor.startup(async () => {
 		context: ['message', 'message-mobile', 'threads'],
 		async action(_, props) {
 			const { message = messageArgs(this).msg } = props;
-			const permalink = await MessageAction.getPermaLink(message._id);
+			const permalink = await getPermaLink(message._id);
 			imperativeModal.open({
 				component: ShareMessageModal,
 				props: {
@@ -123,7 +124,7 @@ Meteor.startup(async () => {
 		async action(_, props) {
 			try {
 				const { message = messageArgs(this).msg } = props;
-				const permalink = await MessageAction.getPermaLink(message._id);
+				const permalink = await getPermaLink(message._id);
 				await navigator.clipboard.writeText(permalink);
 				dispatchToastMessage({ type: 'success', message: t('Copied') });
 			} catch (e) {
diff --git a/apps/meteor/app/ui/client/views/app/lib/CommonRoomTemplateInstance.ts b/apps/meteor/app/ui/client/views/app/lib/CommonRoomTemplateInstance.ts
deleted file mode 100644
index 2dddb429935..00000000000
--- a/apps/meteor/app/ui/client/views/app/lib/CommonRoomTemplateInstance.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import type { ContextType } from 'react';
-
-import type { ChatContext } from '../../../../../../client/views/room/contexts/ChatContext';
-import type { ToolboxContextValue } from '../../../../../../client/views/room/contexts/ToolboxContext';
-
-export type CommonRoomTemplateInstance = {
-	data: {
-		rid: string;
-		tabBar: ToolboxContextValue;
-		chatContext: ContextType<typeof ChatContext>;
-	};
-};
diff --git a/apps/meteor/client/components/message/ToolboxHolder.tsx b/apps/meteor/client/components/message/MessageToolboxHolder.tsx
similarity index 64%
rename from apps/meteor/client/components/message/ToolboxHolder.tsx
rename to apps/meteor/client/components/message/MessageToolboxHolder.tsx
index 0b5199d29eb..54f4ebab823 100644
--- a/apps/meteor/client/components/message/ToolboxHolder.tsx
+++ b/apps/meteor/client/components/message/MessageToolboxHolder.tsx
@@ -2,19 +2,20 @@ import type { IMessage } from '@rocket.chat/core-typings';
 import { MessageToolboxWrapper } from '@rocket.chat/fuselage';
 import { useQuery } from '@tanstack/react-query';
 import type { ReactElement } from 'react';
-import React, { memo, useRef } from 'react';
+import React, { Suspense, lazy, memo, useRef } from 'react';
 
 import type { MessageActionContext } from '../../../app/ui-utils/client/lib/MessageAction';
 import { useChat } from '../../views/room/contexts/ChatContext';
 import { useIsVisible } from '../../views/room/hooks/useIsVisible';
-import Toolbox from './toolbox/Toolbox';
 
-type ToolboxHolderProps = {
+type MessageToolboxHolderProps = {
 	message: IMessage;
 	context?: MessageActionContext;
 };
 
-const ToolboxHolder = ({ message, context }: ToolboxHolderProps): ReactElement => {
+const MessageToolbox = lazy(() => import('./toolbox/MessageToolbox'));
+
+const MessageToolboxHolder = ({ message, context }: MessageToolboxHolderProps): ReactElement => {
 	const ref = useRef(null);
 
 	const [visible] = useIsVisible(ref);
@@ -33,15 +34,17 @@ const ToolboxHolder = ({ message, context }: ToolboxHolderProps): ReactElement =
 	return (
 		<MessageToolboxWrapper ref={ref}>
 			{visible && depsQueryResult.isSuccess && depsQueryResult.data.room && (
-				<Toolbox
-					message={message}
-					messageContext={context}
-					room={depsQueryResult.data.room}
-					subscription={depsQueryResult.data.subscription}
-				/>
+				<Suspense fallback={null}>
+					<MessageToolbox
+						message={message}
+						messageContext={context}
+						room={depsQueryResult.data.room}
+						subscription={depsQueryResult.data.subscription}
+					/>
+				</Suspense>
 			)}
 		</MessageToolboxWrapper>
 	);
 };
 
-export default memo(ToolboxHolder);
+export default memo(MessageToolboxHolder);
diff --git a/apps/meteor/client/components/message/toolbox/Toolbox.tsx b/apps/meteor/client/components/message/toolbox/MessageToolbox.tsx
similarity index 82%
rename from apps/meteor/client/components/message/toolbox/Toolbox.tsx
rename to apps/meteor/client/components/message/toolbox/MessageToolbox.tsx
index f957c75a81c..efdfc5b0b49 100644
--- a/apps/meteor/client/components/message/toolbox/Toolbox.tsx
+++ b/apps/meteor/client/components/message/toolbox/MessageToolbox.tsx
@@ -1,6 +1,6 @@
 import type { IMessage, IRoom, ISubscription, ITranslatedMessage } from '@rocket.chat/core-typings';
 import { isThreadMessage, isRoomFederated } from '@rocket.chat/core-typings';
-import { MessageToolbox, MessageToolboxItem } from '@rocket.chat/fuselage';
+import { MessageToolbox as FuselageMessageToolbox, MessageToolboxItem } from '@rocket.chat/fuselage';
 import { useFeaturePreview } from '@rocket.chat/ui-client';
 import { useUser, useSettings, useTranslation, useMethod } from '@rocket.chat/ui-contexts';
 import { useQuery } from '@tanstack/react-query';
@@ -15,7 +15,7 @@ import EmojiElement from '../../../views/composer/EmojiPicker/EmojiElement';
 import { useIsSelecting } from '../../../views/room/MessageList/contexts/SelectedMessagesContext';
 import { useAutoTranslate } from '../../../views/room/MessageList/hooks/useAutoTranslate';
 import { useChat } from '../../../views/room/contexts/ChatContext';
-import { useToolboxContext } from '../../../views/room/contexts/ToolboxContext';
+import { useRoomToolbox } from '../../../views/room/contexts/RoomToolboxContext';
 import MessageActionMenu from './MessageActionMenu';
 
 const getMessageContext = (message: IMessage, room: IRoom, context?: MessageActionContext): MessageActionContext => {
@@ -38,16 +38,16 @@ const getMessageContext = (message: IMessage, room: IRoom, context?: MessageActi
 	return 'message';
 };
 
-type ToolboxProps = {
+type MessageToolboxProps = {
 	message: IMessage & Partial<ITranslatedMessage>;
 	messageContext?: MessageActionContext;
 	room: IRoom;
 	subscription?: ISubscription;
 };
 
-const Toolbox = ({ message, messageContext, room, subscription }: ToolboxProps): ReactElement | null => {
+const MessageToolbox = ({ message, messageContext, room, subscription }: MessageToolboxProps): ReactElement | null => {
 	const t = useTranslation();
-	const user = useUser();
+	const user = useUser() ?? undefined;
 	const settings = useSettings();
 
 	const quickReactionsEnabled = useFeaturePreview('quickReactions');
@@ -64,21 +64,15 @@ const Toolbox = ({ message, messageContext, room, subscription }: ToolboxProps):
 	const actionButtonApps = useMessageActionAppsActionButtons(context);
 
 	const actionsQueryResult = useQuery(['rooms', room._id, 'messages', message._id, 'actions'] as const, async () => {
-		const messageActions = await MessageAction.getButtons(
-			{ message, room, user: user ?? undefined, subscription, settings: mapSettings, chat },
-			context,
-			'message',
-		);
-		const menuActions = await MessageAction.getButtons(
-			{ message, room, user: user ?? undefined, subscription, settings: mapSettings, chat },
-			context,
-			'menu',
-		);
-
-		return { message: messageActions, menu: menuActions };
+		const props = { message, room, user, subscription, settings: mapSettings, chat };
+
+		const toolboxItems = await MessageAction.getAll(props, context, 'message');
+		const menuItems = await MessageAction.getAll(props, context, 'menu');
+
+		return { message: toolboxItems, menu: menuItems };
 	});
 
-	const toolbox = useToolboxContext();
+	const toolbox = useRoomToolbox();
 
 	const selecting = useIsSelecting();
 
@@ -96,7 +90,7 @@ const Toolbox = ({ message, messageContext, room, subscription }: ToolboxProps):
 	};
 
 	return (
-		<MessageToolbox>
+		<FuselageMessageToolbox>
 			{quickReactionsEnabled &&
 				isReactionAllowed &&
 				quickReactions.slice(0, 3).map(({ emoji, image }) => {
@@ -122,8 +116,8 @@ const Toolbox = ({ message, messageContext, room, subscription }: ToolboxProps):
 					data-qa-type='message-action-menu-options'
 				/>
 			)}
-		</MessageToolbox>
+		</FuselageMessageToolbox>
 	);
 };
 
-export default memo(Toolbox);
+export default memo(MessageToolbox);
diff --git a/apps/meteor/client/components/message/variants/RoomMessage.tsx b/apps/meteor/client/components/message/variants/RoomMessage.tsx
index 895cc1ec7df..2e82753051a 100644
--- a/apps/meteor/client/components/message/variants/RoomMessage.tsx
+++ b/apps/meteor/client/components/message/variants/RoomMessage.tsx
@@ -17,8 +17,8 @@ import { useJumpToMessage } from '../../../views/room/MessageList/hooks/useJumpT
 import { useChat } from '../../../views/room/contexts/ChatContext';
 import IgnoredContent from '../IgnoredContent';
 import MessageHeader from '../MessageHeader';
+import MessageToolboxHolder from '../MessageToolboxHolder';
 import StatusIndicators from '../StatusIndicators';
-import ToolboxHolder from '../ToolboxHolder';
 import MessageAvatar from '../header/MessageAvatar';
 import RoomMessageContent from './room/RoomMessageContent';
 
@@ -104,7 +104,7 @@ const RoomMessage = ({
 					<RoomMessageContent message={message} unread={unread} mention={mention} all={all} searchText={searchText} />
 				)}
 			</MessageContainer>
-			{!message.private && <ToolboxHolder message={message} context={context} />}
+			{!message.private && <MessageToolboxHolder message={message} context={context} />}
 		</Message>
 	);
 };
diff --git a/apps/meteor/client/components/message/variants/ThreadMessage.tsx b/apps/meteor/client/components/message/variants/ThreadMessage.tsx
index 565e90cf5a8..804b70ba355 100644
--- a/apps/meteor/client/components/message/variants/ThreadMessage.tsx
+++ b/apps/meteor/client/components/message/variants/ThreadMessage.tsx
@@ -10,8 +10,8 @@ import { useJumpToMessage } from '../../../views/room/MessageList/hooks/useJumpT
 import { useChat } from '../../../views/room/contexts/ChatContext';
 import IgnoredContent from '../IgnoredContent';
 import MessageHeader from '../MessageHeader';
+import MessageToolboxHolder from '../MessageToolboxHolder';
 import StatusIndicators from '../StatusIndicators';
-import ToolboxHolder from '../ToolboxHolder';
 import MessageAvatar from '../header/MessageAvatar';
 import ThreadMessageContent from './thread/ThreadMessageContent';
 
@@ -68,7 +68,7 @@ const ThreadMessage = ({ message, sequential, unread, showUserAvatar }: ThreadMe
 
 				{ignored ? <IgnoredContent onShowMessageIgnored={toggleIgnoring} /> : <ThreadMessageContent message={message} />}
 			</MessageContainer>
-			{!message.private && <ToolboxHolder message={message} context='threads' />}
+			{!message.private && <MessageToolboxHolder message={message} context='threads' />}
 		</Message>
 	);
 };
diff --git a/apps/meteor/client/lib/getPermaLink.ts b/apps/meteor/client/lib/getPermaLink.ts
new file mode 100644
index 00000000000..8c74bc7933a
--- /dev/null
+++ b/apps/meteor/client/lib/getPermaLink.ts
@@ -0,0 +1,39 @@
+import type { IMessage, Serialized } from '@rocket.chat/core-typings';
+import { Meteor } from 'meteor/meteor';
+
+const getMessage = async (msgId: string): Promise<Serialized<IMessage> | null> => {
+	try {
+		const { sdk } = await import('../../app/utils/client/lib/SDKClient');
+		const { message } = await sdk.rest.get('/v1/chat.getMessage', { msgId });
+		return message;
+	} catch {
+		return null;
+	}
+};
+
+export const getPermaLink = async (msgId: string): Promise<string> => {
+	if (!msgId) {
+		throw new Error('invalid-parameter');
+	}
+
+	const { ChatMessage, ChatRoom, ChatSubscription } = await import('../../app/models/client');
+
+	const msg = ChatMessage.findOne(msgId) || (await getMessage(msgId));
+	if (!msg) {
+		throw new Error('message-not-found');
+	}
+	const roomData = ChatRoom.findOne({
+		_id: msg.rid,
+	});
+
+	if (!roomData) {
+		throw new Error('room-not-found');
+	}
+
+	const subData = ChatSubscription.findOne({ 'rid': roomData._id, 'u._id': Meteor.userId() });
+
+	const { roomCoordinator } = await import('./rooms/roomCoordinator');
+
+	const roomURL = roomCoordinator.getURL(roomData.t, { ...(subData || roomData), tab: '' });
+	return `${roomURL}?msg=${msgId}`;
+};
diff --git a/apps/meteor/client/lib/utils/legacyJumpToMessage.ts b/apps/meteor/client/lib/utils/legacyJumpToMessage.ts
index 3888e672bdc..c1fcbbbb8f3 100644
--- a/apps/meteor/client/lib/utils/legacyJumpToMessage.ts
+++ b/apps/meteor/client/lib/utils/legacyJumpToMessage.ts
@@ -9,10 +9,6 @@ import { goToRoomById } from './goToRoomById';
 
 /** @deprecated */
 export const legacyJumpToMessage = async (message: IMessage) => {
-	if (matchMedia('(max-width: 500px)').matches) {
-		(Template.instance() as any)?.tabBar?.close();
-	}
-
 	if (isThreadMessage(message) || message.tcount) {
 		const { tab, context } = router.getRouteParameters();
 
diff --git a/apps/meteor/client/lib/utils/prependReplies.ts b/apps/meteor/client/lib/utils/prependReplies.ts
index b4a38d4d63b..47f93435124 100644
--- a/apps/meteor/client/lib/utils/prependReplies.ts
+++ b/apps/meteor/client/lib/utils/prependReplies.ts
@@ -1,11 +1,11 @@
 import type { IMessage } from '@rocket.chat/core-typings';
 
-import { MessageAction } from '../../../app/ui-utils/client/lib/MessageAction';
+import { getPermaLink } from '../getPermaLink';
 
 export const prependReplies = async (msg: string, replies: IMessage[] = []): Promise<string> => {
 	const chunks = await Promise.all(
 		replies.map(async ({ _id }) => {
-			const permalink = await MessageAction.getPermaLink(_id);
+			const permalink = await getPermaLink(_id);
 
 			return `[ ](${permalink})`;
 		}),
diff --git a/apps/meteor/client/startup/actionButtons/permalinkPinned.ts b/apps/meteor/client/startup/actionButtons/permalinkPinned.ts
index f3d67786270..118f9ff4780 100644
--- a/apps/meteor/client/startup/actionButtons/permalinkPinned.ts
+++ b/apps/meteor/client/startup/actionButtons/permalinkPinned.ts
@@ -2,6 +2,7 @@ import { Meteor } from 'meteor/meteor';
 
 import { MessageAction } from '../../../app/ui-utils/client';
 import { t } from '../../../app/utils/lib/i18n';
+import { getPermaLink } from '../../lib/getPermaLink';
 import { dispatchToastMessage } from '../../lib/toast';
 import { messageArgs } from '../../lib/utils/messageArgs';
 
@@ -14,7 +15,7 @@ Meteor.startup(() => {
 		async action(_, props) {
 			try {
 				const { message = messageArgs(this).msg } = props;
-				const permalink = await MessageAction.getPermaLink(message._id);
+				const permalink = await getPermaLink(message._id);
 				navigator.clipboard.writeText(permalink);
 				dispatchToastMessage({ type: 'success', message: t('Copied') });
 			} catch (e) {
diff --git a/apps/meteor/client/startup/actionButtons/permalinkStar.ts b/apps/meteor/client/startup/actionButtons/permalinkStar.ts
index 303cfd5d0f9..60204ffd4e6 100644
--- a/apps/meteor/client/startup/actionButtons/permalinkStar.ts
+++ b/apps/meteor/client/startup/actionButtons/permalinkStar.ts
@@ -2,6 +2,7 @@ import { Meteor } from 'meteor/meteor';
 
 import { MessageAction } from '../../../app/ui-utils/client';
 import { t } from '../../../app/utils/lib/i18n';
+import { getPermaLink } from '../../lib/getPermaLink';
 import { dispatchToastMessage } from '../../lib/toast';
 import { messageArgs } from '../../lib/utils/messageArgs';
 
@@ -15,7 +16,7 @@ Meteor.startup(() => {
 		async action(_, props) {
 			try {
 				const { message = messageArgs(this).msg } = props;
-				const permalink = await MessageAction.getPermaLink(message._id);
+				const permalink = await getPermaLink(message._id);
 				navigator.clipboard.writeText(permalink);
 				dispatchToastMessage({ type: 'success', message: t('Copied') });
 			} catch (e) {
diff --git a/apps/meteor/client/views/admin/moderation/ModerationConsolePage.tsx b/apps/meteor/client/views/admin/moderation/ModerationConsolePage.tsx
index 1d6433d96d9..16445c291f6 100644
--- a/apps/meteor/client/views/admin/moderation/ModerationConsolePage.tsx
+++ b/apps/meteor/client/views/admin/moderation/ModerationConsolePage.tsx
@@ -1,9 +1,9 @@
 import { useTranslation, useRouteParameter, useToastMessageDispatch } from '@rocket.chat/ui-contexts';
 import React from 'react';
 
-import { MessageAction } from '../../../../app/ui-utils/client';
 import { Contextualbar } from '../../../components/Contextualbar';
 import Page from '../../../components/Page';
+import { getPermaLink } from '../../../lib/getPermaLink';
 import MessageReportInfo from './MessageReportInfo';
 import ModerationConsoleTable from './ModerationConsoleTable';
 import UserMessages from './UserMessages';
@@ -16,7 +16,7 @@ const ModerationConsolePage = () => {
 
 	const handleRedirect = async (mid: string) => {
 		try {
-			const permalink = await MessageAction.getPermaLink(mid);
+			const permalink = await getPermaLink(mid);
 			// open the permalink in same tab
 			window.open(permalink, '_self');
 		} catch (error) {
diff --git a/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx b/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx
index c9a5b55e4e4..effb96cf91e 100644
--- a/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx
+++ b/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx
@@ -1,17 +1,19 @@
-import type { ReactElement } from 'react';
 import React, { useState } from 'react';
 
+import { useRoomToolbox } from '../../room/contexts/RoomToolboxContext';
 import ContactHistoryList from './ContactHistoryList';
 import ContactHistoryMessagesList from './MessageList/ContactHistoryMessagesList';
 
-const ContactHistory = ({ tabBar: { close } }: any): ReactElement => {
+const ContactHistory = () => {
 	const [chatId, setChatId] = useState<string>('');
+	const { close: closeTab } = useRoomToolbox();
+
 	return (
 		<>
 			{chatId && chatId !== '' ? (
 				<ContactHistoryMessagesList chatId={chatId} setChatId={setChatId} close={close} />
 			) : (
-				<ContactHistoryList setChatId={setChatId} close={close} />
+				<ContactHistoryList setChatId={setChatId} close={closeTab} />
 			)}
 		</>
 	);
diff --git a/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/CallsContextualBarRoom.tsx b/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/CallsContextualBarRoom.tsx
index 8da33f5424c..5cbbb1199d5 100644
--- a/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/CallsContextualBarRoom.tsx
+++ b/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/CallsContextualBarRoom.tsx
@@ -1,14 +1,15 @@
-import type { ReactElement } from 'react';
 import React from 'react';
 
 import { useVoipRoom } from '../../../../room/contexts/RoomContext';
+import { useRoomToolbox } from '../../../../room/contexts/RoomToolboxContext';
 import { VoipInfo } from './VoipInfo';
 
 // Contextual Bar for room view
-const VoipInfoWithData = ({ tabBar: { close } }: any): ReactElement => {
+const VoipInfoWithData = () => {
 	const room = useVoipRoom();
+	const { close: closeTab } = useRoomToolbox();
 
-	return <VoipInfo room={room} onClickClose={close} />;
+	return <VoipInfo room={room} onClickClose={closeTab} />;
 };
 
 export default VoipInfoWithData;
diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatsContextualBar.tsx b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatsContextualBar.tsx
index f5d48fd39e2..e0d31371a71 100644
--- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatsContextualBar.tsx
+++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatsContextualBar.tsx
@@ -2,7 +2,7 @@ import { useRoute, useRouteParameter, useTranslation } from '@rocket.chat/ui-con
 import React, { useMemo } from 'react';
 
 import { ContextualbarHeader, ContextualbarIcon, ContextualbarTitle, ContextualbarClose } from '../../../../../components/Contextualbar';
-import { useTabBarClose } from '../../../../room/contexts/ToolboxContext';
+import { useTabBarClose } from '../../../../room/contexts/RoomToolboxContext';
 import ChatInfo from './ChatInfo';
 import { RoomEditWithData } from './RoomEdit';
 
diff --git a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactsContextualBar.tsx b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactsContextualBar.tsx
index 4b7e73386df..e72ad2b5af9 100644
--- a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactsContextualBar.tsx
+++ b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactsContextualBar.tsx
@@ -5,7 +5,7 @@ import React from 'react';
 
 import { ContextualbarHeader, ContextualbarIcon, ContextualbarTitle, ContextualbarClose } from '../../../../../components/Contextualbar';
 import { useOmnichannelRoom } from '../../../../room/contexts/RoomContext';
-import { useTabBarClose } from '../../../../room/contexts/ToolboxContext';
+import { useTabBarClose } from '../../../../room/contexts/RoomToolboxContext';
 import ContactEditWithData from './ContactEditWithData';
 import ContactInfo from './ContactInfo';
 
diff --git a/apps/meteor/client/views/outlookCalendar/OutlookEventsRoute.tsx b/apps/meteor/client/views/outlookCalendar/OutlookEventsRoute.tsx
index ce73e326f02..d5a2e16e963 100644
--- a/apps/meteor/client/views/outlookCalendar/OutlookEventsRoute.tsx
+++ b/apps/meteor/client/views/outlookCalendar/OutlookEventsRoute.tsx
@@ -1,6 +1,6 @@
 import React, { useState } from 'react';
 
-import { useTabBarClose } from '../room/contexts/ToolboxContext';
+import { useTabBarClose } from '../room/contexts/RoomToolboxContext';
 import OutlookEventsList from './OutlookEventsList';
 import OutlookSettingsList from './OutlookSettingsList';
 
diff --git a/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx b/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx
index cc7df975051..8405ef43bf5 100644
--- a/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx
+++ b/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx
@@ -6,8 +6,6 @@ import { useSyncExternalStore } from 'use-sync-external-store/shim';
 
 import BurgerMenu from '../../../../components/BurgerMenu';
 import { useOmnichannelRoom } from '../../contexts/RoomContext';
-import { ToolboxContext, useToolboxContext } from '../../contexts/ToolboxContext';
-import type { ToolboxActionConfig } from '../../lib/Toolbox';
 import RoomHeader from '../RoomHeader';
 import { BackButton } from './BackButton';
 import QuickActions from './QuickActions';
@@ -37,7 +35,6 @@ const OmnichannelRoomHeader: FC<OmnichannelRoomHeaderProps> = ({ slots: parentSl
 
 	const { isMobile } = useLayout();
 	const room = useOmnichannelRoom();
-	const toolbox = useToolboxContext();
 
 	const slots = useMemo(
 		() => ({
@@ -53,19 +50,7 @@ const OmnichannelRoomHeader: FC<OmnichannelRoomHeaderProps> = ({ slots: parentSl
 		[isMobile, currentRouteName, parentSlot],
 	);
 
-	return (
-		<ToolboxContext.Provider
-			value={useMemo(
-				() => ({
-					...toolbox,
-					actions: new Map([...(Array.from(toolbox.actions.entries()) as [string, ToolboxActionConfig][])]),
-				}),
-				[toolbox],
-			)}
-		>
-			<RoomHeader slots={slots} room={room} />
-		</ToolboxContext.Provider>
-	);
+	return <RoomHeader slots={slots} room={room} />;
 };
 
 export default OmnichannelRoomHeader;
diff --git a/apps/meteor/client/views/room/Header/Omnichannel/VoipRoomHeader.tsx b/apps/meteor/client/views/room/Header/Omnichannel/VoipRoomHeader.tsx
index ec7beb37dda..ea0a1575d30 100644
--- a/apps/meteor/client/views/room/Header/Omnichannel/VoipRoomHeader.tsx
+++ b/apps/meteor/client/views/room/Header/Omnichannel/VoipRoomHeader.tsx
@@ -7,8 +7,6 @@ import { useSyncExternalStore } from 'use-sync-external-store/shim';
 
 import { parseOutboundPhoneNumber } from '../../../../../ee/client/lib/voip/parseOutboundPhoneNumber';
 import BurgerMenu from '../../../../components/BurgerMenu';
-import { ToolboxContext, useToolboxContext } from '../../contexts/ToolboxContext';
-import type { ToolboxActionConfig } from '../../lib/Toolbox';
 import type { RoomHeaderProps } from '../RoomHeader';
 import RoomHeader from '../RoomHeader';
 import { BackButton } from './BackButton';
@@ -26,7 +24,6 @@ const VoipRoomHeader: FC<VoipRoomHeaderProps> = ({ slots: parentSlot, room }) =>
 	);
 
 	const { isMobile } = useLayout();
-	const toolbox = useToolboxContext();
 
 	const slots = useMemo(
 		() => ({
@@ -40,19 +37,7 @@ const VoipRoomHeader: FC<VoipRoomHeaderProps> = ({ slots: parentSlot, room }) =>
 		}),
 		[isMobile, currentRouteName, parentSlot],
 	);
-	return (
-		<ToolboxContext.Provider
-			value={useMemo(
-				() => ({
-					...toolbox,
-					actions: new Map([...(Array.from(toolbox.actions.entries()) as [string, ToolboxActionConfig][])]),
-				}),
-				[toolbox],
-			)}
-		>
-			<RoomHeader slots={slots} room={{ ...room, name: parseOutboundPhoneNumber(room.fname) }} />
-		</ToolboxContext.Provider>
-	);
+	return <RoomHeader slots={slots} room={{ ...room, name: parseOutboundPhoneNumber(room.fname) }} />;
 };
 
 export default VoipRoomHeader;
diff --git a/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolbox.tsx b/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolbox.tsx
index 4a26c608dba..47e715503d3 100644
--- a/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolbox.tsx
+++ b/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolbox.tsx
@@ -2,13 +2,12 @@ import type { Box } from '@rocket.chat/fuselage';
 import { Menu, Option } from '@rocket.chat/fuselage';
 import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
 import { HeaderToolboxAction, HeaderToolboxDivider } from '@rocket.chat/ui-client';
-import type { TranslationKey } from '@rocket.chat/ui-contexts';
 import { useLayout, useTranslation } from '@rocket.chat/ui-contexts';
 import type { ComponentProps, ReactElement } from 'react';
 import React, { memo, useRef } from 'react';
 
 // used to open the menu option by keyboard
-import { useToolboxContext, useTab, useTabBarOpen } from '../../contexts/ToolboxContext';
+import { useRoomToolbox, useTabBarOpen } from '../../contexts/RoomToolboxContext';
 import type { ToolboxActionConfig, OptionRenderer } from '../../lib/Toolbox';
 
 const renderMenuOption: OptionRenderer = ({ label: { title, icon }, ...props }: any) => (
@@ -21,14 +20,12 @@ type RoomToolboxProps = {
 
 const RoomToolbox = ({ className }: RoomToolboxProps) => {
 	const t = useTranslation();
-	const tab = useTab();
 	const openTabBar = useTabBarOpen();
 	const { isMobile } = useLayout();
 	const hiddenActionRenderers = useRef<{ [key: string]: OptionRenderer }>({});
 
-	const { actions: mapActions } = useToolboxContext();
+	const { actions, tab } = useRoomToolbox();
 
-	const actions = (Array.from(mapActions.values()) as ToolboxActionConfig[]).sort((a, b) => (a.order || 0) - (b.order || 0));
 	const featuredActions = actions.filter((action) => action.featured);
 	const filteredActions = actions.filter((action) => !action.featured);
 	const visibleActions = isMobile ? [] : filteredActions.slice(0, 6);
@@ -60,47 +57,41 @@ const RoomToolbox = ({ className }: RoomToolboxProps) => {
 
 	return (
 		<>
-			{featuredActions.map(
-				({ renderAction, id, icon, title, action = actionDefault, disabled, 'data-tooltip': dataTooltip, tooltip }, index) => {
-					const props = {
-						id,
-						icon,
-						title: t(title),
-						className,
-						index,
-						pressed: id === tab?.id,
-						action,
-						disabled,
-						...(dataTooltip ? { 'data-tooltip': t(dataTooltip as TranslationKey) } : {}),
-						...(tooltip ? { tooltip } : {}),
-					};
-					if (renderAction) {
-						return renderAction(props);
-					}
-					return <HeaderToolboxAction {...props} key={id} />;
-				},
-			)}
+			{featuredActions.map(({ renderAction, id, icon, title, action = actionDefault, disabled, tooltip }, index) => {
+				const props = {
+					id,
+					icon,
+					title: t(title),
+					className,
+					index,
+					pressed: id === tab?.id,
+					action,
+					disabled,
+					...(tooltip ? { tooltip } : {}),
+				};
+				if (renderAction) {
+					return renderAction(props);
+				}
+				return <HeaderToolboxAction {...props} key={id} />;
+			})}
 			{featuredActions.length > 0 && <HeaderToolboxDivider />}
-			{visibleActions.map(
-				({ renderAction, id, icon, title, action = actionDefault, disabled, 'data-tooltip': dataTooltip, tooltip }, index) => {
-					const props = {
-						id,
-						icon,
-						title: t(title),
-						className,
-						index,
-						pressed: id === tab?.id,
-						action,
-						disabled,
-						...(dataTooltip ? { 'data-tooltip': t(dataTooltip as TranslationKey) } : {}),
-						...(tooltip ? { tooltip } : {}),
-					};
-					if (renderAction) {
-						return renderAction(props);
-					}
-					return <HeaderToolboxAction {...props} key={id} />;
-				},
-			)}
+			{visibleActions.map(({ renderAction, id, icon, title, action = actionDefault, disabled, tooltip }, index) => {
+				const props = {
+					id,
+					icon,
+					title: t(title),
+					className,
+					index,
+					pressed: id === tab?.id,
+					action,
+					disabled,
+					...(tooltip ? { tooltip } : {}),
+				};
+				if (renderAction) {
+					return renderAction(props);
+				}
+				return <HeaderToolboxAction {...props} key={id} />;
+			})}
 			{(filteredActions.length > 6 || isMobile) && (
 				<Menu
 					data-qa-id='ToolBox-Menu'
diff --git a/apps/meteor/client/views/room/MemberListRouter.js b/apps/meteor/client/views/room/MemberListRouter.js
index 78651b0f88d..372d7269461 100644
--- a/apps/meteor/client/views/room/MemberListRouter.js
+++ b/apps/meteor/client/views/room/MemberListRouter.js
@@ -2,7 +2,7 @@ import { useUserId } from '@rocket.chat/ui-contexts';
 import React from 'react';
 
 import { useRoom } from './contexts/RoomContext';
-import { useTab, useTabBarClose, useTabContext } from './contexts/ToolboxContext';
+import { useRoomToolbox, useTabBarClose } from './contexts/RoomToolboxContext';
 import RoomMembers from './contextualBar/RoomMembers';
 import UserInfo from './contextualBar/UserInfo';
 
@@ -19,11 +19,10 @@ const getUid = (room, ownUserId) => {
 };
 
 const MemberListRouter = ({ rid }) => {
-	const username = useTabContext();
+	const { tab, context: username } = useRoomToolbox();
 	const room = useRoom();
 	const onClickClose = useTabBarClose();
 	const ownUserId = useUserId();
-	const tab = useTab();
 
 	const isMembersList = tab.id === 'members-list' || tab.id === 'user-info-group';
 
diff --git a/apps/meteor/client/views/room/Room/Room.tsx b/apps/meteor/client/views/room/Room/Room.tsx
index aef502a16a0..ecf97659f4c 100644
--- a/apps/meteor/client/views/room/Room/Room.tsx
+++ b/apps/meteor/client/views/room/Room/Room.tsx
@@ -8,7 +8,7 @@ import Header from '../Header';
 import MessageHighlightProvider from '../MessageList/providers/MessageHighlightProvider';
 import RoomBody from '../components/body/RoomBody';
 import { useRoom } from '../contexts/RoomContext';
-import { useTab, useToolboxContext } from '../contexts/ToolboxContext';
+import { useRoomToolbox } from '../contexts/RoomToolboxContext';
 import AppsContextualBar from '../contextualBar/Apps';
 import { useAppsContextualBar } from '../hooks/useAppsContextualBar';
 import RoomLayout from '../layout/RoomLayout';
@@ -20,9 +20,8 @@ const Room = (): ReactElement => {
 
 	const room = useRoom();
 
-	const toolbox = useToolboxContext();
+	const toolbox = useRoomToolbox();
 
-	const tab = useTab();
 	const appsContextualBarContext = useAppsContextualBar();
 
 	return (
@@ -34,12 +33,12 @@ const Room = (): ReactElement => {
 					header={<Header room={room} />}
 					body={<RoomBody />}
 					aside={
-						(tab && (
+						(toolbox.tab && (
 							<ErrorBoundary fallback={null}>
 								<SelectedMessagesProvider>
-									{typeof tab.template !== 'string' && typeof tab.template !== 'undefined' && (
+									{typeof toolbox.tab.template !== 'string' && typeof toolbox.tab.template !== 'undefined' && (
 										<Suspense fallback={<ContextualbarSkeleton />}>
-											{createElement(tab.template, { tabBar: toolbox, _id: room._id, rid: room._id, teamId: room.teamId })}
+											{createElement(toolbox.tab.template, { _id: room._id, rid: room._id, teamId: room.teamId })}
 										</Suspense>
 									)}
 								</SelectedMessagesProvider>
diff --git a/apps/meteor/client/views/room/components/body/RoomBody.tsx b/apps/meteor/client/views/room/components/body/RoomBody.tsx
index aaa0d8a6318..b21b0743b63 100644
--- a/apps/meteor/client/views/room/components/body/RoomBody.tsx
+++ b/apps/meteor/client/views/room/components/body/RoomBody.tsx
@@ -32,7 +32,7 @@ import { MessageList } from '../../MessageList/MessageList';
 import MessageListErrorBoundary from '../../MessageList/MessageListErrorBoundary';
 import { useChat } from '../../contexts/ChatContext';
 import { useRoom, useRoomSubscription, useRoomMessages } from '../../contexts/RoomContext';
-import { useToolboxContext } from '../../contexts/ToolboxContext';
+import { useRoomToolbox } from '../../contexts/RoomToolboxContext';
 import { useScrollMessageList } from '../../hooks/useScrollMessageList';
 import DropTargetOverlay from './DropTargetOverlay';
 import JumpToRecentMessageButton from './JumpToRecentMessageButton';
@@ -55,7 +55,7 @@ const RoomBody = (): ReactElement => {
 	const isLayoutEmbedded = useEmbeddedLayout();
 	const room = useRoom();
 	const user = useUser();
-	const toolbox = useToolboxContext();
+	const toolbox = useRoomToolbox();
 	const admin = useRole('admin');
 	const subscription = useRoomSubscription();
 
@@ -260,11 +260,6 @@ const RoomBody = (): ReactElement => {
 
 	const router = useRouter();
 
-	const roomRef = useRef(room);
-	roomRef.current = room;
-	const tabBarRef = useRef(toolbox);
-	tabBarRef.current = toolbox;
-
 	const debouncedReadMessageRead = useMemo(
 		() =>
 			withDebouncing({ wait: 500 })(() => {
diff --git a/apps/meteor/client/views/room/components/contextualBar/MessageListTab.tsx b/apps/meteor/client/views/room/components/contextualBar/MessageListTab.tsx
index e30dd3f3cd9..d1a11f69f65 100644
--- a/apps/meteor/client/views/room/components/contextualBar/MessageListTab.tsx
+++ b/apps/meteor/client/views/room/components/contextualBar/MessageListTab.tsx
@@ -26,7 +26,7 @@ import { isMessageFirstUnread } from '../../MessageList/lib/isMessageFirstUnread
 import { isMessageNewDay } from '../../MessageList/lib/isMessageNewDay';
 import MessageListProvider from '../../MessageList/providers/MessageListProvider';
 import { useRoomSubscription } from '../../contexts/RoomContext';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 
 type MessageListTabProps = {
 	iconName: IconName;
diff --git a/apps/meteor/client/views/room/contexts/RoomAPIContext.ts b/apps/meteor/client/views/room/contexts/RoomAPIContext.ts
deleted file mode 100644
index 2c2b14cac50..00000000000
--- a/apps/meteor/client/views/room/contexts/RoomAPIContext.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { createContext } from 'react';
-
-type RoomAPIContextValue = {};
-
-export const RoomAPIContext = createContext<RoomAPIContextValue | undefined>(undefined);
diff --git a/apps/meteor/client/views/room/contexts/RoomToolboxContext.ts b/apps/meteor/client/views/room/contexts/RoomToolboxContext.ts
new file mode 100644
index 00000000000..570d72e7caa
--- /dev/null
+++ b/apps/meteor/client/views/room/contexts/RoomToolboxContext.ts
@@ -0,0 +1,25 @@
+import { createContext, useContext } from 'react';
+
+import type { ToolboxActionConfig } from '../lib/Toolbox';
+
+export type RoomToolboxContextValue = {
+	actions: ToolboxActionConfig[];
+	tab?: ToolboxActionConfig;
+	context?: string;
+	open: (actionId: string, context?: string) => void;
+	openRoomInfo: (username?: string) => void;
+	close: () => void;
+};
+
+export const RoomToolboxContext = createContext<RoomToolboxContextValue>({
+	actions: [],
+	open: () => undefined,
+	openRoomInfo: () => undefined,
+	close: () => undefined,
+});
+
+export const useRoomToolbox = () => useContext(RoomToolboxContext);
+
+export const useTabBarOpen = (): ((actionId: string, context?: string) => void) => useContext(RoomToolboxContext).open;
+export const useTabBarClose = (): (() => void) => useContext(RoomToolboxContext).close;
+export const useTabBarOpenUserInfo = (): ((username: string) => void) => useContext(RoomToolboxContext).openRoomInfo;
diff --git a/apps/meteor/client/views/room/contexts/ToolboxContext.ts b/apps/meteor/client/views/room/contexts/ToolboxContext.ts
deleted file mode 100644
index 21fac8bda5a..00000000000
--- a/apps/meteor/client/views/room/contexts/ToolboxContext.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import type { EventHandlerOf } from '@rocket.chat/emitter';
-import { createContext, useContext } from 'react';
-
-import type { ToolboxActionConfig, ToolboxAction, Events } from '../lib/Toolbox';
-import { actions, listen } from '../lib/Toolbox';
-
-export type ToolboxEventHandler = (handler: EventHandlerOf<Events, 'change'>) => () => void;
-
-export type ToolboxContextValue = {
-	actions: Map<ToolboxActionConfig['id'], ToolboxAction>;
-	listen: ToolboxEventHandler;
-	tabBar?: any;
-	context?: any;
-	open: (actionId: string, context?: string) => void;
-	openRoomInfo: (username?: string) => void;
-	close: () => void;
-	activeTabBar?: ToolboxActionConfig;
-	setData?: (data: Record<string, unknown>) => void;
-};
-
-export const ToolboxContext = createContext<ToolboxContextValue>({
-	actions,
-	listen,
-	open: () => undefined,
-	openRoomInfo: () => undefined,
-	close: () => undefined,
-});
-
-export const useToolboxContext = (): ToolboxContextValue => useContext(ToolboxContext);
-
-export const useTabContext = (): unknown | undefined => useContext(ToolboxContext).context;
-export const useTab = (): ToolboxActionConfig | undefined => useContext(ToolboxContext).activeTabBar;
-export const useTabBarOpen = (): ((actionId: string, context?: string) => void) => useContext(ToolboxContext).open;
-export const useTabBarClose = (): (() => void) => useContext(ToolboxContext).close;
-export const useTabBarOpenUserInfo = (): ((username: string) => void) => useContext(ToolboxContext).openRoomInfo;
diff --git a/apps/meteor/client/views/room/contextualBar/Apps/AppsWithData.tsx b/apps/meteor/client/views/room/contextualBar/Apps/AppsWithData.tsx
index b50817dae53..5a6c0102d86 100644
--- a/apps/meteor/client/views/room/contextualBar/Apps/AppsWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/Apps/AppsWithData.tsx
@@ -17,7 +17,7 @@ import type { Dispatch, SyntheticEvent, ContextType } from 'react';
 import React, { memo, useState, useEffect, useReducer } from 'react';
 
 import { useUiKitActionManager } from '../../../../hooks/useUiKitActionManager';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import Apps from './Apps';
 
 type FieldStateValue = string | Array<string> | undefined;
diff --git a/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx b/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx
index 0d18e1eeeb8..2c6a2f6d9ac 100644
--- a/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx
@@ -6,7 +6,7 @@ import React, { useMemo, useEffect, useState, memo } from 'react';
 
 import { useEndpointAction } from '../../../../hooks/useEndpointAction';
 import { useEndpointData } from '../../../../hooks/useEndpointData';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import AutoTranslate from './AutoTranslate';
 
 const AutoTranslateWithData = ({ rid }: { rid: IRoom['_id'] }): ReactElement => {
diff --git a/apps/meteor/client/views/room/contextualBar/Discussions/DiscussionsListContextBar.tsx b/apps/meteor/client/views/room/contextualBar/Discussions/DiscussionsListContextBar.tsx
index 3a9c22ec390..6501aecf5b5 100644
--- a/apps/meteor/client/views/room/contextualBar/Discussions/DiscussionsListContextBar.tsx
+++ b/apps/meteor/client/views/room/contextualBar/Discussions/DiscussionsListContextBar.tsx
@@ -6,7 +6,7 @@ import React, { useCallback, useMemo, useState } from 'react';
 
 import { useRecordList } from '../../../../hooks/lists/useRecordList';
 import { AsyncStatePhase } from '../../../../hooks/useAsyncState';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import DiscussionsList from './DiscussionsList';
 import { useDiscussionsList } from './useDiscussionsList';
 
diff --git a/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx b/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx
index 9e81e084791..152bd51acff 100644
--- a/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx
+++ b/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx
@@ -12,7 +12,7 @@ import {
 	ContextualbarClose,
 	ContextualbarScrollableContent,
 } from '../../../../components/Contextualbar';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import FileExport from './FileExport';
 import MailExportForm from './MailExportForm';
 
diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannelWithData.js b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannelWithData.js
index 24f9772cdb5..1222ce27188 100644
--- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannelWithData.js
+++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannelWithData.js
@@ -1,7 +1,7 @@
 import { useUserRoom } from '@rocket.chat/ui-contexts';
 import React from 'react';
 
-import { useTabBarClose } from '../../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../../contexts/RoomToolboxContext';
 import EditChannel from './EditChannel';
 
 function EditChannelWithData({ rid, onClickBack }) {
diff --git a/apps/meteor/client/views/room/contextualBar/Info/RoomInfoRouter.tsx b/apps/meteor/client/views/room/contextualBar/Info/RoomInfoRouter.tsx
index b17b0260ec7..c57b64ee474 100644
--- a/apps/meteor/client/views/room/contextualBar/Info/RoomInfoRouter.tsx
+++ b/apps/meteor/client/views/room/contextualBar/Info/RoomInfoRouter.tsx
@@ -3,7 +3,7 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
 import React, { useState } from 'react';
 
 import { useRoom } from '../../contexts/RoomContext';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import EditRoomInfoWithData from './EditRoomInfo';
 import RoomInfo from './RoomInfo';
 import { useCanEditRoom } from './hooks/useCanEditRoom';
diff --git a/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcuts.stories.tsx b/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcuts.stories.tsx
index 58f4e65e5de..8bd3494d115 100644
--- a/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcuts.stories.tsx
+++ b/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcuts.stories.tsx
@@ -13,5 +13,5 @@ export default {
 	decorators: [(fn) => <Contextualbar height='100vh'>{fn()}</Contextualbar>],
 } as ComponentMeta<typeof KeyboardShortcutsWithData>;
 
-export const Default: ComponentStory<typeof KeyboardShortcutsWithData> = (args) => <KeyboardShortcutsWithData {...args} />;
+export const Default: ComponentStory<typeof KeyboardShortcutsWithData> = () => <KeyboardShortcutsWithData />;
 Default.storyName = 'KeyboardShortcuts';
diff --git a/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcutsWithData.tsx b/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcutsWithData.tsx
index c35baf4933b..e2a202556c6 100644
--- a/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcutsWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcutsWithData.tsx
@@ -1,13 +1,12 @@
-import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
 import type { ReactElement } from 'react';
 import React from 'react';
 
-import type { ToolboxContextValue } from '../../contexts/ToolboxContext';
+import { useRoomToolbox } from '../../contexts/RoomToolboxContext';
 import KeyboardShortcuts from './KeyboardShortcuts';
 
-const KeyboardShortcutsWithData = ({ tabBar }: { tabBar: ToolboxContextValue['tabBar'] }): ReactElement => {
-	const handleClose = useMutableCallback(() => tabBar?.close());
-	return <KeyboardShortcuts handleClose={handleClose} />;
+const KeyboardShortcutsWithData = (): ReactElement => {
+	const { close: closeTab } = useRoomToolbox();
+	return <KeyboardShortcuts handleClose={closeTab} />;
 };
 
 export default KeyboardShortcutsWithData;
diff --git a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx
index b67ff96c34e..8c157d43560 100644
--- a/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx
+++ b/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx
@@ -1,6 +1,6 @@
 import { Callout } from '@rocket.chat/fuselage';
 import { useTranslation } from '@rocket.chat/ui-contexts';
-import React, { useCallback, useState } from 'react';
+import React, { useState } from 'react';
 
 import {
 	ContextualbarClose,
@@ -9,7 +9,7 @@ import {
 	ContextualbarTitle,
 	ContextualbarIcon,
 } from '../../../../components/Contextualbar';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useRoomToolbox } from '../../contexts/RoomToolboxContext';
 import MessageSearch from './components/MessageSearch';
 import MessageSearchForm from './components/MessageSearchForm';
 import { useMessageSearchProviderQuery } from './hooks/useMessageSearchProviderQuery';
@@ -17,10 +17,7 @@ import { useMessageSearchProviderQuery } from './hooks/useMessageSearchProviderQ
 const MessageSearchTab = () => {
 	const providerQuery = useMessageSearchProviderQuery();
 
-	const tabBarClose = useTabBarClose();
-	const handleCloseButtonClick = useCallback(() => {
-		tabBarClose();
-	}, [tabBarClose]);
+	const { close: closeTab } = useRoomToolbox();
 
 	const [{ searchText, globalSearch }, handleSearch] = useState({ searchText: '', globalSearch: false });
 
@@ -31,7 +28,7 @@ const MessageSearchTab = () => {
 			<ContextualbarHeader>
 				<ContextualbarIcon name='magnifier' />
 				<ContextualbarTitle>{t('Search_Messages')}</ContextualbarTitle>
-				<ContextualbarClose onClick={handleCloseButtonClick} />
+				<ContextualbarClose onClick={closeTab} />
 			</ContextualbarHeader>
 			<ContextualbarContent flexShrink={1} flexGrow={1} paddingInline={0}>
 				{providerQuery.isSuccess && (
diff --git a/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferencesWithData.tsx b/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferencesWithData.tsx
index 62bbdf032e6..79ca02e5d9f 100644
--- a/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferencesWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferencesWithData.tsx
@@ -5,7 +5,7 @@ import React, { memo } from 'react';
 import { useForm, FormProvider } from 'react-hook-form';
 
 import { useEndpointAction } from '../../../../hooks/useEndpointAction';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import NotificationPreferences from './NotificationPreferences';
 
 export type NotificationFormValues = {
diff --git a/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx b/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx
index b5763d77af8..323e2cf7240 100644
--- a/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx
@@ -6,7 +6,7 @@ import ORTInstance from '../../../../../app/otr/client/OTR';
 import { OtrRoomState } from '../../../../../app/otr/lib/OtrRoomState';
 import { usePresence } from '../../../../hooks/usePresence';
 import { useReactiveValue } from '../../../../hooks/useReactiveValue';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import OTR from './OTR';
 
 const OTRWithData = ({ rid }: { rid: IRoom['_id'] }): ReactElement => {
diff --git a/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx b/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx
index b294df0af5d..13395d1929c 100644
--- a/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx
@@ -1,14 +1,15 @@
 import type { IRoom } from '@rocket.chat/core-typings';
 import { isDirectMessageRoom } from '@rocket.chat/core-typings';
 import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
-import { useSetModal, useToastMessageDispatch, useUserRoom, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
+import { useSetModal, useToastMessageDispatch, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts';
 import moment from 'moment';
 import type { ReactElement } from 'react';
 import React, { useCallback, useMemo, useState } from 'react';
 import { useForm, FormProvider } from 'react-hook-form';
 
 import GenericModal from '../../../../components/GenericModal';
-import type { ToolboxContextValue } from '../../contexts/ToolboxContext';
+import { useRoom } from '../../contexts/RoomContext';
+import { useRoomToolbox } from '../../contexts/RoomToolboxContext';
 import PruneMessages from './PruneMessages';
 
 const getTimeZoneOffset = (): string => {
@@ -36,11 +37,11 @@ export const initialValues = {
 
 const DEFAULT_PRUNE_LIMIT = 2000;
 
-const PruneMessagesWithData = ({ rid, tabBar }: { rid: IRoom['_id']; tabBar: ToolboxContextValue['tabBar'] }): ReactElement => {
+const PruneMessagesWithData = ({ rid }: { rid: IRoom['_id'] }): ReactElement => {
 	const t = useTranslation();
-	const room = useUserRoom(rid);
+	const room = useRoom();
 	const setModal = useSetModal();
-	const onClickClose = useMutableCallback(() => tabBar?.close());
+	const { close } = useRoomToolbox();
 	const closeModal = useCallback(() => setModal(null), [setModal]);
 	const dispatchToastMessage = useToastMessageDispatch();
 	const pruneMessagesAction = useEndpoint('POST', '/v1/rooms.cleanHistory');
@@ -191,13 +192,7 @@ const PruneMessagesWithData = ({ rid, tabBar }: { rid: IRoom['_id']; tabBar: Too
 
 	return (
 		<FormProvider {...methods}>
-			<PruneMessages
-				callOutText={callOutText}
-				validateText={validateText}
-				users={users}
-				onClickClose={onClickClose}
-				onClickPrune={handlePrune}
-			/>
+			<PruneMessages callOutText={callOutText} validateText={validateText} users={users} onClickClose={close} onClickPrune={handlePrune} />
 		</FormProvider>
 	);
 };
diff --git a/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFilesWithData.js b/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFilesWithData.js
index 4f3d4ccd263..1892e5a17f1 100644
--- a/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFilesWithData.js
+++ b/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFilesWithData.js
@@ -5,7 +5,7 @@ import React, { useState, useCallback, useMemo } from 'react';
 import GenericModal from '../../../../components/GenericModal';
 import { useRecordList } from '../../../../hooks/lists/useRecordList';
 import { AsyncStatePhase } from '../../../../hooks/useAsyncState';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import RoomFiles from './RoomFiles';
 import { useFilesList } from './hooks/useFilesList';
 import { useMessageDeletionIsAllowed } from './hooks/useMessageDeletionIsAllowed';
diff --git a/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.tsx b/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.tsx
index 3233fc7e196..672bea49aa4 100644
--- a/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.tsx
@@ -7,7 +7,7 @@ import React from 'react';
 
 import { useForm } from '../../../../../hooks/useForm';
 import { useRoom } from '../../../contexts/RoomContext';
-import { useTabBarClose } from '../../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../../contexts/RoomToolboxContext';
 import AddUsers from './AddUsers';
 
 type AddUsersWithDataProps = {
diff --git a/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsersWithData.tsx b/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsersWithData.tsx
index 6c04b60ec86..f6a80b19645 100644
--- a/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsersWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsersWithData.tsx
@@ -5,7 +5,7 @@ import type { ReactElement } from 'react';
 import React, { useState, useEffect } from 'react';
 
 import { useFormatDateAndTime } from '../../../../../hooks/useFormatDateAndTime';
-import { useTabBarClose } from '../../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../../contexts/RoomToolboxContext';
 import InviteUsers from './InviteUsers';
 
 type InviteUsersWithDataProps = {
diff --git a/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersWithData.tsx b/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersWithData.tsx
index b7484d68f8e..e18c61da776 100644
--- a/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersWithData.tsx
@@ -7,7 +7,7 @@ import React, { useCallback, useMemo, useState } from 'react';
 
 import * as Federation from '../../../../lib/federation/Federation';
 import { useMembersList } from '../../../hooks/useMembersList';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import UserInfoWithData from '../UserInfo';
 import AddUsers from './AddUsers';
 import InviteUsers from './InviteUsers';
diff --git a/apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx b/apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx
index 3c551603f65..10aadf11636 100644
--- a/apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx
+++ b/apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx
@@ -15,7 +15,7 @@ import {
 	ContextualbarBack,
 	ContextualbarInnerContent,
 } from '../../../../components/Contextualbar';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import { useGoToThreadList } from '../../hooks/useGoToThreadList';
 import ChatProvider from '../../providers/ChatProvider';
 import ThreadChat from './components/ThreadChat';
diff --git a/apps/meteor/client/views/room/contextualBar/Threads/ThreadList.tsx b/apps/meteor/client/views/room/contextualBar/Threads/ThreadList.tsx
index 58c7341cc88..a7c7148c2e3 100644
--- a/apps/meteor/client/views/room/contextualBar/Threads/ThreadList.tsx
+++ b/apps/meteor/client/views/room/contextualBar/Threads/ThreadList.tsx
@@ -19,7 +19,7 @@ import { useRecordList } from '../../../../hooks/lists/useRecordList';
 import { AsyncStatePhase } from '../../../../lib/asyncState';
 import type { ThreadsListOptions } from '../../../../lib/lists/ThreadsList';
 import { useRoom, useRoomSubscription } from '../../contexts/RoomContext';
-import { useTabBarClose } from '../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../contexts/RoomToolboxContext';
 import { useGoToThread } from '../../hooks/useGoToThread';
 import ThreadListItem from './components/ThreadListItem';
 import { useThreadsList } from './hooks/useThreadsList';
diff --git a/apps/meteor/client/views/room/contextualBar/Threads/Threads.tsx b/apps/meteor/client/views/room/contextualBar/Threads/Threads.tsx
index fe33cfa89cc..2c916ccb1d5 100644
--- a/apps/meteor/client/views/room/contextualBar/Threads/Threads.tsx
+++ b/apps/meteor/client/views/room/contextualBar/Threads/Threads.tsx
@@ -1,12 +1,12 @@
 import type { ReactElement } from 'react';
 import React from 'react';
 
-import { useTabContext } from '../../contexts/ToolboxContext';
+import { useRoomToolbox } from '../../contexts/RoomToolboxContext';
 import Thread from './Thread';
 import ThreadList from './ThreadList';
 
 const Threads = (): ReactElement => {
-	const tmid = useTabContext() as string | undefined;
+	const { context: tmid } = useRoomToolbox();
 
 	if (tmid) {
 		return <Thread tmid={tmid} />;
diff --git a/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx b/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx
index 434db3aed0d..7782c04a6b1 100644
--- a/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx
+++ b/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx
@@ -13,7 +13,7 @@ import ComposerContainer from '../../../components/body/composer/ComposerContain
 import { useFileUploadDropTarget } from '../../../components/body/hooks/useFileUploadDropTarget';
 import { useChat } from '../../../contexts/ChatContext';
 import { useRoom, useRoomSubscription } from '../../../contexts/RoomContext';
-import { useTabBarClose } from '../../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../../contexts/RoomToolboxContext';
 import ThreadMessageList from './ThreadMessageList';
 
 type ThreadChatProps = {
diff --git a/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListWithData.tsx b/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListWithData.tsx
index fbabc97f0e0..c934951cff5 100644
--- a/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListWithData.tsx
+++ b/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListWithData.tsx
@@ -4,7 +4,7 @@ import React, { useMemo } from 'react';
 
 import { useRecordList } from '../../../../../hooks/lists/useRecordList';
 import { AsyncStatePhase } from '../../../../../hooks/useAsyncState';
-import { useTabBarClose } from '../../../contexts/ToolboxContext';
+import { useTabBarClose } from '../../../contexts/RoomToolboxContext';
 import VideoConfList from './VideoConfList';
 import { useVideoConfList } from './useVideoConfList';
 
diff --git a/apps/meteor/client/views/room/lib/Toolbox/index.tsx b/apps/meteor/client/views/room/lib/Toolbox/index.tsx
index a805172d63e..9c9a83b21fc 100644
--- a/apps/meteor/client/views/room/lib/Toolbox/index.tsx
+++ b/apps/meteor/client/views/room/lib/Toolbox/index.tsx
@@ -4,12 +4,6 @@ import type { Keys as IconName } from '@rocket.chat/icons';
 import type { TranslationKey } from '@rocket.chat/ui-contexts';
 import type { ReactNode, MouseEvent, ComponentProps, ComponentType } from 'react';
 
-import type { ToolboxContextValue } from '../../contexts/ToolboxContext';
-import type { Events as GeneratorEvents } from './generator';
-import { generator } from './generator';
-
-type ToolboxHook = ({ room }: { room: IRoom }) => ToolboxActionConfig | null;
-
 type ActionRendererProps = Omit<ToolboxActionConfig, 'renderAction' | 'groups' | 'title'> & {
 	className: ComponentProps<typeof Box>['className'];
 	index: number;
@@ -21,33 +15,23 @@ type OptionRendererProps = ComponentProps<typeof Option>;
 export type OptionRenderer = (props: OptionRendererProps) => ReactNode;
 
 export type ToolboxActionConfig = {
-	'id': string;
-	'icon'?: IconName;
-	'title': TranslationKey;
-	'anonymous'?: boolean;
-	'tooltip'?: string;
-	'data-tooltip'?: string;
-	'disabled'?: boolean;
-	'renderAction'?: (props: ActionRendererProps) => ReactNode;
-	'full'?: true;
-	'renderOption'?: OptionRenderer;
-	'order'?: number;
-	'groups': Array<'group' | 'channel' | 'live' | 'direct' | 'direct_multiple' | 'team' | 'voip'>;
-	'hotkey'?: string;
-	'action'?: (e?: MouseEvent<HTMLElement>) => void;
-	'template'?: ComponentType<{
-		tabBar: ToolboxContextValue;
+	id: string;
+	icon?: IconName;
+	title: TranslationKey;
+	anonymous?: boolean;
+	tooltip?: string;
+	disabled?: boolean;
+	renderAction?: (props: ActionRendererProps) => ReactNode;
+	full?: true;
+	renderOption?: OptionRenderer;
+	order?: number;
+	groups: Array<'group' | 'channel' | 'live' | 'direct' | 'direct_multiple' | 'team' | 'voip'>;
+	hotkey?: string;
+	action?: (e?: MouseEvent<HTMLElement>) => void;
+	template?: ComponentType<{
 		_id: IRoom['_id'];
 		rid: IRoom['_id'];
 		teamId: IRoom['teamId'];
 	}>;
-	'featured'?: boolean;
+	featured?: boolean;
 };
-
-export type ToolboxAction = ToolboxHook | ToolboxActionConfig;
-
-const { listen, store: actions } = generator<ToolboxAction>();
-
-export type Events = GeneratorEvents<ToolboxAction>;
-
-export { listen, actions };
diff --git a/apps/meteor/client/views/room/providers/RoomProvider.tsx b/apps/meteor/client/views/room/providers/RoomProvider.tsx
index 1e5a8fd3c7f..8dde725b013 100644
--- a/apps/meteor/client/views/room/providers/RoomProvider.tsx
+++ b/apps/meteor/client/views/room/providers/RoomProvider.tsx
@@ -15,7 +15,6 @@ import { roomCoordinator } from '../../../lib/rooms/roomCoordinator';
 import RoomNotFound from '../RoomNotFound';
 import RoomSkeleton from '../RoomSkeleton';
 import { useRoomRolesManagement } from '../components/body/hooks/useRoomRolesManagement';
-import { RoomAPIContext } from '../contexts/RoomAPIContext';
 import { RoomContext } from '../contexts/RoomContext';
 import ComposerPopupProvider from './ComposerPopupProvider';
 import RoomToolboxProvider from './RoomToolboxProvider';
@@ -136,20 +135,16 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => {
 		};
 	}, [rid, subscribed]);
 
-	const api = useMemo(() => ({}), []);
-
 	if (!pseudoRoom) {
 		return isSuccess && !room ? <RoomNotFound /> : <RoomSkeleton />;
 	}
 
 	return (
-		<RoomAPIContext.Provider value={api}>
-			<RoomContext.Provider value={context}>
-				<RoomToolboxProvider>
-					<ComposerPopupProvider room={pseudoRoom}>{children}</ComposerPopupProvider>
-				</RoomToolboxProvider>
-			</RoomContext.Provider>
-		</RoomAPIContext.Provider>
+		<RoomContext.Provider value={context}>
+			<RoomToolboxProvider>
+				<ComposerPopupProvider room={pseudoRoom}>{children}</ComposerPopupProvider>
+			</RoomToolboxProvider>
+		</RoomContext.Provider>
 	);
 };
 
diff --git a/apps/meteor/client/views/room/providers/RoomToolboxProvider.tsx b/apps/meteor/client/views/room/providers/RoomToolboxProvider.tsx
index 6fa16dfa61b..851c3111cc2 100644
--- a/apps/meteor/client/views/room/providers/RoomToolboxProvider.tsx
+++ b/apps/meteor/client/views/room/providers/RoomToolboxProvider.tsx
@@ -1,33 +1,43 @@
-import { useDebouncedState, useMutableCallback, useSafely } from '@rocket.chat/fuselage-hooks';
+import type { RoomType, IRoom } from '@rocket.chat/core-typings';
+import { useMutableCallback, useStableArray } from '@rocket.chat/fuselage-hooks';
 import { useUserId, useSetting, useRouter, useRouteParameter } from '@rocket.chat/ui-contexts';
 import type { ReactNode } from 'react';
-import React, { useContext, useLayoutEffect, useMemo, useState } from 'react';
+import React, { useMemo } from 'react';
 
 import { useRoom } from '../contexts/RoomContext';
-import type { ToolboxContextValue } from '../contexts/ToolboxContext';
-import { ToolboxContext } from '../contexts/ToolboxContext';
+import type { RoomToolboxContextValue } from '../contexts/RoomToolboxContext';
+import { RoomToolboxContext } from '../contexts/RoomToolboxContext';
 import type { ToolboxActionConfig } from '../lib/Toolbox/index';
-import VirtualAction from './VirtualAction';
 import { useAppsRoomActions } from './hooks/useAppsRoomActions';
 import { useCoreRoomActions } from './hooks/useCoreRoomActions';
 
+const groupsDict = {
+	l: 'live',
+	v: 'voip',
+	d: 'direct',
+	p: 'group',
+	c: 'channel',
+} as const satisfies Record<RoomType, ToolboxActionConfig['groups'][number]>;
+
+const getGroup = (room: IRoom) => {
+	if (room.teamMain) {
+		return 'team';
+	}
+
+	if (room.t === 'd' && (room.uids?.length ?? 0) > 2) {
+		return 'direct_multiple';
+	}
+
+	return groupsDict[room.t];
+};
+
 type RoomToolboxProviderProps = { children: ReactNode };
 
 const RoomToolboxProvider = ({ children }: RoomToolboxProviderProps) => {
 	const room = useRoom();
 
-	const [list, setList] = useSafely(useDebouncedState(() => new Map<string, ToolboxActionConfig>(), 5));
-	const handleChange = useMutableCallback((fn) => {
-		fn(list);
-		setList((list) => new Map(list));
-	});
-
 	const router = useRouter();
 
-	const tab = useRouteParameter('tab');
-
-	const activeTabBar = useMemo(() => (tab ? list.get(tab) : undefined), [tab, list]);
-
 	const close = useMutableCallback(() => {
 		const routeName = router.getRouteName();
 
@@ -47,7 +57,7 @@ const RoomToolboxProvider = ({ children }: RoomToolboxProviderProps) => {
 	});
 
 	const open = useMutableCallback((actionId: string, context?: string) => {
-		if (actionId === activeTabBar?.id && context === undefined) {
+		if (actionId === tab?.id && context === undefined) {
 			return close();
 		}
 
@@ -90,52 +100,43 @@ const RoomToolboxProvider = ({ children }: RoomToolboxProviderProps) => {
 		}
 	});
 
-	const { listen, actions } = useContext(ToolboxContext);
-	const [legacyCoreRoomActions, updateLegacyCoreRoomActions] = useSafely(useState(() => Array.from(actions.entries())));
+	const context = useRouteParameter('context');
+
+	const coreRoomActions = useCoreRoomActions();
+	const appsRoomActions = useAppsRoomActions();
+
+	const allowAnonymousRead = useSetting<boolean>('Accounts_AllowAnonymousRead', false);
+	const uid = useUserId();
 
-	useLayoutEffect(
-		() =>
-			listen((actions) => {
-				updateLegacyCoreRoomActions(Array.from(actions.entries()));
-			}),
-		[listen, updateLegacyCoreRoomActions],
+	const actions = useStableArray(
+		[...coreRoomActions, ...appsRoomActions]
+			.filter((action) => uid || (allowAnonymousRead && 'anonymous' in action && action.anonymous))
+			.filter((action) => !action.groups || action.groups.includes(getGroup(room)))
+			.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)),
 	);
 
-	const context = useRouteParameter('context');
+	const tabActionId = useRouteParameter('tab');
+	const tab = useMemo(() => {
+		if (!tabActionId) {
+			return undefined;
+		}
+
+		return actions.find((action) => action.id === tabActionId);
+	}, [actions, tabActionId]);
 
 	const contextValue = useMemo(
-		(): ToolboxContextValue => ({
-			listen,
-			actions: new Map(list),
-			activeTabBar,
+		(): RoomToolboxContextValue => ({
+			actions,
+			tab,
 			context,
 			open,
 			close,
 			openRoomInfo,
 		}),
-		[listen, list, activeTabBar, context, open, close, openRoomInfo],
+		[actions, tab, context, open, close, openRoomInfo],
 	);
 
-	const coreRoomActions = useCoreRoomActions();
-	const appsRoomActions = useAppsRoomActions();
-
-	const allowAnonymousRead = useSetting<boolean>('Accounts_AllowAnonymousRead', false);
-	const uid = useUserId();
-
-	const roomActions = [
-		...legacyCoreRoomActions,
-		...coreRoomActions.map((action) => [action.id, action] as [ToolboxActionConfig['id'], ToolboxActionConfig]),
-		...appsRoomActions.map((action) => [action.id, action] as [ToolboxActionConfig['id'], ToolboxActionConfig]),
-	].filter(([, action]) => uid || (allowAnonymousRead && 'anonymous' in action && action.anonymous));
-
-	return (
-		<ToolboxContext.Provider value={contextValue}>
-			{roomActions.map(([id, roomAction]) => (
-				<VirtualAction key={id + room._id} action={roomAction} handleChange={handleChange} />
-			))}
-			{children}
-		</ToolboxContext.Provider>
-	);
+	return <RoomToolboxContext.Provider value={contextValue}>{children}</RoomToolboxContext.Provider>;
 };
 
 export default RoomToolboxProvider;
diff --git a/apps/meteor/client/views/room/providers/VirtualAction.tsx b/apps/meteor/client/views/room/providers/VirtualAction.tsx
deleted file mode 100644
index ad1cb6c3b14..00000000000
--- a/apps/meteor/client/views/room/providers/VirtualAction.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import type { IRoom, RoomType } from '@rocket.chat/core-typings';
-import { useLayoutEffect, memo } from 'react';
-
-import { useRoom } from '../contexts/RoomContext';
-import type { ToolboxAction, ToolboxActionConfig } from '../lib/Toolbox/index';
-
-const groupsDict = {
-	l: 'live',
-	v: 'voip',
-	d: 'direct',
-	p: 'group',
-	c: 'channel',
-} as const satisfies Record<RoomType, string>;
-
-const getGroup = (room: IRoom) => {
-	if (room.teamMain) {
-		return 'team';
-	}
-
-	if (room.t === 'd' && (room.uids?.length ?? 0) > 2) {
-		return 'direct_multiple';
-	}
-
-	return groupsDict[room.t];
-};
-
-type VirtualActionProps = {
-	action: ToolboxAction;
-	handleChange: (callback: (list: Map<ToolboxActionConfig['id'], ToolboxAction>) => void) => void;
-};
-
-const VirtualAction = ({ action, handleChange }: VirtualActionProps) => {
-	const room = useRoom();
-
-	const config = typeof action === 'function' ? action({ room }) : action;
-
-	const group = getGroup(room);
-
-	const visible = !!config && (!config.groups || (groupsDict[room.t] && config.groups.includes(group)));
-
-	useLayoutEffect(() => {
-		if (!visible) {
-			return;
-		}
-
-		handleChange((list) => list.set(config.id, config));
-
-		return () => {
-			handleChange((list) => list.delete(config.id));
-		};
-	}, [config, visible, handleChange]);
-
-	return null;
-};
-
-export default memo(VirtualAction);
diff --git a/apps/meteor/client/views/room/providers/hooks/useCoreRoomActions.ts b/apps/meteor/client/views/room/providers/hooks/useCoreRoomActions.ts
index 244d5ac2f09..4c926942d3c 100644
--- a/apps/meteor/client/views/room/providers/hooks/useCoreRoomActions.ts
+++ b/apps/meteor/client/views/room/providers/hooks/useCoreRoomActions.ts
@@ -1,6 +1,10 @@
+import { useStableArray } from '@rocket.chat/fuselage-hooks';
+
 import { roomActionHooks } from '../../../../ui';
 import type { ToolboxActionConfig } from '../../lib/Toolbox/index';
 
 export const useCoreRoomActions = () => {
-	return roomActionHooks.map((roomActionHook) => roomActionHook()).filter((roomAction): roomAction is ToolboxActionConfig => !!roomAction);
+	return useStableArray(
+		roomActionHooks.map((roomActionHook) => roomActionHook()).filter((roomAction): roomAction is ToolboxActionConfig => !!roomAction),
+	);
 };
diff --git a/apps/meteor/client/views/room/providers/hooks/useUserCard.ts b/apps/meteor/client/views/room/providers/hooks/useUserCard.ts
index c4a10886450..c4fcf1b70d2 100644
--- a/apps/meteor/client/views/room/providers/hooks/useUserCard.ts
+++ b/apps/meteor/client/views/room/providers/hooks/useUserCard.ts
@@ -3,7 +3,7 @@ import { useCallback, useEffect } from 'react';
 
 import { openUserCard, closeUserCard } from '../../../../../app/ui/client/lib/userCard';
 import { useRoom } from '../../contexts/RoomContext';
-import { useTabBarOpenUserInfo } from '../../contexts/ToolboxContext';
+import { useTabBarOpenUserInfo } from '../../contexts/RoomToolboxContext';
 
 export const useUserCard = () => {
 	useEffect(() => {
diff --git a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx
index 1ebb457979e..6764d615c48 100644
--- a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx
+++ b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx
@@ -8,7 +8,7 @@ import { useRecordList } from '../../../../hooks/lists/useRecordList';
 import { AsyncStatePhase } from '../../../../lib/asyncState';
 import { roomCoordinator } from '../../../../lib/rooms/roomCoordinator';
 import CreateChannelWithData from '../../../../sidebar/header/CreateChannel';
-import { useTabBarClose } from '../../../room/contexts/ToolboxContext';
+import { useTabBarClose } from '../../../room/contexts/RoomToolboxContext';
 import RoomInfo from '../../../room/contextualBar/Info';
 import AddExistingModal from './AddExistingModal';
 import BaseTeamsChannels from './BaseTeamsChannels';
diff --git a/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js b/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js
index 8044d15d938..7518c754efa 100644
--- a/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js
+++ b/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js
@@ -16,7 +16,7 @@ import { GenericModalDoNotAskAgain } from '../../../../components/GenericModal';
 import { useDontAskAgain } from '../../../../hooks/useDontAskAgain';
 import { useEndpointAction } from '../../../../hooks/useEndpointAction';
 import { roomCoordinator } from '../../../../lib/rooms/roomCoordinator';
-import { useTabBarClose, useTabBarOpen } from '../../../room/contexts/ToolboxContext';
+import { useTabBarClose, useTabBarOpen } from '../../../room/contexts/RoomToolboxContext';
 import ConvertToChannelModal from '../../ConvertToChannelModal';
 import DeleteTeamModal from './Delete';
 import LeaveTeam from './LeaveTeam';
diff --git a/apps/meteor/ee/client/apps/gameCenter/GameCenter.tsx b/apps/meteor/ee/client/apps/gameCenter/GameCenter.tsx
index 1d192e7b14e..b1254602a3c 100644
--- a/apps/meteor/ee/client/apps/gameCenter/GameCenter.tsx
+++ b/apps/meteor/ee/client/apps/gameCenter/GameCenter.tsx
@@ -3,7 +3,7 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
 import React, { useState } from 'react';
 import type { ReactElement, SyntheticEvent } from 'react';
 
-import { useTabBarClose } from '../../../../client/views/room/contexts/ToolboxContext';
+import { useTabBarClose } from '../../../../client/views/room/contexts/RoomToolboxContext';
 import GameCenterContainer from './GameCenterContainer';
 import GameCenterList from './GameCenterList';
 import { useExternalComponentsQuery } from './hooks/useExternalComponentsQuery';
diff --git a/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponseList.tsx b/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponseList.tsx
index 67f13856f40..33b55c66562 100644
--- a/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponseList.tsx
+++ b/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponseList.tsx
@@ -15,7 +15,7 @@ import {
 	ContextualbarFooter,
 } from '../../../../../../client/components/Contextualbar';
 import ScrollableContentWrapper from '../../../../../../client/components/ScrollableContentWrapper';
-import { useTabContext } from '../../../../../../client/views/room/contexts/ToolboxContext';
+import { useRoomToolbox } from '../../../../../../client/views/room/contexts/RoomToolboxContext';
 import Item from './Item';
 import WrapCannedResponse from './WrapCannedResponse';
 
@@ -53,7 +53,7 @@ const CannedResponseList: FC<{
 	const t = useTranslation();
 	const inputRef = useAutoFocus<HTMLInputElement>(true);
 
-	const cannedId = useTabContext();
+	const { context: cannedId } = useRoomToolbox();
 
 	const { ref, contentBoxSize: { inlineSize = 378 } = {} } = useResizeObserver<HTMLElement>({
 		debounceDelay: 200,
diff --git a/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/index.tsx b/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/index.tsx
index f862a63fdf6..73b368095f5 100644
--- a/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/index.tsx
+++ b/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/index.tsx
@@ -1,19 +1,21 @@
 import { useDebouncedValue, useLocalStorage, useMutableCallback } from '@rocket.chat/fuselage-hooks';
 import { useSetModal, useRouter } from '@rocket.chat/ui-contexts';
-import type { FC, MouseEvent } from 'react';
+import type { MouseEvent } from 'react';
 import React, { memo, useCallback, useMemo, useState } from 'react';
 
 import { useRecordList } from '../../../../../../client/hooks/lists/useRecordList';
 import { AsyncStatePhase } from '../../../../../../client/lib/asyncState';
 import { useChat } from '../../../../../../client/views/room/contexts/ChatContext';
 import { useRoom } from '../../../../../../client/views/room/contexts/RoomContext';
+import { useRoomToolbox } from '../../../../../../client/views/room/contexts/RoomToolboxContext';
 import { useCannedResponseFilterOptions } from '../../../hooks/useCannedResponseFilterOptions';
 import { useCannedResponseList } from '../../../hooks/useCannedResponseList';
 import CreateCannedResponse from '../../CannedResponse/modals';
 import CannedResponseList from './CannedResponseList';
 
-export const WrapCannedResponseList: FC<{ tabBar: any }> = ({ tabBar }) => {
+export const WrapCannedResponseList = () => {
 	const room = useRoom();
+	const { close: closeTab } = useRoomToolbox();
 	const router = useRouter();
 	const setModal = useSetModal();
 
@@ -65,7 +67,7 @@ export const WrapCannedResponseList: FC<{ tabBar: any }> = ({ tabBar }) => {
 			loadMoreItems={loadMoreItems}
 			cannedItems={items}
 			itemCount={itemCount}
-			onClose={tabBar.close}
+			onClose={closeTab}
 			loading={phase === AsyncStatePhase.LOADING}
 			options={options}
 			text={text}
diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/Message.spec.tsx b/apps/meteor/tests/unit/client/views/room/MessageList/Message.spec.tsx
index c5242f0d540..b6a0f9ecd95 100644
--- a/apps/meteor/tests/unit/client/views/room/MessageList/Message.spec.tsx
+++ b/apps/meteor/tests/unit/client/views/room/MessageList/Message.spec.tsx
@@ -47,7 +47,7 @@ const RoomMessage = proxyquire.noCallThru().load('../../../../../../client/compo
 	'./room/RoomMessageContent': () => baseMessage.msg,
 	'../MessageHeader': () => <p>message header</p>,
 	'../StatusIndicators': { MessageIndicators: () => <p>message indicators</p> },
-	'../ToolboxHolder': () => <p>toolbox</p>,
+	'../MessageToolboxHolder': () => <p>toolbox</p>,
 }).default as typeof _RoomMessage;
 
 describe('Message', () => {
-- 
GitLab