Skip to content

Commit

Permalink
refactor: Message actions (1st iteration) (#34133)
Browse files Browse the repository at this point in the history
  • Loading branch information
tassoevan authored Dec 12, 2024
1 parent f11efb4 commit 3d41ae2
Show file tree
Hide file tree
Showing 65 changed files with 1,686 additions and 1,423 deletions.
89 changes: 0 additions & 89 deletions apps/meteor/app/autotranslate/client/lib/actionButton.ts
Original file line number Diff line number Diff line change
@@ -1,96 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';

import { AutoTranslate } from './autotranslate';
import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator';
import {
hasTranslationLanguageInAttachments,
hasTranslationLanguageInMessage,
} from '../../../../client/views/room/MessageList/lib/autoTranslate';
import { hasAtLeastOnePermission } from '../../../authorization/client';
import { Messages } from '../../../models/client';
import { settings } from '../../../settings/client';
import { MessageAction } from '../../../ui-utils/client/lib/MessageAction';
import { sdk } from '../../../utils/client/lib/SDKClient';

Meteor.startup(() => {
AutoTranslate.init();

Tracker.autorun(() => {
if (settings.get('AutoTranslate_Enabled') && hasAtLeastOnePermission(['auto-translate'])) {
MessageAction.addButton({
id: 'translate',
icon: 'language',
label: 'Translate',
context: ['message', 'message-mobile', 'threads'],
type: 'interaction',
action(_, { message }) {
const language = AutoTranslate.getLanguage(message.rid);
if (!hasTranslationLanguageInMessage(message, language) && !hasTranslationLanguageInAttachments(message.attachments, language)) {
(AutoTranslate.messageIdsToWait as any)[message._id] = true;
Messages.update({ _id: message._id }, { $set: { autoTranslateFetching: true } });
void sdk.call('autoTranslate.translateMessage', message, language);
}
const action = 'autoTranslateShowInverse' in message ? '$unset' : '$set';
Messages.update({ _id: message._id }, { [action]: { autoTranslateShowInverse: true } });
},
condition({ message, subscription, user, room }) {
if (!user) {
return false;
}
const language = subscription?.autoTranslateLanguage || AutoTranslate.getLanguage(message.rid) || '';
const isLivechatRoom = roomCoordinator.isLivechatRoom(room?.t);
const isDifferentUser = message?.u && message.u._id !== user._id;
const autoTranslateEnabled = subscription?.autoTranslate || isLivechatRoom;
const hasLanguage =
hasTranslationLanguageInMessage(message, language) || hasTranslationLanguageInAttachments(message.attachments, language);

return Boolean(
(message as { autoTranslateShowInverse?: boolean }).autoTranslateShowInverse ||
(isDifferentUser && autoTranslateEnabled && !hasLanguage),
);
},
order: 90,
});
MessageAction.addButton({
id: 'view-original',
icon: 'language',
label: 'View_original',
context: ['message', 'message-mobile', 'threads'],
type: 'interaction',
action(_, props) {
const { message } = props;
const language = AutoTranslate.getLanguage(message.rid);
if (!hasTranslationLanguageInMessage(message, language) && !hasTranslationLanguageInAttachments(message.attachments, language)) {
(AutoTranslate.messageIdsToWait as any)[message._id] = true;
Messages.update({ _id: message._id }, { $set: { autoTranslateFetching: true } });
void sdk.call('autoTranslate.translateMessage', message, language);
}
const action = 'autoTranslateShowInverse' in message ? '$unset' : '$set';
Messages.update({ _id: message._id }, { [action]: { autoTranslateShowInverse: true } });
},
condition({ message, subscription, user, room }) {
const language = subscription?.autoTranslateLanguage || AutoTranslate.getLanguage(message.rid) || '';
const isLivechatRoom = roomCoordinator.isLivechatRoom(room?.t);
if (!user) {
return false;
}
const isDifferentUser = message?.u && message.u._id !== user._id;
const autoTranslateEnabled = subscription?.autoTranslate || isLivechatRoom;
const hasLanguage =
hasTranslationLanguageInMessage(message, language) || hasTranslationLanguageInAttachments(message.attachments, language);

return Boolean(
!(message as { autoTranslateShowInverse?: boolean }).autoTranslateShowInverse &&
isDifferentUser &&
autoTranslateEnabled &&
hasLanguage,
);
},
order: 90,
});
} else {
MessageAction.removeButton('toggle-language');
}
});
});
2 changes: 1 addition & 1 deletion apps/meteor/app/autotranslate/client/lib/autotranslate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Meteor.startup(() => {
export const AutoTranslate = {
initialized: false,
providersMetadata: {} as { [providerNamer: string]: { name: string; displayName: string } },
messageIdsToWait: {} as { [messageId: string]: string },
messageIdsToWait: {} as { [messageId: string]: boolean },
supportedLanguages: [] as ISupportedLanguage[] | undefined,

findSubscriptionByRid: mem((rid) => Subscriptions.findOne({ rid })),
Expand Down
3 changes: 0 additions & 3 deletions apps/meteor/app/ui-utils/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import './lib/messageActionDefault';

export { MessageAction } from './lib/MessageAction';
export { messageBox } from './lib/messageBox';
export { LegacyRoomManager } from './lib/LegacyRoomManager';
export { upsertMessage, RoomHistoryManager } from './lib/RoomHistoryManager';
Expand Down
96 changes: 7 additions & 89 deletions apps/meteor/app/ui-utils/client/lib/MessageAction.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
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';
type MessageActionGroup = 'menu';

export type MessageActionContext =
| 'message'
Expand All @@ -25,92 +18,17 @@ 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<typeof ChatContext>;
};

export type MessageActionConfig = {
id: string;
icon: IconName;
variant?: 'danger' | 'success' | 'warning';
label: TranslationKey;
order?: number;
/* @deprecated */
color?: string;
role?: string;
group?: MessageActionGroup | MessageActionGroup[];
order: number;
/** @deprecated */
color?: 'alert';
group: MessageActionGroup;
context?: MessageActionContext[];
action: (
e: Pick<Event, 'preventDefault' | 'stopPropagation' | 'currentTarget'> | undefined,
{
message,
tabbar,
room,
chat,
autoTranslateOptions,
}: {
message: IMessage & Partial<ITranslatedMessage>;
tabbar: RoomToolboxContextValue;
room?: IRoom;
chat: ContextType<typeof ChatContext>;
autoTranslateOptions?: AutoTranslateOptions;
},
) => any;
condition?: (props: MessageActionConditionProps) => Promise<boolean> | boolean;
action: (e: Pick<Event, 'preventDefault' | 'stopPropagation' | 'currentTarget'> | undefined) => any;
type?: MessageActionType;
disabled?: (props: MessageActionConditionProps) => boolean;
disabled?: boolean;
};

class MessageAction {
public buttons: Record<MessageActionConfig['id'], MessageActionConfig> = {};

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 });
}

this.buttons[config.id] = config;
}

public removeButton(id: MessageActionConfig['id']): void {
delete this.buttons[id];
}

public async getAll(
props: MessageActionConditionProps,
context: MessageActionContext,
group: MessageActionGroup,
): Promise<MessageActionConfig[]> {
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.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);
}
}

const instance = new MessageAction();

export { instance as MessageAction };
Loading

0 comments on commit 3d41ae2

Please sign in to comment.