-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Welcome to the Rocket.Chat wiki!
This is a personal documentation of my findings while exploring the Rocket.chat core monorepo. Most of it is through my digging and understanding of how everything comes together.
Important: Don't bother looking up the official documentation. Those are for developers looking to create third party apps on top of the Rocket.chat interface or framework. The project I am looking to contribute to currently requires peeking at the Rocket.chat core codebase, especially the Composer component. I am entirely on my own at the moment.
Just wrap <span title="example"></span> around a particular DOM/TSX element and run the yarn dsv command, and on mouse hovering that element, a floating bubble will show "example" on that element. It has been helping me to quickly explore the codebase by "bookmarking" elements.
-
apps/meteor/packages/rocketchat-i18n/i18n/is a symlink topackages/i18n/src/locales -
apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.jsonorpackages/i18n/src/locales/en.i18n.jsonstores all the default English files. Probably the easiest thing to tinker about modifying strings for every existing sentence on RC. - Numbers enclosing in tag structures such as
<0></0>,<1></1>,<2></2>and so on, are replaced. Texts within these tags can be thought of as labels. These are not rendered. Sometimes, they are labeled within{{variable}}. Need a better understanding of thereact-i18nextlibrary. - The
react-18nextlibrary has been explained visually here. -
apps/meteor/client/views/room/composeris the root folder probably containing all the files related to the Message Composer. -
apps/meteor/client/views/room/composer/RoomComposer/RoomComposer.tsxis the root component of the Composer. It loads all the{children}components within this component. -
apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx:
- In L403: This code is responsible for the emoji picker
<MessageComposerAction
icon='emoji'
disabled={!useEmojis || isRecording || !canSend}
onClick={handleOpenEmojiPicker}
title={t('Emoji')}
/>- In L409: This code renders the divider between the Emoji picker button and the Bold formatter button
<MessageComposerActionsDivider />- In L410: This code renders the formatter buttons Bold, Italics, Strikethrough, Inline code, Multi-Line code, Link and KaTeX
{chat.composer && formatters.length > 0 && (
MessageBoxFormattingToolbar
composer={chat.composer}
variant={sizes.inlineSize < 480 ? 'small' : 'large'}
items={formatters}
disabled={isRecording || !canSend}
/>
)}- In L428: This code renders the Submit button. How the button functions needs to be studied. Also disabling this code does not disable the Enter to send hotkey.
<MessageComposerToolbarSubmit>
{!canSend && (
<MessageComposerButton primary onClick={onJoin} loading={joinMutation.isPending}>
{t('Join')}
</MessageComposerButton>
)}
{canSend && (
<>
{isEditing && <MessageComposerButton onClick={closeEditing}>{t('Cancel')}</MessageComposerButton>}
<MessageComposerAction
aria-label={t('Send')}
icon='send'
disabled={!canSend || (!typing && !isEditing)}
onClick={handleSendMessage}
secondary={typing || isEditing}
info={typing || isEditing}
/>
</>
)}
</MessageComposerToolbarSubmit>- In L161: When logging the parameters sent to
onSend(),textholds the value of the user input in the Composer textbox,tshowisundefined,previewUrlsisundefinedandisSlashCommandAllowedistrue
const handleSendMessage = useEffectEvent(() => {
const text = chat.composer?.text ?? '';
chat.composer?.clear();
popup.clear();
// console.log("Executing handleSendMessage");
// console.log("Text:", text);
// console.log("tshow:", tshow);
// console.log("previewUrls:", previewUrls);
// console.log("isSlashCommandAllowed:", isSlashCommandAllowed);
onSend?.({
value: text,
tshow,
previewUrls,
isSlashCommandAllowed,
});
});- From L44 to L67: Modifying the code as shown below to accept a hardcoded message proves that the onSend function is defined here and
MessageBox.tsxis imported in L11
onSend: async ({
value: _text,
tshow,
previewUrls,
isSlashCommandAllowed,
}: {
value: string;
tshow?: boolean;
previewUrls?: string[];
isSlashCommandAllowed?: boolean;
}): Promise<void> => {
try {
await chat?.action.stop('typing');
const hardcodedMessage = "This is a hardcoded message!";
const newMessageSent = await chat?.flows.sendMessage({
text: hardcodedMessage,
tshow,
previewUrls,
isSlashCommandAllowed,
});
if (newMessageSent) onSend?.();
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
}
},- From L146: There is a definition for sendMessage, but I do not think it is part of the stack call.
readonly flows: {
readonly uploadFiles: (files: readonly File[], resetFileInput?: () => void) => Promise<void>;
readonly sendMessage: ({
text,
tshow,
}: {
text: string;
tshow?: boolean;
previewUrls?: string[];
isSlashCommandAllowed?: boolean;
}) => Promise<boolean>;
readonly processSlashCommand: (message: IMessage, userId: string | null) => Promise<boolean>;
readonly processTooLongMessage: (message: IMessage) => Promise<boolean>;
readonly processMessageEditing: (
message: Pick<IMessage, '_id' | 't'> & Partial<Omit<IMessage, '_id' | 't'>>,
previewUrls?: string[],
) => Promise<boolean>;
readonly processSetReaction: (message: Pick<IMessage, 'msg'>) => Promise<boolean>;
readonly requestMessageDeletion: (message: IMessage) => Promise<void>;
readonly replyBroadcast: (message: IMessage) => Promise<void>;
};- In L14:
sendMessageis imported
import { sendMessage } from '../../../../client/lib/chats/flows/sendMessage';- In L178:
sendMessagebinding function is present
this.flows = {
uploadFiles: uploadFiles.bind(null, this),
sendMessage: sendMessage.bind(this, this),
processSlashCommand: processSlashCommand.bind(null, this),
processTooLongMessage: processTooLongMessage.bind(null, this),
processMessageEditing: processMessageEditing.bind(null, this),
processSetReaction: processSetReaction.bind(null, this),
requestMessageDeletion: requestMessageDeletion.bind(this, this),
replyBroadcast: replyBroadcast.bind(null, this),
};-
L38: The
sendMessagefunction is declared here. Executing aconsole.trace()confirms the stack call.
export const sendMessage = async (
chat: ChatAPI,
{
text,
tshow,
previewUrls,
isSlashCommandAllowed,
}: { text: string; tshow?: boolean; previewUrls?: string[]; isSlashCommandAllowed?: boolean },
): Promise<boolean> => {
console.trace("sendMessage function called with: text: ", text, ", tshow: ", tshow, ", previewUrls: ", previewUrls, ", isSlashCommandAllowed: ", isSlashCommandAllowed);
.
.
.
}-
L317:
textis defined as a getter function and NOT a variable. Theinput.valuereturns santized text from thetextareacomponent.
get text(): string {
return input.value;
},