Skip to content

Commit

Permalink
Merge branch 'develop' into fix-livechat-appearance-CE
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Nov 25, 2024
2 parents 4f5ef2a + 7b4dc03 commit 784cb67
Show file tree
Hide file tree
Showing 34 changed files with 449 additions and 523 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ jobs:
docker run --rm -w /app/bundle/programs/server/npm/node_modules/matrix-appservice-bridge ghcr.io/rocketchat/rocket.chat:$RC_DOCKER_TAG -e 'require(".")'
- name: Rename official Docker tag to GitHub Container Registry
if: matrix.platform == needs.release-versions.outputs.official-platform
if: matrix.platform == needs.release-versions.outputs.official-platform && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') && github.actor != 'dependabot[bot]'
run: |
IMAGE_NAME_BASE="ghcr.io/${LOWERCASE_REPOSITORY}/rocket.chat:${DOCKER_TAG}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { IMessage } from '@rocket.chat/core-typings';
import { useToastMessageDispatch, useEndpoint } from '@rocket.chat/ui-contexts';
import { useQueryClient, useMutation } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';

import { toggleStarredMessage } from '../../../lib/mutationEffects/starredMessage';
import { roomsQueryKeys } from '../../../lib/queryKeys';

export const useStarMessageMutation = () => {
const { t } = useTranslation();
const dispatchToastMessage = useToastMessageDispatch();

const queryClient = useQueryClient();

const starMessage = useEndpoint('POST', '/v1/chat.starMessage');

return useMutation({
mutationFn: async (message: IMessage) => {
await starMessage({ messageId: message._id });
},
onSuccess: (_data, message) => {
toggleStarredMessage(message, true);
dispatchToastMessage({ type: 'success', message: t('Message_has_been_starred') });
},
onError: (error) => {
dispatchToastMessage({ type: 'error', message: error });
},
onSettled: (_data, _error, message) => {
queryClient.invalidateQueries(roomsQueryKeys.starredMessages(message.rid));
queryClient.invalidateQueries(roomsQueryKeys.messageActions(message.rid, message._id));
},
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { IMessage } from '@rocket.chat/core-typings';
import { useToastMessageDispatch, useEndpoint } from '@rocket.chat/ui-contexts';
import { useQueryClient, useMutation } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';

import { toggleStarredMessage } from '../../../lib/mutationEffects/starredMessage';
import { roomsQueryKeys } from '../../../lib/queryKeys';

export const useUnstarMessageMutation = () => {
const { t } = useTranslation();
const dispatchToastMessage = useToastMessageDispatch();

const queryClient = useQueryClient();

const unstarMessage = useEndpoint('POST', '/v1/chat.unStarMessage');

return useMutation({
mutationFn: async (message: IMessage) => {
await unstarMessage({ messageId: message._id });
},
onSuccess: (_data, message) => {
toggleStarredMessage(message, false);
dispatchToastMessage({ type: 'success', message: t('Message_has_been_unstarred') });
},
onError: (error) => {
dispatchToastMessage({ type: 'error', message: error });
},
onSettled: (_data, _error, message) => {
queryClient.invalidateQueries(roomsQueryKeys.starredMessages(message.rid));
queryClient.invalidateQueries(roomsQueryKeys.messageActions(message.rid, message._id));
},
});
};
33 changes: 22 additions & 11 deletions apps/meteor/client/components/message/toolbar/MessageToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ import React, { memo, useMemo, useRef } from 'react';
import MessageActionMenu from './MessageActionMenu';
import MessageToolbarStarsActionMenu from './MessageToolbarStarsActionMenu';
import { useNewDiscussionMessageAction } from './useNewDiscussionMessageAction';
import { usePermalinkStar } from './usePermalinkStar';
import { useStarMessageAction } from './useStarMessageAction';
import { useUnstarMessageAction } from './useUnstarMessageAction';
import { useWebDAVMessageAction } from './useWebDAVMessageAction';
import type { MessageActionContext } from '../../../../app/ui-utils/client/lib/MessageAction';
import { MessageAction } from '../../../../app/ui-utils/client/lib/MessageAction';
import { useEmojiPickerData } from '../../../contexts/EmojiPickerContext';
import { useMessageActionAppsActionButtons } from '../../../hooks/useAppActionButtons';
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';
Expand Down Expand Up @@ -87,17 +91,24 @@ const MessageToolbar = ({
// TODO: move this to another place
useWebDAVMessageAction();
useNewDiscussionMessageAction();

const actionsQueryResult = useQuery(['rooms', room._id, 'messages', message._id, 'actions'] as const, 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');

return {
message: toolboxItems.filter((action) => !hiddenActions.includes(action.id)),
menu: menuItems.filter((action) => !(isLayoutEmbedded && action.id === 'reply-directly') && !hiddenActions.includes(action.id)),
};
useStarMessageAction(message, { room, user });
useUnstarMessageAction(message, { room, user });
usePermalinkStar(message, { subscription, user });

const actionsQueryResult = 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');

return {
message: toolboxItems.filter((action) => !hiddenActions.includes(action.id)),
menu: menuItems.filter((action) => !(isLayoutEmbedded && action.id === 'reply-directly') && !hiddenActions.includes(action.id)),
};
},
keepPreviousData: true,
});

const toolbox = useRoomToolbox();
Expand Down
48 changes: 48 additions & 0 deletions apps/meteor/client/components/message/toolbar/usePermalinkStar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { IMessage, ISubscription, IUser } from '@rocket.chat/core-typings';
import { isE2EEMessage } from '@rocket.chat/core-typings';
import { useToastMessageDispatch } from '@rocket.chat/ui-contexts';
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';

import { MessageAction } from '../../../../app/ui-utils/client/lib/MessageAction';
import { getPermaLink } from '../../../lib/getPermaLink';

export const usePermalinkStar = (
message: IMessage,
{ user, subscription }: { user: IUser | undefined; subscription: ISubscription | undefined },
) => {
const { t } = useTranslation();

const dispatchToastMessage = useToastMessageDispatch();

const encrypted = isE2EEMessage(message);

useEffect(() => {
if (!subscription) {
return;
}

MessageAction.addButton({
id: 'permalink-star',
icon: 'permalink',
label: 'Copy_link',
context: ['starred'],
async action() {
try {
const permalink = await getPermaLink(message._id);
navigator.clipboard.writeText(permalink);
dispatchToastMessage({ type: 'success', message: t('Copied') });
} catch (e) {
dispatchToastMessage({ type: 'error', message: e });
}
},
order: 10,
group: 'menu',
disabled: () => encrypted,
});

return () => {
MessageAction.removeButton('permalink-star');
};
}, [dispatchToastMessage, encrypted, message._id, message.starred, subscription, t, user?._id]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings';
import { isOmnichannelRoom } from '@rocket.chat/core-typings';
import { useSetting } from '@rocket.chat/ui-contexts';
import { useEffect } from 'react';

import { MessageAction } from '../../../../app/ui-utils/client/lib/MessageAction';
import { useStarMessageMutation } from '../hooks/useStarMessageMutation';

export const useStarMessageAction = (message: IMessage, { room, user }: { room: IRoom; user: IUser | undefined }) => {
const allowStarring = useSetting('Message_AllowStarring', true);

const { mutateAsync: starMessage } = useStarMessageMutation();

useEffect(() => {
if (!allowStarring || isOmnichannelRoom(room)) {
return;
}

if (Array.isArray(message.starred) && message.starred.some((star) => star._id === user?._id)) {
return;
}

MessageAction.addButton({
id: 'star-message',
icon: 'star',
label: 'Star',
type: 'interaction',
context: ['starred', 'message', 'message-mobile', 'threads', 'federated', 'videoconf', 'videoconf-threads'],
async action() {
await starMessage(message);
},
order: 3,
group: 'menu',
});

return () => {
MessageAction.removeButton('star-message');
};
}, [allowStarring, message, room, starMessage, user?._id]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings';
import { isOmnichannelRoom } from '@rocket.chat/core-typings';
import { useSetting } from '@rocket.chat/ui-contexts';
import { useEffect } from 'react';

import { MessageAction } from '../../../../app/ui-utils/client/lib/MessageAction';
import { useUnstarMessageMutation } from '../hooks/useUnstarMessageMutation';

export const useUnstarMessageAction = (message: IMessage, { room, user }: { room: IRoom; user: IUser | undefined }) => {
const allowStarring = useSetting('Message_AllowStarring');

const { mutateAsync: unstarMessage } = useUnstarMessageMutation();

useEffect(() => {
if (!allowStarring || isOmnichannelRoom(room)) {
return;
}

if (!Array.isArray(message.starred) || message.starred.every((star) => star._id !== user?._id)) {
return;
}

MessageAction.addButton({
id: 'unstar-message',
icon: 'star',
label: 'Unstar_Message',
type: 'interaction',
context: ['starred', 'message', 'message-mobile', 'threads', 'federated', 'videoconf', 'videoconf-threads'],
async action() {
await unstarMessage(message);
},
order: 3,
group: 'menu',
});

return () => {
MessageAction.removeButton('unstar-message');
};
}, [allowStarring, message, room, unstarMessage, user?._id]);
};
9 changes: 5 additions & 4 deletions apps/meteor/client/hooks/useReactiveQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export const useReactiveQuery = <TQueryFnData, TData = TQueryFnData, TQueryKey e
): UseQueryResult<TData, Error> => {
const queryClient = useQueryClient();

return useQuery(
return useQuery({
queryKey,
(): Promise<TQueryFnData> =>
queryFn: (): Promise<TQueryFnData> =>
new Promise((resolve, reject) => {
queueMicrotask(() => {
Tracker.autorun((c) => {
Expand All @@ -33,6 +33,7 @@ export const useReactiveQuery = <TQueryFnData, TData = TQueryFnData, TQueryKey e
});
});
}),
{ staleTime: Infinity, ...options },
);
staleTime: Infinity,
...options,
});
};
19 changes: 19 additions & 0 deletions apps/meteor/client/lib/mutationEffects/room.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Meteor } from 'meteor/meteor';

import { Subscriptions } from '../../../app/models/client';

export const toggleFavoriteRoom = (roomId: string, favorite: boolean) => {
const userId = Meteor.userId()!;

Subscriptions.update(
{
'rid': roomId,
'u._id': userId,
},
{
$set: {
f: favorite,
},
},
);
};
29 changes: 29 additions & 0 deletions apps/meteor/client/lib/mutationEffects/starredMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { IMessage } from '@rocket.chat/core-typings';
import { Meteor } from 'meteor/meteor';

import { Messages } from '../../../app/models/client';

export const toggleStarredMessage = (message: IMessage, starred: boolean) => {
const uid = Meteor.userId()!;

if (starred) {
Messages.update(
{ _id: message._id },
{
$addToSet: {
starred: { _id: uid },
},
},
);
return;
}

Messages.update(
{ _id: message._id },
{
$pull: {
starred: { _id: uid },
},
},
);
};
17 changes: 17 additions & 0 deletions apps/meteor/client/lib/queryKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { IMessage, IRoom, Serialized } from '@rocket.chat/core-typings';

export const roomsQueryKeys = {
all: ['rooms'] as const,
room: (rid: IRoom['_id']) => ['rooms', rid] as const,
starredMessages: (rid: IRoom['_id']) => [...roomsQueryKeys.room(rid), 'starred-messages'] as const,
messages: (rid: IRoom['_id']) => [...roomsQueryKeys.room(rid), 'messages'] as const,
message: (rid: IRoom['_id'], mid: IMessage['_id']) => [...roomsQueryKeys.messages(rid), mid] as const,
messageActions: (rid: IRoom['_id'], mid: IMessage['_id']) => [...roomsQueryKeys.message(rid, mid), 'actions'] as const,
messageActionsWithParameters: (rid: IRoom['_id'], message: IMessage | Serialized<IMessage>) =>
[...roomsQueryKeys.messageActions(rid, message._id), message] as const,
};

export const subscriptionsQueryKeys = {
all: ['subscriptions'] as const,
subscription: (rid: IRoom['_id']) => [...subscriptionsQueryKeys.all, { rid }] as const,
};
2 changes: 0 additions & 2 deletions apps/meteor/client/methods/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import './hideRoom';
import './openRoom';
import './pinMessage';
import './starMessage';
import './toggleFavorite';
import './unpinMessage';
import './updateMessage';
Loading

0 comments on commit 784cb67

Please sign in to comment.