diff --git a/apps/meteor/app/ui-utils/client/lib/MessageAction.ts b/apps/meteor/app/ui-utils/client/lib/MessageAction.ts index 0a5483c4acaa..426caea0ecf9 100644 --- a/apps/meteor/app/ui-utils/client/lib/MessageAction.ts +++ b/apps/meteor/app/ui-utils/client/lib/MessageAction.ts @@ -1,12 +1,6 @@ -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 type { ContextType } from 'react'; - -import type { AutoTranslateOptions } from '../../../../client/views/room/MessageList/hooks/useAutoTranslate'; -import type { ChatContext } from '../../../../client/views/room/contexts/ChatContext'; -import type { RoomToolboxContextValue } from '../../../../client/views/room/contexts/RoomToolboxContext'; type MessageActionGroup = 'message' | 'menu'; @@ -25,60 +19,30 @@ export type MessageActionContext = type MessageActionType = 'communication' | 'interaction' | 'duplication' | 'apps' | 'management'; -export type MessageActionConditionProps = { - message: IMessage; - user: IUser | undefined; - room: IRoom; - subscription?: ISubscription; - context?: MessageActionContext; - settings: { [key: string]: SettingValue }; - chat: ContextType; -}; - export type MessageActionConfig = { id: string; icon: IconName; variant?: 'danger' | 'success' | 'warning'; label: TranslationKey; - order?: number; + order: number; /* @deprecated */ - color?: string; - role?: string; - group?: MessageActionGroup | MessageActionGroup[]; + color?: 'alert'; + group: MessageActionGroup; context?: MessageActionContext[]; - action: ( - e: Pick | undefined, - { - message, - tabbar, - room, - chat, - autoTranslateOptions, - }: { - message: IMessage & Partial; - tabbar: RoomToolboxContextValue; - room?: IRoom; - chat: ContextType; - autoTranslateOptions?: AutoTranslateOptions; - }, - ) => any; - condition?: (props: MessageActionConditionProps) => Promise | boolean; + action: (e: Pick | undefined) => any; + condition?: () => Promise | boolean; type?: MessageActionType; - disabled?: (props: MessageActionConditionProps) => boolean; + disabled?: boolean; }; class MessageAction { - public buttons: Record = {}; + private buttons: Record = {}; public addButton(config: MessageActionConfig): void { if (!config?.id) { return; } - if (!config.group) { - config.group = 'menu'; - } - if (config.condition) { config.condition = mem(config.condition, { maxAge: 1000, cacheKey: JSON.stringify }); } @@ -90,19 +54,15 @@ class MessageAction { delete this.buttons[id]; } - public async getAll( - props: MessageActionConditionProps, - context: MessageActionContext, - group: MessageActionGroup, - ): Promise { + public async getAll(context: MessageActionContext, group: MessageActionGroup): Promise { return ( await Promise.all( 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.group === group) .filter((button) => !button.context || button.context.includes(context)) .map(async (button) => { - return [button, !button.condition || (await button.condition({ ...props, context }))] as const; + return [button, !button.condition || (await button.condition())] as const; }), ) ) diff --git a/apps/meteor/client/components/message/toolbar/MessageActionMenu.tsx b/apps/meteor/client/components/message/toolbar/MessageActionMenu.tsx index 143c0a3fe46a..dcb2fcaf4699 100644 --- a/apps/meteor/client/components/message/toolbar/MessageActionMenu.tsx +++ b/apps/meteor/client/components/message/toolbar/MessageActionMenu.tsx @@ -4,7 +4,7 @@ import type { MouseEvent, ReactElement } from 'react'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import type { MessageActionConditionProps, MessageActionConfig } from '../../../../app/ui-utils/client/lib/MessageAction'; +import type { MessageActionConfig } from '../../../../app/ui-utils/client/lib/MessageAction'; type MessageActionConfigOption = Omit & { action: (e?: MouseEvent) => void; @@ -19,11 +19,10 @@ type MessageActionSection = { type MessageActionMenuProps = { onChangeMenuVisibility: (visible: boolean) => void; options: MessageActionConfigOption[]; - context: MessageActionConditionProps; isMessageEncrypted: boolean; }; -const MessageActionMenu = ({ options, onChangeMenuVisibility, context, isMessageEncrypted }: MessageActionMenuProps): ReactElement => { +const MessageActionMenu = ({ options, onChangeMenuVisibility, isMessageEncrypted }: MessageActionMenuProps): ReactElement => { const { t } = useTranslation(); const id = useUniqueId(); const groupOptions = options @@ -34,9 +33,9 @@ const MessageActionMenu = ({ options, onChangeMenuVisibility, context, isMessage content: t(option.label), onClick: option.action, type: option.type, - ...(option.disabled && { disabled: option?.disabled?.(context) }), - ...(option.disabled && - option?.disabled?.(context) && { tooltip: t('Action_not_available_encrypted_content', { action: t(option.label) }) }), + ...(typeof option.disabled === 'boolean' && { disabled: option.disabled }), + ...(typeof option.disabled === 'boolean' && + option.disabled && { tooltip: t('Action_not_available_encrypted_content', { action: t(option.label) }) }), })) .reduce( (acc, option) => { diff --git a/apps/meteor/client/components/message/toolbar/MessageToolbar.tsx b/apps/meteor/client/components/message/toolbar/MessageToolbar.tsx index 5111c597b93b..dcc9d1332b07 100644 --- a/apps/meteor/client/components/message/toolbar/MessageToolbar.tsx +++ b/apps/meteor/client/components/message/toolbar/MessageToolbar.tsx @@ -3,10 +3,10 @@ import type { IMessage, IRoom, ISubscription, ITranslatedMessage } from '@rocket import { isThreadMessage, isRoomFederated, isVideoConfMessage, isE2EEMessage } from '@rocket.chat/core-typings'; import { MessageToolbar as FuselageMessageToolbar, MessageToolbarItem } from '@rocket.chat/fuselage'; import { useFeaturePreview } from '@rocket.chat/ui-client'; -import { useUser, useSettings, useTranslation, useMethod, useLayoutHiddenActions, useSetting } from '@rocket.chat/ui-contexts'; +import { useUser, useTranslation, useMethod, useLayoutHiddenActions, useSetting } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ComponentProps, ReactElement } from 'react'; -import React, { memo, useMemo, useRef } from 'react'; +import React, { memo, useRef } from 'react'; import MessageActionMenu from './MessageActionMenu'; import MessageToolbarStarsActionMenu from './MessageToolbarStarsActionMenu'; @@ -42,9 +42,6 @@ import { useEmbeddedLayout } from '../../../hooks/useEmbeddedLayout'; import { roomsQueryKeys } from '../../../lib/queryKeys'; 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 { useRoomToolbox } from '../../../views/room/contexts/RoomToolboxContext'; const getMessageContext = (message: IMessage, room: IRoom, context?: MessageActionContext): MessageActionContext => { if (context) { @@ -84,7 +81,6 @@ const MessageToolbar = ({ }: MessageToolbarProps): ReactElement | null => { const t = useTranslation(); const user = useUser() ?? undefined; - const settings = useSettings(); const isLayoutEmbedded = useEmbeddedLayout(); const toolbarRef = useRef(null); @@ -96,21 +92,18 @@ const MessageToolbar = ({ const context = getMessageContext(message, room, messageContext); - const mapSettings = useMemo(() => Object.fromEntries(settings.map((setting) => [setting._id, setting.value])), [settings]); - - const chat = useChat(); const { quickReactions, addRecentEmoji } = useEmojiPickerData(); - const actionButtonApps = useMessageActionAppsActionButtons(context); + const actionButtonApps = useMessageActionAppsActionButtons(message, context); - const starsAction = useMessageActionAppsActionButtons(context, 'ai'); + const starsAction = useMessageActionAppsActionButtons(message, context, 'ai'); const { messageToolbox: hiddenActions } = useLayoutHiddenActions(); const allowStarring = useSetting('Message_AllowStarring'); // TODO: move this to another place - useWebDAVMessageAction(); - useNewDiscussionMessageAction(); + useWebDAVMessageAction(message, { subscription }); + useNewDiscussionMessageAction(message, { user, room, subscription }); useUnpinMessageAction(message, { room, subscription }); usePinMessageAction(message, { room, subscription }); useStarMessageAction(message, { room, user }); @@ -158,13 +151,11 @@ const MessageToolbar = ({ useShowMessageReactionsAction(message); useReadReceiptsDetailsAction(message); - const actionsQueryResult = useQuery({ + const { isSuccess, data } = useQuery({ queryKey: roomsQueryKeys.messageActionsWithParameters(room._id, message), queryFn: async () => { - 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'); + const toolboxItems = await MessageAction.getAll(context, 'message'); + const menuItems = await MessageAction.getAll(context, 'menu'); return { message: toolboxItems.filter((action) => !hiddenActions.includes(action.id)), @@ -174,17 +165,13 @@ const MessageToolbar = ({ keepPreviousData: true, }); - const toolbox = useRoomToolbox(); - const selecting = useIsSelecting(); - const autoTranslateOptions = useAutoTranslate(subscription); - - if (selecting || (!actionsQueryResult.data?.message.length && !actionsQueryResult.data?.menu.length)) { + if (selecting || (!data?.message.length && !data?.menu.length)) { return null; } - const isReactionAllowed = actionsQueryResult.data?.message.find(({ id }) => id === 'reaction-message'); + const isReactionAllowed = data?.message.find(({ id }) => id === 'reaction-message'); const handleSetReaction = (emoji: string) => { setReaction(`:${emoji}:`, message._id); @@ -198,44 +185,38 @@ const MessageToolbar = ({ quickReactions.slice(0, 3).map(({ emoji, image }) => { return handleSetReaction(emoji)} />; })} - {actionsQueryResult.isSuccess && - actionsQueryResult.data.message.map((action) => ( + {isSuccess && + data.message.map((action) => ( action.action(e, { message, tabbar: toolbox, room, chat, autoTranslateOptions })} + onClick={(e): void => action.action(e)} key={action.id} icon={action.icon} - title={ - action?.disabled?.({ message, room, user, subscription, settings: mapSettings, chat, context }) - ? t('Action_not_available_encrypted_content', { action: t(action.label) }) - : t(action.label) - } + title={action?.disabled ? t('Action_not_available_encrypted_content', { action: t(action.label) }) : t(action.label)} data-qa-id={action.label} data-qa-type='message-action-menu' - disabled={action?.disabled?.({ message, room, user, subscription, settings: mapSettings, chat, context })} + disabled={action?.disabled} /> ))} {starsAction.data && starsAction.data.length > 0 && ( ({ ...action, - action: (e) => action.action(e, { message, tabbar: toolbox, room, chat, autoTranslateOptions }), + action: (e) => action.action(e), }))} onChangeMenuVisibility={onChangeMenuVisibility} data-qa-type='message-action-stars-menu-options' - context={{ message, room, user, subscription, settings: mapSettings, chat, context }} isMessageEncrypted={isE2EEMessage(message)} /> )} - {actionsQueryResult.isSuccess && actionsQueryResult.data.menu.length > 0 && ( + {isSuccess && data.menu.length > 0 && ( ({ + options={[...data?.menu, ...(actionButtonApps.data ?? [])].filter(Boolean).map((action) => ({ ...action, - action: (e) => action.action(e, { message, tabbar: toolbox, room, chat, autoTranslateOptions }), + action: (e) => action.action(e), }))} onChangeMenuVisibility={onChangeMenuVisibility} data-qa-type='message-action-menu-options' - context={{ message, room, user, subscription, settings: mapSettings, chat, context }} isMessageEncrypted={isE2EEMessage(message)} /> )} diff --git a/apps/meteor/client/components/message/toolbar/MessageToolbarStarsActionMenu.tsx b/apps/meteor/client/components/message/toolbar/MessageToolbarStarsActionMenu.tsx index 44f9bc558ddd..198e84ec8d97 100644 --- a/apps/meteor/client/components/message/toolbar/MessageToolbarStarsActionMenu.tsx +++ b/apps/meteor/client/components/message/toolbar/MessageToolbarStarsActionMenu.tsx @@ -4,7 +4,7 @@ import type { MouseEvent, ReactElement } from 'react'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import type { MessageActionConditionProps, MessageActionConfig } from '../../../../app/ui-utils/client/lib/MessageAction'; +import type { MessageActionConfig } from '../../../../app/ui-utils/client/lib/MessageAction'; type MessageActionConfigOption = Omit & { action: (e?: MouseEvent) => void; @@ -19,16 +19,10 @@ type MessageActionSection = { type MessageActionMenuProps = { onChangeMenuVisibility: (visible: boolean) => void; options: MessageActionConfigOption[]; - context: MessageActionConditionProps; isMessageEncrypted: boolean; }; -const MessageToolbarStarsActionMenu = ({ - options, - onChangeMenuVisibility, - context, - isMessageEncrypted, -}: MessageActionMenuProps): ReactElement => { +const MessageToolbarStarsActionMenu = ({ options, onChangeMenuVisibility, isMessageEncrypted }: MessageActionMenuProps): ReactElement => { const { t } = useTranslation(); const id = useUniqueId(); @@ -40,9 +34,9 @@ const MessageToolbarStarsActionMenu = ({ content: t(option.label), onClick: option.action, type: option.type, - ...(option.disabled && { disabled: option?.disabled?.(context) }), - ...(option.disabled && - option?.disabled?.(context) && { tooltip: t('Action_not_available_encrypted_content', { action: t(option.label) }) }), + ...(typeof option.disabled === 'boolean' && { disabled: option.disabled }), + ...(typeof option.disabled === 'boolean' && + option.disabled && { tooltip: t('Action_not_available_encrypted_content', { action: t(option.label) }) }), }; const group = option.type || ''; diff --git a/apps/meteor/client/components/message/toolbar/useCopyAction.ts b/apps/meteor/client/components/message/toolbar/useCopyAction.ts index 47c817ab68a7..1604eb0308bd 100644 --- a/apps/meteor/client/components/message/toolbar/useCopyAction.ts +++ b/apps/meteor/client/components/message/toolbar/useCopyAction.ts @@ -27,7 +27,7 @@ export const useCopyAction = (message: IMessage, { subscription }: { subscriptio label: 'Copy_text', context: ['message', 'message-mobile', 'threads', 'federated'], type: 'duplication', - async action(_, { message }) { + async action() { const msgText = getMainMessageText(message).msg; await navigator.clipboard.writeText(msgText); dispatchToastMessage({ type: 'success', message: t('Copied') }); diff --git a/apps/meteor/client/components/message/toolbar/useForwardMessageAction.tsx b/apps/meteor/client/components/message/toolbar/useForwardMessageAction.tsx index eb51efdef2a0..ca7fc4a32976 100644 --- a/apps/meteor/client/components/message/toolbar/useForwardMessageAction.tsx +++ b/apps/meteor/client/components/message/toolbar/useForwardMessageAction.tsx @@ -31,7 +31,7 @@ export const useForwardMessageAction = (message: IMessage) => { }, order: 0, group: 'message', - disabled: () => encrypted, + disabled: encrypted, }); return () => { diff --git a/apps/meteor/client/components/message/toolbar/useNewDiscussionMessageAction.tsx b/apps/meteor/client/components/message/toolbar/useNewDiscussionMessageAction.tsx index 2812e1c06ba8..802f7ec56af9 100644 --- a/apps/meteor/client/components/message/toolbar/useNewDiscussionMessageAction.tsx +++ b/apps/meteor/client/components/message/toolbar/useNewDiscussionMessageAction.tsx @@ -1,27 +1,60 @@ -import { useSetModal, useSetting } from '@rocket.chat/ui-contexts'; +import type { IMessage, IRoom, ISubscription, IUser } from '@rocket.chat/core-typings'; +import { usePermission, useSetModal, useSetting } from '@rocket.chat/ui-contexts'; import React, { useEffect } from 'react'; -import { hasPermission } from '../../../../app/authorization/client'; import { MessageAction } from '../../../../app/ui-utils/client/lib/MessageAction'; import { roomCoordinator } from '../../../lib/rooms/roomCoordinator'; import CreateDiscussion from '../../CreateDiscussion'; -export const useNewDiscussionMessageAction = () => { +export const useNewDiscussionMessageAction = ( + message: IMessage, + { user, room, subscription }: { user: IUser | undefined; room: IRoom; subscription: ISubscription | undefined }, +) => { const enabled = useSetting('Discussion_enabled', false); const setModal = useSetModal(); + const canStartDiscussion = usePermission('start-discussion', room._id); + const canStartDiscussionOtherUser = usePermission('start-discussion-other-user', room._id); + useEffect(() => { if (!enabled) { - return MessageAction.removeButton('start-discussion'); + return; + } + + const { + u: { _id: uid }, + drid, + dcount, + } = message; + if (drid || !Number.isNaN(Number(dcount))) { + return; + } + + if (!subscription) { + return; + } + + const isLivechatRoom = roomCoordinator.isLivechatRoom(room.t); + if (isLivechatRoom) { + return; + } + + if (!user) { + return; + } + + if (!(uid !== user._id ? canStartDiscussionOtherUser : canStartDiscussion)) { + return; } + MessageAction.addButton({ id: 'start-discussion', icon: 'discussion', label: 'Discussion_start', type: 'communication', context: ['message', 'message-mobile', 'videoconf'], - async action(_, { message, room }) { + async action() { setModal( { />, ); }, - condition({ - message: { - u: { _id: uid }, - drid, - dcount, - }, - room, - subscription, - user, - }) { - if (drid || !Number.isNaN(Number(dcount))) { - return false; - } - if (!subscription) { - return false; - } - const isLivechatRoom = roomCoordinator.isLivechatRoom(room.t); - if (isLivechatRoom) { - return false; - } - - if (!user) { - return false; - } - - return uid !== user._id ? hasPermission('start-discussion-other-user', room._id) : hasPermission('start-discussion', room._id); - }, order: 1, group: 'menu', }); + return () => { MessageAction.removeButton('start-discussion'); }; - }, [enabled, setModal]); + }, [canStartDiscussion, canStartDiscussionOtherUser, enabled, message, room?._id, room?.prid, room.t, setModal, subscription, user]); }; diff --git a/apps/meteor/client/components/message/toolbar/usePermalinkAction.ts b/apps/meteor/client/components/message/toolbar/usePermalinkAction.ts index 78a197d5c5d7..a1335e958a7c 100644 --- a/apps/meteor/client/components/message/toolbar/usePermalinkAction.ts +++ b/apps/meteor/client/components/message/toolbar/usePermalinkAction.ts @@ -42,7 +42,7 @@ export const usePermalinkAction = ( }, order, group: 'menu', - disabled: () => encrypted, + disabled: encrypted, }); return () => { diff --git a/apps/meteor/client/components/message/toolbar/useReactionMessageAction.ts b/apps/meteor/client/components/message/toolbar/useReactionMessageAction.ts index 3456a01204a4..6f6c764c99ab 100644 --- a/apps/meteor/client/components/message/toolbar/useReactionMessageAction.ts +++ b/apps/meteor/client/components/message/toolbar/useReactionMessageAction.ts @@ -5,11 +5,14 @@ import { useEffect } from 'react'; import { MessageAction } from '../../../../app/ui-utils/client'; import { sdk } from '../../../../app/utils/client/lib/SDKClient'; import { roomCoordinator } from '../../../lib/rooms/roomCoordinator'; +import { useChat } from '../../../views/room/contexts/ChatContext'; export const useReactionMessageAction = ( message: IMessage, { user, room, subscription }: { user: IUser | undefined; room: IRoom; subscription: ISubscription | undefined }, ) => { + const chat = useChat(); + useEffect(() => { if (!room || isOmnichannelRoom(room) || !subscription || message.private || !user) { return; @@ -24,7 +27,7 @@ export const useReactionMessageAction = ( icon: 'add-reaction', label: 'Add_Reaction', context: ['message', 'message-mobile', 'threads', 'federated', 'videoconf', 'videoconf-threads'], - action(event, { message, chat }) { + action(event) { event?.stopPropagation(); chat?.emojiPicker.open(event?.currentTarget as Element, (emoji) => sdk.call('setReaction', `:${emoji}:`, message._id)); }, @@ -35,5 +38,5 @@ export const useReactionMessageAction = ( return () => { MessageAction.removeButton('reaction-message'); }; - }, [message.private, room, subscription, user]); + }, [chat?.emojiPicker, message._id, message.private, room, subscription, user]); }; diff --git a/apps/meteor/client/components/message/toolbar/useReplyInDMAction.ts b/apps/meteor/client/components/message/toolbar/useReplyInDMAction.ts index 5f3b8781dcb7..cec1de1b0ca6 100644 --- a/apps/meteor/client/components/message/toolbar/useReplyInDMAction.ts +++ b/apps/meteor/client/components/message/toolbar/useReplyInDMAction.ts @@ -24,7 +24,6 @@ export const useReplyInDMAction = ( icon: 'reply-directly', label: 'Reply_in_direct_message', context: ['message', 'message-mobile', 'threads', 'federated'], - role: 'link', type: 'communication', action() { roomCoordinator.openRouteLink( @@ -49,7 +48,7 @@ export const useReplyInDMAction = ( }, order: 0, group: 'menu', - disabled: () => encrypted, + disabled: encrypted, }); return () => { diff --git a/apps/meteor/client/components/message/toolbar/useShowMessageReactionsAction.tsx b/apps/meteor/client/components/message/toolbar/useShowMessageReactionsAction.tsx index a97f3be6d8f2..4f4b006fea5e 100644 --- a/apps/meteor/client/components/message/toolbar/useShowMessageReactionsAction.tsx +++ b/apps/meteor/client/components/message/toolbar/useShowMessageReactionsAction.tsx @@ -5,11 +5,11 @@ import React, { useEffect } from 'react'; import { MessageAction } from '../../../../app/ui-utils/client'; import ReactionListModal from '../../../views/room/modals/ReactionListModal'; -export const useShowMessageReactionsAction = ({ reactions = {} }: IMessage) => { +export const useShowMessageReactionsAction = (message: IMessage) => { const setModal = useSetModal(); useEffect(() => { - if (!reactions) { + if (!message.reactions) { return; } @@ -22,7 +22,7 @@ export const useShowMessageReactionsAction = ({ reactions = {} }: IMessage) => { action() { setModal( { setModal(null); }} @@ -36,5 +36,5 @@ export const useShowMessageReactionsAction = ({ reactions = {} }: IMessage) => { return () => { MessageAction.removeButton('reaction-list'); }; - }, [reactions, setModal]); + }, [message.reactions, setModal]); }; diff --git a/apps/meteor/client/components/message/toolbar/useTranslateAction.ts b/apps/meteor/client/components/message/toolbar/useTranslateAction.ts index 4b43a683ea1f..ba81ae9de82a 100644 --- a/apps/meteor/client/components/message/toolbar/useTranslateAction.ts +++ b/apps/meteor/client/components/message/toolbar/useTranslateAction.ts @@ -44,6 +44,7 @@ export const useTranslateAction = ( label: 'Translate', context: ['message', 'message-mobile', 'threads'], type: 'interaction', + group: 'menu', action() { if (!hasTranslations) { AutoTranslate.messageIdsToWait[message._id] = true; diff --git a/apps/meteor/client/components/message/toolbar/useViewOriginalTranslationAction.ts b/apps/meteor/client/components/message/toolbar/useViewOriginalTranslationAction.ts index 519074a2dfeb..25f32857de45 100644 --- a/apps/meteor/client/components/message/toolbar/useViewOriginalTranslationAction.ts +++ b/apps/meteor/client/components/message/toolbar/useViewOriginalTranslationAction.ts @@ -44,6 +44,7 @@ export const useViewOriginalTranslationAction = ( label: 'View_original', context: ['message', 'message-mobile', 'threads'], type: 'interaction', + group: 'menu', action() { if (!hasTranslations) { AutoTranslate.messageIdsToWait[message._id] = true; diff --git a/apps/meteor/client/components/message/toolbar/useWebDAVMessageAction.tsx b/apps/meteor/client/components/message/toolbar/useWebDAVMessageAction.tsx index 166872acaa42..082985710fc9 100644 --- a/apps/meteor/client/components/message/toolbar/useWebDAVMessageAction.tsx +++ b/apps/meteor/client/components/message/toolbar/useWebDAVMessageAction.tsx @@ -1,3 +1,4 @@ +import type { IMessage, ISubscription } from '@rocket.chat/core-typings'; import { useSetModal, useSetting } from '@rocket.chat/ui-contexts'; import React, { useEffect } from 'react'; @@ -6,7 +7,7 @@ import { getURL } from '../../../../app/utils/client'; import { useWebDAVAccountIntegrationsQuery } from '../../../hooks/webdav/useWebDAVAccountIntegrationsQuery'; import SaveToWebdavModal from '../../../views/room/webdav/SaveToWebdavModal'; -export const useWebDAVMessageAction = () => { +export const useWebDAVMessageAction = (message: IMessage, { subscription }: { subscription: ISubscription | undefined }) => { const enabled = useSetting('Webdav_Integration_Enabled', false); const { data } = useWebDAVAccountIntegrationsQuery({ enabled }); @@ -14,7 +15,7 @@ export const useWebDAVMessageAction = () => { const setModal = useSetModal(); useEffect(() => { - if (!enabled) { + if (!enabled || !subscription || !data?.length || !message.file) { return; } @@ -22,14 +23,18 @@ export const useWebDAVMessageAction = () => { id: 'webdav-upload', icon: 'upload', label: 'Save_To_Webdav', - condition: ({ message, subscription }) => { - return !!subscription && !!data?.length && !!message.file; - }, - action(_, { message }) { + action() { const [attachment] = message.attachments || []; const url = getURL(attachment.title_link as string, { full: true }); - setModal( setModal(undefined)} />); + setModal( + { + setModal(null); + }} + />, + ); }, order: 100, group: 'menu', @@ -38,5 +43,5 @@ export const useWebDAVMessageAction = () => { return () => { MessageAction.removeButton('webdav-upload'); }; - }, [data?.length, enabled, setModal]); + }, [data?.length, enabled, message.attachments, message.file, setModal, subscription]); }; diff --git a/apps/meteor/client/hooks/useAppActionButtons.ts b/apps/meteor/client/hooks/useAppActionButtons.ts index 0dcb2d380d46..692df862470f 100644 --- a/apps/meteor/client/hooks/useAppActionButtons.ts +++ b/apps/meteor/client/hooks/useAppActionButtons.ts @@ -1,4 +1,5 @@ import { type IUIActionButton, type UIActionButtonContext } from '@rocket.chat/apps-engine/definition/ui'; +import type { IMessage } from '@rocket.chat/core-typings'; import { useDebouncedCallback } from '@rocket.chat/fuselage-hooks'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useStream, useToastMessageDispatch, useUserId } from '@rocket.chat/ui-contexts'; @@ -161,7 +162,7 @@ export const useUserDropdownAppsActionButtons = () => { } as UseQueryResult; }; -export const useMessageActionAppsActionButtons = (context?: MessageActionContext, category?: string) => { +export const useMessageActionAppsActionButtons = (message: IMessage, context?: MessageActionContext, category?: string) => { const result = useAppActionButtons('messageAction'); const actionManager = useUiKitActionManager(); const applyButtonFilters = useApplyButtonFilters(category); @@ -185,13 +186,14 @@ export const useMessageActionAppsActionButtons = (context?: MessageActionContext order: 7, type: 'apps', variant: action.variant, - action: (_, params) => { + group: 'menu', + action: () => { void actionManager .emitInteraction(action.appId, { type: 'actionButton', - rid: params.message.rid, - tmid: params.message.tmid, - mid: params.message._id, + rid: message.rid, + tmid: message.tmid, + mid: message._id, actionId: action.actionId, payload: { context: action.context }, }) @@ -211,7 +213,17 @@ export const useMessageActionAppsActionButtons = (context?: MessageActionContext return item; }), - [actionManager, applyButtonFilters, dispatchToastMessage, filterActionsByContext, result.data, t], + [ + actionManager, + applyButtonFilters, + dispatchToastMessage, + filterActionsByContext, + message._id, + message.rid, + message.tmid, + result.data, + t, + ], ); return { ...result,