diff --git a/app/e2e/client/rocketchat.e2e.js b/app/e2e/client/rocketchat.e2e.js index e2867bfba7bae..9c35861666f6a 100644 --- a/app/e2e/client/rocketchat.e2e.js +++ b/app/e2e/client/rocketchat.e2e.js @@ -5,6 +5,7 @@ import { Tracker } from 'meteor/tracker'; import { EJSON } from 'meteor/ejson'; import { FlowRouter } from 'meteor/kadira:flow-router'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import { Emitter } from '@rocket.chat/emitter'; import { E2ERoom } from './rocketchat.e2e.room'; import { @@ -32,7 +33,6 @@ import './events.js'; import './tabbar'; let failedToDecodeKey = false; -let showingE2EAlert = false; const waitUntilFind = (fn) => new Promise((resolve) => { Tracker.autorun((c) => { @@ -40,16 +40,21 @@ const waitUntilFind = (fn) => new Promise((resolve) => { return result && resolve(result) && c.stop(); }); }); - -class E2E { +class E2E extends Emitter { constructor() { + super(); this.started = false; this.enabled = new ReactiveVar(false); this._ready = new ReactiveVar(false); this.instancesByRoomId = {}; this.readyPromise = new Deferred(); - this.readyPromise.then(() => { + + this.on('ready', () => { this._ready.set(true); + this.log('startClient -> Done'); + this.log('decryptPendingSubscriptions'); + this.decryptPendingSubscriptions(); + this.log('decryptPendingSubscriptions -> Done'); }); } @@ -187,20 +192,17 @@ class E2E { }); } - this.readyPromise.resolve(); this.log('startClient -> Done'); - this.log('decryptPendingSubscriptions'); + this.log('decryptSubscriptions'); - this.decryptPendingSubscriptions(); - this.log('decryptPendingSubscriptions -> Done'); + this.decryptSubscriptions(); + this.log('decryptSubscriptions -> Done'); + this.emit('ready'); } async stopClient() { this.log('-> Stop Client'); - // This flag is used to avoid closing unrelated alerts. - if (showingE2EAlert) { - banners.close(); - } + this.closeAlert(); Meteor._localStorage.removeItem('public_key'); Meteor._localStorage.removeItem('private_key'); @@ -209,11 +211,6 @@ class E2E { this.enabled.set(false); this._ready.set(false); this.started = false; - - this.readyPromise = new Deferred(); - this.readyPromise.then(() => { - this._ready.set(true); - }); } async changePassword(newPassword) { @@ -417,26 +414,22 @@ class E2E { async decryptSubscription(rid) { const e2eRoom = await this.getInstanceByRoomId(rid); - this.log('decryptPendingSubscriptions ->', rid); + this.log('decryptSubscription ->', rid); e2eRoom?.decryptPendingSubscription(); } - async decryptPendingSubscriptions() { + async decryptSubscriptions() { Subscriptions.find({ encrypted: true, }).forEach((room) => this.decryptSubscription(room._id)); } openAlert(config) { - showingE2EAlert = true; - banners.open(config); + banners.open({ id: 'e2e', ...config }); } closeAlert() { - if (showingE2EAlert) { - banners.close(); - } - showingE2EAlert = false; + banners.closeById('e2e'); } } @@ -491,7 +484,7 @@ Meteor.startup(function() { } - doc.encrypted ? e2eRoom.enable() : e2eRoom.pause(); + doc.encrypted ? e2eRoom.unPause() : e2eRoom.pause(); // Cover private groups and direct messages if (!e2eRoom.isSupportedRoomType(doc.t)) { diff --git a/app/e2e/client/rocketchat.e2e.room.js b/app/e2e/client/rocketchat.e2e.room.js index 83ac0bf3aa2f3..4eaae50e9d187 100644 --- a/app/e2e/client/rocketchat.e2e.room.js +++ b/app/e2e/client/rocketchat.e2e.room.js @@ -31,7 +31,6 @@ export const E2E_ROOM_STATES = { NO_PASSWORD_SET: 'NO_PASSWORD_SET', NOT_STARTED: 'NOT_STARTED', DISABLED: 'DISABLED', - PAUSED: 'PAUSED', HANDSHAKE: 'HANDSHAKE', ESTABLISHING: 'ESTABLISHING', CREATING_KEYS: 'CREATING_KEYS', @@ -42,41 +41,24 @@ export const E2E_ROOM_STATES = { }; const KEY_ID = Symbol('keyID'); +const PAUSED = Symbol('PAUSED'); const reduce = (prev, next) => { if (prev === next) { return next === E2E_ROOM_STATES.ERROR; } - - switch (next) { - case E2E_ROOM_STATES.READY: - if (prev === E2E_ROOM_STATES.PAUSED) { - return E2E_ROOM_STATES.READY; - } - return E2E_ROOM_STATES.DISABLED; - case E2E_ROOM_STATES.PAUSED: - if (prev === E2E_ROOM_STATES.READY) { - return E2E_ROOM_STATES.PAUSED; - } - return E2E_ROOM_STATES.DISABLED; - } switch (prev) { - case E2E_ROOM_STATES.PAUSED: - if (next === E2E_ROOM_STATES.READY) { - return E2E_ROOM_STATES.READY; - } - return false; case E2E_ROOM_STATES.NOT_STARTED: - return [E2E_ROOM_STATES.ESTABLISHING, E2E_ROOM_STATES.PAUSED, E2E_ROOM_STATES.DISABLED, E2E_ROOM_STATES.KEYS_RECEIVED].includes(next) && next; + return [E2E_ROOM_STATES.ESTABLISHING, E2E_ROOM_STATES.DISABLED, E2E_ROOM_STATES.KEYS_RECEIVED].includes(next) && next; case E2E_ROOM_STATES.READY: return [E2E_ROOM_STATES.PAUSED, E2E_ROOM_STATES.DISABLED].includes(next) && next; case E2E_ROOM_STATES.ERROR: return [E2E_ROOM_STATES.KEYS_RECEIVED, E2E_ROOM_STATES.NOT_STARTED].includes(next) && next; case E2E_ROOM_STATES.WAITING_KEYS: - return [E2E_ROOM_STATES.KEYS_RECEIVED, E2E_ROOM_STATES.ERROR, E2E_ROOM_STATES.PAUSED, E2E_ROOM_STATES.DISABLED].includes(next) && next; + return [E2E_ROOM_STATES.KEYS_RECEIVED, E2E_ROOM_STATES.ERROR, E2E_ROOM_STATES.DISABLED].includes(next) && next; case E2E_ROOM_STATES.ESTABLISHING: - return [E2E_ROOM_STATES.READY, E2E_ROOM_STATES.KEYS_RECEIVED, E2E_ROOM_STATES.ERROR, E2E_ROOM_STATES.PAUSED, E2E_ROOM_STATES.DISABLED, E2E_ROOM_STATES.WAITING_KEYS].includes(next) && next; + return [E2E_ROOM_STATES.READY, E2E_ROOM_STATES.KEYS_RECEIVED, E2E_ROOM_STATES.ERROR, E2E_ROOM_STATES.DISABLED, E2E_ROOM_STATES.WAITING_KEYS].includes(next) && next; default: return next; } @@ -119,7 +101,7 @@ export class E2ERoom extends Emitter { this.typeOfRoom = t; this.once(E2E_ROOM_STATES.READY, () => this.decryptPendingMessages()); - this.once(E2E_ROOM_STATES.READY, () => this.decryptPendingSubscription()); + this.once(E2E_ROOM_STATES.READY, () => this.decryptSubscription()); this.on('STATE_CHANGED', (prev) => { if (this.roomId === Session.get('openedRoom')) { this.log(`[PREV: ${ prev }]`, 'State CHANGED'); @@ -139,7 +121,15 @@ export class E2ERoom extends Emitter { } pause() { - ![E2E_ROOM_STATES.PAUSED, E2E_ROOM_STATES.DISABLED].includes(this.state) && this.setState(this.state === E2E_ROOM_STATES.READY ? E2E_ROOM_STATES.PAUSED : E2E_ROOM_STATES.DISABLED); + this[PAUSED] = true; + } + + unPause() { + this[PAUSED] = false; + } + + isPaused() { + return this[PAUSED]; } enable() { @@ -158,10 +148,6 @@ export class E2ERoom extends Emitter { return [E2E_ROOM_STATES.DISABLED].includes(this.state); } - isPaused() { - return [E2E_ROOM_STATES.PAUSED].includes(this.state); - } - wait(state) { return new Promise((resolve) => (state === this.state ? resolve(this) : this.once(state, () => resolve(this)))).then((el) => { this.log(this.state, el); @@ -185,14 +171,14 @@ export class E2ERoom extends Emitter { this[KEY_ID] = keyID; } - async decryptPendingSubscription() { + async decryptSubscription() { const subscription = Subscriptions.findOne({ rid: this.roomId, }); const data = await (subscription.lastMessage?.msg && this.decrypt(subscription.lastMessage.msg)); if (!data?.text) { - this.log('decryptPendingSubscriptions nothing to do'); + this.log('decryptSubscriptions nothing to do'); return; } @@ -204,7 +190,7 @@ export class E2ERoom extends Emitter { 'lastMessage.e2e': 'done', }, }); - this.log('decryptPendingSubscriptions Done'); + this.log('decryptSubscriptions Done'); } async decryptPendingMessages() { diff --git a/app/version-check/client/index.js b/app/version-check/client/index.js index ba77a6f671508..77c7f0ee476ca 100644 --- a/app/version-check/client/index.js +++ b/app/version-check/client/index.js @@ -18,6 +18,7 @@ Meteor.startup(function() { firstBanner.textArguments = firstBanner.textArguments || []; banners.open({ + id: firstBanner.id, title: TAPi18n.__(firstBanner.title), text: TAPi18n.__(firstBanner.text, ...firstBanner.textArguments), modifiers: firstBanner.modifiers, diff --git a/client/lib/banners.ts b/client/lib/banners.ts index 7595658025f45..3ece45d2d4f4f 100644 --- a/client/lib/banners.ts +++ b/client/lib/banners.ts @@ -5,6 +5,7 @@ import { mountRoot } from '../reactAdapters'; import { UiKitBannerPayload } from '../../definition/UIKit'; export type LegacyBannerPayload = { + id: string; closable?: boolean; title?: string; text?: string; @@ -31,13 +32,14 @@ export const firstSubscription: Subscription = { export const open = (payload: BannerPayload): void => { mountRoot(); - let index = -1; + let index = queue.findIndex((_payload) => { + if (isLegacyPayload(_payload)) { + return _payload.id === (payload as LegacyBannerPayload).id; + } + return (_payload as UiKitBannerPayload).viewId === (payload as UiKitBannerPayload).viewId; + }); - if (!isLegacyPayload(payload)) { - index = queue.findIndex((_payload) => !isLegacyPayload(_payload) && _payload.viewId === payload.viewId); - } - - if (index < 0) { + if (index === -1) { index = queue.length; } @@ -51,15 +53,21 @@ export const open = (payload: BannerPayload): void => { }; -export const closeById = (viewId: string): void => { - const index = queue.findIndex((banner) => !isLegacyPayload(banner) && banner.viewId === viewId); +export const closeById = (id: string): void => { + const index = queue.findIndex((banner) => { + if (!isLegacyPayload(banner)) { + return banner.viewId === id; + } + return banner.id === id; + }); + if (index < 0) { return; } queue.splice(index, 1); emitter.emit('update'); - emitter.emit('update-first'); + index === 0 && emitter.emit('update-first'); }; export const close = (): void => { diff --git a/client/startup/startup.js b/client/startup/startup.js index b2fd8bfcc6fb8..802b9af9bd634 100644 --- a/client/startup/startup.js +++ b/client/startup/startup.js @@ -85,6 +85,7 @@ Meteor.startup(function() { const { connectToCloud = false, workspaceRegistered = false } = data; if (connectToCloud === true && workspaceRegistered !== true) { banners.open({ + id: 'cloud-registration', title: t('Cloud_registration_pending_title'), html: t('Cloud_registration_pending_html'), modifiers: ['large', 'danger'], diff --git a/client/startup/unread.js b/client/startup/unread.js index e8c473871f201..6072b23561ae8 100644 --- a/client/startup/unread.js +++ b/client/startup/unread.js @@ -31,21 +31,22 @@ Meteor.startup(() => { let unreadAlert = false; - const unreadCount = fetchSubscriptions().reduce((ret, subscription) => { - const room = ChatRoom.findOne({ _id: subscription.rid }, { fields: { usersCount: 1 } }); - fireGlobalEvent('unread-changed-by-subscription', { ...subscription, usersCount: room && room.usersCount }); + const unreadCount = fetchSubscriptions().reduce((ret, subscription) => + Tracker.nonreactive(() => { + const room = ChatRoom.findOne({ _id: subscription.rid }, { fields: { usersCount: 1 } }); + fireGlobalEvent('unread-changed-by-subscription', { ...subscription, usersCount: room && room.usersCount }); - if (subscription.alert || subscription.unread > 0) { - // Increment the total unread count. - if (subscription.alert === true && subscription.unreadAlert !== 'nothing') { - if (subscription.unreadAlert === 'all' || userUnreadAlert !== false) { - unreadAlert = '•'; + if (subscription.alert || subscription.unread > 0) { + // Increment the total unread count. + if (subscription.alert === true && subscription.unreadAlert !== 'nothing') { + if (subscription.unreadAlert === 'all' || userUnreadAlert !== false) { + unreadAlert = '•'; + } } + return ret + subscription.unread; } - return ret + subscription.unread; - } - return ret; - }, 0); + return ret; + }), 0); menu.updateUnreadBars();