diff --git a/.changeset/angry-rocks-try.md b/.changeset/angry-rocks-try.md new file mode 100644 index 000000000000..8072b9db48fb --- /dev/null +++ b/.changeset/angry-rocks-try.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed an issue causing monitors to dissapear from a saved unit every time a user saved the item. This was caused by the UI not sending the correct _id of the monitors that were already saved, and this caused the Backend to ignore them and remove from the list. diff --git a/.changeset/cold-beds-hope.md b/.changeset/cold-beds-hope.md new file mode 100644 index 000000000000..33fc910e424f --- /dev/null +++ b/.changeset/cold-beds-hope.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes an issue not allowing override retention policy in channels diff --git a/.changeset/cuddly-owls-join.md b/.changeset/cuddly-owls-join.md new file mode 100644 index 000000000000..0ace3d145d37 --- /dev/null +++ b/.changeset/cuddly-owls-join.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixed an issue that prevented CAS users from being merged with existing user data on login diff --git a/.changeset/fair-grapes-thank.md b/.changeset/fair-grapes-thank.md new file mode 100644 index 000000000000..2d8962f40db9 --- /dev/null +++ b/.changeset/fair-grapes-thank.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": minor +--- + +Allow visitors & integrations to access downloaded files after a room has closed. This was a known limitation in our codebase, where visitors were only able to access uploaded files in a livechat conversation while the conversation was open. diff --git a/.changeset/ninety-rivers-mix.md b/.changeset/ninety-rivers-mix.md new file mode 100644 index 000000000000..fbd10b2a04d1 --- /dev/null +++ b/.changeset/ninety-rivers-mix.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/rest-typings": minor +--- + +Fixed issue with "Export room as file" feature (`rooms.export` endpoint) generating an empty export when given an invalid date diff --git a/.changeset/real-bobcats-train.md b/.changeset/real-bobcats-train.md new file mode 100644 index 000000000000..6d51414c9fc4 --- /dev/null +++ b/.changeset/real-bobcats-train.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/rest-typings': patch +'@rocket.chat/meteor': patch +--- + +Don't show Join default channels option on edit user form. diff --git a/.changeset/shy-oranges-provide.md b/.changeset/shy-oranges-provide.md new file mode 100644 index 000000000000..7141a58da575 --- /dev/null +++ b/.changeset/shy-oranges-provide.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes link image preview not opening in gallery mode diff --git a/.changeset/smooth-knives-turn.md b/.changeset/smooth-knives-turn.md new file mode 100644 index 000000000000..3964ecc8481b --- /dev/null +++ b/.changeset/smooth-knives-turn.md @@ -0,0 +1,7 @@ +--- +"@rocket.chat/meteor": patch +--- + +Executing a logout and login action in the same "tab/instance", some streams were not being recreated, causing countless types of bugs. + +PS: as a workaround reloading after logout or login in also solves the problem. diff --git a/.changeset/weak-turkeys-sit.md b/.changeset/weak-turkeys-sit.md new file mode 100644 index 000000000000..c4673b9d049d --- /dev/null +++ b/.changeset/weak-turkeys-sit.md @@ -0,0 +1,8 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed a bad behavior with the interaction between OTR system messages & trash collection. We use trash collection as a temporary storage that holds recently deleted items from some collections. Messages is one of those. This was causing "User joined OTR" messages to be viewable when querying the trash collection. +Since OTR messages are by definition private, code was updated to bypass trash collection when removing these special messages. + +Note: this only applies to these system messages. OTR user's messages are not stored on the database. diff --git a/.changeset/wise-pianos-explode.md b/.changeset/wise-pianos-explode.md new file mode 100644 index 000000000000..3473275e20ab --- /dev/null +++ b/.changeset/wise-pianos-explode.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed issue with external users being able to reset their passwords even when the "Allow Password Change for OAuth Users" setting is disabled diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 48b0af912d15..a834776aeff5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -28,6 +28,6 @@ apps/meteor/server/startup/migrations @RocketChat/Architecture /apps/meteor/ee/app/canned-responses @RocketChat/omnichannel /apps/meteor/ee/app/livechat @RocketChat/omnichannel /apps/meteor/ee/app/livechat-enterprise @RocketChat/omnichannel -/apps/meteor/ee/client/omnichannel @RocketChat/omnichannel +/apps/meteor/client/omnichannel @RocketChat/omnichannel /apps/meteor/client/components/omnichannel @RocketChat/omnichannel /apps/meteor/client/components/voip @RocketChat/omnichannel diff --git a/.github/workflows/pr-title-checker.yml b/.github/workflows/pr-title-checker.yml index 356ac10c9759..bc9d1f042d58 100644 --- a/.github/workflows/pr-title-checker.yml +++ b/.github/workflows/pr-title-checker.yml @@ -12,6 +12,6 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: thehanimo/pr-title-checker@v1.3.7 + - uses: thehanimo/pr-title-checker@v1.4.1 with: GITHUB_TOKEN: ${{ secrets.RC_TITLE_CHECKER }} diff --git a/apps/meteor/.storybook/main.js b/apps/meteor/.storybook/main.js index 0e0b6db7c0e9..d70d3c5d7cc3 100644 --- a/apps/meteor/.storybook/main.js +++ b/apps/meteor/.storybook/main.js @@ -7,7 +7,6 @@ module.exports = { '../client/**/*.stories.{js,tsx}', '../app/**/*.stories.{js,tsx}', '../ee/app/**/*.stories.{js,tsx}', - '../ee/client/**/*.stories.{js,tsx}', ], addons: [ '@storybook/addon-essentials', diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index 9576a79f6678..40998201b03b 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -2,7 +2,7 @@ import { Media } from '@rocket.chat/core-services'; import type { IRoom, IUpload } from '@rocket.chat/core-typings'; import { Messages, Rooms, Users, Uploads } from '@rocket.chat/models'; import type { Notifications } from '@rocket.chat/rest-typings'; -import { isGETRoomsNameExists, isRoomsImagesProps, isRoomsMuteUnmuteUserProps } from '@rocket.chat/rest-typings'; +import { isGETRoomsNameExists, isRoomsImagesProps, isRoomsMuteUnmuteUserProps, isRoomsExportProps } from '@rocket.chat/rest-typings'; import { Meteor } from 'meteor/meteor'; import { isTruthy } from '../../../../lib/isTruthy'; @@ -599,15 +599,11 @@ API.v1.addRoute( API.v1.addRoute( 'rooms.export', - { authRequired: true }, + { authRequired: true, validateParams: isRoomsExportProps }, { async post() { const { rid, type } = this.bodyParams; - if (!rid || !type || !['email', 'file'].includes(type)) { - throw new Meteor.Error('error-invalid-params'); - } - if (!(await hasPermissionAsync(this.userId, 'mail-messages', rid))) { throw new Meteor.Error('error-action-not-allowed', 'Mailing is not allowed'); } @@ -627,12 +623,8 @@ API.v1.addRoute( const { dateFrom, dateTo } = this.bodyParams; const { format } = this.bodyParams; - if (!['html', 'json'].includes(format || '')) { - throw new Meteor.Error('error-invalid-format'); - } - - const convertedDateFrom = new Date(dateFrom || ''); - const convertedDateTo = new Date(dateTo || ''); + const convertedDateFrom = dateFrom ? new Date(dateFrom) : new Date(0); + const convertedDateTo = dateTo ? new Date(dateTo) : new Date(); convertedDateTo.setDate(convertedDateTo.getDate() + 1); if (convertedDateFrom > convertedDateTo) { @@ -658,10 +650,6 @@ API.v1.addRoute( throw new Meteor.Error('error-invalid-recipient'); } - if (messages?.length === 0) { - throw new Meteor.Error('error-invalid-messages'); - } - const result = await dataExport.sendViaEmail( { rid, diff --git a/apps/meteor/app/authorization/client/index.ts b/apps/meteor/app/authorization/client/index.ts index dd335c13030e..7dc1a3466f49 100644 --- a/apps/meteor/app/authorization/client/index.ts +++ b/apps/meteor/app/authorization/client/index.ts @@ -1,4 +1,5 @@ import { hasAllPermission, hasAtLeastOnePermission, hasPermission, userHasAllPermission } from './hasPermission'; import { hasRole, hasAnyRole } from './hasRole'; +import './restrictedRoles'; export { hasAllPermission, hasAtLeastOnePermission, hasRole, hasAnyRole, hasPermission, userHasAllPermission }; diff --git a/apps/meteor/app/authorization/client/restrictedRoles.ts b/apps/meteor/app/authorization/client/restrictedRoles.ts new file mode 100644 index 000000000000..5aa5e426c2bd --- /dev/null +++ b/apps/meteor/app/authorization/client/restrictedRoles.ts @@ -0,0 +1,12 @@ +import { Meteor } from 'meteor/meteor'; + +import { sdk } from '../../utils/client/lib/SDKClient'; +import { AuthorizationUtils } from '../lib'; + +Meteor.startup(async () => { + const result = await sdk.call('license:isEnterprise'); + if (result) { + // #ToDo: Load this from the server with an API call instead of having a duplicate list + AuthorizationUtils.addRolePermissionWhiteList('guest', ['view-d-room', 'view-joined-room', 'view-p-room', 'start-discussion']); + } +}); diff --git a/apps/meteor/ee/app/canned-responses/client/collections/CannedResponse.ts b/apps/meteor/app/canned-responses/client/collections/CannedResponse.ts similarity index 100% rename from apps/meteor/ee/app/canned-responses/client/collections/CannedResponse.ts rename to apps/meteor/app/canned-responses/client/collections/CannedResponse.ts diff --git a/apps/meteor/ee/app/canned-responses/client/index.ts b/apps/meteor/app/canned-responses/client/index.ts similarity index 100% rename from apps/meteor/ee/app/canned-responses/client/index.ts rename to apps/meteor/app/canned-responses/client/index.ts diff --git a/apps/meteor/ee/app/canned-responses/client/startup/responses.js b/apps/meteor/app/canned-responses/client/startup/responses.js similarity index 84% rename from apps/meteor/ee/app/canned-responses/client/startup/responses.js rename to apps/meteor/app/canned-responses/client/startup/responses.js index 6d5834d91cc0..595945283261 100644 --- a/apps/meteor/ee/app/canned-responses/client/startup/responses.js +++ b/apps/meteor/app/canned-responses/client/startup/responses.js @@ -1,9 +1,9 @@ import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; -import { hasPermission } from '../../../../../app/authorization/client'; -import { settings } from '../../../../../app/settings/client'; -import { sdk } from '../../../../../app/utils/client/lib/SDKClient'; +import { hasPermission } from '../../../authorization/client'; +import { settings } from '../../../settings/client'; +import { sdk } from '../../../utils/client/lib/SDKClient'; import { CannedResponse } from '../collections/CannedResponse'; const events = { diff --git a/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts b/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts index 4f6c06780942..e17faebea384 100644 --- a/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts +++ b/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts @@ -117,14 +117,10 @@ const validators: RoomSettingsValidators = { } }, async retentionEnabled({ userId, value, room, rid }) { - if (!hasRetentionPolicy(room)) { - throw new Meteor.Error('error-action-not-allowed', 'Room does not have retention policy', { - method: 'saveRoomSettings', - action: 'Editing_room', - }); - } - - if (!(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && value !== room.retention.enabled) { + if ( + !(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && + (!hasRetentionPolicy(room) || value !== room.retention.enabled) + ) { throw new Meteor.Error('error-action-not-allowed', 'Editing room retention policy is not allowed', { method: 'saveRoomSettings', action: 'Editing_room', @@ -132,14 +128,10 @@ const validators: RoomSettingsValidators = { } }, async retentionMaxAge({ userId, value, room, rid }) { - if (!hasRetentionPolicy(room)) { - throw new Meteor.Error('error-action-not-allowed', 'Room does not have retention policy', { - method: 'saveRoomSettings', - action: 'Editing_room', - }); - } - - if (!(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && value !== room.retention.maxAge) { + if ( + !(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && + (!hasRetentionPolicy(room) || value !== room.retention.maxAge) + ) { throw new Meteor.Error('error-action-not-allowed', 'Editing room retention policy is not allowed', { method: 'saveRoomSettings', action: 'Editing_room', @@ -147,14 +139,10 @@ const validators: RoomSettingsValidators = { } }, async retentionExcludePinned({ userId, value, room, rid }) { - if (!hasRetentionPolicy(room)) { - throw new Meteor.Error('error-action-not-allowed', 'Room does not have retention policy', { - method: 'saveRoomSettings', - action: 'Editing_room', - }); - } - - if (!(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && value !== room.retention.excludePinned) { + if ( + !(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && + (!hasRetentionPolicy(room) || value !== room.retention.excludePinned) + ) { throw new Meteor.Error('error-action-not-allowed', 'Editing room retention policy is not allowed', { method: 'saveRoomSettings', action: 'Editing_room', @@ -162,14 +150,10 @@ const validators: RoomSettingsValidators = { } }, async retentionFilesOnly({ userId, value, room, rid }) { - if (!hasRetentionPolicy(room)) { - throw new Meteor.Error('error-action-not-allowed', 'Room does not have retention policy', { - method: 'saveRoomSettings', - action: 'Editing_room', - }); - } - - if (!(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && value !== room.retention.filesOnly) { + if ( + !(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && + (!hasRetentionPolicy(room) || value !== room.retention.filesOnly) + ) { throw new Meteor.Error('error-action-not-allowed', 'Editing room retention policy is not allowed', { method: 'saveRoomSettings', action: 'Editing_room', @@ -177,14 +161,10 @@ const validators: RoomSettingsValidators = { } }, async retentionIgnoreThreads({ userId, value, room, rid }) { - if (!hasRetentionPolicy(room)) { - throw new Meteor.Error('error-action-not-allowed', 'Room does not have retention policy', { - method: 'saveRoomSettings', - action: 'Editing_room', - }); - } - - if (!(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && value !== room.retention.ignoreThreads) { + if ( + !(await hasPermissionAsync(userId, 'edit-room-retention-policy', rid)) && + (!hasRetentionPolicy(room) || value !== room.retention.ignoreThreads) + ) { throw new Meteor.Error('error-action-not-allowed', 'Editing room retention policy is not allowed', { method: 'saveRoomSettings', action: 'Editing_room', @@ -469,7 +449,7 @@ export async function saveRoomSettings( rid, }); - if (setting === 'retentionOverrideGlobal') { + if (setting === 'retentionOverrideGlobal' && settings.retentionOverrideGlobal === false) { delete settings.retentionMaxAge; delete settings.retentionExcludePinned; delete settings.retentionFilesOnly; diff --git a/apps/meteor/ee/app/ecdh/Session.ts b/apps/meteor/app/ecdh/Session.ts similarity index 100% rename from apps/meteor/ee/app/ecdh/Session.ts rename to apps/meteor/app/ecdh/Session.ts diff --git a/apps/meteor/ee/app/ecdh/client/ClientSession.ts b/apps/meteor/app/ecdh/client/ClientSession.ts similarity index 100% rename from apps/meteor/ee/app/ecdh/client/ClientSession.ts rename to apps/meteor/app/ecdh/client/ClientSession.ts diff --git a/apps/meteor/ee/app/license/client/index.ts b/apps/meteor/app/license/client/index.ts similarity index 85% rename from apps/meteor/ee/app/license/client/index.ts rename to apps/meteor/app/license/client/index.ts index f0340c8d0ae5..efe1f68bc5e8 100644 --- a/apps/meteor/ee/app/license/client/index.ts +++ b/apps/meteor/app/license/client/index.ts @@ -1,5 +1,5 @@ -import { queryClient } from '../../../../client/lib/queryClient'; import { fetchFeatures } from '../../../client/lib/fetchFeatures'; +import { queryClient } from '../../../client/lib/queryClient'; export async function hasLicense(feature: string): Promise { try { diff --git a/apps/meteor/ee/app/livechat-enterprise/client/components/modals/PlaceChatOnHoldModal.tsx b/apps/meteor/app/livechat-enterprise/client/components/modals/PlaceChatOnHoldModal.tsx similarity index 100% rename from apps/meteor/ee/app/livechat-enterprise/client/components/modals/PlaceChatOnHoldModal.tsx rename to apps/meteor/app/livechat-enterprise/client/components/modals/PlaceChatOnHoldModal.tsx diff --git a/apps/meteor/ee/app/livechat-enterprise/client/index.ts b/apps/meteor/app/livechat-enterprise/client/index.ts similarity index 90% rename from apps/meteor/ee/app/livechat-enterprise/client/index.ts rename to apps/meteor/app/livechat-enterprise/client/index.ts index 1fc3ef704139..7be870039276 100644 --- a/apps/meteor/ee/app/livechat-enterprise/client/index.ts +++ b/apps/meteor/app/livechat-enterprise/client/index.ts @@ -1,5 +1,4 @@ import { hasLicense } from '../../license/client'; -import '../lib/messageTypes'; import './startup'; void hasLicense('livechat-enterprise').then((enabled) => { diff --git a/apps/meteor/ee/app/livechat-enterprise/lib/messageTypes.ts b/apps/meteor/app/livechat-enterprise/client/messageTypes.ts similarity index 67% rename from apps/meteor/ee/app/livechat-enterprise/lib/messageTypes.ts rename to apps/meteor/app/livechat-enterprise/client/messageTypes.ts index 9c15c277a1b2..90d390fe6be7 100644 --- a/apps/meteor/ee/app/livechat-enterprise/lib/messageTypes.ts +++ b/apps/meteor/app/livechat-enterprise/client/messageTypes.ts @@ -1,7 +1,26 @@ import type { IMessage } from '@rocket.chat/core-typings'; -import { MessageTypes } from '../../../../app/ui-utils/client'; -import { t } from '../../../../app/utils/lib/i18n'; +import { MessageTypes } from '../../ui-utils/client'; +import { t } from '../../utils/lib/i18n'; + +MessageTypes.registerType({ + id: 'livechat_transfer_history_fallback', + system: true, + message: 'New_chat_transfer_fallback', + data(message: any) { + if (!message.transferData) { + return { + fallback: 'SHOULD_NEVER_HAPPEN', + }; + } + const from = message.transferData.prevDepartment; + const to = message.transferData.department.name; + + return { + fallback: t('Livechat_transfer_failed_fallback', { from, to }), + }; + }, +}); MessageTypes.registerType({ id: 'omnichannel_priority_change_history', diff --git a/apps/meteor/ee/app/livechat-enterprise/client/startup.ts b/apps/meteor/app/livechat-enterprise/client/startup.ts similarity index 60% rename from apps/meteor/ee/app/livechat-enterprise/client/startup.ts rename to apps/meteor/app/livechat-enterprise/client/startup.ts index 3c3ec1c02139..0535f8926a7d 100644 --- a/apps/meteor/ee/app/livechat-enterprise/client/startup.ts +++ b/apps/meteor/app/livechat-enterprise/client/startup.ts @@ -1,10 +1,10 @@ import { Meteor } from 'meteor/meteor'; -import { businessHourManager } from '../../../../app/livechat/client/views/app/business-hours/BusinessHours'; -import type { IBusinessHourBehavior } from '../../../../app/livechat/client/views/app/business-hours/IBusinessHourBehavior'; -import { SingleBusinessHourBehavior } from '../../../../app/livechat/client/views/app/business-hours/Single'; -import { settings } from '../../../../app/settings/client'; import { hasLicense } from '../../license/client'; +import { businessHourManager } from '../../livechat/client/views/app/business-hours/BusinessHours'; +import type { IBusinessHourBehavior } from '../../livechat/client/views/app/business-hours/IBusinessHourBehavior'; +import { SingleBusinessHourBehavior } from '../../livechat/client/views/app/business-hours/Single'; +import { settings } from '../../settings/client'; import { MultipleBusinessHoursBehavior } from './views/business-hours/Multiple'; const businessHours: Record = { diff --git a/apps/meteor/ee/app/livechat-enterprise/client/views/business-hours/Multiple.ts b/apps/meteor/app/livechat-enterprise/client/views/business-hours/Multiple.ts similarity index 79% rename from apps/meteor/ee/app/livechat-enterprise/client/views/business-hours/Multiple.ts rename to apps/meteor/app/livechat-enterprise/client/views/business-hours/Multiple.ts index a57344da73dc..698462dcaed2 100644 --- a/apps/meteor/ee/app/livechat-enterprise/client/views/business-hours/Multiple.ts +++ b/apps/meteor/app/livechat-enterprise/client/views/business-hours/Multiple.ts @@ -1,7 +1,7 @@ import type { ILivechatBusinessHour } from '@rocket.chat/core-typings'; import { LivechatBusinessHourTypes } from '@rocket.chat/core-typings'; -import type { IBusinessHourBehavior } from '../../../../../../app/livechat/client/views/app/business-hours/IBusinessHourBehavior'; +import type { IBusinessHourBehavior } from '../../../../livechat/client/views/app/business-hours/IBusinessHourBehavior'; export class MultipleBusinessHoursBehavior implements IBusinessHourBehavior { getView(): string { diff --git a/apps/meteor/ee/app/livechat-enterprise/client/views/livechatSideNavItems.ts b/apps/meteor/app/livechat-enterprise/client/views/livechatSideNavItems.ts similarity index 91% rename from apps/meteor/ee/app/livechat-enterprise/client/views/livechatSideNavItems.ts rename to apps/meteor/app/livechat-enterprise/client/views/livechatSideNavItems.ts index c89931208451..6d9d9f31e24c 100644 --- a/apps/meteor/ee/app/livechat-enterprise/client/views/livechatSideNavItems.ts +++ b/apps/meteor/app/livechat-enterprise/client/views/livechatSideNavItems.ts @@ -1,5 +1,5 @@ -import { hasPermission, hasAtLeastOnePermission } from '../../../../../app/authorization/client'; -import { registerOmnichannelSidebarItem } from '../../../../../client/views/omnichannel/sidebarItems'; +import { registerOmnichannelSidebarItem } from '../../../../client/views/omnichannel/sidebarItems'; +import { hasPermission, hasAtLeastOnePermission } from '../../../authorization/client'; registerOmnichannelSidebarItem({ href: '/omnichannel/reports', diff --git a/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts b/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts index 77190992612a..545e1e73342d 100644 --- a/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts +++ b/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts @@ -356,12 +356,6 @@ export class CachedCollection extends Emitter< this.trySync(); }); - if (!this.userRelated) { - return this.setupListener(); - } - - CachedCollectionManager.onLogin(async () => { - await this.setupListener(); - }); + return this.setupListener(); } } diff --git a/apps/meteor/app/utils/client/lib/SDKClient.ts b/apps/meteor/app/utils/client/lib/SDKClient.ts index 18ff309970df..c174f9125f49 100644 --- a/apps/meteor/app/utils/client/lib/SDKClient.ts +++ b/apps/meteor/app/utils/client/lib/SDKClient.ts @@ -51,6 +51,7 @@ type EventMap = Str type StreamMapValue = { stop: () => void; + error: (cb: (...args: any[]) => void) => void; onChange: ReturnType['onChange']; ready: () => Promise; isReady: boolean; @@ -62,6 +63,7 @@ const createNewMeteorStream = (streamName: StreamNames, key: StreamKeys { - console.error(err); ee.emit('ready', [err]); + ee.emit('error', err); }, }, ); @@ -115,6 +117,11 @@ const createNewMeteorStream = (streamName: StreamNames, key: StreamKeys void) => + ee.once('error', (error) => { + cb(error); + }), + get isReady() { return meta.ready; }, @@ -179,6 +186,7 @@ const createStreamManager = () => { if (!streams.has(eventLiteral)) { streams.set(eventLiteral, stream); } + stream.error(() => stop()); return { id: '', diff --git a/apps/meteor/ee/client/apps/@types/IOrchestrator.ts b/apps/meteor/client/apps/@types/IOrchestrator.ts similarity index 100% rename from apps/meteor/ee/client/apps/@types/IOrchestrator.ts rename to apps/meteor/client/apps/@types/IOrchestrator.ts diff --git a/apps/meteor/ee/client/apps/RealAppsEngineUIHost.js b/apps/meteor/client/apps/RealAppsEngineUIHost.js similarity index 78% rename from apps/meteor/ee/client/apps/RealAppsEngineUIHost.js rename to apps/meteor/client/apps/RealAppsEngineUIHost.js index bcd1a254a4bd..4377f7c66aba 100644 --- a/apps/meteor/ee/client/apps/RealAppsEngineUIHost.js +++ b/apps/meteor/client/apps/RealAppsEngineUIHost.js @@ -1,11 +1,11 @@ import { AppsEngineUIHost } from '@rocket.chat/apps-engine/client/AppsEngineUIHost'; import { Meteor } from 'meteor/meteor'; -import { ChatRoom } from '../../../app/models/client'; -import { getUserAvatarURL } from '../../../app/utils/client/getUserAvatarURL'; -import { sdk } from '../../../app/utils/client/lib/SDKClient'; -import { RoomManager } from '../../../client/lib/RoomManager'; -import { baseURI } from '../../../client/lib/baseURI'; +import { ChatRoom } from '../../app/models/client'; +import { getUserAvatarURL } from '../../app/utils/client/getUserAvatarURL'; +import { sdk } from '../../app/utils/client/lib/SDKClient'; +import { RoomManager } from '../lib/RoomManager'; +import { baseURI } from '../lib/baseURI'; export class RealAppsEngineUIHost extends AppsEngineUIHost { constructor() { diff --git a/apps/meteor/ee/client/apps/gameCenter/GameCenter.tsx b/apps/meteor/client/apps/gameCenter/GameCenter.tsx similarity index 87% rename from apps/meteor/ee/client/apps/gameCenter/GameCenter.tsx rename to apps/meteor/client/apps/gameCenter/GameCenter.tsx index 75f4882ce747..3261d1e1c51e 100644 --- a/apps/meteor/ee/client/apps/gameCenter/GameCenter.tsx +++ b/apps/meteor/client/apps/gameCenter/GameCenter.tsx @@ -3,8 +3,8 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import React, { useState } from 'react'; import type { ReactElement } from 'react'; -import { preventSyntheticEvent } from '../../../../client/lib/utils/preventSyntheticEvent'; -import { useRoomToolbox } from '../../../../client/views/room/contexts/RoomToolboxContext'; +import { preventSyntheticEvent } from '../../lib/utils/preventSyntheticEvent'; +import { useRoomToolbox } from '../../views/room/contexts/RoomToolboxContext'; import GameCenterContainer from './GameCenterContainer'; import GameCenterList from './GameCenterList'; import { useExternalComponentsQuery } from './hooks/useExternalComponentsQuery'; diff --git a/apps/meteor/ee/client/apps/gameCenter/GameCenterContainer.tsx b/apps/meteor/client/apps/gameCenter/GameCenterContainer.tsx similarity index 95% rename from apps/meteor/ee/client/apps/gameCenter/GameCenterContainer.tsx rename to apps/meteor/client/apps/gameCenter/GameCenterContainer.tsx index 1f37e5d6358a..f589dd21ed50 100644 --- a/apps/meteor/ee/client/apps/gameCenter/GameCenterContainer.tsx +++ b/apps/meteor/client/apps/gameCenter/GameCenterContainer.tsx @@ -9,7 +9,7 @@ import { ContextualbarBack, ContextualbarContent, ContextualbarClose, -} from '../../../../client/components/Contextualbar'; +} from '../../components/Contextualbar'; import type { IGame } from './GameCenter'; interface IGameCenterContainerProps { diff --git a/apps/meteor/ee/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx b/apps/meteor/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx similarity index 79% rename from apps/meteor/ee/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx rename to apps/meteor/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx index e7afa0d9e689..d0dcc6fad4fe 100644 --- a/apps/meteor/ee/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx +++ b/apps/meteor/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx @@ -4,11 +4,11 @@ import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useState } from 'react'; -import GenericModal from '../../../../client/components/GenericModal'; -import UserAutoCompleteMultipleFederated from '../../../../client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated'; -import { useOpenedRoom } from '../../../../client/lib/RoomManager'; -import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator'; -import { callWithErrorHandling } from '../../../../client/lib/utils/callWithErrorHandling'; +import GenericModal from '../../components/GenericModal'; +import UserAutoCompleteMultipleFederated from '../../components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated'; +import { useOpenedRoom } from '../../lib/RoomManager'; +import { roomCoordinator } from '../../lib/rooms/roomCoordinator'; +import { callWithErrorHandling } from '../../lib/utils/callWithErrorHandling'; import type { IGame } from './GameCenter'; type Username = Exclude; diff --git a/apps/meteor/ee/client/apps/gameCenter/GameCenterList.tsx b/apps/meteor/client/apps/gameCenter/GameCenterList.tsx similarity index 91% rename from apps/meteor/ee/client/apps/gameCenter/GameCenterList.tsx rename to apps/meteor/client/apps/gameCenter/GameCenterList.tsx index f45ba934ba3b..58a4f05f5362 100644 --- a/apps/meteor/ee/client/apps/gameCenter/GameCenterList.tsx +++ b/apps/meteor/client/apps/gameCenter/GameCenterList.tsx @@ -3,13 +3,8 @@ import { useSetModal, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useCallback } from 'react'; -import { - ContextualbarHeader, - ContextualbarTitle, - ContextualbarClose, - ContextualbarContent, -} from '../../../../client/components/Contextualbar'; -import { FormSkeleton } from '../../../../client/components/Skeleton'; +import { ContextualbarHeader, ContextualbarTitle, ContextualbarClose, ContextualbarContent } from '../../components/Contextualbar'; +import { FormSkeleton } from '../../components/Skeleton'; import type { IGame } from './GameCenter'; import GameCenterInvitePlayersModal from './GameCenterInvitePlayersModal'; diff --git a/apps/meteor/ee/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts b/apps/meteor/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts similarity index 100% rename from apps/meteor/ee/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts rename to apps/meteor/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts diff --git a/apps/meteor/ee/client/apps/orchestrator.ts b/apps/meteor/client/apps/orchestrator.ts similarity index 94% rename from apps/meteor/ee/client/apps/orchestrator.ts rename to apps/meteor/client/apps/orchestrator.ts index d16be3d0c8c7..f33807d25be4 100644 --- a/apps/meteor/ee/client/apps/orchestrator.ts +++ b/apps/meteor/client/apps/orchestrator.ts @@ -4,10 +4,10 @@ import type { IPermission } from '@rocket.chat/apps-engine/definition/permission import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; import type { Serialized } from '@rocket.chat/core-typings'; -import { hasAtLeastOnePermission } from '../../../app/authorization/client'; -import { sdk } from '../../../app/utils/client/lib/SDKClient'; -import { dispatchToastMessage } from '../../../client/lib/toast'; -import type { App } from '../../../client/views/marketplace/types'; +import { hasAtLeastOnePermission } from '../../app/authorization/client'; +import { sdk } from '../../app/utils/client/lib/SDKClient'; +import { dispatchToastMessage } from '../lib/toast'; +import type { App } from '../views/marketplace/types'; import type { IAppExternalURL, ICategory } from './@types/IOrchestrator'; import { RealAppsEngineUIHost } from './RealAppsEngineUIHost'; diff --git a/apps/meteor/client/components/InfoPanel/InfoPanel.stories.tsx b/apps/meteor/client/components/InfoPanel/InfoPanel.stories.tsx index 4e8e44b1f932..39242161ed46 100644 --- a/apps/meteor/client/components/InfoPanel/InfoPanel.stories.tsx +++ b/apps/meteor/client/components/InfoPanel/InfoPanel.stories.tsx @@ -52,7 +52,7 @@ export const Default: ComponentStory = () => ( - + ); diff --git a/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx b/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx index 27202afa496c..06f6ed133dc3 100644 --- a/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx +++ b/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx @@ -4,23 +4,26 @@ import type { FC } from 'react'; import React from 'react'; import { useFormattedRelativeTime } from '../../hooks/useFormattedRelativeTime'; +import { getMaxAgeInMS } from '../../views/room/hooks/useRetentionPolicy'; type RetentionPolicyCalloutProps = { - filesOnlyDefault: boolean; - excludePinnedDefault: boolean; - maxAgeDefault: number; + filesOnly: boolean; + excludePinned: boolean; + maxAge: number; }; -const RetentionPolicyCallout: FC = ({ filesOnlyDefault, excludePinnedDefault, maxAgeDefault }) => { +const RetentionPolicyCallout: FC = ({ filesOnly, excludePinned, maxAge }) => { const t = useTranslation(); - const time = useFormattedRelativeTime(maxAgeDefault); + const time = useFormattedRelativeTime(getMaxAgeInMS(maxAge)); return ( - - {filesOnlyDefault && excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning_FilesOnly', { time })}

} - {filesOnlyDefault && !excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning_UnpinnedFilesOnly', { time })}

} - {!filesOnlyDefault && excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning', { time })}

} - {!filesOnlyDefault && !excludePinnedDefault &&

{t('RetentionPolicy_RoomWarning_Unpinned', { time })}

} + +
+ {filesOnly && excludePinned &&

{t('RetentionPolicy_RoomWarning_FilesOnly', { time })}

} + {filesOnly && !excludePinned &&

{t('RetentionPolicy_RoomWarning_UnpinnedFilesOnly', { time })}

} + {!filesOnly && excludePinned &&

{t('RetentionPolicy_RoomWarning', { time })}

} + {!filesOnly && !excludePinned &&

{t('RetentionPolicy_RoomWarning_Unpinned', { time })}

} +
); }; diff --git a/apps/meteor/client/components/Omnichannel/modals/CloseChatModal.tsx b/apps/meteor/client/components/Omnichannel/modals/CloseChatModal.tsx index 0fd882f2c5cc..401448ceb396 100644 --- a/apps/meteor/client/components/Omnichannel/modals/CloseChatModal.tsx +++ b/apps/meteor/client/components/Omnichannel/modals/CloseChatModal.tsx @@ -18,7 +18,7 @@ import type { ReactElement } from 'react'; import React, { useCallback, useState, useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; -import { useHasLicenseModule } from '../../../../ee/client/hooks/useHasLicenseModule'; +import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule'; import { dispatchToastMessage } from '../../../lib/toast'; import GenericModal from '../../GenericModal'; import Tags from '../Tags'; diff --git a/apps/meteor/client/components/RoomAutoComplete/Avatar.tsx b/apps/meteor/client/components/RoomAutoComplete/Avatar.tsx deleted file mode 100644 index 1437c4ebbe89..000000000000 --- a/apps/meteor/client/components/RoomAutoComplete/Avatar.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Options } from '@rocket.chat/fuselage'; -import { RoomAvatar } from '@rocket.chat/ui-avatar'; -import type { FC } from 'react'; -import React from 'react'; - -type AvatarProps = { - value: string; - type: string; - avatarETag?: string; -}; - -const Avatar: FC = ({ value, type, avatarETag, ...props }) => ( - -); - -export default Avatar; diff --git a/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx b/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx index 39fbf9577776..10bea7cc0b60 100644 --- a/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx +++ b/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx @@ -3,34 +3,49 @@ import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import { RoomAvatar } from '@rocket.chat/ui-avatar'; import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; -import type { ReactElement, ComponentProps } from 'react'; +import type { ComponentProps } from 'react'; import React, { memo, useMemo, useState } from 'react'; -import Avatar from './Avatar'; - const generateQuery = ( term = '', ): { selector: string; } => ({ selector: JSON.stringify({ name: term }) }); -type RoomAutoCompleteProps = Omit, 'filter'>; +type RoomAutoCompleteProps = Omit, 'filter'> & { scope?: 'admin' | 'regular' }; + +const AVATAR_SIZE = 'x20'; -const RoomAutoComplete = ({ value, onChange, ...props }: RoomAutoCompleteProps): ReactElement => { +const ROOM_AUTOCOMPLETE_PARAMS = { + admin: { + endpoint: '/v1/rooms.autocomplete.adminRooms', + key: 'roomsAutoCompleteAdmin', + }, + regular: { + endpoint: '/v1/rooms.autocomplete.channelAndPrivate', + key: 'roomsAutoCompleteRegular', + }, +} as const; + +const RoomAutoComplete = ({ value, onChange, scope = 'regular', ...props }: RoomAutoCompleteProps) => { const [filter, setFilter] = useState(''); const filterDebounced = useDebouncedValue(filter, 300); - const autocomplete = useEndpoint('GET', '/v1/rooms.autocomplete.channelAndPrivate'); + const roomsAutoCompleteEndpoint = useEndpoint('GET', ROOM_AUTOCOMPLETE_PARAMS[scope].endpoint); - const result = useQuery(['rooms.autocomplete.channelAndPrivate', filterDebounced], () => autocomplete(generateQuery(filterDebounced)), { - keepPreviousData: true, - }); + const result = useQuery( + [ROOM_AUTOCOMPLETE_PARAMS[scope].key, filterDebounced], + () => roomsAutoCompleteEndpoint(generateQuery(filterDebounced)), + { + keepPreviousData: true, + }, + ); const options = useMemo( () => result.isSuccess - ? result.data.items.map(({ name, _id, avatarETag, t }) => ({ + ? result.data.items.map(({ name, fname, _id, avatarETag, t }) => ({ value: _id, - label: { name, avatarETag, type: t }, + label: { name: fname || name, avatarETag, type: t }, })) : [], [result.data?.items, result.isSuccess], @@ -43,18 +58,18 @@ const RoomAutoComplete = ({ value, onChange, ...props }: RoomAutoCompleteProps): onChange={onChange} filter={filter} setFilter={setFilter} - renderSelected={({ selected: { value, label } }): ReactElement => ( + renderSelected={({ selected: { value, label } }) => ( <> - + {label?.name} )} - renderItem={({ value, label, ...props }): ReactElement => ( -