Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
052a23b
refactor: replace ReactiveVar in VideoRecorder with Emitter + hook
ggazzo Apr 22, 2026
87605b8
refactor: drop Meteor.startup wrapper from autotranslate actionButton
ggazzo Apr 22, 2026
dfd65a5
refactor: drop meteor/meteor type import from join slash command
ggazzo Apr 22, 2026
3c3a4bc
refactor: drop meteor/meteor from getConfig
ggazzo Apr 22, 2026
d763df6
refactor: drop meteor/tracker from timeAgo
ggazzo Apr 22, 2026
8ffd497
refactor: replace setReaction client method stub with explicit optimi…
ggazzo Apr 23, 2026
bac52df
refactor: replace sendMessage client method stub with explicit optimi…
ggazzo Apr 23, 2026
096a447
chore: mark Meteor.absoluteUrl rootUrl override for removal with DDP
ggazzo Apr 23, 2026
a22a64a
refactor: replace Tracker.autorun with settings.observe in queueManager
ggazzo Apr 23, 2026
ca67c54
refactor: drop meteor/meteor and meteor/tracker from autotranslate mo…
ggazzo Apr 23, 2026
dc8f862
refactor: replace ReactiveVar/Tracker in RoomHistoryManager with Emit…
ggazzo Apr 23, 2026
dde0473
chore: mark Meteor.absoluteUrl/OAuth overrides for removal with DDP
ggazzo Apr 23, 2026
28b73ed
refactor: drop meteor/meteor type import from useIframe
ggazzo Apr 23, 2026
32b7c77
refactor: drop meteor/accounts-base from RoomE2EESetup
ggazzo Apr 23, 2026
bea31bf
refactor: drop meteor/tracker from GameCenterInvitePlayersModal
ggazzo Apr 23, 2026
2464755
refactor: replace meteor/session with in-memory Emitter in SessionPro…
ggazzo Apr 23, 2026
cda6d36
refactor: drop meteor/meteor type import from IOAuthProvider
ggazzo Apr 23, 2026
922c602
refactor: drop dead Tracker.autorun from IndexRoute
ggazzo Apr 24, 2026
e653eda
refactor: drop Meteor.startup wrapper from incomingMessages
ggazzo Apr 24, 2026
af5390d
refactor: drop meteor/* from roles startup
ggazzo Apr 24, 2026
31053ab
refactor: drop meteor/* from autotranslate stream startup
ggazzo Apr 24, 2026
cc96a59
chore: mark Meteor.autorun userId sync in userAndUsers for removal wi…
ggazzo Apr 24, 2026
d8a7e10
refactor: drop meteor/* from client/startup/startup.ts
ggazzo Apr 24, 2026
f8af87c
refactor: drop useReactiveValue from useIsSingleBusinessHours
ggazzo Apr 24, 2026
cc3e0a7
refactor: drop useReactiveValue from readOnly-aware hooks/components
ggazzo Apr 24, 2026
473d505
refactor: drop useReactiveValue from MessageBox.canSend
ggazzo Apr 24, 2026
5a51985
refactor: remove weird iife
tassoevan Apr 29, 2026
dbbd6be
fix: use subscription's `stop` method as effect cleanup function
tassoevan Apr 29, 2026
d5a191f
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into work…
tassoevan Apr 29, 2026
2a3f03e
refactor: remove unused `afterLogoutCleanUp` callback on client
tassoevan Apr 29, 2026
da589a5
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into work…
tassoevan Apr 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions apps/meteor/app/autotranslate/client/lib/actionButton.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import { Meteor } from 'meteor/meteor';

import { AutoTranslate } from './autotranslate';

Meteor.startup(() => {
AutoTranslate.init();
});
AutoTranslate.init();
56 changes: 33 additions & 23 deletions apps/meteor/app/autotranslate/client/lib/autotranslate.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import type { IRoom, ISubscription, ISupportedLanguage, ITranslatedMessage, MessageAttachmentDefault } from '@rocket.chat/core-typings';
import { isTranslatedMessageAttachment } from '@rocket.chat/core-typings';
import mem from 'mem';
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';

import { PermissionsCachedStore } from '../../../../client/cachedStores';
import { settings } from '../../../../client/lib/settings';
import { getUserId } from '../../../../client/lib/user';
import { watchUser, watchUserId } from '../../../../client/meteor/user';
import { Messages, Subscriptions } from '../../../../client/stores';
import { getUserId, userIdStore } from '../../../../client/lib/user';
import { Messages, Subscriptions, Users } from '../../../../client/stores';
import {
hasTranslationLanguageInAttachments,
hasTranslationLanguageInMessage,
Expand All @@ -18,15 +16,16 @@ import { sdk } from '../../../utils/client/lib/SDKClient';
let userLanguage = 'en';
let username = '';

Meteor.startup(() => {
Tracker.autorun(() => {
const user = watchUser();
if (!user) return;

userLanguage = user.language || 'en';
username = user.username || '';
});
});
const refreshUserCache = () => {
const uid = userIdStore.getState();
const user = uid ? Users.use.getState().get(uid) : undefined;
if (!user) return;
userLanguage = user.language || 'en';
username = user.username || '';
};
refreshUserCache();
userIdStore.subscribe(refreshUserCache);
Users.use.subscribe(refreshUserCache);

export const AutoTranslate = {
initialized: false,
Expand Down Expand Up @@ -84,14 +83,7 @@ export const AutoTranslate = {
return;
}

Tracker.autorun(async (c) => {
const uid = watchUserId();
if (!settings.watch('AutoTranslate_Enabled') || !uid || !hasPermission('auto-translate')) {
return;
}

c.stop();

const loadProviders = async () => {
try {
[this.providersMetadata, this.supportedLanguages] = await Promise.all([
sdk.call('autoTranslate.getProviderUiMetadata'),
Expand All @@ -101,7 +93,25 @@ export const AutoTranslate = {
// Avoid unwanted error message on UI when autotranslate is disabled while fetching data
console.error((e as Error).message);
}
});
};

let loaded = false;
const unsubs: Array<() => void> = [];
const tryLoad = async () => {
if (loaded) return;
if (!settings.peek('AutoTranslate_Enabled') || !userIdStore.getState() || !hasPermission('auto-translate')) {
return;
}
loaded = true;
unsubs.splice(0).forEach((unsubscribe) => unsubscribe());
await loadProviders();
};

unsubs.push(userIdStore.subscribe(() => void tryLoad()));
unsubs.push(settings.observe('AutoTranslate_Enabled', () => void tryLoad()));
unsubs.push(PermissionsCachedStore.useReady.subscribe(() => void tryLoad()));

void tryLoad();

Subscriptions.use.subscribe(() => {
mem.clear(this.findSubscriptionByRid);
Expand Down
1 change: 0 additions & 1 deletion apps/meteor/app/lib/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
import '../lib/MessageTypes';
import './OAuthProxy';
import './methods/sendMessage';
69 changes: 34 additions & 35 deletions apps/meteor/app/lib/client/methods/sendMessage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { IMessage } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { clientCallbacks } from '@rocket.chat/ui-client';
import { Meteor } from 'meteor/meteor';

import { onClientMessageReceived } from '../../../../client/lib/onClientMessageReceived';
import { settings } from '../../../../client/lib/settings';
Expand All @@ -11,40 +9,41 @@ import { Messages, Rooms } from '../../../../client/stores';
import { trim } from '../../../../lib/utils/stringUtils';
import { t } from '../../../utils/lib/i18n';

Meteor.methods<ServerMethods>({
async sendMessage(message) {
const uid = getUserId();
if (!uid || trim(message.msg) === '') {
return false;
}
const messageAlreadyExists = message._id && Messages.state.get(message._id);
if (messageAlreadyExists) {
return dispatchToastMessage({ type: 'error', message: t('Message_Already_Sent') });
}
const user = getUser();
if (!user?.username) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'sendMessage' });
}
message.ts = new Date();
message.u = {
export const runOptimisticSendMessage = async (
message: Partial<IMessage> & { rid: IMessage['rid']; msg: IMessage['msg'] },
): Promise<void> => {
const uid = getUserId();
if (!uid || trim(message.msg) === '') {
return;
}
const messageAlreadyExists = message._id && Messages.state.get(message._id);
if (messageAlreadyExists) {
dispatchToastMessage({ type: 'error', message: t('Message_Already_Sent') });
return;
}
const user = getUser();
if (!user?.username) {
return;
}

const room = Rooms.state.get(message.rid);
if (room?.federated) {
return;
}

const optimistic: IMessage = {
...(message as IMessage),
ts: new Date(),
u: {
_id: uid,
username: user.username,
name: user.name || '',
};
message.temp = true;
if (settings.peek('Message_Read_Receipt_Enabled')) {
message.unread = true;
}

// If the room is federated, send the message to matrix only
const room = Rooms.state.get(message.rid);
if (room?.federated) {
return;
}
},
temp: true,
...(settings.peek('Message_Read_Receipt_Enabled') ? { unread: true } : {}),
};

await onClientMessageReceived(message as IMessage).then((message) => {
Messages.state.store(message);
return clientCallbacks.run('afterSaveMessage', message, { room, user });
});
},
});
const processed = await onClientMessageReceived(optimistic);
Messages.state.store(processed);
await clientCallbacks.run('afterSaveMessage', processed, { room, user });
};
15 changes: 9 additions & 6 deletions apps/meteor/app/livechat/client/lib/stream/queueManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
type IOmnichannelAgent,
type Serialized,
} from '@rocket.chat/core-typings';
import { Tracker } from 'meteor/tracker';

import { useLivechatInquiryStore } from '../../../../../client/hooks/useLivechatInquiryStore';
import { queryClient } from '../../../../../client/lib/queryClient';
Expand Down Expand Up @@ -64,8 +63,10 @@ const removeInquiry = async (inquiry: ILivechatInquiryRecord) => {
return queryClient.invalidateQueries({ queryKey: ['rooms', { reference: inquiry.rid, type: 'l' }] });
};

const INQUIRY_COUNT_SETTING = 'Livechat_guest_pool_max_number_incoming_livechats_displayed';

const getInquiriesFromAPI = async () => {
const count = settings.peek('Livechat_guest_pool_max_number_incoming_livechats_displayed') ?? 0;
const count = settings.peek<number>(INQUIRY_COUNT_SETTING) ?? 0;
const { inquiries } = await sdk.rest.get('/v1/livechat/inquiries.queuedForUser', { count });
return inquiries;
};
Expand Down Expand Up @@ -140,10 +141,12 @@ const subscribe = async (userId: IOmnichannelAgent['_id']) => {
const cleanDepartmentListeners = addListenerForeachDepartment(agentDepartments);
const globalCleanup = addGlobalListener();

const computation = Tracker.autorun(async () => {
const inquiriesFromAPI = await getInquiriesFromAPI();
const refetchInquiries = async () => updateInquiries(await getInquiriesFromAPI());

await refetchInquiries();

await updateInquiries(inquiriesFromAPI);
const unobserveInquiryCount = settings.observe(INQUIRY_COUNT_SETTING, () => {
void refetchInquiries();
});

return () => {
Expand All @@ -152,8 +155,8 @@ const subscribe = async (userId: IOmnichannelAgent['_id']) => {
cleanAgentListener?.();
cleanDepartmentListeners?.();
globalCleanup?.();
unobserveInquiryCount();
departments.clear();
computation.stop();
};
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
Expand Down
1 change: 0 additions & 1 deletion apps/meteor/app/reactions/client/index.ts

This file was deleted.

123 changes: 60 additions & 63 deletions apps/meteor/app/reactions/client/methods/setReaction.ts
Original file line number Diff line number Diff line change
@@ -1,84 +1,81 @@
import type { IMessage } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { Meteor } from 'meteor/meteor';

import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator';
import { getUser, getUserId } from '../../../../client/lib/user';
import { Rooms, Subscriptions, Messages } from '../../../../client/stores';
import { emoji } from '../../../emoji/client';

Meteor.methods<ServerMethods>({
async setReaction(reaction, messageId) {
if (!getUserId()) {
throw new Meteor.Error(203, 'User_logged_out');
}

const user = getUser();
export const runOptimisticSetReaction = (reaction: string, messageId: IMessage['_id']): void => {
if (!getUserId()) {
return;
}

if (!user?.username) {
return false;
}
const user = getUser();
if (!user?.username) {
return;
}

const message: IMessage | undefined = Messages.state.get(messageId);
if (!message) {
return false;
}
const message: IMessage | undefined = Messages.state.get(messageId);
if (!message) {
return;
}

const room = Rooms.state.get(message.rid);
if (!room) {
return false;
}

if (message.private) {
return false;
}
const room = Rooms.state.get(message.rid);
if (!room) {
return;
}

if (!emoji.list[reaction]) {
return false;
}
if (message.private) {
return;
}

if (roomCoordinator.readOnly(room, user)) {
return false;
}
if (!emoji.list[reaction]) {
return;
}

if (!Subscriptions.state.find(({ rid }) => rid === message.rid)) {
return false;
}
if (roomCoordinator.readOnly(room, user)) {
return;
}

if (message.reactions?.[reaction] && message.reactions[reaction].usernames.indexOf(user.username) !== -1) {
message.reactions[reaction].usernames.splice(message.reactions[reaction].usernames.indexOf(user.username), 1);
if (!Subscriptions.state.find(({ rid }) => rid === message.rid)) {
return;
}

if (message.reactions[reaction].usernames.length === 0) {
delete message.reactions[reaction];
}
if (message.reactions?.[reaction] && message.reactions[reaction].usernames.indexOf(user.username) !== -1) {
message.reactions[reaction].usernames.splice(message.reactions[reaction].usernames.indexOf(user.username), 1);

if (!message.reactions || typeof message.reactions !== 'object' || Object.keys(message.reactions).length === 0) {
delete message.reactions;
Messages.state.update(
(record) => record._id === messageId,
({ reactions: _, ...record }) => record,
);
} else {
Messages.state.update(
(record) => record._id === messageId,
(record) => ({ ...record, reactions: message.reactions }),
);
}
} else {
if (!message.reactions) {
message.reactions = {};
}
if (!message.reactions[reaction]) {
message.reactions[reaction] = {
usernames: [],
};
}
message.reactions[reaction].usernames.push(user.username);
if (message.reactions[reaction].usernames.length === 0) {
delete message.reactions[reaction];
}

if (!message.reactions || typeof message.reactions !== 'object' || Object.keys(message.reactions).length === 0) {
delete message.reactions;
Messages.state.update(
(record) => record._id === messageId,
(record) => ({ ...record, reactions: message.reactions }),
({ reactions: _, ...record }) => record,
);
return;
}
},
});

Messages.state.update(
(record) => record._id === messageId,
(record) => ({ ...record, reactions: message.reactions }),
);
return;
}

if (!message.reactions) {
message.reactions = {};
}
if (!message.reactions[reaction]) {
message.reactions[reaction] = {
usernames: [],
};
}
message.reactions[reaction].usernames.push(user.username);

Messages.state.update(
(record) => record._id === messageId,
(record) => ({ ...record, reactions: message.reactions }),
);
};
4 changes: 1 addition & 3 deletions apps/meteor/app/slashcommands-join/client/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { Meteor } from 'meteor/meteor';

import { slashCommands } from '../../utils/client/slashCommand';

slashCommands.add({
Expand All @@ -10,7 +8,7 @@ slashCommands.add({
permission: 'view-c-room',
},
result(err, _result: unknown, params: Record<string, any>) {
if ((err as Meteor.Error).error === 'error-user-already-in-room') {
if ((err as { error?: string } | undefined)?.error === 'error-user-already-in-room') {
params.cmd = 'open';
params.msg.msg = params.msg.msg.replace('join', 'open');
return void slashCommands.run({ command: 'open', params: params.params, message: params.msg, triggerId: '', userId: params.userId });
Expand Down
Loading
Loading