From e5ce2dc4987a654936fa4242ab1dcedc29fb55d7 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Wed, 14 Aug 2024 14:18:40 +0000 Subject: [PATCH 001/170] Bump 6.11.1 --- .changeset/bump-patch-1723645120544.md | 5 +++++ yarn.lock | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 .changeset/bump-patch-1723645120544.md diff --git a/.changeset/bump-patch-1723645120544.md b/.changeset/bump-patch-1723645120544.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1723645120544.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/yarn.lock b/yarn.lock index a04c45ee1f64..d36e9c6d753a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8968,10 +8968,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0-rc.6 - "@rocket.chat/ui-contexts": 9.0.0-rc.6 - "@rocket.chat/ui-kit": 0.36.0-rc.0 - "@rocket.chat/ui-video-conf": 9.0.0-rc.6 + "@rocket.chat/ui-avatar": 5.0.0 + "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-kit": 0.36.0 + "@rocket.chat/ui-video-conf": 9.0.0 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9060,8 +9060,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 9.0.0-rc.6 - "@rocket.chat/ui-contexts": 9.0.0-rc.6 + "@rocket.chat/ui-client": 9.0.0 + "@rocket.chat/ui-contexts": 9.0.0 katex: "*" react: "*" languageName: unknown @@ -10281,7 +10281,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 9.0.0-rc.6 + "@rocket.chat/ui-contexts": 9.0.0 react: ~17.0.2 languageName: unknown linkType: soft @@ -10334,7 +10334,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 9.0.0-rc.6 + "@rocket.chat/ui-contexts": 9.0.0 react: ~17.0.2 languageName: unknown linkType: soft @@ -10510,8 +10510,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0-rc.6 - "@rocket.chat/ui-contexts": 9.0.0-rc.6 + "@rocket.chat/ui-avatar": 5.0.0 + "@rocket.chat/ui-contexts": 9.0.0 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10600,8 +10600,8 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/layout": "*" - "@rocket.chat/tools": 0.2.2-rc.0 - "@rocket.chat/ui-contexts": 9.0.0-rc.6 + "@rocket.chat/tools": 0.2.2 + "@rocket.chat/ui-contexts": 9.0.0 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From b3ac6d93ae36af9ddd7cf750e34301891ccd2579 Mon Sep 17 00:00:00 2001 From: "Julio A." <52619625+julio-cfa@users.noreply.github.com> Date: Thu, 15 Aug 2024 23:02:15 +0200 Subject: [PATCH 002/170] fix: security hotfix (#33062) --- .changeset/perfect-dancers-grab.md | 5 + apps/meteor/app/api/server/v1/rooms.ts | 10 +- apps/meteor/app/api/server/v1/users.ts | 6 + .../app/livechat/imports/server/rest/sms.ts | 12 +- .../views/admin/oauthApps/EditOauthApp.tsx | 3 +- apps/meteor/ee/server/lib/audit/methods.ts | 46 +++- apps/meteor/server/lib/ldap/Manager.ts | 2 +- apps/meteor/server/methods/reportMessage.ts | 13 ++ .../server/methods/sendConfirmationEmail.ts | 13 ++ .../providers/mobex.ts | 5 + .../providers/twilio.ts | 26 +++ .../providers/voxtelesys.ts | 5 + apps/meteor/server/settings/message.ts | 2 +- apps/meteor/tests/end-to-end/api/methods.ts | 162 +++++++++++++- apps/meteor/tests/end-to-end/api/rooms.ts | 1 - apps/meteor/tests/end-to-end/api/users.ts | 41 +++- .../providers/twilio.spec.ts | 211 ++++++++++++++++++ packages/core-typings/package.json | 3 +- packages/core-typings/src/omnichannel/sms.ts | 3 + packages/rest-typings/src/v1/rooms.ts | 69 +++++- yarn.lock | 13 ++ 21 files changed, 605 insertions(+), 46 deletions(-) create mode 100644 .changeset/perfect-dancers-grab.md create mode 100644 apps/meteor/tests/unit/server/services/omnichannel-integrations/providers/twilio.spec.ts diff --git a/.changeset/perfect-dancers-grab.md b/.changeset/perfect-dancers-grab.md new file mode 100644 index 000000000000..eacb88108a0f --- /dev/null +++ b/.changeset/perfect-dancers-grab.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index e3296b98ef17..ee76dcdd9fe3 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -2,7 +2,13 @@ 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, isRoomsExportProps } from '@rocket.chat/rest-typings'; +import { + isGETRoomsNameExists, + isRoomsCleanHistoryProps, + isRoomsImagesProps, + isRoomsMuteUnmuteUserProps, + isRoomsExportProps, +} from '@rocket.chat/rest-typings'; import { Meteor } from 'meteor/meteor'; import { isTruthy } from '../../../../lib/isTruthy'; @@ -355,7 +361,7 @@ API.v1.addRoute( API.v1.addRoute( 'rooms.cleanHistory', - { authRequired: true }, + { authRequired: true, validateParams: isRoomsCleanHistoryProps }, { async post() { const { _id } = await findRoomByIdOrName({ params: this.bodyParams }); diff --git a/apps/meteor/app/api/server/v1/users.ts b/apps/meteor/app/api/server/v1/users.ts index 7ae585b89dfa..6c680b6648d8 100644 --- a/apps/meteor/app/api/server/v1/users.ts +++ b/apps/meteor/app/api/server/v1/users.ts @@ -750,6 +750,12 @@ API.v1.addRoute( { authRequired: false }, { async post() { + const isPasswordResetEnabled = settings.get('Accounts_PasswordReset'); + + if (!isPasswordResetEnabled) { + return API.v1.failure('Password reset is not enabled'); + } + const { email } = this.bodyParams; if (!email) { return API.v1.failure("The 'email' param is required"); diff --git a/apps/meteor/app/livechat/imports/server/rest/sms.ts b/apps/meteor/app/livechat/imports/server/rest/sms.ts index 6f8ce64bc635..6b2411cf8e3d 100644 --- a/apps/meteor/app/livechat/imports/server/rest/sms.ts +++ b/apps/meteor/app/livechat/imports/server/rest/sms.ts @@ -97,12 +97,18 @@ const normalizeLocationSharing = (payload: ServiceData) => { // @ts-expect-error - this is an special endpoint that requires the return to not be wrapped as regular returns API.v1.addRoute('livechat/sms-incoming/:service', { async post() { - if (!(await OmnichannelIntegration.isConfiguredSmsService(this.urlParams.service))) { + const { service } = this.urlParams; + if (!(await OmnichannelIntegration.isConfiguredSmsService(service))) { return API.v1.failure('Invalid service'); } const smsDepartment = settings.get('SMS_Default_Omnichannel_Department'); - const SMSService = await OmnichannelIntegration.getSmsService(this.urlParams.service); + const SMSService = await OmnichannelIntegration.getSmsService(service); + + if (!SMSService.validateRequest(this.request)) { + return API.v1.failure('Invalid request'); + } + const sms = SMSService.parse(this.bodyParams); const { department } = this.queryParams; let targetDepartment = await defineDepartment(department || smsDepartment); @@ -121,7 +127,7 @@ API.v1.addRoute('livechat/sms-incoming/:service', { }, source: { type: OmnichannelSourceType.SMS, - alias: this.urlParams.service, + alias: service, }, }; diff --git a/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx b/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx index 19bef201492f..79d2fbe11140 100644 --- a/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx +++ b/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx @@ -8,6 +8,7 @@ import { FieldRow, FieldError, FieldHint, + PasswordInput, TextAreaInput, ToggleSwitch, FieldGroup, @@ -136,7 +137,7 @@ const EditOauthApp = ({ onChange, data, ...props }: EditOauthAppProps): ReactEle {t('Client_Secret')} - + diff --git a/apps/meteor/ee/server/lib/audit/methods.ts b/apps/meteor/ee/server/lib/audit/methods.ts index add64414c6e8..b221f4a2f1e1 100644 --- a/apps/meteor/ee/server/lib/audit/methods.ts +++ b/apps/meteor/ee/server/lib/audit/methods.ts @@ -88,11 +88,18 @@ Meteor.methods({ check(startDate, Date); check(endDate, Date); - const user = await Meteor.userAsync(); + const user = (await Meteor.userAsync()) as IUser; if (!user || !(await hasPermissionAsync(user._id, 'can-audit'))) { throw new Meteor.Error('Not allowed'); } + const userFields = { + _id: user._id, + username: user.username, + ...(user.name && { name: user.name }), + ...(user.avatarETag && { avatarETag: user.avatarETag }), + }; + const rooms: IRoom[] = await LivechatRooms.findByVisitorIdAndAgentId(visitor, agent, { projection: { _id: 1 }, }).toArray(); @@ -118,7 +125,7 @@ Meteor.methods({ await AuditLog.insertOne({ ts: new Date(), results: messages.length, - u: user, + u: userFields, fields: { msg, users: usernames, rids, room: name, startDate, endDate, type, visitor, agent }, }); @@ -128,11 +135,18 @@ Meteor.methods({ check(startDate, Date); check(endDate, Date); - const user = await Meteor.userAsync(); + const user = (await Meteor.userAsync()) as IUser; if (!user || !(await hasPermissionAsync(user._id, 'can-audit'))) { throw new Meteor.Error('Not allowed'); } + const userFields = { + _id: user._id, + username: user.username, + ...(user.name && { name: user.name }), + ...(user.avatarETag && { avatarETag: user.avatarETag }), + }; + let rids; let name; @@ -169,9 +183,10 @@ Meteor.methods({ await AuditLog.insertOne({ ts: new Date(), results: messages.length, - u: user, + u: userFields, fields: { msg, users: usernames, rids, room: name, startDate, endDate, type, visitor, agent }, }); + updateCounter({ settingsId: 'Message_Auditing_Panel_Load_Count' }); return messages; @@ -183,13 +198,24 @@ Meteor.methods({ if (!uid || !(await hasPermissionAsync(uid, 'can-audit-log'))) { throw new Meteor.Error('Not allowed'); } - return AuditLog.find({ - // 'u._id': userId, - ts: { - $gt: startDate, - $lt: endDate, + return AuditLog.find( + { + // 'u._id': userId, + ts: { + $gt: startDate, + $lt: endDate, + }, }, - }).toArray(); + { + projection: { + 'u.services': 0, + 'u.roles': 0, + 'u.lastLogin': 0, + 'u.statusConnection': 0, + 'u.emails': 0, + }, + }, + ).toArray(); }, }); diff --git a/apps/meteor/server/lib/ldap/Manager.ts b/apps/meteor/server/lib/ldap/Manager.ts index ab000b142225..f0efcc04539d 100644 --- a/apps/meteor/server/lib/ldap/Manager.ts +++ b/apps/meteor/server/lib/ldap/Manager.ts @@ -165,7 +165,7 @@ export class LDAPManager { const { attribute: idAttribute, value: id } = uniqueId; const username = this.slugifyUsername(ldapUser, usedUsername || id || '') || undefined; - const emails = this.getLdapEmails(ldapUser, username); + const emails = this.getLdapEmails(ldapUser, username).map((email) => email.trim()); const name = this.getLdapName(ldapUser) || undefined; const userData: IImportUser = { diff --git a/apps/meteor/server/methods/reportMessage.ts b/apps/meteor/server/methods/reportMessage.ts index 05ac5aaf7e7b..14ef69189b33 100644 --- a/apps/meteor/server/methods/reportMessage.ts +++ b/apps/meteor/server/methods/reportMessage.ts @@ -3,6 +3,7 @@ import type { IMessage } from '@rocket.chat/core-typings'; import { ModerationReports, Rooms, Users, Messages } from '@rocket.chat/models'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { check } from 'meteor/check'; +import { DDPRateLimiter } from 'meteor/ddp-rate-limiter'; import { Meteor } from 'meteor/meteor'; import { canAccessRoomAsync } from '../../app/authorization/server/functions/canAccessRoom'; @@ -82,3 +83,15 @@ Meteor.methods({ return true; }, }); + +DDPRateLimiter.addRule( + { + type: 'method', + name: 'reportMessage', + userId() { + return true; + }, + }, + 5, + 60000, +); diff --git a/apps/meteor/server/methods/sendConfirmationEmail.ts b/apps/meteor/server/methods/sendConfirmationEmail.ts index 8c7d056532d3..9ed7e0b99da2 100644 --- a/apps/meteor/server/methods/sendConfirmationEmail.ts +++ b/apps/meteor/server/methods/sendConfirmationEmail.ts @@ -2,6 +2,7 @@ import { Users } from '@rocket.chat/models'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { Accounts } from 'meteor/accounts-base'; import { check } from 'meteor/check'; +import { DDPRateLimiter } from 'meteor/ddp-rate-limiter'; import { Meteor } from 'meteor/meteor'; import { methodDeprecationLogger } from '../../app/lib/server/lib/deprecationWarningLogger'; @@ -31,3 +32,15 @@ Meteor.methods({ } }, }); + +DDPRateLimiter.addRule( + { + type: 'method', + name: 'sendConfirmationEmail', + userId() { + return true; + }, + }, + 5, + 60000, +); diff --git a/apps/meteor/server/services/omnichannel-integrations/providers/mobex.ts b/apps/meteor/server/services/omnichannel-integrations/providers/mobex.ts index 19284b8e1e6b..d036345663cd 100644 --- a/apps/meteor/server/services/omnichannel-integrations/providers/mobex.ts +++ b/apps/meteor/server/services/omnichannel-integrations/providers/mobex.ts @@ -1,6 +1,7 @@ import { Base64 } from '@rocket.chat/base64'; import type { ISMSProvider, ServiceData, SMSProviderResult, SMSProviderResponse } from '@rocket.chat/core-typings'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; +import type { Request } from 'express'; import { settings } from '../../../../app/settings/server'; import { SystemLogger } from '../../../lib/logger/system'; @@ -196,6 +197,10 @@ export class Mobex implements ISMSProvider { }; } + validateRequest(_request: Request): boolean { + return true; + } + error(error: Error & { reason?: string }): SMSProviderResponse { let message = ''; if (error.reason) { diff --git a/apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts b/apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts index 3aff869a95a0..4a1c8d9d0ebf 100644 --- a/apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts +++ b/apps/meteor/server/services/omnichannel-integrations/providers/twilio.ts @@ -1,6 +1,7 @@ import { api } from '@rocket.chat/core-services'; import type { ISMSProvider, ServiceData, SMSProviderResponse, SMSProviderResult } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; +import type { Request } from 'express'; import filesize from 'filesize'; import twilio from 'twilio'; @@ -244,6 +245,31 @@ export class Twilio implements ISMSProvider { }; } + isRequestFromTwilio(signature: string, requestBody: object): boolean { + const authToken = settings.get('SMS_Twilio_authToken'); + const siteUrl = settings.get('Site_Url'); + + if (!authToken || !siteUrl) { + SystemLogger.error(`(Twilio) -> URL or Twilio token not configured.`); + return false; + } + + const twilioUrl = siteUrl.endsWith('/') + ? `${siteUrl}api/v1/livechat/sms-incoming/twilio` + : `${siteUrl}/api/v1/livechat/sms-incoming/twilio`; + return twilio.validateRequest(authToken, signature, twilioUrl, requestBody); + } + + validateRequest(request: Request): boolean { + // We're not getting original twilio requests on CI :p + if (process.env.TEST_MODE === 'true') { + return true; + } + const twilioHeader = request.headers['x-twilio-signature'] || ''; + const twilioSignature = Array.isArray(twilioHeader) ? twilioHeader[0] : twilioHeader; + return this.isRequestFromTwilio(twilioSignature, request.body); + } + error(error: Error & { reason?: string }): SMSProviderResponse { let message = ''; if (error.reason) { diff --git a/apps/meteor/server/services/omnichannel-integrations/providers/voxtelesys.ts b/apps/meteor/server/services/omnichannel-integrations/providers/voxtelesys.ts index 3e78907bbf75..aa42bacad624 100644 --- a/apps/meteor/server/services/omnichannel-integrations/providers/voxtelesys.ts +++ b/apps/meteor/server/services/omnichannel-integrations/providers/voxtelesys.ts @@ -2,6 +2,7 @@ import { api } from '@rocket.chat/core-services'; import type { ISMSProvider, ServiceData, SMSProviderResponse } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; +import type { Request } from 'express'; import filesize from 'filesize'; import { settings } from '../../../../app/settings/server'; @@ -162,6 +163,10 @@ export class Voxtelesys implements ISMSProvider { }; } + validateRequest(_request: Request): boolean { + return true; + } + error(error: Error & { reason?: string }): SMSProviderResponse { let message = ''; if (error.reason) { diff --git a/apps/meteor/server/settings/message.ts b/apps/meteor/server/settings/message.ts index 6ec6e3355655..520af87d2333 100644 --- a/apps/meteor/server/settings/message.ts +++ b/apps/meteor/server/settings/message.ts @@ -32,7 +32,7 @@ export const createMessageSettings = () => ], }); - await this.add('Message_Attachments_Strip_Exif', false, { + await this.add('Message_Attachments_Strip_Exif', true, { type: 'boolean', public: true, i18nDescription: 'Message_Attachments_Strip_ExifDescription', diff --git a/apps/meteor/tests/end-to-end/api/methods.ts b/apps/meteor/tests/end-to-end/api/methods.ts index e1ca05d1fbf2..197a71f8e8f2 100644 --- a/apps/meteor/tests/end-to-end/api/methods.ts +++ b/apps/meteor/tests/end-to-end/api/methods.ts @@ -2030,6 +2030,13 @@ describe('Meteor.methods', () => { let messageWithMarkdownId: IMessage['_id']; let channelName: string; const siteUrl = process.env.SITE_URL || process.env.TEST_API_URL || 'http://localhost:3000'; + let testUser: TestUser; + let testUserCredentials: Credentials; + + before(async () => { + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + }); before('create room', (done) => { channelName = `methods-test-channel-${Date.now()}`; @@ -2125,13 +2132,14 @@ describe('Meteor.methods', () => { after(() => Promise.all([ deleteRoom({ type: 'p', roomId: rid }), + deleteUser(testUser), updatePermission('bypass-time-limit-edit-and-delete', ['bot', 'app']), updateSetting('Message_AllowEditing_BlockEditInMinutes', 0), ]), ); - it('should update a message with a URL', (done) => { - void request + it('should update a message with a URL', async () => { + await request .post(methodCall('updateMessage')) .set(credentials) .send({ @@ -2149,8 +2157,53 @@ describe('Meteor.methods', () => { expect(res.body).to.have.a.property('message').that.is.a('string'); const data = JSON.parse(res.body.message); expect(data).to.have.a.property('msg').that.is.an('string'); + }); + }); + + it('should fail if user does not have permissions to update a message with the same content', async () => { + await request + .post(methodCall('updateMessage')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'updateMessage', + params: [{ _id: messageId, rid, msg: 'test message with https://github.com' }], + id: 'id', + msg: 'method', + }), }) - .end(done); + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('msg').that.is.an('string'); + expect(data.error).to.have.a.property('error', 'error-action-not-allowed'); + }); + }); + + it('should fail if user does not have permissions to update a message with different content', async () => { + await request + .post(methodCall('updateMessage')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'updateMessage', + params: [{ _id: messageId, rid, msg: 'updating test message with https://github.com' }], + id: 'id', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('msg').that.is.an('string'); + expect(data.error).to.have.a.property('error', 'error-action-not-allowed'); + }); }); it('should add a quote attachment to a message', async () => { @@ -3295,4 +3348,107 @@ describe('Meteor.methods', () => { .end(done); }); }); + (IS_EE ? describe : describe.skip)('[@auditGetAuditions] EE', () => { + let testUser: TestUser; + let testUserCredentials: Credentials; + + const now = new Date(); + const startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime(); + const endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999).getTime(); + + before('create test user', async () => { + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + }); + + before('generate audits data', async () => { + await request + .post(methodCall('auditGetMessages')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'auditGetMessages', + params: [ + { + type: '', + msg: 'test1234', + startDate: { $date: startDate }, + endDate: { $date: endDate }, + rid: 'GENERAL', + users: [], + }, + ], + id: '14', + msg: 'method', + }), + }); + }); + + after(() => Promise.all([deleteUser(testUser)])); + + it('should fail if the user does not have permissions to get auditions', async () => { + await request + .post(methodCall('auditGetAuditions')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'auditGetAuditions', + params: [ + { + startDate: { $date: startDate }, + endDate: { $date: endDate }, + }, + ], + id: '18', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('message'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('error'); + expect(data.error).to.have.a.property('error', 'Not allowed'); + }); + }); + + it('should not return more user data than necessary - e.g. passwords, hashes, tokens', async () => { + await request + .post(methodCall('auditGetAuditions')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'auditGetAuditions', + params: [ + { + startDate: { $date: startDate }, + endDate: { $date: endDate }, + }, + ], + id: '18', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('result').that.is.an('array'); + expect(data.result.length).to.be.greaterThan(0); + expect(data).to.have.a.property('msg', 'result'); + expect(data).to.have.a.property('id', '18'); + data.result.forEach((item: any) => { + expect(item).to.have.all.keys('_id', 'ts', 'results', 'u', 'fields', '_updatedAt'); + expect(item.u).to.not.have.property('services'); + expect(item.u).to.not.have.property('roles'); + expect(item.u).to.not.have.property('lastLogin'); + expect(item.u).to.not.have.property('statusConnection'); + expect(item.u).to.not.have.property('emails'); + }); + }); + }); + }); }); diff --git a/apps/meteor/tests/end-to-end/api/rooms.ts b/apps/meteor/tests/end-to-end/api/rooms.ts index a8d64b1f4c7d..b502bca6add8 100644 --- a/apps/meteor/tests/end-to-end/api/rooms.ts +++ b/apps/meteor/tests/end-to-end/api/rooms.ts @@ -1024,7 +1024,6 @@ describe('[Rooms]', () => { .end(done); }); }); - describe('[/rooms.info]', () => { let testChannel: IRoom; let testGroup: IRoom; diff --git a/apps/meteor/tests/end-to-end/api/users.ts b/apps/meteor/tests/end-to-end/api/users.ts index d6112dd2416b..ea2aa5baa99b 100644 --- a/apps/meteor/tests/end-to-end/api/users.ts +++ b/apps/meteor/tests/end-to-end/api/users.ts @@ -2624,18 +2624,37 @@ describe('[Users]', () => { }); describe('[/users.forgotPassword]', () => { + it('should return an error when "Accounts_PasswordReset" is disabled', (done) => { + void updateSetting('Accounts_PasswordReset', false).then(() => { + void request + .post(api('users.forgotPassword')) + .send({ + email: adminEmail, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'Password reset is not enabled'); + }) + .end(done); + }); + }); + it('should send email to user (return success), when is a valid email', (done) => { - void request - .post(api('users.forgotPassword')) - .send({ - email: adminEmail, - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - }) - .end(done); + void updateSetting('Accounts_PasswordReset', true).then(() => { + void request + .post(api('users.forgotPassword')) + .send({ + email: adminEmail, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); }); it('should not send email to user(return error), when is a invalid email', (done) => { diff --git a/apps/meteor/tests/unit/server/services/omnichannel-integrations/providers/twilio.spec.ts b/apps/meteor/tests/unit/server/services/omnichannel-integrations/providers/twilio.spec.ts new file mode 100644 index 000000000000..f3c5d281aefb --- /dev/null +++ b/apps/meteor/tests/unit/server/services/omnichannel-integrations/providers/twilio.spec.ts @@ -0,0 +1,211 @@ +import crypto from 'crypto'; + +import { expect } from 'chai'; +import proxyquire from 'proxyquire'; +import sinon from 'sinon'; + +const settingsStub = { + get: sinon.stub(), +}; + +const twilioStub = { + validateRequest: sinon.stub(), + isRequestFromTwilio: sinon.stub(), +}; + +const { Twilio } = proxyquire.noCallThru().load('../../../../../../server/services/omnichannel-integrations/providers/twilio.ts', { + '../../../../app/settings/server': { settings: settingsStub }, + '../../../../app/utils/server/restrictions': { fileUploadIsValidContentType: sinon.stub() }, + '../../../lib/i18n': { i18n: sinon.stub() }, + '../../../lib/logger/system': { SystemLogger: { error: sinon.stub() } }, +}); + +/** + * Get a valid Twilio signature for a request + * + * @param {String} authToken your Twilio AuthToken + * @param {String} url your webhook URL + * @param {Object} params the included request parameters + */ +function getSignature(authToken: string, url: string, params: Record): string { + // get all request parameters + const data = Object.keys(params) + // sort them + .sort() + // concatenate them to a string + + .reduce((acc, key) => acc + key + params[key], url); + + return ( + crypto + // sign the string with sha1 using your AuthToken + .createHmac('sha1', authToken) + .update(Buffer.from(data, 'utf-8')) + // base64 encode it + .digest('base64') + ); +} + +describe('Twilio Request Validation', () => { + beforeEach(() => { + settingsStub.get.reset(); + twilioStub.validateRequest.reset(); + twilioStub.isRequestFromTwilio.reset(); + }); + + it('should not validate a request when process.env.TEST_MODE is true', () => { + process.env.TEST_MODE = 'true'; + + const twilio = new Twilio(); + const request = { + headers: { + 'x-twilio-signature': 'test', + }, + }; + + expect(twilio.validateRequest(request)).to.be.true; + }); + + it('should not validate a request when process.env.TEST_MODE is true', () => { + process.env.TEST_MODE = 'true'; + + const twilio = new Twilio(); + const request = { + headers: { + 'x-twilio-signature': 'test', + }, + }; + + expect(twilio.validateRequest(request)).to.be.true; + }); + + it('should validate a request when process.env.TEST_MODE is false', () => { + process.env.TEST_MODE = 'false'; + + settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test'); + settingsStub.get.withArgs('Site_Url').returns('https://example.com'); + + const twilio = new Twilio(); + const requestBody = { + To: 'test', + From: 'test', + Body: 'test', + }; + + const request = { + headers: { + 'x-twilio-signature': getSignature('test', 'https://example.com/api/v1/livechat/sms-incoming/twilio', requestBody), + }, + body: requestBody, + }; + + expect(twilio.validateRequest(request)).to.be.true; + }); + + it('should reject a request where signature doesnt match', () => { + settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test'); + settingsStub.get.withArgs('Site_Url').returns('https://example.com'); + + const twilio = new Twilio(); + const requestBody = { + To: 'test', + From: 'test', + Body: 'test', + }; + + const request = { + headers: { + 'x-twilio-signature': getSignature('anotherAuthToken', 'https://example.com/api/v1/livechat/sms-incoming/twilio', requestBody), + }, + body: requestBody, + }; + + expect(twilio.validateRequest(request)).to.be.false; + }); + + it('should reject a request where signature is missing', () => { + settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test'); + settingsStub.get.withArgs('Site_Url').returns('https://example.com'); + + const twilio = new Twilio(); + const requestBody = { + To: 'test', + From: 'test', + Body: 'test', + }; + + const request = { + headers: {}, + body: requestBody, + }; + + expect(twilio.validateRequest(request)).to.be.false; + }); + + it('should reject a request where the signature doesnt correspond body', () => { + settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test'); + settingsStub.get.withArgs('Site_Url').returns('https://example.com'); + + const twilio = new Twilio(); + const requestBody = { + To: 'test', + From: 'test', + Body: 'test', + }; + + const request = { + headers: { + 'x-twilio-signature': getSignature('test', 'https://example.com/api/v1/livechat/sms-incoming/twilio', {}), + }, + body: requestBody, + }; + + expect(twilio.validateRequest(request)).to.be.false; + }); + + it('should return false if URL is not provided', () => { + process.env.TEST_MODE = 'false'; + + settingsStub.get.withArgs('SMS_Twilio_authToken').returns('test'); + settingsStub.get.withArgs('Site_Url').returns(''); + + const twilio = new Twilio(); + const requestBody = { + To: 'test', + From: 'test', + Body: 'test', + }; + + const request = { + headers: { + 'x-twilio-signature': getSignature('test', 'https://example.com/api/v1/livechat/sms-incoming/twilio', requestBody), + }, + body: requestBody, + }; + + expect(twilio.validateRequest(request)).to.be.false; + }); + + it('should return false if authToken is not provided', () => { + process.env.TEST_MODE = 'false'; + + settingsStub.get.withArgs('SMS_Twilio_authToken').returns(''); + settingsStub.get.withArgs('Site_Url').returns('https://example.com'); + + const twilio = new Twilio(); + const requestBody = { + To: 'test', + From: 'test', + Body: 'test', + }; + + const request = { + headers: { + 'x-twilio-signature': getSignature('test', 'https://example.com/api/v1/livechat/sms-incoming/twilio', requestBody), + }, + body: requestBody, + }; + + expect(twilio.validateRequest(request)).to.be.false; + }); +}); diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index a9f4fdd293e3..3c0c97198b7f 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -25,7 +25,8 @@ "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/icons": "^0.36.0", "@rocket.chat/message-parser": "workspace:^", - "@rocket.chat/ui-kit": "workspace:~" + "@rocket.chat/ui-kit": "workspace:~", + "@types/express": "^4.17.21" }, "volta": { "extends": "../../package.json" diff --git a/packages/core-typings/src/omnichannel/sms.ts b/packages/core-typings/src/omnichannel/sms.ts index 7ff7a4768a13..49364da2b8c3 100644 --- a/packages/core-typings/src/omnichannel/sms.ts +++ b/packages/core-typings/src/omnichannel/sms.ts @@ -1,3 +1,5 @@ +import type { Request } from 'express'; + type ServiceMedia = { url: string; contentType: string; @@ -27,6 +29,7 @@ export interface ISMSProviderConstructor { export interface ISMSProvider { parse(data: unknown): ServiceData; + validateRequest(request: Request): boolean; sendBatch?(from: string, to: string[], message: string): Promise; response(): SMSProviderResponse; diff --git a/packages/rest-typings/src/v1/rooms.ts b/packages/rest-typings/src/v1/rooms.ts index 1c0b6a360f7b..868fd5850157 100644 --- a/packages/rest-typings/src/v1/rooms.ts +++ b/packages/rest-typings/src/v1/rooms.ts @@ -527,6 +527,62 @@ const roomsImagesPropsSchema = { export const isRoomsImagesProps = ajv.compile(roomsImagesPropsSchema); +export type RoomsCleanHistoryProps = { + roomId: IRoom['_id']; + latest: string; + oldest: string; + inclusive?: boolean; + excludePinned?: boolean; + filesOnly?: boolean; + users?: IUser['username'][]; + limit?: number; + ignoreDiscussion?: boolean; + ignoreThreads?: boolean; +}; + +const roomsCleanHistorySchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + latest: { + type: 'string', + }, + oldest: { + type: 'string', + }, + inclusive: { + type: 'boolean', + }, + excludePinned: { + type: 'boolean', + }, + filesOnly: { + type: 'boolean', + }, + users: { + type: 'array', + items: { + type: 'string', + }, + }, + limit: { + type: 'number', + }, + ignoreDiscussion: { + type: 'boolean', + }, + ignoreThreads: { + type: 'boolean', + }, + }, + required: ['roomId', 'latest', 'oldest'], + additionalProperties: false, +}; + +export const isRoomsCleanHistoryProps = ajv.compile(roomsCleanHistorySchema); + export type RoomsEndpoints = { '/v1/rooms.autocomplete.channelAndPrivate': { GET: (params: RoomsAutoCompleteChannelAndPrivateProps) => { @@ -559,18 +615,7 @@ export type RoomsEndpoints = { }; '/v1/rooms.cleanHistory': { - POST: (params: { - roomId: IRoom['_id']; - latest: string; - oldest: string; - inclusive?: boolean; - excludePinned?: boolean; - filesOnly?: boolean; - users?: IUser['username'][]; - limit?: number; - ignoreDiscussion?: boolean; - ignoreThreads?: boolean; - }) => { _id: IRoom['_id']; count: number; success: boolean }; + POST: (params: RoomsCleanHistoryProps) => { _id: IRoom['_id']; count: number; success: boolean }; }; '/v1/rooms.createDiscussion': { diff --git a/yarn.lock b/yarn.lock index d36e9c6d753a..84ca676c886c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8645,6 +8645,7 @@ __metadata: "@rocket.chat/icons": ^0.36.0 "@rocket.chat/message-parser": "workspace:^" "@rocket.chat/ui-kit": "workspace:~" + "@types/express": ^4.17.21 eslint: ~8.45.0 mongodb: ^4.17.2 prettier: ~2.8.8 @@ -13548,6 +13549,18 @@ __metadata: languageName: node linkType: hard +"@types/express@npm:^4.17.21": + version: 4.17.21 + resolution: "@types/express@npm:4.17.21" + dependencies: + "@types/body-parser": "*" + "@types/express-serve-static-core": ^4.17.33 + "@types/qs": "*" + "@types/serve-static": "*" + checksum: fb238298630370a7392c7abdc80f495ae6c716723e114705d7e3fb67e3850b3859bbfd29391463a3fb8c0b32051847935933d99e719c0478710f8098ee7091c5 + languageName: node + linkType: hard + "@types/fibers@npm:^3.1.3": version: 3.1.3 resolution: "@types/fibers@npm:3.1.3" From 3ca62ee7f78914bef393ae97c5ddd3719e794b81 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 21:18:41 +0000 Subject: [PATCH 003/170] fix: Retention policy cron max age settings reactivity (#33049) Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com> --- .../server/cronPruneMessages.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/meteor/app/retention-policy/server/cronPruneMessages.ts b/apps/meteor/app/retention-policy/server/cronPruneMessages.ts index 337691bfbe57..640aa517a679 100644 --- a/apps/meteor/app/retention-policy/server/cronPruneMessages.ts +++ b/apps/meteor/app/retention-policy/server/cronPruneMessages.ts @@ -6,13 +6,20 @@ import { getCronAdvancedTimerFromPrecisionSetting } from '../../../lib/getCronAd import { cleanRoomHistory } from '../../lib/server/functions/cleanRoomHistory'; import { settings } from '../../settings/server'; -const maxTimes = { - c: 0, - p: 0, - d: 0, +type RetentionRoomTypes = 'c' | 'p' | 'd'; + +const getMaxAgeSettingIdByRoomType = (type: RetentionRoomTypes) => { + switch (type) { + case 'c': + return settings.get('RetentionPolicy_TTL_Channels'); + case 'p': + return settings.get('RetentionPolicy_TTL_Groups'); + case 'd': + return settings.get('RetentionPolicy_TTL_DMs'); + } }; -let types: (keyof typeof maxTimes)[] = []; +let types: RetentionRoomTypes[] = []; const oldest = new Date('0001-01-01T00:00:00Z'); @@ -29,7 +36,7 @@ async function job(): Promise { // get all rooms with default values for await (const type of types) { - const maxAge = maxTimes[type] || 0; + const maxAge = getMaxAgeSettingIdByRoomType(type) || 0; const latest = new Date(now.getTime() - maxAge); const rooms = await Rooms.find( @@ -95,9 +102,6 @@ settings.watchMultiple( 'RetentionPolicy_AppliesToChannels', 'RetentionPolicy_AppliesToGroups', 'RetentionPolicy_AppliesToDMs', - 'RetentionPolicy_TTL_Channels', - 'RetentionPolicy_TTL_Groups', - 'RetentionPolicy_TTL_DMs', 'RetentionPolicy_Advanced_Precision', 'RetentionPolicy_Advanced_Precision_Cron', 'RetentionPolicy_Precision', @@ -120,10 +124,6 @@ settings.watchMultiple( types.push('d'); } - maxTimes.c = settings.get('RetentionPolicy_TTL_Channels'); - maxTimes.p = settings.get('RetentionPolicy_TTL_Groups'); - maxTimes.d = settings.get('RetentionPolicy_TTL_DMs'); - const precision = (settings.get('RetentionPolicy_Advanced_Precision') && settings.get('RetentionPolicy_Advanced_Precision_Cron')) || getCronAdvancedTimerFromPrecisionSetting(settings.get('RetentionPolicy_Precision')); From 12e000d8894e83418345f2550e22d2a3c444eb4b Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Fri, 16 Aug 2024 00:45:00 +0000 Subject: [PATCH 004/170] Release 6.11.1 [no ci] --- .changeset/bump-patch-1723645120544.md | 5 --- .changeset/perfect-dancers-grab.md | 5 --- apps/meteor/CHANGELOG.md | 36 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 +++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 +++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 +++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 15 ++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 ++++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 +++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 +++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 +++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/api-client/CHANGELOG.md | 10 ++++++ ee/packages/api-client/package.json | 2 +- ee/packages/ddp-client/CHANGELOG.md | 10 ++++++ ee/packages/ddp-client/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 +++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 ++++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 +++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 ++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/apps/CHANGELOG.md | 10 ++++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 ++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 ++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 ++++++ packages/cron/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 +++++++ packages/fuselage-ui-kit/package.json | 8 ++--- packages/gazzodown/CHANGELOG.md | 11 ++++++ packages/gazzodown/package.json | 6 ++-- packages/instance-status/CHANGELOG.md | 9 +++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 +++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 +++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 +++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 +++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 +++++ packages/ui-avatar/package.json | 4 +-- packages/ui-client/CHANGELOG.md | 9 +++++ packages/ui-client/package.json | 4 +-- packages/ui-contexts/CHANGELOG.md | 11 ++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 ++++++ packages/ui-video-conf/package.json | 6 ++-- packages/uikit-playground/CHANGELOG.md | 11 ++++++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 9 +++++ packages/web-ui-registration/package.json | 4 +-- 68 files changed, 410 insertions(+), 54 deletions(-) delete mode 100644 .changeset/bump-patch-1723645120544.md delete mode 100644 .changeset/perfect-dancers-grab.md diff --git a/.changeset/bump-patch-1723645120544.md b/.changeset/bump-patch-1723645120544.md deleted file mode 100644 index e1eaa7980afb..000000000000 --- a/.changeset/bump-patch-1723645120544.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Bump @rocket.chat/meteor version. diff --git a/.changeset/perfect-dancers-grab.md b/.changeset/perfect-dancers-grab.md deleted file mode 100644 index eacb88108a0f..000000000000 --- a/.changeset/perfect-dancers-grab.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index f466c34da838..aa58cd1ba36a 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,41 @@ # @rocket.chat/meteor +## 6.11.1 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- Bump @rocket.chat/meteor version. + +- ([#33062](https://github.com/RocketChat/Rocket.Chat/pull/33062)) Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/api-client@0.2.4 + - @rocket.chat/license@0.2.4 + - @rocket.chat/omnichannel-services@0.3.1 + - @rocket.chat/pdf-worker@0.2.1 + - @rocket.chat/presence@0.2.4 + - @rocket.chat/apps@0.1.4 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/cron@0.1.4 + - @rocket.chat/fuselage-ui-kit@9.0.1 + - @rocket.chat/gazzodown@9.0.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/ui-contexts@9.0.1 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.1 + - @rocket.chat/ui-theming@0.2.0 + - @rocket.chat/ui-avatar@5.0.1 + - @rocket.chat/ui-client@9.0.1 + - @rocket.chat/ui-video-conf@9.0.1 + - @rocket.chat/web-ui-registration@9.0.1 + - @rocket.chat/instance-status@0.1.4 +
+ ## 6.11.0 ### Minor Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index d5c0801e8d9c..74c84a88cef2 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.11.0" + "version": "6.11.1" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 230250c5ca64..87dd221531e1 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.3.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/models@0.2.1 +
+ ## 1.3.0 ### Minor Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 76a0c59d54e6..59f351444031 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.0", + "version": "1.3.1", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 2cb522daf0d0..044bb765e2db 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.11.0", + "version": "6.11.1", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index fd5eb3925946..c72b16bd401f 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index ac28eb76e76d..895d955510fd 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.3", + "version": "0.4.4", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index df7be3c9b1eb..03f7cb62a50b 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index bff15e7f7d91..7c6783838a84 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.3", + "version": "0.4.4", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 1162e17c05d7..22ddcea338a5 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/ddp-streamer +## 0.3.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/ui-contexts@9.0.1 + - @rocket.chat/models@0.2.1 + - @rocket.chat/instance-status@0.1.4 +
+ ## 0.3.3 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 7bcf45bf354c..e2d4fd6320b0 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.3", + "version": "0.3.4", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index aac67c02dd3d..b9837882510c 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/omnichannel-services@0.3.1 + - @rocket.chat/pdf-worker@0.2.1 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index f23c79d97652..293e5c1be775 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.3", + "version": "0.4.4", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index b9544b0cdde9..614c49928415 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/presence@0.2.4 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index c800dd4d6c80..457eb9225b6c 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.3", + "version": "0.4.4", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 12271005af74..53be288ed34d 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/omnichannel-services@0.3.1 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 0a227cb271c0..72bc5d688e36 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.3", + "version": "0.4.4", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 3fbf664a0b30..284e853f4737 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 812522a5f1d8..d1f2e64acfc0 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.3", + "version": "0.4.4", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/api-client/CHANGELOG.md b/ee/packages/api-client/CHANGELOG.md index 8fe130aeaf28..7430778db198 100644 --- a/ee/packages/api-client/CHANGELOG.md +++ b/ee/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 +
+ ## 0.2.3 ### Patch Changes diff --git a/ee/packages/api-client/package.json b/ee/packages/api-client/package.json index bc809cff907f..d5744d456a46 100644 --- a/ee/packages/api-client/package.json +++ b/ee/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.3", + "version": "0.2.4", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/ddp-client/CHANGELOG.md b/ee/packages/ddp-client/CHANGELOG.md index 0f9b5f7f26b3..c26b0c47f6cb 100644 --- a/ee/packages/ddp-client/CHANGELOG.md +++ b/ee/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ddp-client +## 0.3.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/api-client@0.2.4 +
+ ## 0.3.3 ### Patch Changes diff --git a/ee/packages/ddp-client/package.json b/ee/packages/ddp-client/package.json index 46d67b3ee508..192ea63af72d 100644 --- a/ee/packages/ddp-client/package.json +++ b/ee/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.3", + "version": "0.3.4", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 8cc9df0dd502..9dce96a0310d 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 +
+ ## 0.2.3 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 468a3d1a857c..e5317dc08bcc 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.3", + "version": "0.2.4", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index a4a49de7aa30..d3bbf0b00655 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/pdf-worker@0.2.1 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/model-typings@0.6.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.3.0 ### Minor Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index b66697cd7ed8..f6c66eba4550 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.0", + "version": "0.3.1", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index 5ebe251216a7..a67dc8eafd21 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 +
+ ## 0.2.0 ### Minor Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 7ce07434aca7..d2a0e3029eff 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.0", + "version": "0.2.1", "private": true, "devDependencies": { "@storybook/addon-essentials": "~6.5.16", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index 3d1a7e35b705..93d927c5bc5c 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/core-services@0.5.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.2.3 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index b7c4ea821fe2..a01538b8de6c 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.3", + "version": "0.2.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index 690dc984c631..edc1f5da7e54 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.11.0", + "version": "6.11.1", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 07f4af49f31e..e9efd36ae6bc 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/model-typings@0.6.1 +
+ ## 0.1.3 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 32a25abbbf43..254e1566e120 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.3", + "version": "0.1.4", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index 0c10b78c3bf4..9871852c0245 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.5.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.5.0 ### Minor Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 0c459736456c..072157066bcf 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.5.0", + "version": "0.5.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index fb313a4d1320..42bcd35326fa 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.11.1 + ## 6.11.0 ### Minor Changes diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 3c0c97198b7f..16e17d410ad5 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.11.0", + "version": "6.11.1", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 33c0c9872a60..b2b06e586370 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/models@0.2.1 +
+ ## 0.1.3 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index 868d5b5fb504..ede7f521da8c 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.3", + "version": "0.1.4", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index e8fe73f6d549..0b1435f47f1b 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 9.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/gazzodown@9.0.1 + - @rocket.chat/ui-contexts@9.0.1 + - @rocket.chat/ui-avatar@5.0.1 + - @rocket.chat/ui-video-conf@9.0.1 +
+ ## 9.0.0 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 4a1d7e4b7839..32d18d782968 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "9.0.0", + "version": "9.0.1", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.0", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-avatar": "5.0.1", + "@rocket.chat/ui-contexts": "9.0.1", "@rocket.chat/ui-kit": "0.36.0", - "@rocket.chat/ui-video-conf": "9.0.0", + "@rocket.chat/ui-video-conf": "9.0.1", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 4febdb0f54b2..48b701cbeb54 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 9.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/ui-contexts@9.0.1 + - @rocket.chat/ui-client@9.0.1 +
+ ## 9.0.0 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 054a6ccaef66..7341d79bba85 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "9.0.0", + "version": "9.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -71,8 +71,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "9.0.0", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-client": "9.0.1", + "@rocket.chat/ui-contexts": "9.0.1", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index 849ccf591d08..d314c504721c 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.2.1 +
+ ## 0.1.3 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 088cba613d8e..2037a3cf5f61 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.3", + "version": "0.1.4", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index 56265d43563f..87cdaae78911 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.19.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@9.0.1 +
+ ## 1.19.0 ### Minor Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 9d40643dd4c5..6974bd1a2acd 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.0", + "version": "1.19.1", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 29eaadd0e0fe..6b27e4ad4ab1 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.6.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 +
+ ## 0.6.0 ### Minor Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index c06e25f68d73..edc79f10e2df 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.6.0", + "version": "0.6.1", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index e2b984708aaa..772805da3b8f 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.2.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.6.1 +
+ ## 0.2.0 ### Minor Changes diff --git a/packages/models/package.json b/packages/models/package.json index 174464796076..c09d8cea307f 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.0", + "version": "0.2.1", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index efcab160b8e6..9f0e3a01cd21 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.11.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 +
+ ## 6.11.0 ### Minor Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 77a78a6e938a..a7a8275dd276 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.11.0", + "version": "6.11.1", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "@types/jest": "~29.5.7", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index f65d986cfaf5..927a3463e069 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 5.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.1 +
+ ## 5.0.0 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 3f429ca08278..92d1382de36e 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "5.0.0", + "version": "5.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-contexts": "9.0.1", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 5936f8038bc8..8dee0ec12c50 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 9.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.1 +
+ ## 9.0.0 ### Minor Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index d5b6c74cf982..43743f37339f 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "9.0.0", + "version": "9.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -63,7 +63,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-contexts": "9.0.1", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index fb3d074b6fbe..4e21589c1388 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 9.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.1 + - @rocket.chat/rest-typings@6.11.1 + - @rocket.chat/ddp-client@0.3.4 +
+ ## 9.0.0 ### Minor Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 4971be05fdcc..85d6df1b93e6 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "9.0.0", + "version": "9.0.1", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 2a697e293211..feb33d9679e0 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 9.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.1 + - @rocket.chat/ui-avatar@5.0.1 +
+ ## 9.0.0 ### Minor Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index a60e9a9b2d1f..861da958667c 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "9.0.0", + "version": "9.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -36,8 +36,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.0", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-avatar": "5.0.1", + "@rocket.chat/ui-contexts": "9.0.1", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index 0107fc049b8f..7515e3005bc6 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.3.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@9.0.1 + - @rocket.chat/ui-contexts@9.0.1 + - @rocket.chat/ui-avatar@5.0.1 +
+ ## 0.3.3 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 0d1d1ab9e246..2923804daa48 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.3.3", + "version": "0.3.4", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 871e66b0f29c..ab10df1e8c58 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 9.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.1 +
+ ## 9.0.0 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 635633c808e2..3e0a0483eb86 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "9.0.0", + "version": "9.0.1", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -51,7 +51,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-contexts": "9.0.1", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From 72f00a6e9128df85af611794b348f66ee767787f Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Mon, 19 Aug 2024 14:21:17 +0000 Subject: [PATCH 005/170] Bump 6.11.2 --- .changeset/bump-patch-1724077277110.md | 5 +++++ yarn.lock | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 .changeset/bump-patch-1724077277110.md diff --git a/.changeset/bump-patch-1724077277110.md b/.changeset/bump-patch-1724077277110.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1724077277110.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/yarn.lock b/yarn.lock index 84ca676c886c..93f2f41c7999 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8969,10 +8969,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0 - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-avatar": 5.0.1 + "@rocket.chat/ui-contexts": 9.0.1 "@rocket.chat/ui-kit": 0.36.0 - "@rocket.chat/ui-video-conf": 9.0.0 + "@rocket.chat/ui-video-conf": 9.0.1 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9061,8 +9061,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 9.0.0 - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-client": 9.0.1 + "@rocket.chat/ui-contexts": 9.0.1 katex: "*" react: "*" languageName: unknown @@ -10282,7 +10282,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-contexts": 9.0.1 react: ~17.0.2 languageName: unknown linkType: soft @@ -10335,7 +10335,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-contexts": 9.0.1 react: ~17.0.2 languageName: unknown linkType: soft @@ -10511,8 +10511,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0 - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-avatar": 5.0.1 + "@rocket.chat/ui-contexts": 9.0.1 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10602,7 +10602,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-contexts": 9.0.1 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 6bcbc02ed3121c8f2c7e3fe4cccc42416abc8d87 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:07:25 +0000 Subject: [PATCH 006/170] fix: Realtime Monitoring LineCharts not updating (#33086) Co-authored-by: Martin Schoeler <20868078+MartinSchoeler@users.noreply.github.com> --- .../RealTimeMonitoringPage.js | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.js index 5b4d837d211c..b6e29530b5e7 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.js @@ -18,11 +18,19 @@ import ChatsOverview from './overviews/ChatsOverview'; import ConversationOverview from './overviews/ConversationOverview'; import ProductivityOverview from './overviews/ProductivityOverview'; +const randomizeKeys = (keys) => { + keys.current = keys.current.map((_key, i) => { + return `${i}_${new Date().getTime()}`; + }); +}; + const dateRange = getDateRange(); const RealTimeMonitoringPage = () => { const t = useTranslation(); + const keys = useRef([...Array(10).keys()]); + const [reloadFrequency, setReloadFrequency] = useState(5); const [departmentId, setDepartment] = useState(''); @@ -43,6 +51,10 @@ const RealTimeMonitoringPage = () => { [departmentParams], ); + useEffect(() => { + randomizeKeys(keys); + }, [allParams]); + const reloadCharts = useMutableCallback(() => { Object.values(reloadRef.current).forEach((reload) => { reload(); @@ -53,6 +65,7 @@ const RealTimeMonitoringPage = () => { const interval = setInterval(reloadCharts, reloadFrequency * 1000); return () => { clearInterval(interval); + randomizeKeys(keys); }; }, [reloadCharts, reloadFrequency]); @@ -90,30 +103,54 @@ const RealTimeMonitoringPage = () => { - + - - + + - + - - + + - + - + - + - + From 9e1b9ad624e470bd60e83a9bc90c2c70504ac48a Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 18:45:46 +0000 Subject: [PATCH 007/170] fix: Avoid `processRoomAbandonment` callback from erroring when Business Hours config is missing for day (#33084) Co-authored-by: Kevin Aleman <11577696+KevLehman@users.noreply.github.com> --- .changeset/gentle-bugs-think.md | 5 +++++ .../app/livechat/server/hooks/processRoomAbandonment.ts | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .changeset/gentle-bugs-think.md diff --git a/.changeset/gentle-bugs-think.md b/.changeset/gentle-bugs-think.md new file mode 100644 index 000000000000..fc4738f3043a --- /dev/null +++ b/.changeset/gentle-bugs-think.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Prevent `processRoomAbandonment` callback from erroring out when a room was inactive during a day Business Hours was not configured for. diff --git a/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.ts b/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.ts index 8a5a4c280670..8eb53fbb8fa7 100644 --- a/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.ts +++ b/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.ts @@ -43,7 +43,8 @@ const getSecondsSinceLastAgentResponse = async (room: IOmnichannelRoom, agentLas officeDays = (await businessHourManager.getBusinessHour())?.workHours.reduce(parseDays, {}); } - if (!officeDays) { + // Empty object we assume invalid config + if (!officeDays || !Object.keys(officeDays).length) { return getSecondsWhenOfficeHoursIsDisabled(room, agentLastMessage); } @@ -55,6 +56,11 @@ const getSecondsSinceLastAgentResponse = async (room: IOmnichannelRoom, agentLas for (let index = 0; index <= daysOfInactivity; index++) { const today = inactivityDay.clone().format('dddd'); const officeDay = officeDays[today]; + // Config doesnt have data for this day, we skip day + if (!officeDay) { + inactivityDay.add(1, 'days'); + continue; + } const startTodaysOfficeHour = moment(`${officeDay.start.day}:${officeDay.start.time}`, 'dddd:HH:mm').add(index, 'days'); const endTodaysOfficeHour = moment(`${officeDay.finish.day}:${officeDay.finish.time}`, 'dddd:HH:mm').add(index, 'days'); if (officeDays[today].open) { From 9f6883ead4748a847ed263752479943d2df7fee8 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Fri, 23 Aug 2024 03:49:05 +0000 Subject: [PATCH 008/170] Release 6.12.0-rc.0 --- .changeset/pre.json | 102 ++++++++++++++++ apps/meteor/CHANGELOG.md | 111 ++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 14 +++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 ++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 ++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 14 +++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 +++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 ++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 ++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 ++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 ++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 +++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 ++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 ++ ee/packages/presence/package.json | 2 +- ee/packages/ui-theming/CHANGELOG.md | 6 + ee/packages/ui-theming/package.json | 2 +- package.json | 2 +- packages/api-client/CHANGELOG.md | 10 ++ packages/api-client/package.json | 2 +- packages/apps/CHANGELOG.md | 10 ++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 16 +++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 27 +++++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 ++ packages/cron/package.json | 2 +- packages/ddp-client/CHANGELOG.md | 11 ++ packages/ddp-client/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 16 +++ packages/fuselage-ui-kit/package.json | 10 +- packages/gazzodown/CHANGELOG.md | 13 ++ packages/gazzodown/package.json | 6 +- packages/i18n/CHANGELOG.md | 28 +++++ packages/i18n/package.json | 2 +- packages/instance-status/CHANGELOG.md | 9 ++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 12 ++ packages/livechat/package.json | 2 +- packages/mock-providers/CHANGELOG.md | 9 ++ packages/mock-providers/package.json | 2 +- packages/model-typings/CHANGELOG.md | 17 +++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 ++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 16 +++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 11 ++ packages/ui-avatar/package.json | 4 +- packages/ui-client/CHANGELOG.md | 11 ++ packages/ui-client/package.json | 4 +- packages/ui-composer/CHANGELOG.md | 6 + packages/ui-composer/package.json | 2 +- packages/ui-contexts/CHANGELOG.md | 12 ++ packages/ui-contexts/package.json | 2 +- packages/ui-kit/CHANGELOG.md | 6 + packages/ui-kit/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 12 ++ packages/ui-video-conf/package.json | 6 +- packages/uikit-playground/CHANGELOG.md | 17 +++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 11 ++ packages/web-ui-registration/package.json | 4 +- 77 files changed, 717 insertions(+), 50 deletions(-) create mode 100644 .changeset/pre.json diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000000..fabea75cbf61 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,102 @@ +{ + "mode": "pre", + "tag": "rc", + "initialVersions": { + "@rocket.chat/meteor": "6.12.0-develop", + "rocketchat-services": "1.3.0", + "@rocket.chat/account-service": "0.4.3", + "@rocket.chat/authorization-service": "0.4.3", + "@rocket.chat/ddp-streamer": "0.3.3", + "@rocket.chat/omnichannel-transcript": "0.4.3", + "@rocket.chat/presence-service": "0.4.3", + "@rocket.chat/queue-worker": "0.4.3", + "@rocket.chat/stream-hub-service": "0.4.3", + "@rocket.chat/license": "0.2.3", + "@rocket.chat/omnichannel-services": "0.3.0", + "@rocket.chat/pdf-worker": "0.2.0", + "@rocket.chat/presence": "0.2.3", + "@rocket.chat/ui-theming": "0.2.0", + "@rocket.chat/account-utils": "0.0.2", + "@rocket.chat/agenda": "0.1.0", + "@rocket.chat/api-client": "0.2.3", + "@rocket.chat/apps": "0.1.3", + "@rocket.chat/base64": "1.0.13", + "@rocket.chat/cas-validate": "0.0.2", + "@rocket.chat/core-services": "0.5.0", + "@rocket.chat/core-typings": "6.12.0-develop", + "@rocket.chat/cron": "0.1.3", + "@rocket.chat/ddp-client": "0.3.3", + "@rocket.chat/eslint-config": "0.7.0", + "@rocket.chat/favicon": "0.0.2", + "@rocket.chat/fuselage-ui-kit": "9.0.0", + "@rocket.chat/gazzodown": "9.0.0", + "@rocket.chat/i18n": "0.6.0", + "@rocket.chat/instance-status": "0.1.3", + "@rocket.chat/jest-presets": "0.0.1", + "@rocket.chat/jwt": "0.1.1", + "@rocket.chat/livechat": "1.19.0", + "@rocket.chat/log-format": "0.0.2", + "@rocket.chat/logger": "0.0.2", + "@rocket.chat/message-parser": "0.31.29", + "@rocket.chat/mock-providers": "0.1.1", + "@rocket.chat/model-typings": "0.6.0", + "@rocket.chat/models": "0.2.0", + "@rocket.chat/poplib": "0.0.2", + "@rocket.chat/password-policies": "0.0.2", + "@rocket.chat/patch-injection": "0.0.1", + "@rocket.chat/peggy-loader": "0.31.25", + "@rocket.chat/random": "1.2.2", + "@rocket.chat/release-action": "2.2.3", + "@rocket.chat/release-changelog": "0.1.0", + "@rocket.chat/rest-typings": "6.12.0-develop", + "@rocket.chat/server-cloud-communication": "0.0.2", + "@rocket.chat/server-fetch": "0.0.3", + "@rocket.chat/sha256": "1.0.10", + "@rocket.chat/tools": "0.2.2", + "@rocket.chat/ui-avatar": "5.0.0", + "@rocket.chat/ui-client": "9.0.0", + "@rocket.chat/ui-composer": "0.2.0", + "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-kit": "0.36.0", + "@rocket.chat/ui-video-conf": "9.0.0", + "@rocket.chat/uikit-playground": "0.3.3", + "@rocket.chat/web-ui-registration": "9.0.0" + }, + "changesets": [ + "bright-humans-cross", + "brown-crabs-chew", + "calm-tigers-peel", + "cool-rocks-remember", + "empty-toys-smell", + "fast-lobsters-turn", + "funny-boats-guess", + "gentle-bugs-think", + "gentle-news-wonder", + "giant-spiders-pay", + "gorgeous-hotels-attend", + "large-geese-ring", + "lemon-steaks-provide", + "nasty-windows-smile", + "new-mayflies-wait", + "ninety-hounds-exist", + "popular-bottles-visit", + "proud-years-buy", + "purple-dolls-serve", + "rich-pillows-hang", + "rooms-table-ts", + "rotten-camels-pretend", + "rude-dogs-burn", + "six-beers-fry", + "smart-mice-attack", + "spicy-kings-think", + "strong-swans-double", + "strong-terms-love", + "stupid-fishes-relate", + "swift-maps-tickle", + "ten-bulldogs-clap", + "thirty-dryers-help", + "twelve-windows-train", + "two-bikes-crash", + "violet-radios-begin" + ] +} diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index f466c34da838..afc6a6751992 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,116 @@ # @rocket.chat/meteor +## 6.12.0-rc.0 + +### Minor Changes + +- ([#32535](https://github.com/RocketChat/Rocket.Chat/pull/32535)) Federation actions like sending message in a federated DM, reacting in a federated chat, etc, will no longer work if the configuration is invalid. + +- ([#32916](https://github.com/RocketChat/Rocket.Chat/pull/32916)) Added a new Audit endpoint `audit/rooms.members` that allows users with `view-members-list-all-rooms` to fetch a list of the members of any room even if the user is not part of it. + +- ([#32032](https://github.com/RocketChat/Rocket.Chat/pull/32032)) Added a new 'Deactivated' tab to the users page, this tab lists users who have logged in for the first time but have been deactivated for any reason. Also added the UI code for the Active tab; + +- ([#33044](https://github.com/RocketChat/Rocket.Chat/pull/33044)) Replaces an outdated banner with the Bubble component in order to display retention policy warning + +- ([#32867](https://github.com/RocketChat/Rocket.Chat/pull/32867)) Added an accordion for advanced settings on Create teams and channels + +- ([#32709](https://github.com/RocketChat/Rocket.Chat/pull/32709) by [@heet434](https://github.com/heet434)) Add "Created at" column to admin rooms table + +- ([#32535](https://github.com/RocketChat/Rocket.Chat/pull/32535)) New button added to validate Matrix Federation configuration. A new field inside admin settings will reflect the configuration status being either 'Valid' or 'Invalid'. + +- ([#32969](https://github.com/RocketChat/Rocket.Chat/pull/32969)) Upgrades fuselage-toastbar version in order to add pause on hover functionality + +- ([#33003](https://github.com/RocketChat/Rocket.Chat/pull/33003)) Added a new setting to enable/disable file encryption in an end to end encrypted room. + +- ([#32868](https://github.com/RocketChat/Rocket.Chat/pull/32868)) Added `sidepanel` field to `teams.create` and `rooms.saveRoomSettings` endpoints + +- ([#33003](https://github.com/RocketChat/Rocket.Chat/pull/33003)) Fixed a bug related to uploading end to end encrypted file. + + E2EE files and uploads are uploaded as files of mime type `application/octet-stream` as we can't reveal the mime type of actual content since it is encrypted and has to be kept confidential. + + The server resolves the mime type of encrypted file as `application/octet-stream` but it wasn't playing nicely with existing settings related to whitelisted and blacklisted media types. + + E2EE files upload was getting blocked if `application/octet-stream` is not a whitelisted media type. + + Now this PR solves this issue by always accepting E2EE uploads even if `application/octet-stream` is not whitelisted but it will block the upload if `application/octet-stream` is black listed. + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + +- ([#32986](https://github.com/RocketChat/Rocket.Chat/pull/32986)) Fixed login with third-party apps not working without the "Manage OAuth Apps" permission + +- ([#32852](https://github.com/RocketChat/Rocket.Chat/pull/32852)) Federated users can no longer be deleted. + +- ([#33033](https://github.com/RocketChat/Rocket.Chat/pull/33033)) Fixed an issue due to an endpoint pagination that was causing that when an agent have assigned more than 50 departments, the departments have a blank space instead of the name. + +- ([#33058](https://github.com/RocketChat/Rocket.Chat/pull/33058)) Prevent `processRoomAbandonment` callback from erroring out when a room was inactive during a day Business Hours was not configured for. + +- ([#24889](https://github.com/RocketChat/Rocket.Chat/pull/24889) by [@Shivansh2287](https://github.com/Shivansh2287)) Fixes an issue where the Announcement modal with long words was adding a horizontal scrollbar + +- ([#32940](https://github.com/RocketChat/Rocket.Chat/pull/32940)) Stopped non channel members from dragging and dropping files in a channel they do not belong + +- ([#33001](https://github.com/RocketChat/Rocket.Chat/pull/33001)) Allow apps to react/unreact to messages via bridge + +- ([#32809](https://github.com/RocketChat/Rocket.Chat/pull/32809)) Deactivating users who federated will now be permanent. + +- ([#31525](https://github.com/RocketChat/Rocket.Chat/pull/31525)) Fix: Show correct user info actions for non-members in channels. + +- ([#32931](https://github.com/RocketChat/Rocket.Chat/pull/32931)) Fixed an issue that caused UI to show an error when the call to get the Business Hour type from settings returned `undefined`. + +- ([#32743](https://github.com/RocketChat/Rocket.Chat/pull/32743)) Fixes an issue where creating a new user with an invalid username (containing special characters) resulted in an error message, but the user was still created. The user creation process now properly aborts when an invalid username is provided. + +- ([#33109](https://github.com/RocketChat/Rocket.Chat/pull/33109)) Fixes the `expanded` prop being accidentally forwarded to `ContextualbarHeader` + +- ([#32846](https://github.com/RocketChat/Rocket.Chat/pull/32846)) Fixed issue with system messages being counted as agents' first responses in livechat rooms (which caused the "best first response time" and "average first response time" metrics to be unreliable for all agents) + +- ([#32791](https://github.com/RocketChat/Rocket.Chat/pull/32791)) Fixed a behavior when updating messages that prevented the `customFields` prop from being updated if there were no changes to the `msg` property. Now, `customFields` will be always updated on message update even if `msg` doesn't change + +- ([#33101](https://github.com/RocketChat/Rocket.Chat/pull/33101)) Fixed an issue where teams were being created with no room associated with it. + +- ([#33036](https://github.com/RocketChat/Rocket.Chat/pull/33036)) Fixes multiple problems with the `processRoomAbandonment` hook. This hook is in charge of calculating the time a room has been abandoned (this means, the time that elapsed since a room was last answered by an agent until it was closed). However, when business hours were enabled and the user didn't open on one day, if an abandoned room happened to be abandoned _over_ the day there was no business hour configuration, then the process will error out. + Additionally, the values the code was calculating were not right. When business hours are enabled, this code should only count the abandonment time _while a business hour was open_. When rooms were left abandoned for days or weeks, this will also throw an error or output an invalid count. +- ([#33054](https://github.com/RocketChat/Rocket.Chat/pull/33054)) Fixed issue with livechat analytics in a given date range considering conversation data from the following day + +- ([#32981](https://github.com/RocketChat/Rocket.Chat/pull/32981)) fixed an issue with the "follow message" button not changing state after click + +- ([#32928](https://github.com/RocketChat/Rocket.Chat/pull/32928)) Fixed issue where `after-registration-triggers` would show up in a page when the user was not yet registered + +- ([#33047](https://github.com/RocketChat/Rocket.Chat/pull/33047)) Fixed: Custom fields in extraData now correctly added to extraRoomInfo by livechat.beforeRoom callback during livechat room creation. + +- ([#33040](https://github.com/RocketChat/Rocket.Chat/pull/33040)) Fixed an issue related to setting Accounts_ForgetUserSessionOnWindowClose, this setting was not working as expected. + + The new meteor 2.16 release introduced a new option to configure the Accounts package and choose between the local storage or session storage. They also changed how Meteor.\_localstorage works internally. Due to these changes in Meteor, our setting to use session storage wasn't working as expected. This PR fixes this issue and configures the Accounts package according to the workspace settings. + +-
Updated dependencies [8ea6517c4e, c11f3722df, 7f88158036, 127866ce97, 0c919db7b4, b764c415dc, 1f061a1aa5, dd37ea1b35, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.0 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-video-conf@10.0.0-rc.0 + - @rocket.chat/ui-composer@0.2.1-rc.0 + - @rocket.chat/gazzodown@10.0.0-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.0 + - @rocket.chat/ui-client@10.0.0-rc.0 + - @rocket.chat/ui-kit@0.36.1-rc.0 + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/i18n@0.7.0-rc.0 + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/web-ui-registration@10.0.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/omnichannel-services@0.3.1-rc.0 + - @rocket.chat/apps@0.1.4-rc.0 + - @rocket.chat/models@0.2.1-rc.0 + - @rocket.chat/ui-contexts@10.0.0-rc.0 + - @rocket.chat/presence@0.2.4-rc.0 + - @rocket.chat/api-client@0.2.4-rc.0 + - @rocket.chat/license@0.2.4-rc.0 + - @rocket.chat/pdf-worker@0.2.1-rc.0 + - @rocket.chat/cron@0.1.4-rc.0 + - @rocket.chat/instance-status@0.1.4-rc.0 + - @rocket.chat/server-cloud-communication@0.0.2 +
+ ## 6.11.0 ### Minor Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index faf0e8f47de6..529a0ee307e9 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.12.0-develop" + "version": "6.12.0-rc.0" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 230250c5ca64..352967c136b1 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,19 @@ # rocketchat-services +## 1.3.1-rc.0 + +### Patch Changes + +-
Updated dependencies [c11f3722df, 7f88158036, b764c415dc, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/ui-kit@0.36.1-rc.0 + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 +
+ ## 1.3.0 ### Minor Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 58b73351c4e0..32d99abf64c0 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.0", + "version": "1.3.1-rc.0", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 9c49c2cb33f8..23429fed2242 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.12.0-develop", + "version": "6.12.0-rc.0", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index fd5eb3925946..b3f4dd1e7126 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, b764c415dc, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index ac28eb76e76d..36ecb61a9e28 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.3", + "version": "0.4.4-rc.0", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index df7be3c9b1eb..0400f8c98ce9 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, b764c415dc, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index bff15e7f7d91..49299353f38a 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.3", + "version": "0.4.4-rc.0", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 1162e17c05d7..2e893ab08be4 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/ddp-streamer +## 0.3.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, b764c415dc, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 + - @rocket.chat/instance-status@0.1.4-rc.0 +
+ ## 0.3.3 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 1687042e0d31..10cf4b709a7d 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.3", + "version": "0.3.4-rc.0", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index aac67c02dd3d..01b7d95f435b 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/omnichannel-services@0.3.1-rc.0 + - @rocket.chat/models@0.2.1-rc.0 + - @rocket.chat/pdf-worker@0.2.1-rc.0 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index c60542c180ec..ded176a6d413 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.3", + "version": "0.4.4-rc.0", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index b9544b0cdde9..d8d28a169255 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 + - @rocket.chat/presence@0.2.4-rc.0 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index c800dd4d6c80..b7efe31c51d4 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.3", + "version": "0.4.4-rc.0", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 12271005af74..6103b2805fd9 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/omnichannel-services@0.3.1-rc.0 + - @rocket.chat/models@0.2.1-rc.0 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 0a227cb271c0..246d82843599 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.3", + "version": "0.4.4-rc.0", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 3fbf664a0b30..c930928c8e94 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 +
+ ## 0.4.3 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 812522a5f1d8..d2fda6422851 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.3", + "version": "0.4.4-rc.0", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 8cc9df0dd502..5c212f8e6c77 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/core-typings@6.12.0-rc.0 +
+ ## 0.2.3 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 1c746514d443..50d6e575dd4b 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.3", + "version": "0.2.4-rc.0", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index a4a49de7aa30..78d02fb9aa38 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.1-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, b764c415dc, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 + - @rocket.chat/pdf-worker@0.2.1-rc.0 +
+ ## 0.3.0 ### Minor Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index f520d82bd7d3..36ce0e1efb06 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.0", + "version": "0.3.1-rc.0", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index 5ebe251216a7..51df0b0eed01 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.1-rc.0 + +### Patch Changes + +-
Updated dependencies [7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/core-typings@6.12.0-rc.0 +
+ ## 0.2.0 ### Minor Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 749d48ccc9c2..93b521ff65c2 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.0", + "version": "0.2.1-rc.0", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index 3d1a7e35b705..5e569c03b1e6 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/core-services@0.6.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 +
+ ## 0.2.3 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 787eb2053007..9bf86c60c504 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.3", + "version": "0.2.4-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/ee/packages/ui-theming/CHANGELOG.md b/ee/packages/ui-theming/CHANGELOG.md index 2d01b23733b1..7b9d7c385f6c 100644 --- a/ee/packages/ui-theming/CHANGELOG.md +++ b/ee/packages/ui-theming/CHANGELOG.md @@ -1,5 +1,11 @@ # @rocket.chat/ui-theming +## 0.2.1-rc.0 + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + ## 0.2.0 ### Minor Changes diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json index 713265b36bfa..519937865872 100644 --- a/ee/packages/ui-theming/package.json +++ b/ee/packages/ui-theming/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-theming", - "version": "0.2.0", + "version": "0.2.1-rc.0", "private": true, "devDependencies": { "@rocket.chat/css-in-js": "~0.31.25", diff --git a/package.json b/package.json index 29de436373e2..0c0a96a189de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.12.0-develop", + "version": "6.12.0-rc.0", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md index 8fe130aeaf28..2ed77faee070 100644 --- a/packages/api-client/CHANGELOG.md +++ b/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.4-rc.0 + +### Patch Changes + +-
Updated dependencies [b764c415dc, 7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 +
+ ## 0.2.3 ### Patch Changes diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 43de20583d47..520ce86c9127 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.3", + "version": "0.2.4-rc.0", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 07f4af49f31e..5c318e5a4512 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, 7937ff741a, a14c0678bb, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/model-typings@0.7.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 +
+ ## 0.1.3 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 816e271535df..b4ec74defa0d 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.3", + "version": "0.1.4-rc.0", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index 0c10b78c3bf4..48c182f44c68 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,21 @@ # @rocket.chat/core-services +## 0.6.0-rc.0 + +### Minor Changes + +- ([#32868](https://github.com/RocketChat/Rocket.Chat/pull/32868)) Added `sidepanel` field to `teams.create` and `rooms.saveRoomSettings` endpoints + +### Patch Changes + +-
Updated dependencies [c11f3722df, b764c415dc, 7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/ui-kit@0.36.1-rc.0 + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 +
+ ## 0.5.0 ### Minor Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index fe1d4ef0dcea..729f8cac2767 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.5.0", + "version": "0.6.0-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index fb313a4d1320..885f05f60031 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,32 @@ # @rocket.chat/core-typings +## 6.12.0-rc.0 + +### Minor Changes + +- ([#33003](https://github.com/RocketChat/Rocket.Chat/pull/33003)) Added a new setting to enable/disable file encryption in an end to end encrypted room. + +- ([#32868](https://github.com/RocketChat/Rocket.Chat/pull/32868)) Added `sidepanel` field to `teams.create` and `rooms.saveRoomSettings` endpoints + +- ([#33003](https://github.com/RocketChat/Rocket.Chat/pull/33003)) Fixed a bug related to uploading end to end encrypted file. + + E2EE files and uploads are uploaded as files of mime type `application/octet-stream` as we can't reveal the mime type of actual content since it is encrypted and has to be kept confidential. + + The server resolves the mime type of encrypted file as `application/octet-stream` but it wasn't playing nicely with existing settings related to whitelisted and blacklisted media types. + + E2EE files upload was getting blocked if `application/octet-stream` is not a whitelisted media type. + + Now this PR solves this issue by always accepting E2EE uploads even if `application/octet-stream` is not whitelisted but it will block the upload if `application/octet-stream` is black listed. + +### Patch Changes + +- ([#32846](https://github.com/RocketChat/Rocket.Chat/pull/32846)) Fixed issue with system messages being counted as agents' first responses in livechat rooms (which caused the "best first response time" and "average first response time" metrics to be unreliable for all agents) + +-
Updated dependencies [c11f3722df]: + + - @rocket.chat/ui-kit@0.36.1-rc.0 +
+ ## 6.11.0 ### Minor Changes diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 34bdc67438ca..7dccf47493eb 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.12.0-develop", + "version": "6.12.0-rc.0", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 33c0c9872a60..6f05eddf1bc1 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.4-rc.0 + +### Patch Changes + +-
Updated dependencies [7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/models@0.2.1-rc.0 +
+ ## 0.1.3 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index a6484224ded5..b2c70c89aaa4 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.3", + "version": "0.1.4-rc.0", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/ddp-client/CHANGELOG.md b/packages/ddp-client/CHANGELOG.md index 0f9b5f7f26b3..ef67f9df32d7 100644 --- a/packages/ddp-client/CHANGELOG.md +++ b/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ddp-client +## 0.3.4-rc.0 + +### Patch Changes + +-
Updated dependencies [b764c415dc, 7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/api-client@0.2.4-rc.0 +
+ ## 0.3.3 ### Patch Changes diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index 9e4fdfd85910..bc5ee0e8ce7e 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.3", + "version": "0.3.4-rc.0", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index e8fe73f6d549..0ef3df446d2c 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,21 @@ # Change Log +## 10.0.0-rc.0 + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + +-
Updated dependencies [8ea6517c4e, c11f3722df, 7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/ui-video-conf@10.0.0-rc.0 + - @rocket.chat/gazzodown@10.0.0-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.0 + - @rocket.chat/ui-kit@0.36.1-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/ui-contexts@10.0.0-rc.0 +
+ ## 9.0.0 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 9431a0c19d96..1d911f5437cb 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "9.0.0", + "version": "10.0.0-rc.0", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.0", - "@rocket.chat/ui-contexts": "9.0.0", - "@rocket.chat/ui-kit": "0.36.0", - "@rocket.chat/ui-video-conf": "9.0.0", + "@rocket.chat/ui-avatar": "6.0.0-rc.0", + "@rocket.chat/ui-contexts": "10.0.0-rc.0", + "@rocket.chat/ui-kit": "0.36.1-rc.0", + "@rocket.chat/ui-video-conf": "10.0.0-rc.0", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 4febdb0f54b2..f4e7cc8e0492 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/gazzodown +## 10.0.0-rc.0 + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + +-
Updated dependencies [8ea6517c4e, 7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/ui-client@10.0.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/ui-contexts@10.0.0-rc.0 +
+ ## 9.0.0 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 6ecb49fa9544..8f0a87b4a3ee 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "9.0.0", + "version": "10.0.0-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -66,8 +66,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "9.0.0", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-client": "10.0.0-rc.0", + "@rocket.chat/ui-contexts": "10.0.0-rc.0", "katex": "*", "react": "*" }, diff --git a/packages/i18n/CHANGELOG.md b/packages/i18n/CHANGELOG.md index 8c46d5736706..31ca8e91df6d 100644 --- a/packages/i18n/CHANGELOG.md +++ b/packages/i18n/CHANGELOG.md @@ -1,5 +1,33 @@ # @rocket.chat/i18n +## 0.7.0-rc.0 + +### Minor Changes + +- ([#32916](https://github.com/RocketChat/Rocket.Chat/pull/32916)) Added a new Audit endpoint `audit/rooms.members` that allows users with `view-members-list-all-rooms` to fetch a list of the members of any room even if the user is not part of it. + +- ([#32867](https://github.com/RocketChat/Rocket.Chat/pull/32867)) Added an accordion for advanced settings on Create teams and channels + +- ([#33003](https://github.com/RocketChat/Rocket.Chat/pull/33003)) Added a new setting to enable/disable file encryption in an end to end encrypted room. + +- ([#33003](https://github.com/RocketChat/Rocket.Chat/pull/33003)) Fixed a bug related to uploading end to end encrypted file. + + E2EE files and uploads are uploaded as files of mime type `application/octet-stream` as we can't reveal the mime type of actual content since it is encrypted and has to be kept confidential. + + The server resolves the mime type of encrypted file as `application/octet-stream` but it wasn't playing nicely with existing settings related to whitelisted and blacklisted media types. + + E2EE files upload was getting blocked if `application/octet-stream` is not a whitelisted media type. + + Now this PR solves this issue by always accepting E2EE uploads even if `application/octet-stream` is not whitelisted but it will block the upload if `application/octet-stream` is black listed. + +### Patch Changes + +- ([#31525](https://github.com/RocketChat/Rocket.Chat/pull/31525)) Fix: Show correct user info actions for non-members in channels. + +- ([#33029](https://github.com/RocketChat/Rocket.Chat/pull/33029)) Fixes a typo in german translation and fixes the broken hyperlink for Resend and Change Email + +- ([#32743](https://github.com/RocketChat/Rocket.Chat/pull/32743)) Fixes an issue where creating a new user with an invalid username (containing special characters) resulted in an error message, but the user was still created. The user creation process now properly aborts when an invalid username is provided. + ## 0.6.0 ### Minor Changes diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 6927aae08d1c..8bae9a225113 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/i18n", - "version": "0.6.0", + "version": "0.7.0-rc.0", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index 849ccf591d08..8e77d18f93a3 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.4-rc.0 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.2.1-rc.0 +
+ ## 0.1.3 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 088cba613d8e..09068b9bf095 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.3", + "version": "0.1.4-rc.0", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index 56265d43563f..b504a91bef55 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/livechat Change Log +## 1.19.1-rc.0 + +### Patch Changes + +- ([#32928](https://github.com/RocketChat/Rocket.Chat/pull/32928)) Fixed issue where `after-registration-triggers` would show up in a page when the user was not yet registered + +-
Updated dependencies [8ea6517c4e, c11f3722df]: + + - @rocket.chat/gazzodown@10.0.0-rc.0 + - @rocket.chat/ui-kit@0.36.1-rc.0 +
+ ## 1.19.0 ### Minor Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 9d40643dd4c5..c88eeeac89b2 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.0", + "version": "1.19.1-rc.0", "files": [ "/build" ], diff --git a/packages/mock-providers/CHANGELOG.md b/packages/mock-providers/CHANGELOG.md index 300b624d5dff..55af119d59fe 100644 --- a/packages/mock-providers/CHANGELOG.md +++ b/packages/mock-providers/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/mock-providers +## 0.1.2-rc.0 + +### Patch Changes + +-
Updated dependencies [127866ce97, 0c919db7b4, b764c415dc, 1f061a1aa5, dd37ea1b35, 58c0efc732, 58c0efc732]: + + - @rocket.chat/i18n@0.7.0-rc.0 +
+ ## 0.1.1 ### Patch Changes diff --git a/packages/mock-providers/package.json b/packages/mock-providers/package.json index 64310f0695cc..d2b2589b8f89 100644 --- a/packages/mock-providers/package.json +++ b/packages/mock-providers/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/mock-providers", - "version": "0.1.1", + "version": "0.1.2-rc.0", "private": true, "dependencies": { "@rocket.chat/emitter": "~0.31.25", diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 29eaadd0e0fe..ad3bb3bc7ef8 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,22 @@ # @rocket.chat/model-typings +## 0.7.0-rc.0 + +### Minor Changes + +- ([#32868](https://github.com/RocketChat/Rocket.Chat/pull/32868)) Added `sidepanel` field to `teams.create` and `rooms.saveRoomSettings` endpoints + +### Patch Changes + +- ([#32986](https://github.com/RocketChat/Rocket.Chat/pull/32986)) Fixed login with third-party apps not working without the "Manage OAuth Apps" permission + +- ([#33054](https://github.com/RocketChat/Rocket.Chat/pull/33054)) Fixed issue with livechat analytics in a given date range considering conversation data from the following day + +-
Updated dependencies [7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/core-typings@6.12.0-rc.0 +
+ ## 0.6.0 ### Minor Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index f96764fa49af..f548b14cee84 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.6.0", + "version": "0.7.0-rc.0", "private": true, "devDependencies": { "@types/node-rsa": "^1.1.3", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index e2b984708aaa..5db18e89fe9e 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.2.1-rc.0 + +### Patch Changes + +-
Updated dependencies [7f88158036, a14c0678bb, e28be46db7]: + + - @rocket.chat/model-typings@0.7.0-rc.0 +
+ ## 0.2.0 ### Minor Changes diff --git a/packages/models/package.json b/packages/models/package.json index 19f1f28438f6..7867b7ea9bd2 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.0", + "version": "0.2.1-rc.0", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index efcab160b8e6..3485f148c7ec 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,21 @@ # @rocket.chat/rest-typings +## 6.12.0-rc.0 + +### Minor Changes + +- ([#32868](https://github.com/RocketChat/Rocket.Chat/pull/32868)) Added `sidepanel` field to `teams.create` and `rooms.saveRoomSettings` endpoints + +### Patch Changes + +- ([#31525](https://github.com/RocketChat/Rocket.Chat/pull/31525)) Fix: Show correct user info actions for non-members in channels. + +-
Updated dependencies [c11f3722df, 7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/ui-kit@0.36.1-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 +
+ ## 6.11.0 ### Minor Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 53bd1d2f5cb2..1cb919fca8ce 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.12.0-develop", + "version": "6.12.0-rc.0", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index f65d986cfaf5..1ca9f058fb94 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-avatar +## 6.0.0-rc.0 + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.0 +
+ ## 5.0.0 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 1c2dc6dabbc4..5188712463bf 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "5.0.0", + "version": "6.0.0-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-contexts": "10.0.0-rc.0", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 5936f8038bc8..80e2b4ca8bfa 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-client +## 10.0.0-rc.0 + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.0 +
+ ## 9.0.0 ### Minor Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index f43b2d8622b8..d3d7fc1646ec 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "9.0.0", + "version": "10.0.0-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -60,7 +60,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-contexts": "10.0.0-rc.0", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-composer/CHANGELOG.md b/packages/ui-composer/CHANGELOG.md index d37e917e0375..18571eca048a 100644 --- a/packages/ui-composer/CHANGELOG.md +++ b/packages/ui-composer/CHANGELOG.md @@ -1,5 +1,11 @@ # @rocket.chat/ui-composer +## 0.2.1-rc.0 + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + ## 0.2.0 ### Minor Changes diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index d854a6ffea86..0f4534a421a9 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-composer", - "version": "0.2.0", + "version": "0.2.1-rc.0", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index fb3d074b6fbe..1f2f332f676b 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/ui-contexts +## 10.0.0-rc.0 + +### Patch Changes + +-
Updated dependencies [127866ce97, 0c919db7b4, b764c415dc, 1f061a1aa5, dd37ea1b35, 7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: + + - @rocket.chat/i18n@0.7.0-rc.0 + - @rocket.chat/rest-typings@6.12.0-rc.0 + - @rocket.chat/core-typings@6.12.0-rc.0 + - @rocket.chat/ddp-client@0.3.4-rc.0 +
+ ## 9.0.0 ### Minor Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 513aebd86a30..67281b6e0652 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "9.0.0", + "version": "10.0.0-rc.0", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-kit/CHANGELOG.md b/packages/ui-kit/CHANGELOG.md index 9f31c620f4db..7b7a94cfbbe0 100644 --- a/packages/ui-kit/CHANGELOG.md +++ b/packages/ui-kit/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 0.36.1-rc.0 + +### Patch Changes + +- ([#33000](https://github.com/RocketChat/Rocket.Chat/pull/33000)) fix UiKit error message: Failed to resolve module: @rocket.chat/icons + ## 0.36.0 ### Minor Changes diff --git a/packages/ui-kit/package.json b/packages/ui-kit/package.json index c7e8159d457d..cd8ad2399aa5 100644 --- a/packages/ui-kit/package.json +++ b/packages/ui-kit/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-kit", - "version": "0.36.0", + "version": "0.36.1-rc.0", "description": "Interactive UI elements for Rocket.Chat Apps", "homepage": "https://rocket.chat", "author": { diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 2a697e293211..f6c609860a9c 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/ui-video-conf +## 10.0.0-rc.0 + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + +-
Updated dependencies [8ea6517c4e]: + + - @rocket.chat/ui-avatar@6.0.0-rc.0 + - @rocket.chat/ui-contexts@10.0.0-rc.0 +
+ ## 9.0.0 ### Minor Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 5e7d114a3576..b71f1396706d 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "9.0.0", + "version": "10.0.0-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -40,8 +40,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.0", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-avatar": "6.0.0-rc.0", + "@rocket.chat/ui-contexts": "10.0.0-rc.0", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index 0107fc049b8f..d499769b2edf 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,22 @@ # @rocket.chat/uikit-playground +## 0.4.0-rc.0 + +### Minor Changes + +- ([#32969](https://github.com/RocketChat/Rocket.Chat/pull/32969)) Upgrades fuselage-toastbar version in order to add pause on hover functionality + +### Patch Changes + +- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior + +-
Updated dependencies [8ea6517c4e]: + + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.0 + - @rocket.chat/ui-contexts@10.0.0-rc.0 +
+ ## 0.3.3 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index f46f139a66f4..1a3195460525 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.3.3", + "version": "0.4.0-rc.0", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 871e66b0f29c..30164a65f035 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/web-ui-registration +## 10.0.0-rc.0 + +### Patch Changes + +- ([#32743](https://github.com/RocketChat/Rocket.Chat/pull/32743)) Fixes an issue where creating a new user with an invalid username (containing special characters) resulted in an error message, but the user was still created. The user creation process now properly aborts when an invalid username is provided. + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.0 +
+ ## 9.0.0 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index ba3dc31423a6..ae6601f59224 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "9.0.0", + "version": "10.0.0-rc.0", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -47,7 +47,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "9.0.0", + "@rocket.chat/ui-contexts": "10.0.0-rc.0", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From ac084524171073a01e7121bc0f0483ad05093f1d Mon Sep 17 00:00:00 2001 From: "Julio A." <52619625+julio-cfa@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:36:17 +0200 Subject: [PATCH 009/170] fix: imported fixes (#33136) --- .changeset/orange-clocks-wait.md | 5 + .../functions/getModifiedHttpHeaders.ts | 20 ++ apps/meteor/app/lib/server/lib/debug.js | 3 +- .../meteor/app/livechat/server/api/v1/room.ts | 109 +++++---- .../app/livechat/server/api/v1/visitor.ts | 213 +++++++++--------- .../tests/end-to-end/api/miscellaneous.ts | 137 ++++++++++- .../functions/getModifiedHttpHeaders.tests.ts | 59 +++++ 7 files changed, 392 insertions(+), 154 deletions(-) create mode 100644 .changeset/orange-clocks-wait.md create mode 100644 apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts create mode 100644 apps/meteor/tests/unit/app/lib/server/functions/getModifiedHttpHeaders.tests.ts diff --git a/.changeset/orange-clocks-wait.md b/.changeset/orange-clocks-wait.md new file mode 100644 index 000000000000..eacb88108a0f --- /dev/null +++ b/.changeset/orange-clocks-wait.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts b/apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts new file mode 100644 index 000000000000..e62727814de3 --- /dev/null +++ b/apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts @@ -0,0 +1,20 @@ +export const getModifiedHttpHeaders = (httpHeaders: Record) => { + const modifiedHttpHeaders = { ...httpHeaders }; + + if ('x-auth-token' in modifiedHttpHeaders) { + modifiedHttpHeaders['x-auth-token'] = '[redacted]'; + } + + if (modifiedHttpHeaders.cookie) { + const cookies = modifiedHttpHeaders.cookie.split('; '); + const modifiedCookies = cookies.map((cookie: string) => { + if (cookie.startsWith('rc_token=')) { + return 'rc_token=[redacted]'; + } + return cookie; + }); + modifiedHttpHeaders.cookie = modifiedCookies.join('; '); + } + + return modifiedHttpHeaders; +}; diff --git a/apps/meteor/app/lib/server/lib/debug.js b/apps/meteor/app/lib/server/lib/debug.js index aaa492e80337..cbf38528579f 100644 --- a/apps/meteor/app/lib/server/lib/debug.js +++ b/apps/meteor/app/lib/server/lib/debug.js @@ -7,6 +7,7 @@ import _ from 'underscore'; import { getMethodArgs } from '../../../../server/lib/logger/logPayloads'; import { metrics } from '../../../metrics/server'; import { settings } from '../../../settings/server'; +import { getModifiedHttpHeaders } from '../functions/getModifiedHttpHeaders'; const logger = new Logger('Meteor'); @@ -41,7 +42,7 @@ const traceConnection = (enable, filter, prefix, name, connection, userId) => { console.log(name, { id: connection.id, clientAddress: connection.clientAddress, - httpHeaders: connection.httpHeaders, + httpHeaders: getModifiedHttpHeaders(connection.httpHeaders), userId, }); } else { diff --git a/apps/meteor/app/livechat/server/api/v1/room.ts b/apps/meteor/app/livechat/server/api/v1/room.ts index b0f45a63ff87..565f8e0bb3f4 100644 --- a/apps/meteor/app/livechat/server/api/v1/room.ts +++ b/apps/meteor/app/livechat/server/api/v1/room.ts @@ -31,63 +31,72 @@ import { findVisitorInfo } from '../lib/visitors'; const isAgentWithInfo = (agentObj: ILivechatAgent | { hiddenInfo: boolean }): agentObj is ILivechatAgent => !('hiddenInfo' in agentObj); -API.v1.addRoute('livechat/room', { - async get() { - // I'll temporary use check for validation, as validateParams doesnt support what's being done here - const extraCheckParams = await onCheckRoomParams({ - token: String, - rid: Match.Maybe(String), - agentId: Match.Maybe(String), - }); - - check(this.queryParams, extraCheckParams as any); - - const { token, rid, agentId, ...extraParams } = this.queryParams; - - const guest = token && (await findGuest(token)); - if (!guest) { - throw new Error('invalid-token'); - } - - if (!rid) { - const room = await LivechatRooms.findOneOpenByVisitorToken(token, {}); - if (room) { - return API.v1.success({ room, newRoom: false }); - } - - let agent: SelectedAgent | undefined; - const agentObj = agentId && (await findAgent(agentId)); - if (agentObj) { - if (isAgentWithInfo(agentObj)) { - const { username = undefined } = agentObj; - agent = { agentId, username }; - } else { - agent = { agentId }; - } +API.v1.addRoute( + 'livechat/room', + { + rateLimiterOptions: { + numRequestsAllowed: 5, + intervalTimeInMS: 60000, + }, + }, + { + async get() { + // I'll temporary use check for validation, as validateParams doesnt support what's being done here + const extraCheckParams = await onCheckRoomParams({ + token: String, + rid: Match.Maybe(String), + agentId: Match.Maybe(String), + }); + + check(this.queryParams, extraCheckParams as any); + + const { token, rid, agentId, ...extraParams } = this.queryParams; + + const guest = token && (await findGuest(token)); + if (!guest) { + throw new Error('invalid-token'); } - const roomInfo = { - source: { - type: isWidget(this.request.headers) ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, - }, - }; + if (!rid) { + const room = await LivechatRooms.findOneOpenByVisitorToken(token, {}); + if (room) { + return API.v1.success({ room, newRoom: false }); + } - const newRoom = await LivechatTyped.createRoom({ visitor: guest, roomInfo, agent, extraData: extraParams }); + let agent: SelectedAgent | undefined; + const agentObj = agentId && (await findAgent(agentId)); + if (agentObj) { + if (isAgentWithInfo(agentObj)) { + const { username = undefined } = agentObj; + agent = { agentId, username }; + } else { + agent = { agentId }; + } + } - return API.v1.success({ - room: newRoom, - newRoom: true, - }); - } + const roomInfo = { + source: { + type: isWidget(this.request.headers) ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, + }, + }; + + const newRoom = await LivechatTyped.createRoom({ visitor: guest, roomInfo, agent, extraData: extraParams }); - const froom = await LivechatRooms.findOneOpenByRoomIdAndVisitorToken(rid, token, {}); - if (!froom) { - throw new Error('invalid-room'); - } + return API.v1.success({ + room: newRoom, + newRoom: true, + }); + } + + const froom = await LivechatRooms.findOneOpenByRoomIdAndVisitorToken(rid, token, {}); + if (!froom) { + throw new Error('invalid-room'); + } - return API.v1.success({ room: froom, newRoom: false }); + return API.v1.success({ room: froom, newRoom: false }); + }, }, -}); +); // Note: use this route if a visitor is closing a room // If a RC user(like eg agent) is closing a room, use the `livechat/room.closeByUser` route diff --git a/apps/meteor/app/livechat/server/api/v1/visitor.ts b/apps/meteor/app/livechat/server/api/v1/visitor.ts index a5b3f2de35b1..ed32f0e2d279 100644 --- a/apps/meteor/app/livechat/server/api/v1/visitor.ts +++ b/apps/meteor/app/livechat/server/api/v1/visitor.ts @@ -9,119 +9,128 @@ import { settings } from '../../../../settings/server'; import { Livechat as LivechatTyped } from '../../lib/LivechatTyped'; import { findGuest, normalizeHttpHeaderData } from '../lib/livechat'; -API.v1.addRoute('livechat/visitor', { - async post() { - check(this.bodyParams, { - visitor: Match.ObjectIncluding({ - token: String, - name: Match.Maybe(String), - email: Match.Maybe(String), - department: Match.Maybe(String), - phone: Match.Maybe(String), - username: Match.Maybe(String), - customFields: Match.Maybe([ - Match.ObjectIncluding({ - key: String, - value: String, - overwrite: Boolean, - }), - ]), - }), - }); - - const { customFields, id, token, name, email, department, phone, username, connectionData } = this.bodyParams.visitor; - - if (!token?.trim()) { - throw new Meteor.Error('error-invalid-token', 'Token cannot be empty', { method: 'livechat/visitor' }); - } - - const guest = { - token, - ...(id && { id }), - ...(name && { name }), - ...(email && { email }), - ...(department && { department }), - ...(username && { username }), - ...(connectionData && { connectionData }), - ...(phone && typeof phone === 'string' && { phone: { number: phone as string } }), - connectionData: normalizeHttpHeaderData(this.request.headers), - }; - - const visitor = await LivechatTyped.registerGuest(guest); - if (!visitor) { - throw new Meteor.Error('error-livechat-visitor-registration', 'Error registering visitor', { - method: 'livechat/visitor', +API.v1.addRoute( + 'livechat/visitor', + { + rateLimiterOptions: { + numRequestsAllowed: 5, + intervalTimeInMS: 60000, + }, + }, + { + async post() { + check(this.bodyParams, { + visitor: Match.ObjectIncluding({ + token: String, + name: Match.Maybe(String), + email: Match.Maybe(String), + department: Match.Maybe(String), + phone: Match.Maybe(String), + username: Match.Maybe(String), + customFields: Match.Maybe([ + Match.ObjectIncluding({ + key: String, + value: String, + overwrite: Boolean, + }), + ]), + }), }); - } - const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}); - // If it's updating an existing visitor, it must also update the roomInfo - const rooms = await LivechatRooms.findOpenByVisitorToken(visitor?.token, {}, extraQuery).toArray(); - await Promise.all( - rooms.map( - (room: IRoom) => - visitor && - LivechatTyped.saveRoomInfo(room, { - _id: visitor._id, - name: visitor.name, - phone: visitor.phone?.[0]?.phoneNumber, - livechatData: visitor.livechatData as { [k: string]: string }, - }), - ), - ); - - if (customFields && Array.isArray(customFields) && customFields.length > 0) { - const keys = customFields.map((field) => field.key); - const errors: string[] = []; - - const processedKeys = await Promise.all( - await LivechatCustomField.findByIdsAndScope>(keys, 'visitor', { - projection: { _id: 1 }, - }) - .map(async (field) => { - const customField = customFields.find((f) => f.key === field._id); - if (!customField) { - return; - } - - const { key, value, overwrite } = customField; - // TODO: Change this to Bulk update - if (!(await VisitorsRaw.updateLivechatDataByToken(token, key, value, overwrite))) { - errors.push(key); - } - - return key; - }) - .toArray(), - ); + const { customFields, id, token, name, email, department, phone, username, connectionData } = this.bodyParams.visitor; - if (processedKeys.length !== keys.length) { - LivechatTyped.logger.warn({ - msg: 'Some custom fields were not processed', - visitorId: visitor._id, - missingKeys: keys.filter((key) => !processedKeys.includes(key)), - }); + if (!token?.trim()) { + throw new Meteor.Error('error-invalid-token', 'Token cannot be empty', { method: 'livechat/visitor' }); } - if (errors.length > 0) { - LivechatTyped.logger.error({ - msg: 'Error updating custom fields', - visitorId: visitor._id, - errors, + const guest = { + token, + ...(id && { id }), + ...(name && { name }), + ...(email && { email }), + ...(department && { department }), + ...(username && { username }), + ...(connectionData && { connectionData }), + ...(phone && typeof phone === 'string' && { phone: { number: phone as string } }), + connectionData: normalizeHttpHeaderData(this.request.headers), + }; + + const visitor = await LivechatTyped.registerGuest(guest); + if (!visitor) { + throw new Meteor.Error('error-livechat-visitor-registration', 'Error registering visitor', { + method: 'livechat/visitor', }); - throw new Error('error-updating-custom-fields'); } - return API.v1.success({ visitor: await VisitorsRaw.findOneEnabledById(visitor._id) }); - } + const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}); + // If it's updating an existing visitor, it must also update the roomInfo + const rooms = await LivechatRooms.findOpenByVisitorToken(visitor?.token, {}, extraQuery).toArray(); + await Promise.all( + rooms.map( + (room: IRoom) => + visitor && + LivechatTyped.saveRoomInfo(room, { + _id: visitor._id, + name: visitor.name, + phone: visitor.phone?.[0]?.phoneNumber, + livechatData: visitor.livechatData as { [k: string]: string }, + }), + ), + ); - if (!visitor) { - throw new Meteor.Error('error-saving-visitor', 'An error ocurred while saving visitor'); - } + if (customFields && Array.isArray(customFields) && customFields.length > 0) { + const keys = customFields.map((field) => field.key); + const errors: string[] = []; - return API.v1.success({ visitor }); + const processedKeys = await Promise.all( + await LivechatCustomField.findByIdsAndScope>(keys, 'visitor', { + projection: { _id: 1 }, + }) + .map(async (field) => { + const customField = customFields.find((f) => f.key === field._id); + if (!customField) { + return; + } + + const { key, value, overwrite } = customField; + // TODO: Change this to Bulk update + if (!(await VisitorsRaw.updateLivechatDataByToken(token, key, value, overwrite))) { + errors.push(key); + } + + return key; + }) + .toArray(), + ); + + if (processedKeys.length !== keys.length) { + LivechatTyped.logger.warn({ + msg: 'Some custom fields were not processed', + visitorId: visitor._id, + missingKeys: keys.filter((key) => !processedKeys.includes(key)), + }); + } + + if (errors.length > 0) { + LivechatTyped.logger.error({ + msg: 'Error updating custom fields', + visitorId: visitor._id, + errors, + }); + throw new Error('error-updating-custom-fields'); + } + + return API.v1.success({ visitor: await VisitorsRaw.findOneEnabledById(visitor._id) }); + } + + if (!visitor) { + throw new Meteor.Error('error-saving-visitor', 'An error ocurred while saving visitor'); + } + + return API.v1.success({ visitor }); + }, }, -}); +); API.v1.addRoute('livechat/visitor/:token', { async get() { diff --git a/apps/meteor/tests/end-to-end/api/miscellaneous.ts b/apps/meteor/tests/end-to-end/api/miscellaneous.ts index 613a874ecd8c..b8341f7c0994 100644 --- a/apps/meteor/tests/end-to-end/api/miscellaneous.ts +++ b/apps/meteor/tests/end-to-end/api/miscellaneous.ts @@ -5,7 +5,7 @@ import type { IInstance } from '@rocket.chat/rest-typings'; import { AssertionError, expect } from 'chai'; import { after, before, describe, it } from 'mocha'; -import { getCredentials, api, request, credentials } from '../../data/api-data'; +import { getCredentials, api, request, credentials, methodCall } from '../../data/api-data'; import { updatePermission, updateSetting } from '../../data/permissions.helper'; import { createRoom, deleteRoom } from '../../data/rooms.helper'; import { createTeam, deleteTeam } from '../../data/teams.helper'; @@ -703,4 +703,139 @@ describe('miscellaneous', () => { .end(done); }); }); + + describe('[/stdout.queue]', () => { + let testUser: TestUser; + let testUsername: string; + let testUserPassword: string; + before(async () => { + testUser = await createUser(); + testUsername = testUser.username; + testUserPassword = password; + await updateSetting('Log_Trace_Methods', true); + await updateSetting('Log_Level', '2'); + + // populate the logs by sending method calls + const populateLogsPromises = []; + populateLogsPromises.push( + request + .post(methodCall('getRoomRoles')) + .set(credentials) + .set('Cookie', `rc_token=${credentials['X-Auth-Token']}`) + .send({ + message: JSON.stringify({ + method: 'getRoomRoles', + params: ['GENERAL'], + id: 'id', + msg: 'method', + }), + }), + ); + + populateLogsPromises.push( + request + .post(methodCall('private-settings:get')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'private-settings/get', + params: [ + { + $date: new Date().getTime(), + }, + ], + id: 'id', + msg: 'method', + }), + }), + ); + + populateLogsPromises.push( + request.post(api('login')).send({ + user: { + username: testUsername, + }, + password: testUserPassword, + }), + ); + + await Promise.all(populateLogsPromises); + }); + + after(async () => { + await Promise.all([updateSetting('Log_Trace_Methods', false), updateSetting('Log_Level', '0'), deleteUser(testUser)]); + }); + + it('if log trace enabled, x-auth-token should be redacted', async () => { + await request + .get(api('stdout.queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('queue').that.is.an('array'); + + const { queue } = res.body; + let foundRedactedToken = false; + + for (const log of queue) { + if (log.string.includes("'x-auth-token': '[redacted]'")) { + foundRedactedToken = true; + break; + } + } + + expect(foundRedactedToken).to.be.true; + }); + }); + + it('if log trace enabled, rc_token should be redacted', async () => { + await request + .get(api('stdout.queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('queue').that.is.an('array'); + + const { queue } = res.body; + let foundRedactedCookie = false; + + for (const log of queue) { + if (log.string.includes('rc_token=[redacted]')) { + foundRedactedCookie = true; + break; + } + } + + expect(foundRedactedCookie).to.be.true; + }); + }); + + it('should not return user token anywhere in the log stream', async () => { + await request + .get(api('stdout.queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('queue').that.is.an('array'); + + const { queue } = res.body; + let foundTokenValue = false; + + for (const log of queue) { + if (log.string.includes(credentials['X-Auth-Token'])) { + foundTokenValue = true; + break; + } + } + + expect(foundTokenValue).to.be.false; + }); + }); + }); }); diff --git a/apps/meteor/tests/unit/app/lib/server/functions/getModifiedHttpHeaders.tests.ts b/apps/meteor/tests/unit/app/lib/server/functions/getModifiedHttpHeaders.tests.ts new file mode 100644 index 000000000000..5130bbe59a99 --- /dev/null +++ b/apps/meteor/tests/unit/app/lib/server/functions/getModifiedHttpHeaders.tests.ts @@ -0,0 +1,59 @@ +import { expect } from 'chai'; + +import { getModifiedHttpHeaders } from '../../../../../../app/lib/server/functions/getModifiedHttpHeaders'; + +describe('getModifiedHttpHeaders', () => { + it('should redact x-auth-token if present', () => { + const inputHeaders = { + 'x-auth-token': '12345', + 'some-other-header': 'value', + }; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result['x-auth-token']).to.equal('[redacted]'); + expect(result['some-other-header']).to.equal('value'); + }); + + it('should not modify headers if x-auth-token is not present', () => { + const inputHeaders = { + 'some-other-header': 'value', + }; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result).to.deep.equal(inputHeaders); + }); + + it('should redact rc_token in cookies if present', () => { + const inputHeaders = { + cookie: 'session_id=abc123; rc_token=98765; other_cookie=value', + }; + const expectedCookies = 'session_id=abc123; rc_token=[redacted]; other_cookie=value'; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result.cookie).to.equal(expectedCookies); + }); + + it('should not modify cookies if rc_token is not present', () => { + const inputHeaders = { + cookie: 'session_id=abc123; other_cookie=value', + }; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result.cookie).to.equal(inputHeaders.cookie); + }); + + it('should return headers unchanged if neither x-auth-token nor cookie are present', () => { + const inputHeaders = { + 'some-other-header': 'value', + }; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result).to.deep.equal(inputHeaders); + }); + + it('should handle cases with both x-auth-token and rc_token in cookie', () => { + const inputHeaders = { + 'x-auth-token': '12345', + 'cookie': 'session_id=abc123; rc_token=98765; other_cookie=value', + }; + const expectedCookies = 'session_id=abc123; rc_token=[redacted]; other_cookie=value'; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result['x-auth-token']).to.equal('[redacted]'); + expect(result.cookie).to.equal(expectedCookies); + }); +}); From d4dde2b123c98b47e91d81f54f92c02f45be86b0 Mon Sep 17 00:00:00 2001 From: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com> Date: Mon, 26 Aug 2024 18:09:19 +0530 Subject: [PATCH 010/170] regression: Handle live setting forget user session on window close update (#33133) --- apps/meteor/client/startup/accounts.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/meteor/client/startup/accounts.ts b/apps/meteor/client/startup/accounts.ts index 60f2de02bde0..88008a606656 100644 --- a/apps/meteor/client/startup/accounts.ts +++ b/apps/meteor/client/startup/accounts.ts @@ -27,13 +27,15 @@ Accounts.onEmailVerificationLink((token: string) => { }); Meteor.startup(() => { - Tracker.autorun(() => { + Tracker.autorun((computation) => { const forgetUserSessionOnWindowClose = settings.get('Accounts_ForgetUserSessionOnWindowClose'); if (forgetUserSessionOnWindowClose === undefined) { return; } + computation.stop(); + Accounts.config({ clientStorage: forgetUserSessionOnWindowClose ? 'session' : 'local' }); }); }); From 3d019906cc83aa6e9d646269593b3b5053861ed7 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:30:47 +0000 Subject: [PATCH 011/170] fix: Forget session on window close (#33129) Co-authored-by: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com> --- .changeset/two-bikes-crash.md | 7 +++ apps/meteor/client/startup/accounts.ts | 13 +++++ .../externals/meteor/accounts-base.d.ts | 2 + ...account-forgetSessionOnWindowClose.spec.ts | 55 +++++++++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 .changeset/two-bikes-crash.md create mode 100644 apps/meteor/tests/e2e/account-forgetSessionOnWindowClose.spec.ts diff --git a/.changeset/two-bikes-crash.md b/.changeset/two-bikes-crash.md new file mode 100644 index 000000000000..a120435e4a48 --- /dev/null +++ b/.changeset/two-bikes-crash.md @@ -0,0 +1,7 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixed an issue related to setting Accounts_ForgetUserSessionOnWindowClose, this setting was not working as expected. + +The new meteor 2.16 release introduced a new option to configure the Accounts package and choose between the local storage or session storage. They also changed how Meteor.\_localstorage works internally. Due to these changes in Meteor, our setting to use session storage wasn't working as expected. This PR fixes this issue and configures the Accounts package according to the workspace settings. diff --git a/apps/meteor/client/startup/accounts.ts b/apps/meteor/client/startup/accounts.ts index 3be110bc0a09..60f2de02bde0 100644 --- a/apps/meteor/client/startup/accounts.ts +++ b/apps/meteor/client/startup/accounts.ts @@ -2,6 +2,7 @@ import { Accounts } from 'meteor/accounts-base'; import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; +import { settings } from '../../app/settings/client'; import { mainReady } from '../../app/ui-utils/client'; import { sdk } from '../../app/utils/client/lib/SDKClient'; import { t } from '../../app/utils/lib/i18n'; @@ -24,3 +25,15 @@ Accounts.onEmailVerificationLink((token: string) => { }); }); }); + +Meteor.startup(() => { + Tracker.autorun(() => { + const forgetUserSessionOnWindowClose = settings.get('Accounts_ForgetUserSessionOnWindowClose'); + + if (forgetUserSessionOnWindowClose === undefined) { + return; + } + + Accounts.config({ clientStorage: forgetUserSessionOnWindowClose ? 'session' : 'local' }); + }); +}); diff --git a/apps/meteor/definition/externals/meteor/accounts-base.d.ts b/apps/meteor/definition/externals/meteor/accounts-base.d.ts index 3f0b148120e7..31b70f7b7154 100644 --- a/apps/meteor/definition/externals/meteor/accounts-base.d.ts +++ b/apps/meteor/definition/externals/meteor/accounts-base.d.ts @@ -42,6 +42,8 @@ declare module 'meteor/accounts-base' { function _clearAllLoginTokens(userId: string | null): void; + function config(options: { clientStorage: 'session' | 'local' }): void; + class ConfigError extends Error {} class LoginCancelledError extends Error { diff --git a/apps/meteor/tests/e2e/account-forgetSessionOnWindowClose.spec.ts b/apps/meteor/tests/e2e/account-forgetSessionOnWindowClose.spec.ts new file mode 100644 index 000000000000..a19b0e9866da --- /dev/null +++ b/apps/meteor/tests/e2e/account-forgetSessionOnWindowClose.spec.ts @@ -0,0 +1,55 @@ +import { DEFAULT_USER_CREDENTIALS } from './config/constants'; +import { Registration } from './page-objects'; +import { test, expect } from './utils/test'; + +test.describe.serial('Forget session on window close setting', () => { + let poRegistration: Registration; + + test.beforeEach(async ({ page }) => { + poRegistration = new Registration(page); + + await page.goto('/home'); + }); + + test.describe('Setting off', async () => { + test.beforeAll(async ({ api }) => { + await api.post('/settings/Accounts_ForgetUserSessionOnWindowClose', { value: false }); + }); + + test('Login using credentials and reload to stay logged in', async ({ page, context }) => { + await poRegistration.username.type('user1'); + await poRegistration.inputPassword.type(DEFAULT_USER_CREDENTIALS.password); + await poRegistration.btnLogin.click(); + + await expect(page.locator('role=heading[name="Welcome to Rocket.Chat"]')).toBeVisible(); + + const newPage = await context.newPage(); + await newPage.goto('/home'); + + await expect(newPage.locator('role=heading[name="Welcome to Rocket.Chat"]')).toBeVisible(); + }); + }); + + test.describe('Setting on', async () => { + test.beforeAll(async ({ api }) => { + await api.post('/settings/Accounts_ForgetUserSessionOnWindowClose', { value: true }); + }); + + test.afterAll(async ({ api }) => { + await api.post('/settings/Accounts_ForgetUserSessionOnWindowClose', { value: false }); + }); + + test('Login using credentials and reload to get logged out', async ({ page, context }) => { + await poRegistration.username.type('user1'); + await poRegistration.inputPassword.type(DEFAULT_USER_CREDENTIALS.password); + await poRegistration.btnLogin.click(); + + await expect(page.locator('role=heading[name="Welcome to Rocket.Chat"]')).toBeVisible(); + + const newPage = await context.newPage(); + await newPage.goto('/home'); + + await expect(newPage.locator('role=button[name="Login"]')).toBeVisible(); + }); + }); +}); From aa39197d1c41d04fdceec9b0340c02c3ae20ced3 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 20:53:50 +0000 Subject: [PATCH 012/170] fix: imported fixes (#33153) Co-authored-by: Julio A. <52619625+julio-cfa@users.noreply.github.com> --- .changeset/orange-clocks-wait.md | 5 + .../functions/getModifiedHttpHeaders.ts | 20 ++ apps/meteor/app/lib/server/lib/debug.js | 3 +- .../meteor/app/livechat/server/api/v1/room.ts | 109 +++++---- .../app/livechat/server/api/v1/visitor.ts | 213 +++++++++--------- .../tests/end-to-end/api/miscellaneous.ts | 137 ++++++++++- .../functions/getModifiedHttpHeaders.tests.ts | 59 +++++ 7 files changed, 392 insertions(+), 154 deletions(-) create mode 100644 .changeset/orange-clocks-wait.md create mode 100644 apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts create mode 100644 apps/meteor/tests/unit/app/lib/server/functions/getModifiedHttpHeaders.tests.ts diff --git a/.changeset/orange-clocks-wait.md b/.changeset/orange-clocks-wait.md new file mode 100644 index 000000000000..eacb88108a0f --- /dev/null +++ b/.changeset/orange-clocks-wait.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts b/apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts new file mode 100644 index 000000000000..e62727814de3 --- /dev/null +++ b/apps/meteor/app/lib/server/functions/getModifiedHttpHeaders.ts @@ -0,0 +1,20 @@ +export const getModifiedHttpHeaders = (httpHeaders: Record) => { + const modifiedHttpHeaders = { ...httpHeaders }; + + if ('x-auth-token' in modifiedHttpHeaders) { + modifiedHttpHeaders['x-auth-token'] = '[redacted]'; + } + + if (modifiedHttpHeaders.cookie) { + const cookies = modifiedHttpHeaders.cookie.split('; '); + const modifiedCookies = cookies.map((cookie: string) => { + if (cookie.startsWith('rc_token=')) { + return 'rc_token=[redacted]'; + } + return cookie; + }); + modifiedHttpHeaders.cookie = modifiedCookies.join('; '); + } + + return modifiedHttpHeaders; +}; diff --git a/apps/meteor/app/lib/server/lib/debug.js b/apps/meteor/app/lib/server/lib/debug.js index aaa492e80337..cbf38528579f 100644 --- a/apps/meteor/app/lib/server/lib/debug.js +++ b/apps/meteor/app/lib/server/lib/debug.js @@ -7,6 +7,7 @@ import _ from 'underscore'; import { getMethodArgs } from '../../../../server/lib/logger/logPayloads'; import { metrics } from '../../../metrics/server'; import { settings } from '../../../settings/server'; +import { getModifiedHttpHeaders } from '../functions/getModifiedHttpHeaders'; const logger = new Logger('Meteor'); @@ -41,7 +42,7 @@ const traceConnection = (enable, filter, prefix, name, connection, userId) => { console.log(name, { id: connection.id, clientAddress: connection.clientAddress, - httpHeaders: connection.httpHeaders, + httpHeaders: getModifiedHttpHeaders(connection.httpHeaders), userId, }); } else { diff --git a/apps/meteor/app/livechat/server/api/v1/room.ts b/apps/meteor/app/livechat/server/api/v1/room.ts index b0f45a63ff87..565f8e0bb3f4 100644 --- a/apps/meteor/app/livechat/server/api/v1/room.ts +++ b/apps/meteor/app/livechat/server/api/v1/room.ts @@ -31,63 +31,72 @@ import { findVisitorInfo } from '../lib/visitors'; const isAgentWithInfo = (agentObj: ILivechatAgent | { hiddenInfo: boolean }): agentObj is ILivechatAgent => !('hiddenInfo' in agentObj); -API.v1.addRoute('livechat/room', { - async get() { - // I'll temporary use check for validation, as validateParams doesnt support what's being done here - const extraCheckParams = await onCheckRoomParams({ - token: String, - rid: Match.Maybe(String), - agentId: Match.Maybe(String), - }); - - check(this.queryParams, extraCheckParams as any); - - const { token, rid, agentId, ...extraParams } = this.queryParams; - - const guest = token && (await findGuest(token)); - if (!guest) { - throw new Error('invalid-token'); - } - - if (!rid) { - const room = await LivechatRooms.findOneOpenByVisitorToken(token, {}); - if (room) { - return API.v1.success({ room, newRoom: false }); - } - - let agent: SelectedAgent | undefined; - const agentObj = agentId && (await findAgent(agentId)); - if (agentObj) { - if (isAgentWithInfo(agentObj)) { - const { username = undefined } = agentObj; - agent = { agentId, username }; - } else { - agent = { agentId }; - } +API.v1.addRoute( + 'livechat/room', + { + rateLimiterOptions: { + numRequestsAllowed: 5, + intervalTimeInMS: 60000, + }, + }, + { + async get() { + // I'll temporary use check for validation, as validateParams doesnt support what's being done here + const extraCheckParams = await onCheckRoomParams({ + token: String, + rid: Match.Maybe(String), + agentId: Match.Maybe(String), + }); + + check(this.queryParams, extraCheckParams as any); + + const { token, rid, agentId, ...extraParams } = this.queryParams; + + const guest = token && (await findGuest(token)); + if (!guest) { + throw new Error('invalid-token'); } - const roomInfo = { - source: { - type: isWidget(this.request.headers) ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, - }, - }; + if (!rid) { + const room = await LivechatRooms.findOneOpenByVisitorToken(token, {}); + if (room) { + return API.v1.success({ room, newRoom: false }); + } - const newRoom = await LivechatTyped.createRoom({ visitor: guest, roomInfo, agent, extraData: extraParams }); + let agent: SelectedAgent | undefined; + const agentObj = agentId && (await findAgent(agentId)); + if (agentObj) { + if (isAgentWithInfo(agentObj)) { + const { username = undefined } = agentObj; + agent = { agentId, username }; + } else { + agent = { agentId }; + } + } - return API.v1.success({ - room: newRoom, - newRoom: true, - }); - } + const roomInfo = { + source: { + type: isWidget(this.request.headers) ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, + }, + }; + + const newRoom = await LivechatTyped.createRoom({ visitor: guest, roomInfo, agent, extraData: extraParams }); - const froom = await LivechatRooms.findOneOpenByRoomIdAndVisitorToken(rid, token, {}); - if (!froom) { - throw new Error('invalid-room'); - } + return API.v1.success({ + room: newRoom, + newRoom: true, + }); + } + + const froom = await LivechatRooms.findOneOpenByRoomIdAndVisitorToken(rid, token, {}); + if (!froom) { + throw new Error('invalid-room'); + } - return API.v1.success({ room: froom, newRoom: false }); + return API.v1.success({ room: froom, newRoom: false }); + }, }, -}); +); // Note: use this route if a visitor is closing a room // If a RC user(like eg agent) is closing a room, use the `livechat/room.closeByUser` route diff --git a/apps/meteor/app/livechat/server/api/v1/visitor.ts b/apps/meteor/app/livechat/server/api/v1/visitor.ts index a5b3f2de35b1..ed32f0e2d279 100644 --- a/apps/meteor/app/livechat/server/api/v1/visitor.ts +++ b/apps/meteor/app/livechat/server/api/v1/visitor.ts @@ -9,119 +9,128 @@ import { settings } from '../../../../settings/server'; import { Livechat as LivechatTyped } from '../../lib/LivechatTyped'; import { findGuest, normalizeHttpHeaderData } from '../lib/livechat'; -API.v1.addRoute('livechat/visitor', { - async post() { - check(this.bodyParams, { - visitor: Match.ObjectIncluding({ - token: String, - name: Match.Maybe(String), - email: Match.Maybe(String), - department: Match.Maybe(String), - phone: Match.Maybe(String), - username: Match.Maybe(String), - customFields: Match.Maybe([ - Match.ObjectIncluding({ - key: String, - value: String, - overwrite: Boolean, - }), - ]), - }), - }); - - const { customFields, id, token, name, email, department, phone, username, connectionData } = this.bodyParams.visitor; - - if (!token?.trim()) { - throw new Meteor.Error('error-invalid-token', 'Token cannot be empty', { method: 'livechat/visitor' }); - } - - const guest = { - token, - ...(id && { id }), - ...(name && { name }), - ...(email && { email }), - ...(department && { department }), - ...(username && { username }), - ...(connectionData && { connectionData }), - ...(phone && typeof phone === 'string' && { phone: { number: phone as string } }), - connectionData: normalizeHttpHeaderData(this.request.headers), - }; - - const visitor = await LivechatTyped.registerGuest(guest); - if (!visitor) { - throw new Meteor.Error('error-livechat-visitor-registration', 'Error registering visitor', { - method: 'livechat/visitor', +API.v1.addRoute( + 'livechat/visitor', + { + rateLimiterOptions: { + numRequestsAllowed: 5, + intervalTimeInMS: 60000, + }, + }, + { + async post() { + check(this.bodyParams, { + visitor: Match.ObjectIncluding({ + token: String, + name: Match.Maybe(String), + email: Match.Maybe(String), + department: Match.Maybe(String), + phone: Match.Maybe(String), + username: Match.Maybe(String), + customFields: Match.Maybe([ + Match.ObjectIncluding({ + key: String, + value: String, + overwrite: Boolean, + }), + ]), + }), }); - } - const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}); - // If it's updating an existing visitor, it must also update the roomInfo - const rooms = await LivechatRooms.findOpenByVisitorToken(visitor?.token, {}, extraQuery).toArray(); - await Promise.all( - rooms.map( - (room: IRoom) => - visitor && - LivechatTyped.saveRoomInfo(room, { - _id: visitor._id, - name: visitor.name, - phone: visitor.phone?.[0]?.phoneNumber, - livechatData: visitor.livechatData as { [k: string]: string }, - }), - ), - ); - - if (customFields && Array.isArray(customFields) && customFields.length > 0) { - const keys = customFields.map((field) => field.key); - const errors: string[] = []; - - const processedKeys = await Promise.all( - await LivechatCustomField.findByIdsAndScope>(keys, 'visitor', { - projection: { _id: 1 }, - }) - .map(async (field) => { - const customField = customFields.find((f) => f.key === field._id); - if (!customField) { - return; - } - - const { key, value, overwrite } = customField; - // TODO: Change this to Bulk update - if (!(await VisitorsRaw.updateLivechatDataByToken(token, key, value, overwrite))) { - errors.push(key); - } - - return key; - }) - .toArray(), - ); + const { customFields, id, token, name, email, department, phone, username, connectionData } = this.bodyParams.visitor; - if (processedKeys.length !== keys.length) { - LivechatTyped.logger.warn({ - msg: 'Some custom fields were not processed', - visitorId: visitor._id, - missingKeys: keys.filter((key) => !processedKeys.includes(key)), - }); + if (!token?.trim()) { + throw new Meteor.Error('error-invalid-token', 'Token cannot be empty', { method: 'livechat/visitor' }); } - if (errors.length > 0) { - LivechatTyped.logger.error({ - msg: 'Error updating custom fields', - visitorId: visitor._id, - errors, + const guest = { + token, + ...(id && { id }), + ...(name && { name }), + ...(email && { email }), + ...(department && { department }), + ...(username && { username }), + ...(connectionData && { connectionData }), + ...(phone && typeof phone === 'string' && { phone: { number: phone as string } }), + connectionData: normalizeHttpHeaderData(this.request.headers), + }; + + const visitor = await LivechatTyped.registerGuest(guest); + if (!visitor) { + throw new Meteor.Error('error-livechat-visitor-registration', 'Error registering visitor', { + method: 'livechat/visitor', }); - throw new Error('error-updating-custom-fields'); } - return API.v1.success({ visitor: await VisitorsRaw.findOneEnabledById(visitor._id) }); - } + const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}); + // If it's updating an existing visitor, it must also update the roomInfo + const rooms = await LivechatRooms.findOpenByVisitorToken(visitor?.token, {}, extraQuery).toArray(); + await Promise.all( + rooms.map( + (room: IRoom) => + visitor && + LivechatTyped.saveRoomInfo(room, { + _id: visitor._id, + name: visitor.name, + phone: visitor.phone?.[0]?.phoneNumber, + livechatData: visitor.livechatData as { [k: string]: string }, + }), + ), + ); - if (!visitor) { - throw new Meteor.Error('error-saving-visitor', 'An error ocurred while saving visitor'); - } + if (customFields && Array.isArray(customFields) && customFields.length > 0) { + const keys = customFields.map((field) => field.key); + const errors: string[] = []; - return API.v1.success({ visitor }); + const processedKeys = await Promise.all( + await LivechatCustomField.findByIdsAndScope>(keys, 'visitor', { + projection: { _id: 1 }, + }) + .map(async (field) => { + const customField = customFields.find((f) => f.key === field._id); + if (!customField) { + return; + } + + const { key, value, overwrite } = customField; + // TODO: Change this to Bulk update + if (!(await VisitorsRaw.updateLivechatDataByToken(token, key, value, overwrite))) { + errors.push(key); + } + + return key; + }) + .toArray(), + ); + + if (processedKeys.length !== keys.length) { + LivechatTyped.logger.warn({ + msg: 'Some custom fields were not processed', + visitorId: visitor._id, + missingKeys: keys.filter((key) => !processedKeys.includes(key)), + }); + } + + if (errors.length > 0) { + LivechatTyped.logger.error({ + msg: 'Error updating custom fields', + visitorId: visitor._id, + errors, + }); + throw new Error('error-updating-custom-fields'); + } + + return API.v1.success({ visitor: await VisitorsRaw.findOneEnabledById(visitor._id) }); + } + + if (!visitor) { + throw new Meteor.Error('error-saving-visitor', 'An error ocurred while saving visitor'); + } + + return API.v1.success({ visitor }); + }, }, -}); +); API.v1.addRoute('livechat/visitor/:token', { async get() { diff --git a/apps/meteor/tests/end-to-end/api/miscellaneous.ts b/apps/meteor/tests/end-to-end/api/miscellaneous.ts index 613a874ecd8c..b8341f7c0994 100644 --- a/apps/meteor/tests/end-to-end/api/miscellaneous.ts +++ b/apps/meteor/tests/end-to-end/api/miscellaneous.ts @@ -5,7 +5,7 @@ import type { IInstance } from '@rocket.chat/rest-typings'; import { AssertionError, expect } from 'chai'; import { after, before, describe, it } from 'mocha'; -import { getCredentials, api, request, credentials } from '../../data/api-data'; +import { getCredentials, api, request, credentials, methodCall } from '../../data/api-data'; import { updatePermission, updateSetting } from '../../data/permissions.helper'; import { createRoom, deleteRoom } from '../../data/rooms.helper'; import { createTeam, deleteTeam } from '../../data/teams.helper'; @@ -703,4 +703,139 @@ describe('miscellaneous', () => { .end(done); }); }); + + describe('[/stdout.queue]', () => { + let testUser: TestUser; + let testUsername: string; + let testUserPassword: string; + before(async () => { + testUser = await createUser(); + testUsername = testUser.username; + testUserPassword = password; + await updateSetting('Log_Trace_Methods', true); + await updateSetting('Log_Level', '2'); + + // populate the logs by sending method calls + const populateLogsPromises = []; + populateLogsPromises.push( + request + .post(methodCall('getRoomRoles')) + .set(credentials) + .set('Cookie', `rc_token=${credentials['X-Auth-Token']}`) + .send({ + message: JSON.stringify({ + method: 'getRoomRoles', + params: ['GENERAL'], + id: 'id', + msg: 'method', + }), + }), + ); + + populateLogsPromises.push( + request + .post(methodCall('private-settings:get')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'private-settings/get', + params: [ + { + $date: new Date().getTime(), + }, + ], + id: 'id', + msg: 'method', + }), + }), + ); + + populateLogsPromises.push( + request.post(api('login')).send({ + user: { + username: testUsername, + }, + password: testUserPassword, + }), + ); + + await Promise.all(populateLogsPromises); + }); + + after(async () => { + await Promise.all([updateSetting('Log_Trace_Methods', false), updateSetting('Log_Level', '0'), deleteUser(testUser)]); + }); + + it('if log trace enabled, x-auth-token should be redacted', async () => { + await request + .get(api('stdout.queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('queue').that.is.an('array'); + + const { queue } = res.body; + let foundRedactedToken = false; + + for (const log of queue) { + if (log.string.includes("'x-auth-token': '[redacted]'")) { + foundRedactedToken = true; + break; + } + } + + expect(foundRedactedToken).to.be.true; + }); + }); + + it('if log trace enabled, rc_token should be redacted', async () => { + await request + .get(api('stdout.queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('queue').that.is.an('array'); + + const { queue } = res.body; + let foundRedactedCookie = false; + + for (const log of queue) { + if (log.string.includes('rc_token=[redacted]')) { + foundRedactedCookie = true; + break; + } + } + + expect(foundRedactedCookie).to.be.true; + }); + }); + + it('should not return user token anywhere in the log stream', async () => { + await request + .get(api('stdout.queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('queue').that.is.an('array'); + + const { queue } = res.body; + let foundTokenValue = false; + + for (const log of queue) { + if (log.string.includes(credentials['X-Auth-Token'])) { + foundTokenValue = true; + break; + } + } + + expect(foundTokenValue).to.be.false; + }); + }); + }); }); diff --git a/apps/meteor/tests/unit/app/lib/server/functions/getModifiedHttpHeaders.tests.ts b/apps/meteor/tests/unit/app/lib/server/functions/getModifiedHttpHeaders.tests.ts new file mode 100644 index 000000000000..5130bbe59a99 --- /dev/null +++ b/apps/meteor/tests/unit/app/lib/server/functions/getModifiedHttpHeaders.tests.ts @@ -0,0 +1,59 @@ +import { expect } from 'chai'; + +import { getModifiedHttpHeaders } from '../../../../../../app/lib/server/functions/getModifiedHttpHeaders'; + +describe('getModifiedHttpHeaders', () => { + it('should redact x-auth-token if present', () => { + const inputHeaders = { + 'x-auth-token': '12345', + 'some-other-header': 'value', + }; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result['x-auth-token']).to.equal('[redacted]'); + expect(result['some-other-header']).to.equal('value'); + }); + + it('should not modify headers if x-auth-token is not present', () => { + const inputHeaders = { + 'some-other-header': 'value', + }; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result).to.deep.equal(inputHeaders); + }); + + it('should redact rc_token in cookies if present', () => { + const inputHeaders = { + cookie: 'session_id=abc123; rc_token=98765; other_cookie=value', + }; + const expectedCookies = 'session_id=abc123; rc_token=[redacted]; other_cookie=value'; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result.cookie).to.equal(expectedCookies); + }); + + it('should not modify cookies if rc_token is not present', () => { + const inputHeaders = { + cookie: 'session_id=abc123; other_cookie=value', + }; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result.cookie).to.equal(inputHeaders.cookie); + }); + + it('should return headers unchanged if neither x-auth-token nor cookie are present', () => { + const inputHeaders = { + 'some-other-header': 'value', + }; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result).to.deep.equal(inputHeaders); + }); + + it('should handle cases with both x-auth-token and rc_token in cookie', () => { + const inputHeaders = { + 'x-auth-token': '12345', + 'cookie': 'session_id=abc123; rc_token=98765; other_cookie=value', + }; + const expectedCookies = 'session_id=abc123; rc_token=[redacted]; other_cookie=value'; + const result = getModifiedHttpHeaders(inputHeaders); + expect(result['x-auth-token']).to.equal('[redacted]'); + expect(result.cookie).to.equal(expectedCookies); + }); +}); From 560a432ffdda7867378b664497f35fa5547efc79 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Mon, 26 Aug 2024 22:55:58 +0000 Subject: [PATCH 013/170] Release 6.12.0-rc.1 [no ci] --- .changeset/bump-patch-1724712948901.md | 5 +++ .changeset/pre.json | 2 ++ apps/meteor/CHANGELOG.md | 35 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 14 ++++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 14 ++++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 14 ++++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 15 ++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 15 ++++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 14 ++++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 14 ++++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 13 +++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/license/CHANGELOG.md | 10 ++++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 15 ++++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 10 ++++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 12 +++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/api-client/CHANGELOG.md | 11 ++++++ packages/api-client/package.json | 2 +- packages/apps/CHANGELOG.md | 11 ++++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 12 +++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 3 ++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 11 ++++++ packages/cron/package.json | 2 +- packages/ddp-client/CHANGELOG.md | 12 +++++++ packages/ddp-client/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 14 ++++++++ packages/fuselage-ui-kit/package.json | 8 ++--- packages/gazzodown/CHANGELOG.md | 12 +++++++ packages/gazzodown/package.json | 6 ++-- packages/instance-status/CHANGELOG.md | 10 ++++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 10 ++++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 +++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 10 ++++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 10 ++++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 10 ++++++ packages/ui-avatar/package.json | 4 +-- packages/ui-client/CHANGELOG.md | 10 ++++++ packages/ui-client/package.json | 4 +-- packages/ui-contexts/CHANGELOG.md | 12 +++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 11 ++++++ packages/ui-video-conf/package.json | 6 ++-- packages/uikit-playground/CHANGELOG.md | 12 +++++++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 10 ++++++ packages/web-ui-registration/package.json | 4 +-- yarn.lock | 22 ++++++------ 69 files changed, 457 insertions(+), 55 deletions(-) create mode 100644 .changeset/bump-patch-1724712948901.md diff --git a/.changeset/bump-patch-1724712948901.md b/.changeset/bump-patch-1724712948901.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1724712948901.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/pre.json b/.changeset/pre.json index fabea75cbf61..f23c7ae178fa 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -65,6 +65,7 @@ "changesets": [ "bright-humans-cross", "brown-crabs-chew", + "bump-patch-1724712948901", "calm-tigers-peel", "cool-rocks-remember", "empty-toys-smell", @@ -79,6 +80,7 @@ "nasty-windows-smile", "new-mayflies-wait", "ninety-hounds-exist", + "orange-clocks-wait", "popular-bottles-visit", "proud-years-buy", "purple-dolls-serve", diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index 9c1da2279dbb..75b8e3e71df6 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,39 @@ # @rocket.chat/meteor +## 6.12.0-rc.1 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- ([#33136](https://github.com/RocketChat/Rocket.Chat/pull/33136)) Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/license@0.2.5-rc.1 + - @rocket.chat/omnichannel-services@0.3.2-rc.1 + - @rocket.chat/pdf-worker@0.2.2-rc.1 + - @rocket.chat/presence@0.2.5-rc.1 + - @rocket.chat/api-client@0.2.5-rc.1 + - @rocket.chat/apps@0.1.5-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/cron@0.1.5-rc.1 + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.1 + - @rocket.chat/gazzodown@10.0.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/ui-contexts@10.0.0-rc.1 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.2-rc.1 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.1 + - @rocket.chat/ui-client@10.0.0-rc.1 + - @rocket.chat/ui-video-conf@10.0.0-rc.1 + - @rocket.chat/web-ui-registration@10.0.0-rc.1 + - @rocket.chat/instance-status@0.1.5-rc.1 +
+ ## 6.12.0-rc.0 ### Minor Changes @@ -110,6 +144,7 @@ - @rocket.chat/instance-status@0.1.4-rc.0 - @rocket.chat/server-cloud-communication@0.0.2 + ## 6.11.1 ### Patch Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index 529a0ee307e9..184b030fe19d 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.12.0-rc.0" + "version": "6.12.0-rc.1" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index cb411e026346..5b8af0e9703c 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.3.2-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 1.3.1-rc.0 ### Patch Changes @@ -13,6 +26,7 @@ - @rocket.chat/core-services@0.6.0-rc.0 - @rocket.chat/models@0.2.1-rc.0 + ## 1.3.1 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index d55531916cdd..6baf89d95ebf 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.2-rc.0", + "version": "1.3.2-rc.1", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 23429fed2242..e9ac01e6b972 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.12.0-rc.0", + "version": "6.12.0-rc.1", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index e392178dc323..9aec6081bf30 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.4.4-rc.0 ### Patch Changes @@ -12,6 +25,7 @@ - @rocket.chat/core-services@0.6.0-rc.0 - @rocket.chat/models@0.2.1-rc.0 + ## 0.4.4 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index d08ff76a32bb..6b4e12e0ae52 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.5-rc.0", + "version": "0.4.5-rc.1", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index f0ac95f4b858..ee81e466ed3c 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.4.5-rc.0 ### Patch Changes @@ -12,6 +25,7 @@ - @rocket.chat/core-services@0.6.0-rc.0 - @rocket.chat/models@0.2.1-rc.0 + ## 0.4.4 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 3f3ab6bddd41..723f97b071bf 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.5-rc.0", + "version": "0.4.5-rc.1", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 5070335cae3e..80733d804be1 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/ddp-streamer +## 0.3.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 + - @rocket.chat/instance-status@0.1.5-rc.1 +
+ ## 0.3.5-rc.0 ### Patch Changes @@ -13,6 +27,7 @@ - @rocket.chat/models@0.2.1-rc.0 - @rocket.chat/instance-status@0.1.4-rc.0 + ## 0.3.4 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 2aa081c494ed..60198b5a42e6 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.5-rc.0", + "version": "0.3.5-rc.1", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 194c8cefa2d8..7f7f7945dd56 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/omnichannel-services@0.3.2-rc.1 + - @rocket.chat/pdf-worker@0.2.2-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.4.5-rc.0 ### Patch Changes @@ -13,6 +27,7 @@ - @rocket.chat/models@0.2.1-rc.0 - @rocket.chat/pdf-worker@0.2.1-rc.0 + ## 0.4.4 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index ae96ff93a5da..2639125f3dc3 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.5-rc.0", + "version": "0.4.5-rc.1", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index a9331e470e16..853a25180cd4 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/presence@0.2.5-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.4.5-rc.0 ### Patch Changes @@ -12,6 +25,7 @@ - @rocket.chat/models@0.2.1-rc.0 - @rocket.chat/presence@0.2.4-rc.0 + ## 0.4.4 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 0bd6e1523276..35f639b59890 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.5-rc.0", + "version": "0.4.5-rc.1", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index f89555b52009..b39ed0a8815a 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/omnichannel-services@0.3.2-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.4.5-rc.0 ### Patch Changes @@ -12,6 +25,7 @@ - @rocket.chat/omnichannel-services@0.3.1-rc.0 - @rocket.chat/models@0.2.1-rc.0 + ## 0.4.4 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 630f5ff9d63b..1ed210871152 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.5-rc.0", + "version": "0.4.5-rc.1", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index e2226d9be84b..9b5ce23e3638 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.4.5-rc.0 ### Patch Changes @@ -11,6 +23,7 @@ - @rocket.chat/core-services@0.6.0-rc.0 - @rocket.chat/models@0.2.1-rc.0 + ## 0.4.4 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index f140bcdf6203..d06a102d4de9 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.5-rc.0", + "version": "0.4.5-rc.1", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 0c35027cfc07..d851f26399a6 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 +
+ ## 0.2.5-rc.0 ### Patch Changes @@ -8,6 +17,7 @@ - @rocket.chat/core-typings@6.12.0-rc.0 + ## 0.2.4 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 5b56a5460222..2cbfc160c8cc 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.5-rc.0", + "version": "0.2.5-rc.1", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index d9cdb867b808..ba0a528d36eb 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.2-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/pdf-worker@0.2.2-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.3.2-rc.0 ### Patch Changes @@ -13,6 +27,7 @@ - @rocket.chat/models@0.2.1-rc.0 - @rocket.chat/pdf-worker@0.2.1-rc.0 + ## 0.3.1 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 755bce1263b2..f818090964b7 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.2-rc.0", + "version": "0.3.2-rc.1", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index bed554a450b7..0a776c02449a 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.2-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 +
+ ## 0.2.2-rc.0 ### Patch Changes @@ -8,6 +17,7 @@ - @rocket.chat/core-typings@6.12.0-rc.0 + ## 0.2.1 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index b6b3ccd5add4..af8f5977011e 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.2-rc.0", + "version": "0.2.2-rc.1", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index 0396e0715f49..7beefdd32fe3 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/core-services@0.6.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.2.5-rc.0 ### Patch Changes @@ -10,6 +21,7 @@ - @rocket.chat/core-services@0.6.0-rc.0 - @rocket.chat/models@0.2.1-rc.0 + ## 0.2.4 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 753b1287c683..4f9afd8c042f 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.5-rc.0", + "version": "0.2.5-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index 0c0a96a189de..9268f2ba988a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.12.0-rc.0", + "version": "6.12.0-rc.1", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md index 980dbc25820b..838a08685baa 100644 --- a/packages/api-client/CHANGELOG.md +++ b/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 +
+ ## 0.2.5-rc.0 ### Patch Changes @@ -9,6 +19,7 @@ - @rocket.chat/rest-typings@6.12.0-rc.0 - @rocket.chat/core-typings@6.12.0-rc.0 + ## 0.2.4 ### Patch Changes diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 98cada713e20..7e289eef6146 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.5-rc.0", + "version": "0.2.5-rc.1", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 7fa142931a20..413ec5b3af90 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/model-typings@0.7.0-rc.1 +
+ ## 0.1.5-rc.0 ### Patch Changes @@ -9,6 +19,7 @@ - @rocket.chat/model-typings@0.7.0-rc.0 - @rocket.chat/core-typings@6.12.0-rc.0 + ## 0.1.4 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 08e3141a3b7e..fec607e1f8ab 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.5-rc.0", + "version": "0.1.5-rc.1", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index d8daff9630c2..ae5e4b1aceb1 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.6.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.6.0-rc.0 ### Minor Changes @@ -15,6 +26,7 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/models@0.2.1-rc.0 + ## 0.5.1 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 729f8cac2767..b8a27cc8d0ab 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.6.0-rc.0", + "version": "0.6.0-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index 417cb749dfbd..58236a95d7da 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.12.0-rc.1 + ## 6.12.0-rc.0 ### Minor Changes @@ -26,6 +28,7 @@ - @rocket.chat/ui-kit@0.36.1-rc.0 + ## 6.11.1 ## 6.11.0 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 39108e7f4ec5..737fb013a0ff 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.12.0-rc.0", + "version": "6.12.0-rc.1", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 6b6133b6cffe..6e42bb323a59 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.1.5-rc.0 ### Patch Changes @@ -9,6 +19,7 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/models@0.2.1-rc.0 + ## 0.1.4 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index da50349f4c9d..c0908cb3e88e 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.5-rc.0", + "version": "0.1.5-rc.1", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/ddp-client/CHANGELOG.md b/packages/ddp-client/CHANGELOG.md index 98eb68739b19..2fb7c90d2327 100644 --- a/packages/ddp-client/CHANGELOG.md +++ b/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ddp-client +## 0.3.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/api-client@0.2.5-rc.1 +
+ ## 0.3.5-rc.0 ### Patch Changes @@ -10,6 +21,7 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/api-client@0.2.4-rc.0 + ## 0.3.4 ### Patch Changes diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index b9c5047a3fe6..51a14bed4cba 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.5-rc.0", + "version": "0.3.5-rc.1", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 380f93d2b239..12f56f72659c 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 10.0.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/gazzodown@10.0.0-rc.1 + - @rocket.chat/ui-contexts@10.0.0-rc.1 + - @rocket.chat/ui-avatar@6.0.0-rc.1 + - @rocket.chat/ui-video-conf@10.0.0-rc.1 +
+ ## 10.0.0-rc.0 ### Patch Changes @@ -15,6 +28,7 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/ui-contexts@10.0.0-rc.0 + ## 9.0.1 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 1d911f5437cb..d906859a5d5a 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "10.0.0-rc.0", + "version": "10.0.0-rc.1", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0-rc.0", - "@rocket.chat/ui-contexts": "10.0.0-rc.0", + "@rocket.chat/ui-avatar": "6.0.0-rc.1", + "@rocket.chat/ui-contexts": "10.0.0-rc.1", "@rocket.chat/ui-kit": "0.36.1-rc.0", - "@rocket.chat/ui-video-conf": "10.0.0-rc.0", + "@rocket.chat/ui-video-conf": "10.0.0-rc.1", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index a66bcb8ac5d4..2137661bff33 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 10.0.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/ui-contexts@10.0.0-rc.1 + - @rocket.chat/ui-client@10.0.0-rc.1 +
+ ## 10.0.0-rc.0 ### Patch Changes @@ -12,6 +23,7 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/ui-contexts@10.0.0-rc.0 + ## 9.0.1 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 8f0a87b4a3ee..7610f0db85cf 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "10.0.0-rc.0", + "version": "10.0.0-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -66,8 +66,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "10.0.0-rc.0", - "@rocket.chat/ui-contexts": "10.0.0-rc.0", + "@rocket.chat/ui-client": "10.0.0-rc.1", + "@rocket.chat/ui-contexts": "10.0.0-rc.1", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index fb5f2b845123..2965cdf9e189 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.5-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.2.2-rc.1 +
+ ## 0.1.5-rc.0 ### Patch Changes @@ -7,6 +16,7 @@ -
Updated dependencies []: - @rocket.chat/models@0.2.1-rc.0
+ ## 0.1.4 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 7f175b22ff07..f957756ad7cd 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.5-rc.0", + "version": "0.1.5-rc.1", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index 0ca65ce566c5..9432f8055254 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.19.2-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@10.0.0-rc.1 +
+ ## 1.19.1-rc.0 ### Patch Changes @@ -11,6 +20,7 @@ - @rocket.chat/gazzodown@10.0.0-rc.0 - @rocket.chat/ui-kit@0.36.1-rc.0 + ## 1.19.1 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 1f2f7bf2bdce..419b34b67604 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.2-rc.0", + "version": "1.19.2-rc.1", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 8198319fd403..6c090c3ff504 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.7.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 +
+ ## 0.7.0-rc.0 ### Minor Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index f548b14cee84..2532ee5edf80 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.7.0-rc.0", + "version": "0.7.0-rc.1", "private": true, "devDependencies": { "@types/node-rsa": "^1.1.3", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 3fedb5d3bfb4..03bf4ac0a3fd 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.2.2-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.7.0-rc.1 +
+ ## 0.2.2-rc.0 ### Patch Changes @@ -8,6 +17,7 @@ - @rocket.chat/model-typings@0.7.0-rc.0 + ## 0.2.1 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index 7d2378e32bfb..b4a07acb8cfd 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.2-rc.0", + "version": "0.2.2-rc.1", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 4b77f3a8efc6..003368df6617 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.12.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 +
+ ## 6.12.0-rc.0 ### Minor Changes @@ -15,6 +24,7 @@ - @rocket.chat/ui-kit@0.36.1-rc.0 - @rocket.chat/core-typings@6.12.0-rc.0 + ## 6.11.1 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 1cb919fca8ce..d037e77e7546 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.12.0-rc.0", + "version": "6.12.0-rc.1", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index 1efc49970211..1c917fd00821 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 6.0.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.1 +
+ ## 6.0.0-rc.0 ### Patch Changes @@ -10,6 +19,7 @@ - @rocket.chat/ui-contexts@10.0.0-rc.0 + ## 5.0.1 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 5188712463bf..32054f4b4984 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "6.0.0-rc.0", + "version": "6.0.0-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "10.0.0-rc.0", + "@rocket.chat/ui-contexts": "10.0.0-rc.1", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 38798caa76e1..a4b1f55300ee 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 10.0.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.1 +
+ ## 10.0.0-rc.0 ### Patch Changes @@ -10,6 +19,7 @@ - @rocket.chat/ui-contexts@10.0.0-rc.0 + ## 9.0.1 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index d3d7fc1646ec..ed67fb084a91 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "10.0.0-rc.0", + "version": "10.0.0-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -60,7 +60,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "10.0.0-rc.0", + "@rocket.chat/ui-contexts": "10.0.0-rc.1", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index c0409d4f263c..e98fa6e55d91 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 10.0.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.1 + - @rocket.chat/rest-typings@6.12.0-rc.1 + - @rocket.chat/ddp-client@0.3.5-rc.1 +
+ ## 10.0.0-rc.0 ### Patch Changes @@ -11,6 +22,7 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/ddp-client@0.3.4-rc.0 + ## 9.0.1 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 67281b6e0652..a5750b7d5065 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "10.0.0-rc.0", + "version": "10.0.0-rc.1", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 07883f1b3256..39e0237d1e49 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 10.0.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.1 + - @rocket.chat/ui-avatar@6.0.0-rc.1 +
+ ## 10.0.0-rc.0 ### Patch Changes @@ -11,6 +21,7 @@ - @rocket.chat/ui-avatar@6.0.0-rc.0 - @rocket.chat/ui-contexts@10.0.0-rc.0 + ## 9.0.1 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index b71f1396706d..8c899c42f03e 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "10.0.0-rc.0", + "version": "10.0.0-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -40,8 +40,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0-rc.0", - "@rocket.chat/ui-contexts": "10.0.0-rc.0", + "@rocket.chat/ui-avatar": "6.0.0-rc.1", + "@rocket.chat/ui-contexts": "10.0.0-rc.1", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index f5f0acc46a60..853ce4759b4d 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.4.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.1 + - @rocket.chat/ui-contexts@10.0.0-rc.1 + - @rocket.chat/ui-avatar@6.0.0-rc.1 +
+ ## 0.4.0-rc.0 ### Minor Changes @@ -16,6 +27,7 @@ - @rocket.chat/ui-avatar@6.0.0-rc.0 - @rocket.chat/ui-contexts@10.0.0-rc.0 + ## 0.3.4 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 1a3195460525..ec3937c2fedd 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.4.0-rc.0", + "version": "0.4.0-rc.1", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 2a71ffad5101..e653ae6501ae 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 10.0.0-rc.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.1 +
+ ## 10.0.0-rc.0 ### Patch Changes @@ -10,6 +19,7 @@ - @rocket.chat/ui-contexts@10.0.0-rc.0 + ## 9.0.1 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index ae6601f59224..ce73a83e6802 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "10.0.0-rc.0", + "version": "10.0.0-rc.1", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -47,7 +47,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "10.0.0-rc.0", + "@rocket.chat/ui-contexts": "10.0.0-rc.1", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", diff --git a/yarn.lock b/yarn.lock index f1704485f7c1..4fbcd9d54089 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8934,10 +8934,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0 - "@rocket.chat/ui-contexts": 9.0.0 - "@rocket.chat/ui-kit": 0.36.0 - "@rocket.chat/ui-video-conf": 9.0.0 + "@rocket.chat/ui-avatar": 6.0.0-rc.0 + "@rocket.chat/ui-contexts": 10.0.0-rc.0 + "@rocket.chat/ui-kit": 0.36.1-rc.0 + "@rocket.chat/ui-video-conf": 10.0.0-rc.0 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9021,8 +9021,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 9.0.0 - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-client": 10.0.0-rc.0 + "@rocket.chat/ui-contexts": 10.0.0-rc.0 katex: "*" react: "*" languageName: unknown @@ -10228,7 +10228,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-contexts": 10.0.0-rc.0 react: ~17.0.2 languageName: unknown linkType: soft @@ -10278,7 +10278,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-contexts": 10.0.0-rc.0 react: ~17.0.2 languageName: unknown linkType: soft @@ -10448,8 +10448,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0 - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-avatar": 6.0.0-rc.0 + "@rocket.chat/ui-contexts": 10.0.0-rc.0 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10536,7 +10536,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 - "@rocket.chat/ui-contexts": 9.0.0 + "@rocket.chat/ui-contexts": 10.0.0-rc.0 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 4baf1e4960a88fda9e47fcfe171f253663060b91 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Tue, 27 Aug 2024 19:29:13 +0000 Subject: [PATCH 014/170] regression: Handle live setting forget user session on window close update (#33165) Co-authored-by: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com> --- apps/meteor/client/startup/accounts.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/meteor/client/startup/accounts.ts b/apps/meteor/client/startup/accounts.ts index 60f2de02bde0..88008a606656 100644 --- a/apps/meteor/client/startup/accounts.ts +++ b/apps/meteor/client/startup/accounts.ts @@ -27,13 +27,15 @@ Accounts.onEmailVerificationLink((token: string) => { }); Meteor.startup(() => { - Tracker.autorun(() => { + Tracker.autorun((computation) => { const forgetUserSessionOnWindowClose = settings.get('Accounts_ForgetUserSessionOnWindowClose'); if (forgetUserSessionOnWindowClose === undefined) { return; } + computation.stop(); + Accounts.config({ clientStorage: forgetUserSessionOnWindowClose ? 'session' : 'local' }); }); }); From 5cbbb4585146fe28474fe89789172218abd266f8 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 28 Aug 2024 11:01:41 -0300 Subject: [PATCH 015/170] fix: Multi-step modals closing unexpectedly (#33158) --- .changeset/wise-avocados-taste.md | 5 +++++ .../components/GenericModal/GenericModal.tsx | 2 +- .../GenericModal/GenericModalSkeleton.tsx | 22 +++++-------------- .../ReadReceiptsModal/ReadReceiptsModal.tsx | 8 ++----- .../ConvertToChannelModal.tsx | 2 +- .../DeleteTeam/DeleteTeamModalWithRooms.tsx | 12 +++------- .../info/LeaveTeam/LeaveTeamWithData.tsx | 12 +++------- .../RemoveUsersModal/RemoveUsersModal.js | 11 ++-------- apps/meteor/tests/e2e/team-management.spec.ts | 4 ---- 9 files changed, 22 insertions(+), 56 deletions(-) create mode 100644 .changeset/wise-avocados-taste.md diff --git a/.changeset/wise-avocados-taste.md b/.changeset/wise-avocados-taste.md new file mode 100644 index 000000000000..c4c9bce010b8 --- /dev/null +++ b/.changeset/wise-avocados-taste.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes an issue where multi-step modals were closing unexpectedly diff --git a/apps/meteor/client/components/GenericModal/GenericModal.tsx b/apps/meteor/client/components/GenericModal/GenericModal.tsx index d371e1ff4ef2..5d025e05827d 100644 --- a/apps/meteor/client/components/GenericModal/GenericModal.tsx +++ b/apps/meteor/client/components/GenericModal/GenericModal.tsx @@ -111,7 +111,7 @@ const GenericModal = ({ {tagline && {tagline}} {title ?? t('Are_you_sure')} - + {onClose && } {children} diff --git a/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx b/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx index d56cbdd26a67..2dcdf3b3578c 100644 --- a/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx +++ b/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx @@ -1,25 +1,13 @@ import { Skeleton } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import React from 'react'; import GenericModal from './GenericModal'; -const GenericModalSkeleton = ({ onClose, ...props }: ComponentProps) => { - const t = useTranslation(); - - return ( - } - confirmText={t('Cancel')} - onConfirm={onClose} - > - - - ); -}; +const GenericModalSkeleton = (props: ComponentProps) => ( + }> + + +); export default GenericModalSkeleton; diff --git a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx index c4da16264646..ca033c2dcb0d 100644 --- a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx +++ b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx @@ -1,11 +1,11 @@ import type { IMessage, ReadReceipt } from '@rocket.chat/core-typings'; -import { Skeleton } from '@rocket.chat/fuselage'; import { useMethod, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React, { useEffect } from 'react'; import GenericModal from '../../../../components/GenericModal'; +import GenericModalSkeleton from '../../../../components/GenericModal/GenericModalSkeleton'; import ReadReceiptRow from './ReadReceiptRow'; type ReadReceiptsModalProps = { @@ -29,11 +29,7 @@ const ReadReceiptsModal = ({ messageId, onClose }: ReadReceiptsModalProps): Reac }, [dispatchToastMessage, t, onClose, readReceiptsResult.isError, readReceiptsResult.error]); if (readReceiptsResult.isLoading || readReceiptsResult.isError) { - return ( - - - - ); + return ; } const readReceipts = readReceiptsResult.data; diff --git a/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx b/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx index c29f6c0ec586..3efcdb89690f 100644 --- a/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx +++ b/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx @@ -20,7 +20,7 @@ const ConvertToChannelModal = ({ onClose, onCancel, onConfirm, teamId, userId }: }); if (phase === AsyncStatePhase.LOADING) { - return ; + return ; } return ; diff --git a/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamModalWithRooms.tsx b/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamModalWithRooms.tsx index 5226a3602c0f..1375ec532c91 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamModalWithRooms.tsx +++ b/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamModalWithRooms.tsx @@ -1,11 +1,10 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { Skeleton } from '@rocket.chat/fuselage'; -import { useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; +import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React, { useMemo } from 'react'; -import GenericModal from '../../../../../components/GenericModal'; +import GenericModalSkeleton from '../../../../../components/GenericModal/GenericModalSkeleton'; import DeleteTeamModal from './DeleteTeamModal'; type DeleteTeamModalWithRoomsProps = { @@ -15,17 +14,12 @@ type DeleteTeamModalWithRoomsProps = { }; const DeleteTeamModalWithRooms = ({ teamId, onConfirm, onCancel }: DeleteTeamModalWithRoomsProps): ReactElement => { - const t = useTranslation(); const query = useMemo(() => ({ teamId }), [teamId]); const getTeamsListRooms = useEndpoint('GET', '/v1/teams.listRooms'); const { data, isLoading } = useQuery(['getTeamsListRooms', query], async () => getTeamsListRooms(query)); if (isLoading) { - return ( - } confirmText={t('Cancel')}> - - - ); + return ; } return ; }; diff --git a/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx b/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx index 9bab0acc3d86..58f98705d2bb 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx +++ b/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx @@ -1,11 +1,10 @@ import type { ITeam } from '@rocket.chat/core-typings'; -import { Skeleton } from '@rocket.chat/fuselage'; -import { useUserId, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts'; +import { useUserId, useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React from 'react'; -import GenericModal from '../../../../../components/GenericModal'; +import GenericModalSkeleton from '../../../../../components/GenericModal/GenericModalSkeleton'; import LeaveTeamModal from './LeaveTeamModal/LeaveTeamModal'; type LeaveTeamWithDataProps = { @@ -15,7 +14,6 @@ type LeaveTeamWithDataProps = { }; const LeaveTeamWithData = ({ teamId, onCancel, onConfirm }: LeaveTeamWithDataProps): ReactElement => { - const t = useTranslation(); const userId = useUserId(); if (!userId) { @@ -26,11 +24,7 @@ const LeaveTeamWithData = ({ teamId, onCancel, onConfirm }: LeaveTeamWithDataPro const { data, isLoading } = useQuery(['teams.listRoomsOfUser'], () => getRoomsOfUser({ teamId, userId })); if (isLoading) { - return ( - } confirmText={t('Cancel')}> - - - ); + return ; } return ; diff --git a/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js b/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js index 76a38b680692..f85d5434c1d1 100644 --- a/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js +++ b/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js @@ -1,8 +1,6 @@ -import { Skeleton } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { useMemo } from 'react'; -import GenericModal from '../../../../../components/GenericModal'; +import GenericModalSkeleton from '../../../../../components/GenericModal/GenericModalSkeleton'; import { useEndpointData } from '../../../../../hooks/useEndpointData'; import { AsyncStatePhase } from '../../../../../lib/asyncState'; import BaseRemoveUsersModal from './BaseRemoveUsersModal'; @@ -10,7 +8,6 @@ import BaseRemoveUsersModal from './BaseRemoveUsersModal'; const initialData = { user: { username: '' } }; const RemoveUsersModal = ({ teamId, userId, onClose, onCancel, onConfirm }) => { - const t = useTranslation(); const { value, phase } = useEndpointData('/v1/teams.listRoomsOfUser', { params: useMemo(() => ({ teamId, userId }), [teamId, userId]) }); const userDataFetch = useEndpointData('/v1/users.info', { params: useMemo(() => ({ userId }), [userId]), initialValue: initialData }); const { @@ -18,11 +15,7 @@ const RemoveUsersModal = ({ teamId, userId, onClose, onCancel, onConfirm }) => { } = userDataFetch?.value; if (phase === AsyncStatePhase.LOADING) { - return ( - } confirmText={t('Cancel')} onConfirm={onClose}> - - - ); + return ; } return ; diff --git a/apps/meteor/tests/e2e/team-management.spec.ts b/apps/meteor/tests/e2e/team-management.spec.ts index 1d2ab3a82854..690fa2b5b5dd 100644 --- a/apps/meteor/tests/e2e/team-management.spec.ts +++ b/apps/meteor/tests/e2e/team-management.spec.ts @@ -116,7 +116,6 @@ test.describe.serial('teams-management', () => { }); test('should remove user1 from targetTeamNonPrivate', async () => { - test.fail(); await poHomeTeam.sidenav.openChat(targetTeamNonPrivate); await poHomeTeam.tabs.kebab.click({ force: true }); await poHomeTeam.tabs.btnTeamMembers.click(); @@ -130,7 +129,6 @@ test.describe.serial('teams-management', () => { }); test('should delete targetTeamNonPrivate', async () => { - test.fail(); await poHomeTeam.sidenav.openChat(targetTeamNonPrivate); await poHomeTeam.tabs.btnRoomInfo.click(); await poHomeTeam.tabs.room.btnDelete.click(); @@ -142,7 +140,6 @@ test.describe.serial('teams-management', () => { }); test('should user1 leave from targetTeam', async ({ browser }) => { - test.fail(); const user1Page = await browser.newPage({ storageState: Users.user1.state }); const user1Channel = new HomeTeam(user1Page); await user1Page.goto(`/group/${targetTeam}`); @@ -163,7 +160,6 @@ test.describe.serial('teams-management', () => { }); test('should convert team into a channel', async ({ page }) => { - test.fail(); await poHomeTeam.sidenav.openChat(targetTeam); await poHomeTeam.tabs.btnRoomInfo.click(); await poHomeTeam.tabs.room.btnMore.click(); From 87a59e0352c25f45c07b9b1d719d6ef7b9852763 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 17:41:20 +0000 Subject: [PATCH 016/170] fix: Multi-step modals closing unexpectedly (#33178) Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com> --- .changeset/wise-avocados-taste.md | 5 +++++ .../components/GenericModal/GenericModal.tsx | 2 +- .../GenericModal/GenericModalSkeleton.tsx | 22 +++++-------------- .../ReadReceiptsModal/ReadReceiptsModal.tsx | 8 ++----- .../ConvertToChannelModal.tsx | 2 +- .../DeleteTeam/DeleteTeamModalWithRooms.tsx | 12 +++------- .../info/LeaveTeam/LeaveTeamWithData.tsx | 12 +++------- .../RemoveUsersModal/RemoveUsersModal.js | 11 ++-------- 8 files changed, 22 insertions(+), 52 deletions(-) create mode 100644 .changeset/wise-avocados-taste.md diff --git a/.changeset/wise-avocados-taste.md b/.changeset/wise-avocados-taste.md new file mode 100644 index 000000000000..c4c9bce010b8 --- /dev/null +++ b/.changeset/wise-avocados-taste.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes an issue where multi-step modals were closing unexpectedly diff --git a/apps/meteor/client/components/GenericModal/GenericModal.tsx b/apps/meteor/client/components/GenericModal/GenericModal.tsx index d371e1ff4ef2..5d025e05827d 100644 --- a/apps/meteor/client/components/GenericModal/GenericModal.tsx +++ b/apps/meteor/client/components/GenericModal/GenericModal.tsx @@ -111,7 +111,7 @@ const GenericModal = ({ {tagline && {tagline}} {title ?? t('Are_you_sure')} - + {onClose && } {children} diff --git a/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx b/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx index d56cbdd26a67..2dcdf3b3578c 100644 --- a/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx +++ b/apps/meteor/client/components/GenericModal/GenericModalSkeleton.tsx @@ -1,25 +1,13 @@ import { Skeleton } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import React from 'react'; import GenericModal from './GenericModal'; -const GenericModalSkeleton = ({ onClose, ...props }: ComponentProps) => { - const t = useTranslation(); - - return ( - } - confirmText={t('Cancel')} - onConfirm={onClose} - > - - - ); -}; +const GenericModalSkeleton = (props: ComponentProps) => ( + }> + + +); export default GenericModalSkeleton; diff --git a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx index c4da16264646..ca033c2dcb0d 100644 --- a/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx +++ b/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx @@ -1,11 +1,11 @@ import type { IMessage, ReadReceipt } from '@rocket.chat/core-typings'; -import { Skeleton } from '@rocket.chat/fuselage'; import { useMethod, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React, { useEffect } from 'react'; import GenericModal from '../../../../components/GenericModal'; +import GenericModalSkeleton from '../../../../components/GenericModal/GenericModalSkeleton'; import ReadReceiptRow from './ReadReceiptRow'; type ReadReceiptsModalProps = { @@ -29,11 +29,7 @@ const ReadReceiptsModal = ({ messageId, onClose }: ReadReceiptsModalProps): Reac }, [dispatchToastMessage, t, onClose, readReceiptsResult.isError, readReceiptsResult.error]); if (readReceiptsResult.isLoading || readReceiptsResult.isError) { - return ( - - - - ); + return ; } const readReceipts = readReceiptsResult.data; diff --git a/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx b/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx index c29f6c0ec586..3efcdb89690f 100644 --- a/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx +++ b/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx @@ -20,7 +20,7 @@ const ConvertToChannelModal = ({ onClose, onCancel, onConfirm, teamId, userId }: }); if (phase === AsyncStatePhase.LOADING) { - return ; + return ; } return ; diff --git a/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamModalWithRooms.tsx b/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamModalWithRooms.tsx index 5226a3602c0f..1375ec532c91 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamModalWithRooms.tsx +++ b/apps/meteor/client/views/teams/contextualBar/info/DeleteTeam/DeleteTeamModalWithRooms.tsx @@ -1,11 +1,10 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { Skeleton } from '@rocket.chat/fuselage'; -import { useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; +import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React, { useMemo } from 'react'; -import GenericModal from '../../../../../components/GenericModal'; +import GenericModalSkeleton from '../../../../../components/GenericModal/GenericModalSkeleton'; import DeleteTeamModal from './DeleteTeamModal'; type DeleteTeamModalWithRoomsProps = { @@ -15,17 +14,12 @@ type DeleteTeamModalWithRoomsProps = { }; const DeleteTeamModalWithRooms = ({ teamId, onConfirm, onCancel }: DeleteTeamModalWithRoomsProps): ReactElement => { - const t = useTranslation(); const query = useMemo(() => ({ teamId }), [teamId]); const getTeamsListRooms = useEndpoint('GET', '/v1/teams.listRooms'); const { data, isLoading } = useQuery(['getTeamsListRooms', query], async () => getTeamsListRooms(query)); if (isLoading) { - return ( - } confirmText={t('Cancel')}> - - - ); + return ; } return ; }; diff --git a/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx b/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx index 9bab0acc3d86..58f98705d2bb 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx +++ b/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx @@ -1,11 +1,10 @@ import type { ITeam } from '@rocket.chat/core-typings'; -import { Skeleton } from '@rocket.chat/fuselage'; -import { useUserId, useEndpoint, useTranslation } from '@rocket.chat/ui-contexts'; +import { useUserId, useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React from 'react'; -import GenericModal from '../../../../../components/GenericModal'; +import GenericModalSkeleton from '../../../../../components/GenericModal/GenericModalSkeleton'; import LeaveTeamModal from './LeaveTeamModal/LeaveTeamModal'; type LeaveTeamWithDataProps = { @@ -15,7 +14,6 @@ type LeaveTeamWithDataProps = { }; const LeaveTeamWithData = ({ teamId, onCancel, onConfirm }: LeaveTeamWithDataProps): ReactElement => { - const t = useTranslation(); const userId = useUserId(); if (!userId) { @@ -26,11 +24,7 @@ const LeaveTeamWithData = ({ teamId, onCancel, onConfirm }: LeaveTeamWithDataPro const { data, isLoading } = useQuery(['teams.listRoomsOfUser'], () => getRoomsOfUser({ teamId, userId })); if (isLoading) { - return ( - } confirmText={t('Cancel')}> - - - ); + return ; } return ; diff --git a/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js b/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js index 76a38b680692..f85d5434c1d1 100644 --- a/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js +++ b/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js @@ -1,8 +1,6 @@ -import { Skeleton } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { useMemo } from 'react'; -import GenericModal from '../../../../../components/GenericModal'; +import GenericModalSkeleton from '../../../../../components/GenericModal/GenericModalSkeleton'; import { useEndpointData } from '../../../../../hooks/useEndpointData'; import { AsyncStatePhase } from '../../../../../lib/asyncState'; import BaseRemoveUsersModal from './BaseRemoveUsersModal'; @@ -10,7 +8,6 @@ import BaseRemoveUsersModal from './BaseRemoveUsersModal'; const initialData = { user: { username: '' } }; const RemoveUsersModal = ({ teamId, userId, onClose, onCancel, onConfirm }) => { - const t = useTranslation(); const { value, phase } = useEndpointData('/v1/teams.listRoomsOfUser', { params: useMemo(() => ({ teamId, userId }), [teamId, userId]) }); const userDataFetch = useEndpointData('/v1/users.info', { params: useMemo(() => ({ userId }), [userId]), initialValue: initialData }); const { @@ -18,11 +15,7 @@ const RemoveUsersModal = ({ teamId, userId, onClose, onCancel, onConfirm }) => { } = userDataFetch?.value; if (phase === AsyncStatePhase.LOADING) { - return ( - } confirmText={t('Cancel')} onConfirm={onClose}> - - - ); + return ; } return ; From 7180790e2836ea0126319cf632d1cfaea43afb16 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:29:22 -0300 Subject: [PATCH 017/170] regression: Encrypted file upload throws an error on mobile (#33169) --- .changeset/smart-baboons-allow.md | 5 +++ .../app/file-upload/server/lib/FileUpload.ts | 7 +++- apps/meteor/tests/end-to-end/api/rooms.ts | 36 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 .changeset/smart-baboons-allow.md diff --git a/.changeset/smart-baboons-allow.md b/.changeset/smart-baboons-allow.md new file mode 100644 index 000000000000..0c593e4ed2c5 --- /dev/null +++ b/.changeset/smart-baboons-allow.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed issue that prevented sending encrypted filed from the mobile app diff --git a/apps/meteor/app/file-upload/server/lib/FileUpload.ts b/apps/meteor/app/file-upload/server/lib/FileUpload.ts index 8714c71f20d6..ac97923be41e 100644 --- a/apps/meteor/app/file-upload/server/lib/FileUpload.ts +++ b/apps/meteor/app/file-upload/server/lib/FileUpload.ts @@ -175,7 +175,12 @@ export const FileUpload = { throw new Meteor.Error('error-invalid-file-type', reason); } - // E2EE files are of type - application/octet-stream, application/octet-stream is whitelisted for E2EE files. + // E2EE files should be of type application/octet-stream. no information about them should be disclosed on upload if they are encrypted + if (isE2EEUpload(file)) { + file.type = 'application/octet-stream'; + } + + // E2EE files are of type application/octet-stream, which is whitelisted for E2EE files if (!fileUploadIsValidContentType(file?.type, isE2EEUpload(file) ? 'application/octet-stream' : undefined)) { const reason = i18n.t('File_type_is_not_accepted', { lng: language }); throw new Meteor.Error('error-invalid-file-type', reason); diff --git a/apps/meteor/tests/end-to-end/api/rooms.ts b/apps/meteor/tests/end-to-end/api/rooms.ts index 5a2caedb075f..bb4cbb8fb196 100644 --- a/apps/meteor/tests/end-to-end/api/rooms.ts +++ b/apps/meteor/tests/end-to-end/api/rooms.ts @@ -747,6 +747,42 @@ describe('[Rooms]', () => { }); }); + it('should correctly save encrypted file with the default media type even if another type is provided', async () => { + let fileId; + + await request + .post(api(`rooms.media/${testChannel._id}`)) + .set(credentials) + .attach('file', fs.createReadStream(path.join(__dirname, '../../mocks/files/sample-jpeg.jpg')), { + contentType: 'image/jpeg', + }) + .field({ content: JSON.stringify({ algorithm: 'rc.v1.aes-sha2', ciphertext: 'something' }) }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('file'); + expect(res.body.file).to.have.property('_id'); + expect(res.body.file).to.have.property('url'); + + fileId = res.body.file._id; + }); + + await request + .post(api(`rooms.mediaConfirm/${testChannel._id}/${fileId}`)) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('message'); + expect(res.body.message).to.have.property('files'); + expect(res.body.message.files).to.be.an('array').of.length(1); + expect(res.body.message.files[0]).to.have.property('type', 'application/octet-stream'); + expect(res.body.message.files[0]).to.have.property('name', 'sample-jpeg.jpg'); + }); + }); + it('should fail encrypted file upload when files encryption is disabled', async () => { await updateSetting('E2E_Enable_Encrypt_Files', false); From 347a37e868912b69790bde600e55466e13793d86 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Wed, 28 Aug 2024 16:44:50 -0300 Subject: [PATCH 018/170] chore: remove notifyListener call that was causing startup issues (#33154) --- apps/meteor/server/startup/cloudRegistration.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/meteor/server/startup/cloudRegistration.ts b/apps/meteor/server/startup/cloudRegistration.ts index 65d870de4d89..e69d4446d6ec 100644 --- a/apps/meteor/server/startup/cloudRegistration.ts +++ b/apps/meteor/server/startup/cloudRegistration.ts @@ -1,7 +1,5 @@ import { Settings } from '@rocket.chat/models'; -import { notifyOnSettingChangedById } from '../../app/lib/server/lib/notifyListener'; - export async function ensureCloudWorkspaceRegistered(): Promise { const cloudWorkspaceClientId = await Settings.getValueById('Cloud_Workspace_Client_Id'); const cloudWorkspaceClientSecret = await Settings.getValueById('Cloud_Workspace_Client_Secret'); @@ -18,6 +16,5 @@ export async function ensureCloudWorkspaceRegistered(): Promise { } // otherwise, set the setup wizard to in_progress forcing admins to complete the registration - (await Settings.updateValueById('Show_Setup_Wizard', 'in_progress')).modifiedCount && - void notifyOnSettingChangedById('Show_Setup_Wizard'); + await Settings.updateValueById('Show_Setup_Wizard', 'in_progress'); } From 6a27d7b28723334170946ef282a291a4626a1424 Mon Sep 17 00:00:00 2001 From: csuadev <72958726+csuadev@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:21:38 +0200 Subject: [PATCH 019/170] test: Add unit test for RoomMenu options (#32891) Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com> --- apps/meteor/client/sidebar/RoomMenu.spec.tsx | 67 ++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 apps/meteor/client/sidebar/RoomMenu.spec.tsx diff --git a/apps/meteor/client/sidebar/RoomMenu.spec.tsx b/apps/meteor/client/sidebar/RoomMenu.spec.tsx new file mode 100644 index 000000000000..e12063c9cdb0 --- /dev/null +++ b/apps/meteor/client/sidebar/RoomMenu.spec.tsx @@ -0,0 +1,67 @@ +import type { RoomType } from '@rocket.chat/core-typings'; +import { mockAppRoot } from '@rocket.chat/mock-providers'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; + +import RoomMenu from './RoomMenu'; + +jest.mock('../../client/lib/rooms/roomCoordinator', () => ({ + roomCoordinator: { + getRoomDirectives: () => ({ + getUiText: () => 'leaveWarning', + }), + }, +})); + +jest.mock('../../app/ui-utils/client', () => ({ + LegacyRoomManager: { + close: jest.fn(), + }, +})); + +const defaultProps = { + rid: 'roomId', + type: 'c' as RoomType, + hideDefaultOptions: false, + placement: 'right-start', +}; + +const renderOptions = { + wrapper: mockAppRoot() + .withTranslations('en', 'core', { + Hide: 'Hide', + Mark_unread: 'Mark Unread', + Favorite: 'Favorite', + Leave_room: 'Leave', + }) + .withSetting('Favorite_Rooms', true) + .withPermission('leave-c') + .withPermission('leave-p') + .build(), + legacyRoot: true, +}; + +it('should display all the menu options for regular rooms', async () => { + render(, renderOptions); + + const menu = screen.queryByRole('button'); + await userEvent.click(menu as HTMLElement); + + expect(await screen.findByRole('option', { name: 'Hide' })).toBeInTheDocument(); + expect(await screen.findByRole('option', { name: 'Favorite' })).toBeInTheDocument(); + expect(await screen.findByRole('option', { name: 'Mark Unread' })).toBeInTheDocument(); + expect(await screen.findByRole('option', { name: 'Leave' })).toBeInTheDocument(); +}); + +it('should display only mark unread and favorite for omnichannel rooms', async () => { + render(, renderOptions); + + const menu = screen.queryByRole('button'); + await userEvent.click(menu as HTMLElement); + + expect(await screen.findAllByRole('option')).toHaveLength(2); + expect(screen.queryByRole('option', { name: 'Hide' })).not.toBeInTheDocument(); + expect(screen.queryByRole('option', { name: 'Leave' })).not.toBeInTheDocument(); +}); From bb7d7212558e4ac8aec3be9181c7e57613338a3e Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Thu, 29 Aug 2024 14:49:17 -0300 Subject: [PATCH 020/170] fix: restore tooltips to units Multiselect (#33174) Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com> --- .changeset/strong-rings-rush.md | 5 +++++ apps/meteor/client/omnichannel/units/UnitEdit.tsx | 2 +- .../meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts | 7 +++++-- apps/meteor/tests/e2e/page-objects/omnichannel-units.ts | 4 ++++ packages/ui-client/src/components/TooltipComponent.tsx | 2 +- 5 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 .changeset/strong-rings-rush.md diff --git a/.changeset/strong-rings-rush.md b/.changeset/strong-rings-rush.md new file mode 100644 index 000000000000..5125f47dcb3b --- /dev/null +++ b/.changeset/strong-rings-rush.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Restored tooltips to the unit edit department field selected options diff --git a/apps/meteor/client/omnichannel/units/UnitEdit.tsx b/apps/meteor/client/omnichannel/units/UnitEdit.tsx index e4bc1c0efb50..e71e8e2a94d0 100644 --- a/apps/meteor/client/omnichannel/units/UnitEdit.tsx +++ b/apps/meteor/client/omnichannel/units/UnitEdit.tsx @@ -228,7 +228,7 @@ const UnitEdit = ({ unitData, unitMonitors, unitDepartments }: UnitEditProps) => value={value} onChange={onChange} onBlur={onBlur} - withTitle={false} + withTitle filter={departmentsFilter} setFilter={setDepartmentsFilter} options={departmentsOptions} diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts index 9c1b5fdd5948..cd33a56caa04 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts @@ -185,11 +185,14 @@ test.describe('OC - Manage Units', () => { await poOmnichannelUnits.btnSave.click(); }); - await test.step('expect department to be in the chosen departments list', async () => { + await test.step('expect department to be in the chosen departments list and have title', async () => { await poOmnichannelUnits.search(unit.name); await poOmnichannelUnits.findRowByName(unit.name).click(); await expect(poOmnichannelUnits.contextualBar).toBeVisible(); - await expect(page.getByRole('option', { name: department2.data.name })).toBeVisible(); + await expect(poOmnichannelUnits.selectOptionChip(department2.data.name)).toBeVisible(); + await poOmnichannelUnits.selectOptionChip(department2.data.name).hover(); + + await expect(page.getByRole('tooltip', { name: department2.data.name })).toBeVisible(); await poOmnichannelUnits.btnContextualbarClose.click(); }); diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts index abcd794f8efa..2d0e24073a45 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts @@ -43,6 +43,10 @@ export class OmnichannelUnits extends OmnichannelAdministration { return this.page.locator(`[role=option][value="${name}"]`); } + public selectOptionChip(name: string) { + return this.page.getByRole('option', { name }); + } + async selectDepartment({ name, _id }: { name: string; _id: string }) { await this.inputDepartments.click(); await this.inputDepartments.fill(name); diff --git a/packages/ui-client/src/components/TooltipComponent.tsx b/packages/ui-client/src/components/TooltipComponent.tsx index 137ec913ec78..4a46e5536a53 100644 --- a/packages/ui-client/src/components/TooltipComponent.tsx +++ b/packages/ui-client/src/components/TooltipComponent.tsx @@ -12,7 +12,7 @@ export const TooltipComponent = ({ title, anchor }: TooltipComponentProps): Reac return ( - {title} + {title} ); }; From 0bfba5bf7fa81c9aa3add080aed590b9ef5721ff Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Thu, 29 Aug 2024 14:49:17 -0300 Subject: [PATCH 021/170] fix: restore tooltips to units Multiselect (#33174) Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com> --- .changeset/strong-rings-rush.md | 5 +++++ apps/meteor/client/omnichannel/units/UnitEdit.tsx | 2 +- .../meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts | 7 +++++-- apps/meteor/tests/e2e/page-objects/omnichannel-units.ts | 4 ++++ packages/ui-client/src/components/TooltipComponent.tsx | 2 +- 5 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 .changeset/strong-rings-rush.md diff --git a/.changeset/strong-rings-rush.md b/.changeset/strong-rings-rush.md new file mode 100644 index 000000000000..5125f47dcb3b --- /dev/null +++ b/.changeset/strong-rings-rush.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Restored tooltips to the unit edit department field selected options diff --git a/apps/meteor/client/omnichannel/units/UnitEdit.tsx b/apps/meteor/client/omnichannel/units/UnitEdit.tsx index e4bc1c0efb50..e71e8e2a94d0 100644 --- a/apps/meteor/client/omnichannel/units/UnitEdit.tsx +++ b/apps/meteor/client/omnichannel/units/UnitEdit.tsx @@ -228,7 +228,7 @@ const UnitEdit = ({ unitData, unitMonitors, unitDepartments }: UnitEditProps) => value={value} onChange={onChange} onBlur={onBlur} - withTitle={false} + withTitle filter={departmentsFilter} setFilter={setDepartmentsFilter} options={departmentsOptions} diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts index 9c1b5fdd5948..cd33a56caa04 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts @@ -185,11 +185,14 @@ test.describe('OC - Manage Units', () => { await poOmnichannelUnits.btnSave.click(); }); - await test.step('expect department to be in the chosen departments list', async () => { + await test.step('expect department to be in the chosen departments list and have title', async () => { await poOmnichannelUnits.search(unit.name); await poOmnichannelUnits.findRowByName(unit.name).click(); await expect(poOmnichannelUnits.contextualBar).toBeVisible(); - await expect(page.getByRole('option', { name: department2.data.name })).toBeVisible(); + await expect(poOmnichannelUnits.selectOptionChip(department2.data.name)).toBeVisible(); + await poOmnichannelUnits.selectOptionChip(department2.data.name).hover(); + + await expect(page.getByRole('tooltip', { name: department2.data.name })).toBeVisible(); await poOmnichannelUnits.btnContextualbarClose.click(); }); diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts index abcd794f8efa..2d0e24073a45 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts @@ -43,6 +43,10 @@ export class OmnichannelUnits extends OmnichannelAdministration { return this.page.locator(`[role=option][value="${name}"]`); } + public selectOptionChip(name: string) { + return this.page.getByRole('option', { name }); + } + async selectDepartment({ name, _id }: { name: string; _id: string }) { await this.inputDepartments.click(); await this.inputDepartments.fill(name); diff --git a/packages/ui-client/src/components/TooltipComponent.tsx b/packages/ui-client/src/components/TooltipComponent.tsx index 137ec913ec78..4a46e5536a53 100644 --- a/packages/ui-client/src/components/TooltipComponent.tsx +++ b/packages/ui-client/src/components/TooltipComponent.tsx @@ -12,7 +12,7 @@ export const TooltipComponent = ({ title, anchor }: TooltipComponentProps): Reac return ( - {title} + {title} ); }; From a9b1ca88ed36c73e90cf2b79c869efae16612405 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 20:22:12 +0000 Subject: [PATCH 022/170] fix: restore tooltips to units Multiselect (#33185) Co-authored-by: Martin Schoeler <20868078+MartinSchoeler@users.noreply.github.com> --- .changeset/strong-rings-rush.md | 5 +++++ apps/meteor/client/omnichannel/units/UnitEdit.tsx | 2 +- .../meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts | 7 +++++-- apps/meteor/tests/e2e/page-objects/omnichannel-units.ts | 4 ++++ packages/ui-client/src/components/TooltipComponent.tsx | 2 +- 5 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 .changeset/strong-rings-rush.md diff --git a/.changeset/strong-rings-rush.md b/.changeset/strong-rings-rush.md new file mode 100644 index 000000000000..5125f47dcb3b --- /dev/null +++ b/.changeset/strong-rings-rush.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Restored tooltips to the unit edit department field selected options diff --git a/apps/meteor/client/omnichannel/units/UnitEdit.tsx b/apps/meteor/client/omnichannel/units/UnitEdit.tsx index e4bc1c0efb50..e71e8e2a94d0 100644 --- a/apps/meteor/client/omnichannel/units/UnitEdit.tsx +++ b/apps/meteor/client/omnichannel/units/UnitEdit.tsx @@ -228,7 +228,7 @@ const UnitEdit = ({ unitData, unitMonitors, unitDepartments }: UnitEditProps) => value={value} onChange={onChange} onBlur={onBlur} - withTitle={false} + withTitle filter={departmentsFilter} setFilter={setDepartmentsFilter} options={departmentsOptions} diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts index 9c1b5fdd5948..cd33a56caa04 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-units.spec.ts @@ -185,11 +185,14 @@ test.describe('OC - Manage Units', () => { await poOmnichannelUnits.btnSave.click(); }); - await test.step('expect department to be in the chosen departments list', async () => { + await test.step('expect department to be in the chosen departments list and have title', async () => { await poOmnichannelUnits.search(unit.name); await poOmnichannelUnits.findRowByName(unit.name).click(); await expect(poOmnichannelUnits.contextualBar).toBeVisible(); - await expect(page.getByRole('option', { name: department2.data.name })).toBeVisible(); + await expect(poOmnichannelUnits.selectOptionChip(department2.data.name)).toBeVisible(); + await poOmnichannelUnits.selectOptionChip(department2.data.name).hover(); + + await expect(page.getByRole('tooltip', { name: department2.data.name })).toBeVisible(); await poOmnichannelUnits.btnContextualbarClose.click(); }); diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts index abcd794f8efa..2d0e24073a45 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-units.ts @@ -43,6 +43,10 @@ export class OmnichannelUnits extends OmnichannelAdministration { return this.page.locator(`[role=option][value="${name}"]`); } + public selectOptionChip(name: string) { + return this.page.getByRole('option', { name }); + } + async selectDepartment({ name, _id }: { name: string; _id: string }) { await this.inputDepartments.click(); await this.inputDepartments.fill(name); diff --git a/packages/ui-client/src/components/TooltipComponent.tsx b/packages/ui-client/src/components/TooltipComponent.tsx index 137ec913ec78..4a46e5536a53 100644 --- a/packages/ui-client/src/components/TooltipComponent.tsx +++ b/packages/ui-client/src/components/TooltipComponent.tsx @@ -12,7 +12,7 @@ export const TooltipComponent = ({ title, anchor }: TooltipComponentProps): Reac return ( - {title} + {title} ); }; From 0f5a39e317d2f7cf4b7b82182d4d3f4b9179f91b Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Thu, 29 Aug 2024 18:08:48 -0300 Subject: [PATCH 023/170] refactor: Realtime Monitoring Counters to TS (#33182) --- .../counter/CounterContainer.stories.tsx | 10 ++++----- ...unterContainer.js => CounterContainer.tsx} | 22 ++++++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) rename apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/{CounterContainer.js => CounterContainer.tsx} (59%) diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterContainer.stories.tsx b/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterContainer.stories.tsx index d3a43adf701d..c3e4d0aeb535 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterContainer.stories.tsx +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterContainer.stories.tsx @@ -12,10 +12,10 @@ export const Default: ComponentStory = (args) => { +export type DataType = { + title: string; + value: number | string; +}[]; + +type Totalizers = { + totalizers: DataType; +}; + +type CounterContainerProps = { + data?: Totalizers; + state: AsyncStatePhase; + initialData: DataType; +}; + +const CounterContainer = ({ data, state, initialData, ...props }: CounterContainerProps) => { const t = useTranslation(); - const [displayData, setDisplayData] = useState(initialData); + const [displayData, setDisplayData] = useState(initialData); const { totalizers } = data || { totalizers: initialData }; @@ -22,7 +38,7 @@ const CounterContainer = ({ data, state, initialData, ...props }) => { return ( {displayData.map(({ title, value }, i) => ( - } count={value} /> + } count={value} /> ))} ); From 54eff23813a4d804f2503769b20ddffed2e9e181 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Thu, 29 Aug 2024 21:06:08 -0300 Subject: [PATCH 024/170] regression: Retention policy warning not truncating text (#33186) --- .../room/body/RetentionPolicyWarning.tsx | 6 +-- apps/meteor/package.json | 2 +- ee/packages/ui-theming/package.json | 2 +- packages/fuselage-ui-kit/package.json | 2 +- packages/gazzodown/package.json | 2 +- packages/ui-avatar/package.json | 2 +- packages/ui-client/package.json | 2 +- packages/ui-composer/package.json | 2 +- packages/ui-video-conf/package.json | 2 +- packages/uikit-playground/package.json | 2 +- yarn.lock | 46 +++++++++---------- 11 files changed, 35 insertions(+), 35 deletions(-) diff --git a/apps/meteor/client/views/room/body/RetentionPolicyWarning.tsx b/apps/meteor/client/views/room/body/RetentionPolicyWarning.tsx index f4939a261145..4629b812bbff 100644 --- a/apps/meteor/client/views/room/body/RetentionPolicyWarning.tsx +++ b/apps/meteor/client/views/room/body/RetentionPolicyWarning.tsx @@ -1,5 +1,5 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { Bubble, MessageDivider } from '@rocket.chat/fuselage'; +import { Box, Bubble } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; @@ -13,11 +13,11 @@ const RetentionPolicyWarning = ({ room }: { room: IRoom }): ReactElement => { const message = usePruneWarningMessage(room); return ( - + {message} - + ); }; diff --git a/apps/meteor/package.json b/apps/meteor/package.json index e9ac01e6b972..ec9c06d820b6 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -241,7 +241,7 @@ "@rocket.chat/favicon": "workspace:^", "@rocket.chat/forked-matrix-appservice-bridge": "^4.0.2", "@rocket.chat/forked-matrix-bot-sdk": "^0.6.0-beta.3", - "@rocket.chat/fuselage": "^0.57.0", + "@rocket.chat/fuselage": "^0.57.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/fuselage-toastbar": "^0.33.0", diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json index 519937865872..bce501e2dc6f 100644 --- a/ee/packages/ui-theming/package.json +++ b/ee/packages/ui-theming/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.57.0", + "@rocket.chat/fuselage": "^0.57.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/ui-contexts": "workspace:~", diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index d906859a5d5a..d35727e58af3 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -66,7 +66,7 @@ "@rocket.chat/apps-engine": "1.45.0-alpha.866", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.57.0", + "@rocket.chat/fuselage": "^0.57.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/icons": "~0.38.0", diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 7610f0db85cf..57ff4d4dd142 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.57.0", + "@rocket.chat/fuselage": "^0.57.1", "@rocket.chat/fuselage-tokens": "^0.33.1", "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/message-parser": "workspace:^", diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 32054f4b4984..e673d1a5db06 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@babel/core": "~7.22.20", - "@rocket.chat/fuselage": "^0.57.0", + "@rocket.chat/fuselage": "^0.57.1", "@rocket.chat/ui-contexts": "workspace:^", "@types/babel__core": "~7.20.3", "@types/react": "~17.0.69", diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index ed67fb084a91..cc3b4df35bf4 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@react-aria/toolbar": "^3.0.0-beta.1", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.57.0", + "@rocket.chat/fuselage": "^0.57.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index 0f4534a421a9..0f69b1df3868 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -19,7 +19,7 @@ "@babel/core": "~7.22.20", "@react-aria/toolbar": "^3.0.0-beta.1", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.57.0", + "@rocket.chat/fuselage": "^0.57.1", "@rocket.chat/icons": "~0.38.0", "@storybook/addon-actions": "~6.5.16", "@storybook/addon-docs": "~6.5.16", diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 8c899c42f03e..03db3dbecef4 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@rocket.chat/css-in-js": "~0.31.25", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.57.0", + "@rocket.chat/fuselage": "^0.57.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index ec3937c2fedd..73cfd4369652 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -15,7 +15,7 @@ "@codemirror/tooltip": "^0.19.16", "@lezer/highlight": "^1.1.6", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.57.0", + "@rocket.chat/fuselage": "^0.57.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/fuselage-toastbar": "^0.33.0", diff --git a/yarn.lock b/yarn.lock index 4fbcd9d54089..2dadeaa4d3d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8883,7 +8883,7 @@ __metadata: "@rocket.chat/apps-engine": 1.45.0-alpha.866 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.57.0 + "@rocket.chat/fuselage": ^0.57.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/gazzodown": "workspace:^" @@ -8934,19 +8934,19 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 6.0.0-rc.0 - "@rocket.chat/ui-contexts": 10.0.0-rc.0 + "@rocket.chat/ui-avatar": 6.0.0-rc.1 + "@rocket.chat/ui-contexts": 10.0.0-rc.1 "@rocket.chat/ui-kit": 0.36.1-rc.0 - "@rocket.chat/ui-video-conf": 10.0.0-rc.0 + "@rocket.chat/ui-video-conf": 10.0.0-rc.1 "@tanstack/react-query": "*" react: "*" react-dom: "*" languageName: unknown linkType: soft -"@rocket.chat/fuselage@npm:^0.57.0": - version: 0.57.0 - resolution: "@rocket.chat/fuselage@npm:0.57.0" +"@rocket.chat/fuselage@npm:^0.57.1": + version: 0.57.1 + resolution: "@rocket.chat/fuselage@npm:0.57.1" dependencies: "@rocket.chat/css-in-js": ^0.31.25 "@rocket.chat/css-supports": ^0.31.25 @@ -8964,7 +8964,7 @@ __metadata: react: ^17.0.2 react-dom: ^17.0.2 react-virtuoso: 1.2.4 - checksum: 80f49f79ca6655067f528a9b427a7bfabbcf1583d0c9f3ed40b79217c7a495e93e0335e15e29b23237bf2ccb5ee5fa063051b40bf4d539439f452ffd45fdb537 + checksum: ed40c4e9ec6f6294e0e7c7a3912ae7c9eca026455506f3f1983483010d3d0c41169f9e38d173e5e63ed0e9824979edd607dda3c881202bf797a97b5b76e83a34 languageName: node linkType: hard @@ -8975,7 +8975,7 @@ __metadata: "@babel/core": ~7.22.20 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.57.0 + "@rocket.chat/fuselage": ^0.57.1 "@rocket.chat/fuselage-tokens": ^0.33.1 "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/message-parser": "workspace:^" @@ -9021,8 +9021,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 10.0.0-rc.0 - "@rocket.chat/ui-contexts": 10.0.0-rc.0 + "@rocket.chat/ui-client": 10.0.0-rc.1 + "@rocket.chat/ui-contexts": 10.0.0-rc.1 katex: "*" react: "*" languageName: unknown @@ -9342,7 +9342,7 @@ __metadata: "@rocket.chat/favicon": "workspace:^" "@rocket.chat/forked-matrix-appservice-bridge": ^4.0.2 "@rocket.chat/forked-matrix-bot-sdk": ^0.6.0-beta.3 - "@rocket.chat/fuselage": ^0.57.0 + "@rocket.chat/fuselage": ^0.57.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/fuselage-toastbar": ^0.33.0 @@ -10214,7 +10214,7 @@ __metadata: resolution: "@rocket.chat/ui-avatar@workspace:packages/ui-avatar" dependencies: "@babel/core": ~7.22.20 - "@rocket.chat/fuselage": ^0.57.0 + "@rocket.chat/fuselage": ^0.57.1 "@rocket.chat/ui-contexts": "workspace:^" "@types/babel__core": ~7.20.3 "@types/react": ~17.0.69 @@ -10228,7 +10228,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 10.0.0-rc.0 + "@rocket.chat/ui-contexts": 10.0.0-rc.1 react: ~17.0.2 languageName: unknown linkType: soft @@ -10240,7 +10240,7 @@ __metadata: "@babel/core": ~7.22.20 "@react-aria/toolbar": ^3.0.0-beta.1 "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.57.0 + "@rocket.chat/fuselage": ^0.57.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/jest-presets": "workspace:~" @@ -10278,7 +10278,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 10.0.0-rc.0 + "@rocket.chat/ui-contexts": 10.0.0-rc.1 react: ~17.0.2 languageName: unknown linkType: soft @@ -10290,7 +10290,7 @@ __metadata: "@babel/core": ~7.22.20 "@react-aria/toolbar": ^3.0.0-beta.1 "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.57.0 + "@rocket.chat/fuselage": ^0.57.1 "@rocket.chat/icons": ~0.38.0 "@storybook/addon-actions": ~6.5.16 "@storybook/addon-docs": ~6.5.16 @@ -10385,7 +10385,7 @@ __metadata: resolution: "@rocket.chat/ui-theming@workspace:ee/packages/ui-theming" dependencies: "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.57.0 + "@rocket.chat/fuselage": ^0.57.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/ui-contexts": "workspace:~" @@ -10415,7 +10415,7 @@ __metadata: "@rocket.chat/css-in-js": ~0.31.25 "@rocket.chat/emitter": ~0.31.25 "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.57.0 + "@rocket.chat/fuselage": ^0.57.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/jest-presets": "workspace:~" @@ -10448,8 +10448,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 6.0.0-rc.0 - "@rocket.chat/ui-contexts": 10.0.0-rc.0 + "@rocket.chat/ui-avatar": 6.0.0-rc.1 + "@rocket.chat/ui-contexts": 10.0.0-rc.1 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10464,7 +10464,7 @@ __metadata: "@codemirror/tooltip": ^0.19.16 "@lezer/highlight": ^1.1.6 "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.57.0 + "@rocket.chat/fuselage": ^0.57.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/fuselage-toastbar": ^0.33.0 @@ -10536,7 +10536,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 - "@rocket.chat/ui-contexts": 10.0.0-rc.0 + "@rocket.chat/ui-contexts": 10.0.0-rc.1 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 44f905e40f13fe7ee4cdf166bf5c8550d69fb698 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Fri, 30 Aug 2024 00:33:01 +0000 Subject: [PATCH 025/170] Release 6.12.0-rc.2 [no ci] --- .changeset/bump-patch-1724977971712.md | 5 +++ .changeset/pre.json | 3 ++ apps/meteor/CHANGELOG.md | 36 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 +++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 +++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 +++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 14 ++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 ++++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 +++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 +++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 +++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 +++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 ++++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 +++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 ++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/api-client/CHANGELOG.md | 10 ++++++ packages/api-client/package.json | 2 +- packages/apps/CHANGELOG.md | 10 ++++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 ++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 ++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 ++++++ packages/cron/package.json | 2 +- packages/ddp-client/CHANGELOG.md | 11 ++++++ packages/ddp-client/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 +++++++ packages/fuselage-ui-kit/package.json | 8 ++--- packages/gazzodown/CHANGELOG.md | 11 ++++++ packages/gazzodown/package.json | 6 ++-- packages/instance-status/CHANGELOG.md | 9 +++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 +++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 +++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 +++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 +++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 +++++ packages/ui-avatar/package.json | 4 +-- packages/ui-client/CHANGELOG.md | 9 +++++ packages/ui-client/package.json | 4 +-- packages/ui-contexts/CHANGELOG.md | 11 ++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 ++++++ packages/ui-video-conf/package.json | 6 ++-- packages/uikit-playground/CHANGELOG.md | 11 ++++++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 9 +++++ packages/web-ui-registration/package.json | 4 +-- 68 files changed, 418 insertions(+), 44 deletions(-) create mode 100644 .changeset/bump-patch-1724977971712.md diff --git a/.changeset/bump-patch-1724977971712.md b/.changeset/bump-patch-1724977971712.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1724977971712.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/pre.json b/.changeset/pre.json index f23c7ae178fa..b16c34f330cd 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -66,6 +66,7 @@ "bright-humans-cross", "brown-crabs-chew", "bump-patch-1724712948901", + "bump-patch-1724977971712", "calm-tigers-peel", "cool-rocks-remember", "empty-toys-smell", @@ -89,8 +90,10 @@ "rotten-camels-pretend", "rude-dogs-burn", "six-beers-fry", + "smart-baboons-allow", "smart-mice-attack", "spicy-kings-think", + "strong-rings-rush", "strong-swans-double", "strong-terms-love", "stupid-fishes-relate", diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index 75b8e3e71df6..862232d77787 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,41 @@ # @rocket.chat/meteor +## 6.12.0-rc.2 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- ([#33169](https://github.com/RocketChat/Rocket.Chat/pull/33169)) Fixed issue that prevented sending encrypted filed from the mobile app + +- ([#33174](https://github.com/RocketChat/Rocket.Chat/pull/33174)) Restored tooltips to the unit edit department field selected options + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/license@0.2.5-rc.2 + - @rocket.chat/omnichannel-services@0.3.2-rc.2 + - @rocket.chat/pdf-worker@0.2.2-rc.2 + - @rocket.chat/presence@0.2.5-rc.2 + - @rocket.chat/api-client@0.2.5-rc.2 + - @rocket.chat/apps@0.1.5-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/cron@0.1.5-rc.2 + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.2 + - @rocket.chat/gazzodown@10.0.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/ui-contexts@10.0.0-rc.2 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.2-rc.2 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.2 + - @rocket.chat/ui-client@10.0.0-rc.2 + - @rocket.chat/ui-video-conf@10.0.0-rc.2 + - @rocket.chat/web-ui-registration@10.0.0-rc.2 + - @rocket.chat/instance-status@0.1.5-rc.2 +
+ ## 6.12.0-rc.1 ### Patch Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index 184b030fe19d..b88a04d76851 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.12.0-rc.1" + "version": "6.12.0-rc.2" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 5b8af0e9703c..1d6a25b73776 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.3.2-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 1.3.2-rc.1 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 6baf89d95ebf..8d9679014361 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.2-rc.1", + "version": "1.3.2-rc.2", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index ec9c06d820b6..ab76940fee8a 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.12.0-rc.1", + "version": "6.12.0-rc.2", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 9aec6081bf30..630cb593da8a 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.4.5-rc.1 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 6b4e12e0ae52..5a4b896658f0 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.5-rc.1", + "version": "0.4.5-rc.2", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index ee81e466ed3c..1c86327bd7c0 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.4.5-rc.1 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 723f97b071bf..f814e9e423ab 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.5-rc.1", + "version": "0.4.5-rc.2", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 80733d804be1..a8f4bf3e076b 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/ddp-streamer +## 0.3.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 + - @rocket.chat/instance-status@0.1.5-rc.2 +
+ ## 0.3.5-rc.1 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 60198b5a42e6..25203f96d8c3 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.5-rc.1", + "version": "0.3.5-rc.2", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 7f7f7945dd56..fa7eb91835b5 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/omnichannel-services@0.3.2-rc.2 + - @rocket.chat/pdf-worker@0.2.2-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.4.5-rc.1 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 2639125f3dc3..80e7c5456bd6 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.5-rc.1", + "version": "0.4.5-rc.2", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 853a25180cd4..80a6bc702eff 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/presence@0.2.5-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.4.5-rc.1 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 35f639b59890..83e816c9f0b4 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.5-rc.1", + "version": "0.4.5-rc.2", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index b39ed0a8815a..6e075a3b50f4 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/omnichannel-services@0.3.2-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.4.5-rc.1 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 1ed210871152..0c8281eaec2b 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.5-rc.1", + "version": "0.4.5-rc.2", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 9b5ce23e3638..7a6d5fa93c67 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.4.5-rc.1 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index d06a102d4de9..125ba400991c 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.5-rc.1", + "version": "0.4.5-rc.2", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index d851f26399a6..a3fb453b888f 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 +
+ ## 0.2.5-rc.1 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 2cbfc160c8cc..d357d2e85243 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.5-rc.1", + "version": "0.2.5-rc.2", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index ba0a528d36eb..51dd515e5a3a 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.2-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/pdf-worker@0.2.2-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.3.2-rc.1 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index f818090964b7..676576e42b3c 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.2-rc.1", + "version": "0.3.2-rc.2", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index 0a776c02449a..f9881b0273ff 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.2-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 +
+ ## 0.2.2-rc.1 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index af8f5977011e..8724b3d4d6e1 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.2-rc.1", + "version": "0.2.2-rc.2", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index 7beefdd32fe3..f211e5812b68 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/core-services@0.6.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.2.5-rc.1 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 4f9afd8c042f..530d53767c7a 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.5-rc.1", + "version": "0.2.5-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index 9268f2ba988a..fd4f9abcfc2f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.12.0-rc.1", + "version": "6.12.0-rc.2", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md index 838a08685baa..3694ba19c009 100644 --- a/packages/api-client/CHANGELOG.md +++ b/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 +
+ ## 0.2.5-rc.1 ### Patch Changes diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 7e289eef6146..d2f203161cb7 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.5-rc.1", + "version": "0.2.5-rc.2", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 413ec5b3af90..bc6dd6e55408 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/model-typings@0.7.0-rc.2 +
+ ## 0.1.5-rc.1 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index fec607e1f8ab..7b23ba55bcf9 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.5-rc.1", + "version": "0.1.5-rc.2", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index ae5e4b1aceb1..8f62112c8922 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.6.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.6.0-rc.1 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index b8a27cc8d0ab..a4e8ada23f19 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.6.0-rc.1", + "version": "0.6.0-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index 58236a95d7da..f9bb8458f37a 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.12.0-rc.2 + ## 6.12.0-rc.1 ## 6.12.0-rc.0 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 737fb013a0ff..eb9c2a47866a 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.12.0-rc.1", + "version": "6.12.0-rc.2", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 6e42bb323a59..6f684940f3c1 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.1.5-rc.1 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index c0908cb3e88e..78e1579405ec 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.5-rc.1", + "version": "0.1.5-rc.2", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/ddp-client/CHANGELOG.md b/packages/ddp-client/CHANGELOG.md index 2fb7c90d2327..9dcb8a73d04c 100644 --- a/packages/ddp-client/CHANGELOG.md +++ b/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ddp-client +## 0.3.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/api-client@0.2.5-rc.2 +
+ ## 0.3.5-rc.1 ### Patch Changes diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index 51a14bed4cba..89db267343fe 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.5-rc.1", + "version": "0.3.5-rc.2", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 12f56f72659c..30c34bf191b7 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 10.0.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/gazzodown@10.0.0-rc.2 + - @rocket.chat/ui-contexts@10.0.0-rc.2 + - @rocket.chat/ui-avatar@6.0.0-rc.2 + - @rocket.chat/ui-video-conf@10.0.0-rc.2 +
+ ## 10.0.0-rc.1 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index d35727e58af3..2dcfab40ce11 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "10.0.0-rc.1", + "version": "10.0.0-rc.2", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0-rc.1", - "@rocket.chat/ui-contexts": "10.0.0-rc.1", + "@rocket.chat/ui-avatar": "6.0.0-rc.2", + "@rocket.chat/ui-contexts": "10.0.0-rc.2", "@rocket.chat/ui-kit": "0.36.1-rc.0", - "@rocket.chat/ui-video-conf": "10.0.0-rc.1", + "@rocket.chat/ui-video-conf": "10.0.0-rc.2", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 2137661bff33..bfdcc3cf881f 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 10.0.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/ui-contexts@10.0.0-rc.2 + - @rocket.chat/ui-client@10.0.0-rc.2 +
+ ## 10.0.0-rc.1 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 57ff4d4dd142..64f33c6bbfd1 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "10.0.0-rc.1", + "version": "10.0.0-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -66,8 +66,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "10.0.0-rc.1", - "@rocket.chat/ui-contexts": "10.0.0-rc.1", + "@rocket.chat/ui-client": "10.0.0-rc.2", + "@rocket.chat/ui-contexts": "10.0.0-rc.2", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index 2965cdf9e189..a654321650cf 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.5-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.2.2-rc.2 +
+ ## 0.1.5-rc.1 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index f957756ad7cd..0e385002d153 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.5-rc.1", + "version": "0.1.5-rc.2", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index 9432f8055254..c4b6702ce273 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.19.2-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@10.0.0-rc.2 +
+ ## 1.19.2-rc.1 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 419b34b67604..8204d6478f4b 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.2-rc.1", + "version": "1.19.2-rc.2", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 6c090c3ff504..1e52e3e6f005 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.7.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 +
+ ## 0.7.0-rc.1 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index 2532ee5edf80..524d012e41a5 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.7.0-rc.1", + "version": "0.7.0-rc.2", "private": true, "devDependencies": { "@types/node-rsa": "^1.1.3", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 03bf4ac0a3fd..f7995184602a 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.2.2-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.7.0-rc.2 +
+ ## 0.2.2-rc.1 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index b4a07acb8cfd..4f32e1edbffa 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.2-rc.1", + "version": "0.2.2-rc.2", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 003368df6617..fab8b499954d 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.12.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 +
+ ## 6.12.0-rc.1 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index d037e77e7546..c11dc05cd6c2 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.12.0-rc.1", + "version": "6.12.0-rc.2", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index 1c917fd00821..52845ddff3be 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 6.0.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.2 +
+ ## 6.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index e673d1a5db06..b34b9e4891f4 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "6.0.0-rc.1", + "version": "6.0.0-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "10.0.0-rc.1", + "@rocket.chat/ui-contexts": "10.0.0-rc.2", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index a4b1f55300ee..a3d0b59dc6d9 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 10.0.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.2 +
+ ## 10.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index cc3b4df35bf4..13119376a79b 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "10.0.0-rc.1", + "version": "10.0.0-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -60,7 +60,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "10.0.0-rc.1", + "@rocket.chat/ui-contexts": "10.0.0-rc.2", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index e98fa6e55d91..37c1e0a5431c 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 10.0.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.2 + - @rocket.chat/rest-typings@6.12.0-rc.2 + - @rocket.chat/ddp-client@0.3.5-rc.2 +
+ ## 10.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index a5750b7d5065..0a5fbf4a83f2 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "10.0.0-rc.1", + "version": "10.0.0-rc.2", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 39e0237d1e49..e7f617bb3c07 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 10.0.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.2 + - @rocket.chat/ui-avatar@6.0.0-rc.2 +
+ ## 10.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 03db3dbecef4..f89db00eae82 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "10.0.0-rc.1", + "version": "10.0.0-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -40,8 +40,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0-rc.1", - "@rocket.chat/ui-contexts": "10.0.0-rc.1", + "@rocket.chat/ui-avatar": "6.0.0-rc.2", + "@rocket.chat/ui-contexts": "10.0.0-rc.2", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index 853ce4759b4d..0154c2a5d005 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.4.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.2 + - @rocket.chat/ui-contexts@10.0.0-rc.2 + - @rocket.chat/ui-avatar@6.0.0-rc.2 +
+ ## 0.4.0-rc.1 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 73cfd4369652..6a91a7681572 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.4.0-rc.1", + "version": "0.4.0-rc.2", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index e653ae6501ae..56bf9390b687 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 10.0.0-rc.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.2 +
+ ## 10.0.0-rc.1 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index ce73a83e6802..cb9c41903091 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "10.0.0-rc.1", + "version": "10.0.0-rc.2", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -47,7 +47,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "10.0.0-rc.1", + "@rocket.chat/ui-contexts": "10.0.0-rc.2", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From bb94c9c67a06a13461374cce1f27e1f7a28e64f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?= <60678893+juliajforesti@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:55:30 -0300 Subject: [PATCH 026/170] feat: add `sidepanelNavigation` to Feature preview list (#33156) --- .changeset/brown-singers-appear.md | 7 ++++++ .../AccountFeaturePreviewPage.tsx | 25 +++++++++++++++++-- packages/i18n/src/locales/en.i18n.json | 6 ++++- .../src/hooks/useFeaturePreviewList.ts | 20 ++++++++++++++- 4 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 .changeset/brown-singers-appear.md diff --git a/.changeset/brown-singers-appear.md b/.changeset/brown-singers-appear.md new file mode 100644 index 000000000000..8a9a69f225ac --- /dev/null +++ b/.changeset/brown-singers-appear.md @@ -0,0 +1,7 @@ +--- +'@rocket.chat/ui-client': minor +'@rocket.chat/i18n': minor +'@rocket.chat/meteor': minor +--- + +added `sidepanelNavigation` to feature preview list diff --git a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx index c8cd7138e5a6..dd9ab6a90959 100644 --- a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx +++ b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx @@ -24,6 +24,21 @@ import { useForm } from 'react-hook-form'; import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../../components/Page'; +const handleEnableQuery = (features: FeaturePreviewProps[]) => { + return features.map((item) => { + if (item.enableQuery) { + const expected = item.enableQuery.value; + const received = features.find((el) => el.name === item.enableQuery?.name)?.value; + if (expected !== received) { + item.disabled = true; + item.value = false; + } else { + item.disabled = false; + } + } + return item; + }); +}; const AccountFeaturePreviewPage = () => { const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); @@ -71,7 +86,7 @@ const AccountFeaturePreviewPage = () => { }; const grouppedFeaturesPreview = Object.entries( - featuresPreview.reduce((result, currentValue) => { + handleEnableQuery(featuresPreview).reduce((result, currentValue) => { (result[currentValue.group] = result[currentValue.group] || []).push(currentValue); return result; }, {} as Record), @@ -108,7 +123,13 @@ const AccountFeaturePreviewPage = () => { {t(feature.i18n)} - + {feature.description && {t(feature.description)}} diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 159c1641e05e..b28b1fc2bfde 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -6533,5 +6533,9 @@ "Sidebar_Sections_Order_Description": "Select the categories in your preferred order", "Incoming_Calls": "Incoming calls", "Advanced_settings": "Advanced settings", - "Security_and_permissions": "Security and permissions" + "Security_and_permissions": "Security and permissions", + "Sidepanel_navigation": "Sidepanel navigation for teams", + "Sidepanel_navigation_description": "Option to open a sidepanel with channels and/or discussions associated with the team. This allows team owners to customize communication methods to best meet their team’s needs. This feature is only available when Enhanced navigation experience is enabled.", + "Show_channels_description": "Show team channels in second sidebar", + "Show_discussions_description": "Show team discussions in second sidebar" } diff --git a/packages/ui-client/src/hooks/useFeaturePreviewList.ts b/packages/ui-client/src/hooks/useFeaturePreviewList.ts index 4e79eebbd13a..172045197f8c 100644 --- a/packages/ui-client/src/hooks/useFeaturePreviewList.ts +++ b/packages/ui-client/src/hooks/useFeaturePreviewList.ts @@ -6,7 +6,8 @@ export type FeaturesAvailable = | 'navigationBar' | 'enable-timestamp-message-parser' | 'contextualbarResizable' - | 'newNavigation'; + | 'newNavigation' + | 'sidepanelNavigation'; export type FeaturePreviewProps = { name: FeaturesAvailable; @@ -16,6 +17,11 @@ export type FeaturePreviewProps = { imageUrl?: string; value: boolean; enabled: boolean; + disabled?: boolean; + enableQuery?: { + name: FeaturesAvailable; + value: boolean; + }; }; export const defaultFeaturesPreview: FeaturePreviewProps[] = [ @@ -60,6 +66,18 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ value: false, enabled: true, }, + { + name: 'sidepanelNavigation', + i18n: 'Sidepanel_navigation', + description: 'Sidepanel_navigation_description', + group: 'Navigation', + value: false, + enabled: false, + enableQuery: { + name: 'newNavigation', + value: true, + }, + }, ]; export const enabledDefaultFeatures = defaultFeaturesPreview.filter((feature) => feature.enabled); From 377b8bbd945c4d9e5e36952f9ee58eaa6515a3bc Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Mon, 2 Sep 2024 11:16:59 -0300 Subject: [PATCH 027/170] refactor: Upgrade to TypeScript 5.5 (#33187) --- ...patch => typia-npm-6.9.0-2fd4d85f25.patch} | 248 ++++++++++-------- apps/meteor/client/hooks/useEndpointAction.ts | 2 +- apps/meteor/client/hooks/useEndpointData.ts | 4 +- apps/meteor/client/lib/createRouteGroup.tsx | 14 +- apps/meteor/client/lib/getLocalePercentage.ts | 9 +- .../providers/CallProvider/CallProvider.tsx | 4 +- .../DeviceProvider/DeviceProvider.tsx | 4 +- .../lib/isSetSinkIdAvailable.tsx | 4 +- .../client/providers/TranslationProvider.tsx | 2 +- .../client/views/admin/viewLogs/ansispan.ts | 15 +- apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 4 +- .../server/services/federation/Federation.ts | 4 +- ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/package.json | 2 +- ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/package.json | 2 +- ee/packages/ui-theming/package.json | 2 +- package.json | 3 +- packages/account-utils/package.json | 2 +- packages/agenda/package.json | 2 +- packages/api-client/package.json | 2 +- packages/apps/package.json | 2 +- packages/base64/package.json | 2 +- packages/cas-validate/package.json | 2 +- packages/core-services/package.json | 2 +- packages/core-typings/package.json | 2 +- packages/cron/package.json | 2 +- packages/ddp-client/package.json | 2 +- packages/favicon/package.json | 2 +- packages/fuselage-ui-kit/package.json | 2 +- packages/gazzodown/package.json | 2 +- packages/i18n/package.json | 2 +- packages/instance-status/package.json | 2 +- packages/jest-presets/package.json | 2 +- packages/jwt/package.json | 2 +- packages/livechat/package.json | 2 +- packages/log-format/package.json | 2 +- packages/logger/package.json | 2 +- packages/message-parser/package.json | 2 +- packages/mock-providers/package.json | 2 +- packages/model-typings/package.json | 2 +- packages/models/package.json | 2 +- packages/node-poplib/package.json | 2 +- packages/password-policies/package.json | 2 +- packages/patch-injection/package.json | 2 +- packages/peggy-loader/package.json | 2 +- packages/random/package.json | 2 +- packages/release-action/package.json | 2 +- packages/release-changelog/package.json | 2 +- packages/rest-typings/package.json | 2 +- .../server-cloud-communication/package.json | 2 +- packages/server-fetch/package.json | 2 +- packages/sha256/package.json | 2 +- packages/tools/package.json | 2 +- packages/ui-avatar/package.json | 2 +- packages/ui-client/package.json | 2 +- packages/ui-composer/package.json | 2 +- packages/ui-contexts/package.json | 2 +- packages/ui-contexts/src/DeviceContext.ts | 6 +- packages/ui-contexts/src/hooks/useEndpoint.ts | 2 +- .../src/hooks/useSetOutputMediaDevice.ts | 10 +- packages/ui-contexts/src/index.ts | 2 +- packages/ui-kit/package.json | 6 +- packages/ui-video-conf/package.json | 2 +- packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/package.json | 2 +- yarn.lock | 199 +++++++------- 75 files changed, 334 insertions(+), 320 deletions(-) rename .yarn/patches/{typia-npm-5.3.3-21d3e18463.patch => typia-npm-6.9.0-2fd4d85f25.patch} (64%) diff --git a/.yarn/patches/typia-npm-5.3.3-21d3e18463.patch b/.yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch similarity index 64% rename from .yarn/patches/typia-npm-5.3.3-21d3e18463.patch rename to .yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch index 1487a9f4712d..22a02fa15957 100644 --- a/.yarn/patches/typia-npm-5.3.3-21d3e18463.patch +++ b/.yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch @@ -1,22 +1,22 @@ diff --git a/lib/factories/internal/metadata/iterate_metadata_intersection.js b/lib/factories/internal/metadata/iterate_metadata_intersection.js -index 260670b8ea37b63dcacadeffa26450f81087c90e..f07b44b16099d896ab40c46f03df86ee2f2c1a90 100644 +index da05ef3ac6f397d68b8fa10285f62d1794c57579..0f2b9b26e01cebd0b9c04a2db8857f911cfbaf57 100644 --- a/lib/factories/internal/metadata/iterate_metadata_intersection.js +++ b/lib/factories/internal/metadata/iterate_metadata_intersection.js -@@ -247,7 +247,7 @@ var iterate_metadata_intersection = function (checker) { +@@ -181,7 +181,7 @@ var iterate_metadata_intersection = function (checker) { var tags = MetadataTypeTagFactory_1.MetadataTypeTagFactory.analyze(errors)(target)(objects.map(function (om) { return om.objects; }).flat(), explore); if (tags.length) if (target === "array") - meta.arrays.at(-1).tags.push(tags); + meta.arrays.slice(-1)[0].tags.push(tags); - else if (booleanLiteral === null) + else if (atomics.size) meta.atomics.find(function (a) { return a.type === target; }).tags.push(tags); - else { + else if (constants.length) { diff --git a/lib/programmers/CheckerProgrammer.js b/lib/programmers/CheckerProgrammer.js -index bbec09f22798d144b96f59bb946e7e32e3438c05..dc13cb47b72358b8e6165b768cff2360db2bd617 100644 +index 662e6ff51c91598229c88f691b7ce07200957167..4028a50cc92ee293e98b13822293d0fb35c64c1f 100644 --- a/lib/programmers/CheckerProgrammer.js +++ b/lib/programmers/CheckerProgrammer.js -@@ -458,8 +458,8 @@ var CheckerProgrammer; - ? "".concat(explore.postfix.slice(0, -1), "[").concat(index, "]\"") +@@ -529,8 +529,8 @@ var CheckerProgrammer; + ? "".concat((0, postfix_of_tuple_1.postfix_of_tuple)(explore.postfix), "[").concat(index, "]\"") : "\"[".concat(index, "]\"") })); }); - var rest = tuple.elements.length && tuple.elements.at(-1).rest !== null @@ -27,7 +27,7 @@ index bbec09f22798d144b96f59bb946e7e32e3438c05..dc13cb47b72358b8e6165b768cff2360 var arrayLength = typescript_1.default.factory.createPropertyAccessExpression(input, "length"); return config.combiner(explore)("and")(input, __spreadArray(__spreadArray(__spreadArray([], __read((rest === null diff --git a/lib/programmers/TypiaProgrammer.js b/lib/programmers/TypiaProgrammer.js -index c75ab1bc077b788e36c32834ea4916c22df34500..99452220e2dd090d4d562296e26fb266faa617f9 100644 +index db244cb5e40fd68e15b7a06936b0f92802e5e4c9..c2f64885f67cc543c62b0b09e141c88684f99253 100644 --- a/lib/programmers/TypiaProgrammer.js +++ b/lib/programmers/TypiaProgrammer.js @@ -165,7 +165,7 @@ var TypiaProgrammer; @@ -39,34 +39,53 @@ index c75ab1bc077b788e36c32834ea4916c22df34500..99452220e2dd090d4d562296e26fb266 })() : [0, 0], 2), line = _k[0], pos = _k[1]; console.error("".concat(file, ":").concat(line, ":").concat(pos, " - ").concat(category, " TS").concat(diag.code, ": ").concat(diag.messageText)); -diff --git a/lib/programmers/internal/application_tuple.js b/lib/programmers/internal/application_tuple.js -index 5c1853a3a1692f95fe702bdae9813e958f54ac4c..04ca996c2ffe72d1cd5969e45a38e91937b975b1 100644 ---- a/lib/programmers/internal/application_tuple.js -+++ b/lib/programmers/internal/application_tuple.js -@@ -22,15 +22,15 @@ var application_tuple = function (options) { - var schema = __assign(__assign({ type: "array", items: tuple.type.elements.map(function (meta, i) { - var _a; - return (0, application_schema_1.application_schema)(options)(false)(components)((_a = meta.rest) !== null && _a !== void 0 ? _a : meta)(__assign(__assign({}, attribute), { "x-typia-rest": i === tuple.type.elements.length - 1 && meta.rest !== null, "x-typia-required": meta.required, "x-typia-optional": meta.optional })); -- }) }, attribute), { minItems: !!((_a = tuple.type.elements.at(-1)) === null || _a === void 0 ? void 0 : _a.rest) -+ }) }, attribute), { minItems: !!((_a = tuple.type.elements.slice(-1)[0]) === null || _a === void 0 ? void 0 : _a.rest) - ? tuple.type.elements.length - 1 -- : tuple.type.elements.filter(function (x) { return !x.optional; }).length, maxItems: !!((_b = tuple.type.elements.at(-1)) === null || _b === void 0 ? void 0 : _b.rest) -+ : tuple.type.elements.filter(function (x) { return !x.optional; }).length, maxItems: !!((_b = tuple.type.elements.slice(-1)[0]) === null || _b === void 0 ? void 0 : _b.rest) - ? undefined - : tuple.type.elements.length }); - if (options.purpose === "ajv") - if (tuple.type.elements.length === 0) - return schema; -- else if (!((_c = tuple.type.elements.at(-1)) === null || _c === void 0 ? void 0 : _c.rest)) -+ else if (!((_c = tuple.type.elements.slice(-1)[0]) === null || _c === void 0 ? void 0 : _c.rest)) - return schema; - var wrapper = __assign(__assign({}, schema), { items: (0, application_schema_1.application_schema)(options)(false)(components)(tuple.type.elements.reduce(function (x, y) { var _a, _b; return Metadata_1.Metadata.merge((_a = x.rest) !== null && _a !== void 0 ? _a : x, (_b = y.rest) !== null && _b !== void 0 ? _b : y); }, Metadata_1.Metadata.initialize()))(tuple.type.recursive ? {} : attribute), "x-typia-tuple": schema, minItems: schema.minItems, maxItems: schema.maxItems }); - return wrapper; +diff --git a/lib/programmers/internal/application_v30_tuple.js b/lib/programmers/internal/application_v30_tuple.js +index 94e8827fd94df3792c1d7b2cdacac604175ba8ca..c9a3a1bcdd978b97a080ed2c467188d808d10c8f 100644 +--- a/lib/programmers/internal/application_v30_tuple.js ++++ b/lib/programmers/internal/application_v30_tuple.js +@@ -21,9 +21,9 @@ var application_v30_tuple = function (components) { + return function (tuple) { + return function (attribute) { + var _a, _b; +- return (__assign(__assign({}, attribute), { type: "array", items: (0, application_v30_schema_1.application_v30_schema)(false)(components)(tuple.type.recursive ? {} : attribute)(tuple.type.elements.reduce(function (x, y) { var _a, _b; return Metadata_1.Metadata.merge((_a = x.rest) !== null && _a !== void 0 ? _a : x, (_b = y.rest) !== null && _b !== void 0 ? _b : y); }, Metadata_1.Metadata.initialize())), minItems: !!((_a = tuple.type.elements.at(-1)) === null || _a === void 0 ? void 0 : _a.rest) ++ return (__assign(__assign({}, attribute), { type: "array", items: (0, application_v30_schema_1.application_v30_schema)(false)(components)(tuple.type.recursive ? {} : attribute)(tuple.type.elements.reduce(function (x, y) { var _a, _b; return Metadata_1.Metadata.merge((_a = x.rest) !== null && _a !== void 0 ? _a : x, (_b = y.rest) !== null && _b !== void 0 ? _b : y); }, Metadata_1.Metadata.initialize())), minItems: !!((_a = tuple.type.elements.slice(-1)[0]) === null || _a === void 0 ? void 0 : _a.rest) + ? tuple.type.elements.length - 1 +- : tuple.type.elements.filter(function (x) { return !x.optional; }).length, maxItems: !!((_b = tuple.type.elements.at(-1)) === null || _b === void 0 ? void 0 : _b.rest) ++ : tuple.type.elements.filter(function (x) { return !x.optional; }).length, maxItems: !!((_b = tuple.type.elements.slice(-1)[0]) === null || _b === void 0 ? void 0 : _b.rest) + ? undefined + : tuple.type.elements.length })); + }; +diff --git a/lib/programmers/internal/application_v31_tuple.js b/lib/programmers/internal/application_v31_tuple.js +index af7bbbe1536244eec93d7311e289fc8b34245c0f..e7f126b72a3480f761f57e4d43826a26b8b06e3f 100644 +--- a/lib/programmers/internal/application_v31_tuple.js ++++ b/lib/programmers/internal/application_v31_tuple.js +@@ -7,7 +7,7 @@ exports.application_v31_tuple = void 0; + var application_v31_tuple = function (generator) { + return function (tuple) { + var _a, _b; +- var tail = (_b = (_a = tuple.type.elements.at(-1)) === null || _a === void 0 ? void 0 : _a.rest) !== null && _b !== void 0 ? _b : null; ++ var tail = (_b = (_a = tuple.type.elements.slice(-1)[0]) === null || _a === void 0 ? void 0 : _a.rest) !== null && _b !== void 0 ? _b : null; + var prefixItems = tuple.type.isRest() + ? tuple.type.elements.slice(0, -1) + : tuple.type.elements; +diff --git a/lib/programmers/internal/decode_union_object.js b/lib/programmers/internal/decode_union_object.js +index c283bdfdcfb99f26954e6d76d35ccef4f78ddcee..7cdef1aeec80238014cf9457ca4351f02e99b638 100644 +--- a/lib/programmers/internal/decode_union_object.js ++++ b/lib/programmers/internal/decode_union_object.js +@@ -72,7 +72,7 @@ var iterate = function (escaper) { + ? typescript_1.default.factory.createIfStatement(b.condition, typescript_1.default.factory.createReturnStatement(b.value), undefined) + : typescript_1.default.factory.createReturnStatement(b.value); + }); +- if (branches.at(-1).condition !== null) ++ if (branches.slice(-1)[0].condition !== null) + statements.push(escaper(input, expected)); + return typescript_1.default.factory.createBlock(statements, true); + }; diff --git a/lib/programmers/json/JsonStringifyProgrammer.js b/lib/programmers/json/JsonStringifyProgrammer.js -index ce0ae787164f7eba68ef35b05232b4b94ad8e7d7..8f70cfc8c8e9d82cd1ec5004ca5637487f57b3bc 100644 +index 77f2812cb509f5b9093dc311f8ae8558e4469a74..54a6c4e22f9cfa87cd30f8ade50e6cb8ccda9957 100644 --- a/lib/programmers/json/JsonStringifyProgrammer.js +++ b/lib/programmers/json/JsonStringifyProgrammer.js -@@ -424,10 +424,10 @@ var JsonStringifyProgrammer; +@@ -469,10 +469,10 @@ var JsonStringifyProgrammer; var rest = (function () { if (tuple.elements.length === 0) return null; @@ -80,10 +99,10 @@ index ce0ae787164f7eba68ef35b05232b4b94ad8e7d7..8f70cfc8c8e9d82cd1ec5004ca563748 })(); return StringifyJoinder_1.StringifyJoiner.tuple(children, rest); diff --git a/lib/programmers/misc/MiscCloneProgrammer.js b/lib/programmers/misc/MiscCloneProgrammer.js -index 3db6bc92637284468c5fe47ef59f51a9b41d06eb..0b3fa9deaaadf28d4f348225c0d44f49700c1bca 100644 +index 38bec89fba26db7a9c3ee71abd49086692c7e78b..9b9d7a9b0606da78224ce083bcbd7e07cd6ce82e 100644 --- a/lib/programmers/misc/MiscCloneProgrammer.js +++ b/lib/programmers/misc/MiscCloneProgrammer.js -@@ -291,11 +291,11 @@ var MiscCloneProgrammer; +@@ -318,11 +318,11 @@ var MiscCloneProgrammer; var rest = (function () { if (tuple.elements.length === 0) return null; @@ -98,10 +117,10 @@ index 3db6bc92637284468c5fe47ef59f51a9b41d06eb..0b3fa9deaaadf28d4f348225c0d44f49 return CloneJoiner_1.CloneJoiner.tuple(children, rest); }; diff --git a/lib/programmers/misc/MiscPruneProgrammer.js b/lib/programmers/misc/MiscPruneProgrammer.js -index 8440aaba9e449dae2468e96dfd7035ac7e170cfc..e97ceec78427b7eed08db23cc4775fdb10c6b2ff 100644 +index d4a9c66c0b5508b4ffdc4b7684364a9d748f6508..33f9356bab69faffadb8c2b49997d2c3ca429810 100644 --- a/lib/programmers/misc/MiscPruneProgrammer.js +++ b/lib/programmers/misc/MiscPruneProgrammer.js -@@ -272,11 +272,11 @@ var MiscPruneProgrammer; +@@ -305,11 +305,11 @@ var MiscPruneProgrammer; var rest = (function () { if (tuple.elements.length === 0) return null; @@ -116,10 +135,10 @@ index 8440aaba9e449dae2468e96dfd7035ac7e170cfc..e97ceec78427b7eed08db23cc4775fdb return PruneJoiner_1.PruneJoiner.tuple(children, rest); }; diff --git a/lib/programmers/notations/NotationGeneralProgrammer.js b/lib/programmers/notations/NotationGeneralProgrammer.js -index 6e0b582a802180d7671c00b999469e7e59193b30..f11cc1d523875a040d3e27ce9a850b083c5d0275 100644 +index dfe64a21a5a81a7e887ab5ae02d73e6d3bdddb03..aa4b6070ed6a83c49018384e3a0c1dbd4a7c540b 100644 --- a/lib/programmers/notations/NotationGeneralProgrammer.js +++ b/lib/programmers/notations/NotationGeneralProgrammer.js -@@ -301,11 +301,11 @@ var NotationGeneralProgrammer; +@@ -328,11 +328,11 @@ var NotationGeneralProgrammer; var rest = (function () { if (tuple.elements.length === 0) return null; @@ -134,36 +153,36 @@ index 6e0b582a802180d7671c00b999469e7e59193b30..f11cc1d523875a040d3e27ce9a850b08 return NotationJoiner_1.NotationJoiner.tuple(children, rest); }; diff --git a/lib/transformers/CallExpressionTransformer.js b/lib/transformers/CallExpressionTransformer.js -index 2c5a23879d171ee271ebf6857dc9c65ec29c0ea7..96a40845614f6c54fe8e4ebc48a7d8efeba52a41 100644 +index f7be23d98552526d8c2348ba0f3d32b8d31e522b..133af0caa37ffcf7330811ef7bda79e75b9ecd89 100644 --- a/lib/transformers/CallExpressionTransformer.js +++ b/lib/transformers/CallExpressionTransformer.js -@@ -101,7 +101,7 @@ var CallExpressionTransformer; - var location = path_1.default.resolve(declaration.getSourceFile().fileName); - if (isTarget(location) === false) - return expression; +@@ -129,7 +129,7 @@ var CallExpressionTransformer; + // TRANSFORMATION + //---- + // FUNCTION NAME - var module = location.split(path_1.default.sep).at(-1).split(".")[0]; + var module = location.split(path_1.default.sep).slice(-1)[0].split(".")[0]; var name = project.checker.getTypeAtLocation(declaration).symbol.name; + // FIND TRANSFORMER var functor = (_b = FUNCTORS[module]) === null || _b === void 0 ? void 0 : _b[name]; - if (functor === undefined) diff --git a/src/factories/internal/metadata/iterate_metadata_intersection.ts b/src/factories/internal/metadata/iterate_metadata_intersection.ts -index f46caa25c987092597073e046ae3b9e8130bd994..1eedd727c74f173a5b98a9572b865e058885811d 100644 +index c4d93a961385c09abb6f448896ad4636b648703b..99b1547e6a501caf28a452390fe721cd47dc2ca1 100644 --- a/src/factories/internal/metadata/iterate_metadata_intersection.ts +++ b/src/factories/internal/metadata/iterate_metadata_intersection.ts -@@ -214,7 +214,7 @@ export const iterate_metadata_intersection = +@@ -188,7 +188,7 @@ export const iterate_metadata_intersection = target, )(objects.map((om) => om.objects).flat(), explore); if (tags.length) - if (target === "array") meta.arrays.at(-1)!.tags.push(tags); + if (target === "array") meta.arrays.slice(-1)[0]!.tags.push(tags); - else if (booleanLiteral === null) + else if (atomics.size) meta.atomics.find((a) => a.type === target)!.tags.push(tags); - else { + else if (constants.length) { diff --git a/src/programmers/CheckerProgrammer.ts b/src/programmers/CheckerProgrammer.ts -index 892748b80755b89d1449f4d515aa3166534c6b19..8cb5ce35fe6f918545c82066f0583dead2661c89 100644 +index 40f46e8212a5173e19e0214422086655de908933..18a1a2371cac697e1b621a8fbc6b090b691e3072 100644 --- a/src/programmers/CheckerProgrammer.ts +++ b/src/programmers/CheckerProgrammer.ts -@@ -702,14 +702,14 @@ export namespace CheckerProgrammer { +@@ -785,14 +785,14 @@ export namespace CheckerProgrammer { ), ); const rest: ts.Expression | null = @@ -181,47 +200,66 @@ index 892748b80755b89d1449f4d515aa3166534c6b19..8cb5ce35fe6f918545c82066f0583dea ...explore, start: tuple.elements.length - 1, diff --git a/src/programmers/TypiaProgrammer.ts b/src/programmers/TypiaProgrammer.ts -index e01eccf62eccd73e1f0720db897f539256a6bbc1..cae5eb6fc702d359d4886acefdb68d42691edf97 100644 +index 67d9fc138483832aae43574fd2753bbe40a27d14..4397517aa620a8733c51917eebfa467f2922bf6d 100644 --- a/src/programmers/TypiaProgrammer.ts +++ b/src/programmers/TypiaProgrammer.ts @@ -101,7 +101,7 @@ export namespace TypiaProgrammer { - .file!.text.substring(0, diag.start) - .split("\n"); - if (lines.length === 0) return [0, 0]; -- return [lines.length, lines.at(-1)!.length + 1]; -+ return [lines.length, lines.slice(-1)[0]!.length + 1]; - })() - : [0, 0]; - console.error( -diff --git a/src/programmers/internal/application_tuple.ts b/src/programmers/internal/application_tuple.ts -index 5e10b9051e4a846f298aa8f086109e8d6bb38bf9..a8e24d5c2a2a4a4d5d1dc49eb45b4784654a4b66 100644 ---- a/src/programmers/internal/application_tuple.ts -+++ b/src/programmers/internal/application_tuple.ts -@@ -28,16 +28,16 @@ export const application_tuple = - }), + .file!.text.substring(0, diag.start) + .split("\n"); + if (lines.length === 0) return [0, 0]; +- return [lines.length, lines.at(-1)!.length + 1]; ++ return [lines.length, lines.slice(-1)[0]!.length + 1]; + })() + : [0, 0]; + console.error( +diff --git a/src/programmers/internal/application_v30_tuple.ts b/src/programmers/internal/application_v30_tuple.ts +index 0431273d439c6069a1bb5fbfd7808c5e8d0ea255..4b27cfc3ebde7ce9dcdb5161d34e70004a327b1e 100644 +--- a/src/programmers/internal/application_v30_tuple.ts ++++ b/src/programmers/internal/application_v30_tuple.ts +@@ -24,10 +24,10 @@ export const application_v30_tuple = + Metadata.initialize(), ), - ...attribute, -- minItems: !!tuple.type.elements.at(-1)?.rest -+ minItems: !!tuple.type.elements.slice(-1)[0]?.rest - ? tuple.type.elements.length - 1 - : tuple.type.elements.filter((x) => !x.optional).length, -- maxItems: !!tuple.type.elements.at(-1)?.rest -+ maxItems: !!tuple.type.elements.slice(-1)[0]?.rest - ? undefined - : tuple.type.elements.length, - }; - if (options.purpose === "ajv") - if (tuple.type.elements.length === 0) return schema; -- else if (!tuple.type.elements.at(-1)?.rest) return schema; -+ else if (!tuple.type.elements.slice(-1)[0]?.rest) return schema; - - const wrapper: IJsonSchema.IArray = { - ...schema, + ), +- minItems: !!tuple.type.elements.at(-1)?.rest ++ minItems: !!tuple.type.elements.slice(-1)[0]?.rest + ? tuple.type.elements.length - 1 + : tuple.type.elements.filter((x) => !x.optional).length, +- maxItems: !!tuple.type.elements.at(-1)?.rest ++ maxItems: !!tuple.type.elements.slice(-1)[0]?.rest + ? undefined! + : tuple.type.elements.length, + }); +diff --git a/src/programmers/internal/application_v31_tuple.ts b/src/programmers/internal/application_v31_tuple.ts +index 426abad3423de706c368b35b2cf6b4845f6f3d91..be15ec0fda1725bf1ea882c9901e0f837c052fde 100644 +--- a/src/programmers/internal/application_v31_tuple.ts ++++ b/src/programmers/internal/application_v31_tuple.ts +@@ -9,7 +9,7 @@ import { MetadataTuple } from "../../schemas/metadata/MetadataTuple"; + export const application_v31_tuple = + (generator: (meta: Metadata) => OpenApi.IJsonSchema) => + (tuple: MetadataTuple): OpenApi.IJsonSchema.ITuple => { +- const tail: Metadata | null = tuple.type.elements.at(-1)?.rest ?? null; ++ const tail: Metadata | null = tuple.type.elements.slice(-1)[0]?.rest ?? null; + const prefixItems: Metadata[] = tuple.type.isRest() + ? tuple.type.elements.slice(0, -1) + : tuple.type.elements; +diff --git a/src/programmers/internal/decode_union_object.ts b/src/programmers/internal/decode_union_object.ts +index f60bf69f91f35dee2efc807475fd6eca71aab052..ef8d51160f7eb9853ec0c827827aaa6c65db1587 100644 +--- a/src/programmers/internal/decode_union_object.ts ++++ b/src/programmers/internal/decode_union_object.ts +@@ -87,7 +87,7 @@ const iterate = + ) + : ts.factory.createReturnStatement(b.value), + ); +- if (branches.at(-1)!.condition !== null) ++ if (branches.slice(-1)[0]!.condition !== null) + statements.push(escaper(input, expected)); + return ts.factory.createBlock(statements, true); + }; diff --git a/src/programmers/json/JsonStringifyProgrammer.ts b/src/programmers/json/JsonStringifyProgrammer.ts -index c317cec2c78e984a6e64c7bf287d0c67e530e309..5974830c62dbd2b865aa2e64e2e757283258d872 100644 +index 558e5bf4b79f5cc28791ba0f5e40ebe6599361ce..c43d77b5d15343af90f7362d1757fc758659d5c9 100644 --- a/src/programmers/json/JsonStringifyProgrammer.ts +++ b/src/programmers/json/JsonStringifyProgrammer.ts -@@ -543,7 +543,7 @@ export namespace JsonStringifyProgrammer { +@@ -560,7 +560,7 @@ export namespace JsonStringifyProgrammer { ); const rest = (() => { if (tuple.elements.length === 0) return null; @@ -230,7 +268,7 @@ index c317cec2c78e984a6e64c7bf287d0c67e530e309..5974830c62dbd2b865aa2e64e2e75728 if (last.rest === null) return null; const code = decode(project)(config)(importer)( -@@ -552,7 +552,7 @@ export namespace JsonStringifyProgrammer { +@@ -569,7 +569,7 @@ export namespace JsonStringifyProgrammer { undefined, [ExpressionFactory.number(tuple.elements.length - 1)], ), @@ -240,10 +278,10 @@ index c317cec2c78e984a6e64c7bf287d0c67e530e309..5974830c62dbd2b865aa2e64e2e75728 ...explore, start: tuple.elements.length - 1, diff --git a/src/programmers/misc/MiscCloneProgrammer.ts b/src/programmers/misc/MiscCloneProgrammer.ts -index 94d768b0a0738c0caccd711671351d1f22fa3848..739fd5f2baf4d2eb8e9dd65d73179242a0244707 100644 +index c8c9cb90085eff7dd68ac332a362674ca33d93d8..76a810816bc4ad57ff5e1787a33cd7f01471ffbe 100644 --- a/src/programmers/misc/MiscCloneProgrammer.ts +++ b/src/programmers/misc/MiscCloneProgrammer.ts -@@ -343,7 +343,7 @@ export namespace MiscCloneProgrammer { +@@ -395,7 +395,7 @@ export namespace MiscCloneProgrammer { const rest = (() => { if (tuple.elements.length === 0) return null; @@ -252,7 +290,7 @@ index 94d768b0a0738c0caccd711671351d1f22fa3848..739fd5f2baf4d2eb8e9dd65d73179242 const rest: Metadata | null = last.rest; if (rest === null) return null; -@@ -353,7 +353,7 @@ export namespace MiscCloneProgrammer { +@@ -405,7 +405,7 @@ export namespace MiscCloneProgrammer { undefined, [ExpressionFactory.number(tuple.elements.length - 1)], ), @@ -262,10 +300,10 @@ index 94d768b0a0738c0caccd711671351d1f22fa3848..739fd5f2baf4d2eb8e9dd65d73179242 ...explore, start: tuple.elements.length - 1, diff --git a/src/programmers/misc/MiscPruneProgrammer.ts b/src/programmers/misc/MiscPruneProgrammer.ts -index ed1465267066e382ae6696a25a806c2489597593..661f3cd93ae66070c978bd3e8d2b8db07189fe47 100644 +index 1051204a00041ddfb39da9de77b35ab8b44b75ee..73db30fdc06955f43dc2f563cbfc174e50a1bc6f 100644 --- a/src/programmers/misc/MiscPruneProgrammer.ts +++ b/src/programmers/misc/MiscPruneProgrammer.ts -@@ -310,7 +310,7 @@ export namespace MiscPruneProgrammer { +@@ -347,7 +347,7 @@ export namespace MiscPruneProgrammer { const rest = (() => { if (tuple.elements.length === 0) return null; @@ -274,7 +312,7 @@ index ed1465267066e382ae6696a25a806c2489597593..661f3cd93ae66070c978bd3e8d2b8db0 const rest: Metadata | null = last.rest; if (rest === null || filter(rest) === false) return null; -@@ -320,7 +320,7 @@ export namespace MiscPruneProgrammer { +@@ -357,7 +357,7 @@ export namespace MiscPruneProgrammer { undefined, [ExpressionFactory.number(tuple.elements.length - 1)], ), @@ -284,10 +322,10 @@ index ed1465267066e382ae6696a25a806c2489597593..661f3cd93ae66070c978bd3e8d2b8db0 ...explore, start: tuple.elements.length - 1, diff --git a/src/programmers/notations/NotationGeneralProgrammer.ts b/src/programmers/notations/NotationGeneralProgrammer.ts -index bd49b1e34002b1a1ec4f5444a8f91fa0ab794360..71d676de290986045910602ab10c6ef09a19c07d 100644 +index d8b2e22a8f9f3bfcb8f3e7987edaa7bf19a48720..96632214cb02b1534dc1987a0f892a3bf41e892f 100644 --- a/src/programmers/notations/NotationGeneralProgrammer.ts +++ b/src/programmers/notations/NotationGeneralProgrammer.ts -@@ -353,7 +353,7 @@ export namespace NotationGeneralProgrammer { +@@ -411,7 +411,7 @@ export namespace NotationGeneralProgrammer { const rest = (() => { if (tuple.elements.length === 0) return null; @@ -296,7 +334,7 @@ index bd49b1e34002b1a1ec4f5444a8f91fa0ab794360..71d676de290986045910602ab10c6ef0 const rest: Metadata | null = last.rest; if (rest === null) return null; -@@ -363,7 +363,7 @@ export namespace NotationGeneralProgrammer { +@@ -421,7 +421,7 @@ export namespace NotationGeneralProgrammer { undefined, [ExpressionFactory.number(tuple.elements.length - 1)], ), @@ -306,15 +344,15 @@ index bd49b1e34002b1a1ec4f5444a8f91fa0ab794360..71d676de290986045910602ab10c6ef0 ...explore, start: tuple.elements.length - 1, diff --git a/src/transformers/CallExpressionTransformer.ts b/src/transformers/CallExpressionTransformer.ts -index c58a1b143ce4f204bb249a4858c9d16a26f97408..9e9ffcf73e4c01aa6ac8c213669fdcd50e0181b9 100644 +index 99a4604f1a1944336b4d93dc61390269c346c243..c31ba72f1d206c441d6c237314a1c4d5c808dd09 100644 --- a/src/transformers/CallExpressionTransformer.ts +++ b/src/transformers/CallExpressionTransformer.ts -@@ -111,7 +111,7 @@ export namespace CallExpressionTransformer { - // TRANSFORMATION - //---- - // FUNCTION NAME -- const module: string = location.split(path.sep).at(-1)!.split(".")[0]!; -+ const module: string = location.split(path.sep).slice(-1)[0]!.split(".")[0]!; - const { name } = project.checker.getTypeAtLocation(declaration).symbol; - - // FIND TRANSFORMER +@@ -131,7 +131,7 @@ export namespace CallExpressionTransformer { + // TRANSFORMATION + //---- + // FUNCTION NAME +- const module: string = location.split(path.sep).at(-1)!.split(".")[0]!; ++ const module: string = location.split(path.sep).slice(-1)[0]!.split(".")[0]!; + const { name } = project.checker.getTypeAtLocation(declaration).symbol; + + // FIND TRANSFORMER diff --git a/apps/meteor/client/hooks/useEndpointAction.ts b/apps/meteor/client/hooks/useEndpointAction.ts index c7c371a04e1f..2cfb22b18548 100644 --- a/apps/meteor/client/hooks/useEndpointAction.ts +++ b/apps/meteor/client/hooks/useEndpointAction.ts @@ -15,7 +15,7 @@ type UseEndpointActionOptions = (undefined ext export function useEndpointAction( method: TMethod, pathPattern: TPathPattern, - options: UseEndpointActionOptions = { keys: {} as UrlParams }, + options: NoInfer> = { keys: {} as UrlParams }, ) { const sendData = useEndpoint(method, pathPattern, options.keys as UrlParams); diff --git a/apps/meteor/client/hooks/useEndpointData.ts b/apps/meteor/client/hooks/useEndpointData.ts index 6e759ad587e5..93942946ede0 100644 --- a/apps/meteor/client/hooks/useEndpointData.ts +++ b/apps/meteor/client/hooks/useEndpointData.ts @@ -20,11 +20,11 @@ const deprecationWarning = log('useEndpointData is deprecated, use @tanstack/rea */ export const useEndpointData = ( endpoint: TPathPattern, - options: { + options: NoInfer<{ keys?: UrlParams; params?: OperationParams<'GET', TPathPattern>; initialValue?: Serialized> | (() => Serialized>); - } = {}, + }> = {}, ): AsyncState>> & { reload: () => void; } => { diff --git a/apps/meteor/client/lib/createRouteGroup.tsx b/apps/meteor/client/lib/createRouteGroup.tsx index e418ecc56e99..70eab4782dd1 100644 --- a/apps/meteor/client/lib/createRouteGroup.tsx +++ b/apps/meteor/client/lib/createRouteGroup.tsx @@ -1,4 +1,4 @@ -import { type IRouterPaths, type RouteName, type RouterPathPattern } from '@rocket.chat/ui-contexts'; +import type { IRouterPaths, RouteName, RouterPathPattern } from '@rocket.chat/ui-contexts'; import React, { type ElementType, type ReactNode } from 'react'; import { router } from '../providers/RouterProvider'; @@ -9,21 +9,21 @@ type GroupName = 'omnichannel' | 'marketplace' | 'account' | 'admin'; type GroupPrefix = IRouterPaths[`${TGroupName}-index`]['pattern']; -type RouteNamesOf = Extract< +type RouteNamesOf = ( | keyof { [TRouteName in RouteName as IRouterPaths[TRouteName]['pattern'] extends `${GroupPrefix}/${string}` ? TRouteName : never]: never; } - | `${GroupName}-index`, - RouteName ->; + | `${GroupName}-index` +) & + RouteName; -type TrimPrefix = T extends `${P}${infer U}` ? U : T; +type TrimPrefix = T extends `${P}${infer U}` ? U : T; export const createRouteGroup = ( name: TGroupName, - prefix: GroupPrefix, + prefix: NoInfer>, RouterComponent: ElementType<{ children?: ReactNode; }>, diff --git a/apps/meteor/client/lib/getLocalePercentage.ts b/apps/meteor/client/lib/getLocalePercentage.ts index e6f2fa3bbff1..3aa84b59f03f 100644 --- a/apps/meteor/client/lib/getLocalePercentage.ts +++ b/apps/meteor/client/lib/getLocalePercentage.ts @@ -1,9 +1,6 @@ -export const getLocalePercentage = (locale: string, total: number, fraction: number, decimalCount = 2): string => { - const option = { +export const getLocalePercentage = (locale: string, total: number, fraction: number, decimalCount = 2) => + new Intl.NumberFormat(locale, { style: 'percent', minimumFractionDigits: decimalCount, maximumFractionDigits: decimalCount, - }; - - return new Intl.NumberFormat(locale, option).format(fraction / total); -}; + }).format(fraction / total); diff --git a/apps/meteor/client/providers/CallProvider/CallProvider.tsx b/apps/meteor/client/providers/CallProvider/CallProvider.tsx index f2c884aeb05f..6e728dc35eb6 100644 --- a/apps/meteor/client/providers/CallProvider/CallProvider.tsx +++ b/apps/meteor/client/providers/CallProvider/CallProvider.tsx @@ -11,7 +11,7 @@ import { } from '@rocket.chat/core-typings'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { Random } from '@rocket.chat/random'; -import type { Device, IExperimentalHTMLAudioElement } from '@rocket.chat/ui-contexts'; +import type { Device } from '@rocket.chat/ui-contexts'; import { useRouter, useUser, @@ -65,7 +65,7 @@ export const CallProvider = ({ children }: CallProviderProps) => { const hasVoIPEnterpriseLicense = useIsVoipEnterprise(); - const remoteAudioMediaRef = useRef(null); // TODO: Create a dedicated file for the AUDIO and make the controls accessible + const remoteAudioMediaRef = useRef(null); // TODO: Create a dedicated file for the AUDIO and make the controls accessible const [queueCounter, setQueueCounter] = useState(0); const [queueName, setQueueName] = useState(''); diff --git a/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx b/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx index 90ced3b0459a..c8fd77fa257b 100644 --- a/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx +++ b/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx @@ -1,5 +1,5 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import type { Device, IExperimentalHTMLAudioElement, DeviceContextValue } from '@rocket.chat/ui-contexts'; +import type { Device, DeviceContextValue } from '@rocket.chat/ui-contexts'; import { DeviceContext } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; import React, { useEffect, useState, useMemo } from 'react'; @@ -33,7 +33,7 @@ export const DeviceProvider = ({ children }: DeviceProviderProps): ReactElement }; const setAudioOutputDevice = useMutableCallback( - ({ outputDevice, HTMLAudioElement }: { outputDevice: Device; HTMLAudioElement: IExperimentalHTMLAudioElement }): void => { + ({ outputDevice, HTMLAudioElement }: { outputDevice: Device; HTMLAudioElement: HTMLAudioElement }): void => { if (!isSetSinkIdAvailable()) { throw new Error('setSinkId is not available in this browser'); } diff --git a/apps/meteor/client/providers/DeviceProvider/lib/isSetSinkIdAvailable.tsx b/apps/meteor/client/providers/DeviceProvider/lib/isSetSinkIdAvailable.tsx index 65bf99ed116f..2f835819afe6 100644 --- a/apps/meteor/client/providers/DeviceProvider/lib/isSetSinkIdAvailable.tsx +++ b/apps/meteor/client/providers/DeviceProvider/lib/isSetSinkIdAvailable.tsx @@ -1,6 +1,4 @@ -import type { IExperimentalHTMLAudioElement } from '@rocket.chat/ui-contexts'; - export const isSetSinkIdAvailable = (): boolean => { - const audio = new Audio() as IExperimentalHTMLAudioElement; + const audio = new Audio(); return !!audio.setSinkId; }; diff --git a/apps/meteor/client/providers/TranslationProvider.tsx b/apps/meteor/client/providers/TranslationProvider.tsx index 0c0ef00b5ac0..eb546c91c6bd 100644 --- a/apps/meteor/client/providers/TranslationProvider.tsx +++ b/apps/meteor/client/providers/TranslationProvider.tsx @@ -84,7 +84,7 @@ const useI18next = (lng: string): typeof i18next => { loadPath: 'i18n/{{lng}}.json', parse: (data: string, _lngs?: string | string[], namespaces: string | string[] = []) => extractTranslationKeys(JSON.parse(data), namespaces), - request: (_options, url, _payload, callback) => { + request: (_options: unknown, url: string, _payload: unknown, callback: (error: unknown, data: unknown) => void) => { const params = url.split('/'); const lng = params[params.length - 1]; diff --git a/apps/meteor/client/views/admin/viewLogs/ansispan.ts b/apps/meteor/client/views/admin/viewLogs/ansispan.ts index 7f1709e48ef2..8aa5bccb1195 100644 --- a/apps/meteor/client/views/admin/viewLogs/ansispan.ts +++ b/apps/meteor/client/views/admin/viewLogs/ansispan.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-control-regex */ const foregroundColors = { 30: 'var(--rcx-color-font-secondary-info, #6C727A)', 31: 'var(--rcx-color-font-danger, #D40C26)', @@ -16,13 +17,13 @@ export const ansispan = (str: string): string => { .replace(/>/g, '>') .replace(/$1') - .replace(/\033\[1m/g, '') - .replace(/\033\[22m/g, '') - .replace(/\033\[3m/g, '') - .replace(/\033\[23m/g, '') - .replace(/\033\[m/g, '') - .replace(/\033\[0m/g, '') - .replace(/\033\[39m/g, ''); + .replace(/\x1b\[1m/g, '') + .replace(/\x1b\[22m/g, '') + .replace(/\x1b\[3m/g, '') + .replace(/\x1b\[23m/g, '') + .replace(/\x1b\[m/g, '') + .replace(/\x1b\[0m/g, '') + .replace(/\x1b\[39m/g, ''); return Object.entries(foregroundColors).reduce((str, [ansiCode, color]) => { const span = ``; return str.replace(new RegExp(`\\033\\[${ansiCode}m`, 'g'), span).replace(new RegExp(`\\033\\[0;${ansiCode}m`, 'g'), span); diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 58b73351c4e0..27794da80e16 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -62,7 +62,7 @@ "pino-pretty": "^7.6.1", "pm2": "^5.2.0", "ts-node": "^10.9.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "volta": { "extends": "../../../package.json" diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 9c49c2cb33f8..b1230a0fa813 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -210,7 +210,7 @@ "supports-color": "~7.2.0", "template-file": "^6.0.1", "ts-node": "^10.9.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "dependencies": { "@babel/runtime": "~7.22.15", @@ -430,7 +430,7 @@ "turndown": "^7.1.2", "twilio": "^3.76.1", "twit": "^2.2.11", - "typia": "^5.3.3", + "typia": "~6.9.0", "ua-parser-js": "^1.0.37", "underscore": "^1.13.6", "universal-perf-hooks": "^1.0.1", diff --git a/apps/meteor/server/services/federation/Federation.ts b/apps/meteor/server/services/federation/Federation.ts index c8e2a9b1bc57..34331dc00971 100644 --- a/apps/meteor/server/services/federation/Federation.ts +++ b/apps/meteor/server/services/federation/Federation.ts @@ -17,7 +17,9 @@ const allowedActionsInFederatedRooms: ValueOf[] = [ RoomMemberActions.LEAVE, ]; -const allowedActionsForModerators = allowedActionsInFederatedRooms.filter((action) => action !== RoomMemberActions.SET_AS_OWNER); +const allowedActionsForModerators: ValueOf[] = allowedActionsInFederatedRooms.filter( + (action) => action !== RoomMemberActions.SET_AS_OWNER, +); const allowedRoomSettingsChangesInFederatedRooms: ValueOf[] = [RoomSettingsEnum.NAME, RoomSettingsEnum.TOPIC]; diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index ac28eb76e76d..c0c3dab2ef8c 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -45,7 +45,7 @@ "@types/polka": "^0.5.6", "eslint": "~8.45.0", "ts-node": "^10.9.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "main": "./dist/ee/apps/account-service/src/service.js", "files": [ diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index bff15e7f7d91..ab1429fd0223 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -41,7 +41,7 @@ "@types/polka": "^0.5.6", "eslint": "~8.45.0", "ts-node": "^10.9.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "main": "./dist/ee/apps/authorization-service/src/service.js", "files": [ diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 1687042e0d31..fab1967867da 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -57,7 +57,7 @@ "eslint": "~8.45.0", "pino-pretty": "^7.6.1", "ts-node": "^10.9.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "main": "./dist/service.js", "files": [ diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index c60542c180ec..959ea0605c02 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -47,7 +47,7 @@ "@types/polka": "^0.5.6", "eslint": "~8.45.0", "ts-node": "^10.9.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "main": "./dist/ee/apps/omnichannel-transcript/src/service.js", "files": [ diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index c800dd4d6c80..49653f0dcbaf 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -41,7 +41,7 @@ "@types/polka": "^0.5.6", "eslint": "~8.45.0", "ts-node": "^10.9.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "main": "./dist/ee/apps/presence-service/src/service.js", "files": [ diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 0a227cb271c0..19b252b70601 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -45,7 +45,7 @@ "@types/polka": "^0.5.6", "eslint": "~8.45.0", "ts-node": "^10.9.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "main": "./dist/ee/apps/queue-worker/src/service.js", "files": [ diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 812522a5f1d8..069e58586fe7 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -43,7 +43,7 @@ "@types/polka": "^0.5.6", "eslint": "~8.45.0", "ts-node": "^10.9.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "main": "./dist/ee/apps/stream-hub-service/src/service.js", "files": [ diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 1c746514d443..76d18fc35a8e 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -10,7 +10,7 @@ "eslint": "~8.45.0", "jest": "~29.7.0", "jest-websocket-mock": "~2.5.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "tsc", diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index f520d82bd7d3..6e9c80ae02ea 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -8,7 +8,7 @@ "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "dependencies": { "@rocket.chat/core-services": "workspace:^", diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 749d48ccc9c2..9c58aff464bd 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -14,7 +14,7 @@ "eslint": "~8.45.0", "jest": "~29.7.0", "react-dom": "~18.3.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "tsc -p tsconfig.build.json && cp -r src/public dist/public", diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 787eb2053007..997f80c60dd7 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -13,7 +13,7 @@ "babel-jest": "^29.0.3", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint src", diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json index 713265b36bfa..2c5e6c41267d 100644 --- a/ee/packages/ui-theming/package.json +++ b/ee/packages/ui-theming/package.json @@ -16,7 +16,7 @@ "eslint-plugin-testing-library": "^5.11.1", "react": "~17.0.2", "react-docgen-typescript-plugin": "~1.0.5", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/package.json b/package.json index 29de436373e2..7cb5f88cdbe9 100644 --- a/package.json +++ b/package.json @@ -64,8 +64,7 @@ "@storybook/react-docgen-typescript-plugin@1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0": "patch:@storybook/react-docgen-typescript-plugin@npm%3A1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0#./.yarn/patches/@storybook-react-docgen-typescript-plugin-npm-1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0-b31cc57c40.patch", "mongodb@^4.17.1": "patch:mongodb@npm:4.17.1#.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch", "@rocket.chat/forked-matrix-sdk-crypto-nodejs": "0.1.0-beta.13", - "typia@5.3.3": "patch:typia@npm:5.3.3#.yarn/patches/typia-npm-5.3.3-21d3e18463.patch", - "typia@~5.3.3": "patch:typia@npm%3A5.3.3#./.yarn/patches/typia-npm-5.3.3-21d3e18463.patch" + "typia@~6.9.0": "patch:typia@npm%3A6.9.0#./.yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch" }, "dependencies": { "node-gyp": "^9.4.1" diff --git a/packages/account-utils/package.json b/packages/account-utils/package.json index e33876a02d28..4ec6cd3bcab5 100644 --- a/packages/account-utils/package.json +++ b/packages/account-utils/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/agenda/package.json b/packages/agenda/package.json index 71b8b01bd6b0..f09921de6c31 100644 --- a/packages/agenda/package.json +++ b/packages/agenda/package.json @@ -14,7 +14,7 @@ "devDependencies": { "@types/debug": "^4.1.10", "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 43de20583d47..6d84bfe46f7e 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -8,7 +8,7 @@ "eslint": "~8.45.0", "jest": "~29.7.0", "jest-fetch-mock": "^3.0.3", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "tsc", diff --git a/packages/apps/package.json b/packages/apps/package.json index 816e271535df..4491237dc047 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/base64/package.json b/packages/base64/package.json index c58a652877a3..441fed0e06c1 100644 --- a/packages/base64/package.json +++ b/packages/base64/package.json @@ -21,7 +21,7 @@ "@typescript-eslint/parser": "~5.60.1", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "volta": { "extends": "../../package.json" diff --git a/packages/cas-validate/package.json b/packages/cas-validate/package.json index 769b74d38e56..a7cccb911781 100644 --- a/packages/cas-validate/package.json +++ b/packages/cas-validate/package.json @@ -5,7 +5,7 @@ "private": true, "devDependencies": { "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/core-services/package.json b/packages/core-services/package.json index fe1d4ef0dcea..281982a62c57 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -16,7 +16,7 @@ "jest": "~29.7.0", "mongodb": "^4.17.2", "prettier": "~2.8.8", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 34bdc67438ca..98d496c05054 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -7,7 +7,7 @@ "eslint": "~8.45.0", "mongodb": "^4.17.2", "prettier": "~2.8.8", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/cron/package.json b/packages/cron/package.json index a6484224ded5..3003eacb39dc 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index 9e4fdfd85910..5d8ef8867497 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -8,7 +8,7 @@ "eslint": "~8.45.0", "jest": "~29.7.0", "jest-websocket-mock": "~2.5.0", - "typescript": "~5.3.3", + "typescript": "~5.5.4", "ws": "^8.13.0" }, "peerDependencies": { diff --git a/packages/favicon/package.json b/packages/favicon/package.json index b61eaee02a68..67f5c6dcdfea 100644 --- a/packages/favicon/package.json +++ b/packages/favicon/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 9431a0c19d96..688033a1a7dc 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -106,7 +106,7 @@ "rimraf": "^3.0.2", "storybook-dark-mode": "~3.0.1", "tslib": "^2.5.3", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "dependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 6ecb49fa9544..d025320e6874 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -41,7 +41,7 @@ "outdent": "^0.8.0", "react-docgen-typescript-plugin": "~1.0.5", "react-dom": "~17.0.2", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "rm -rf dist && tsc -p tsconfig.build.json", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 6927aae08d1c..92fa97c42df7 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -7,7 +7,7 @@ "eslint": "~8.45.0", "jest": "~29.7.0", "tsup": "^6.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "node ./src/index.mjs", diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 088cba613d8e..f15a8feceff5 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -7,7 +7,7 @@ "eslint": "~8.45.0", "mongodb": "^4.17.2", "prettier": "~2.8.8", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/jest-presets/package.json b/packages/jest-presets/package.json index e6c0c9197bce..5fb2e26389a0 100644 --- a/packages/jest-presets/package.json +++ b/packages/jest-presets/package.json @@ -30,7 +30,7 @@ "@types/uuid": "^9", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.4.5" + "typescript": "~5.5.4" }, "volta": { "extends": "../../package.json" diff --git a/packages/jwt/package.json b/packages/jwt/package.json index a6d989e2c275..d945bd3a6f9c 100644 --- a/packages/jwt/package.json +++ b/packages/jwt/package.json @@ -7,7 +7,7 @@ "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "rm -rf dist && tsc", diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 9d40643dd4c5..073c2e999e42 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -85,7 +85,7 @@ "stylelint-order": "^5.0.0", "svg-loader": "^0.0.2", "terser-webpack-plugin": "~4.2.3", - "typescript": "~5.3.3", + "typescript": "~5.5.4", "url-loader": "^4.1.1", "webpack": "^5.89.0", "webpack-bundle-analyzer": "^4.9.1", diff --git a/packages/log-format/package.json b/packages/log-format/package.json index b43a3954a96f..f6f7c03b6f63 100644 --- a/packages/log-format/package.json +++ b/packages/log-format/package.json @@ -6,7 +6,7 @@ "@types/chalk": "^2.2.0", "@types/ejson": "^2.2.1", "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/logger/package.json b/packages/logger/package.json index aae996f35139..d073ebddbf49 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/message-parser/package.json b/packages/message-parser/package.json index fd7e88dc1d86..78ffd3401ff4 100644 --- a/packages/message-parser/package.json +++ b/packages/message-parser/package.json @@ -68,7 +68,7 @@ "rimraf": "^3.0.2", "ts-loader": "~9.4.2", "typedoc": "~0.24.1", - "typescript": "~5.3.3", + "typescript": "~5.5.4", "webpack": "~5.78.0", "webpack-cli": "~5.0.1" }, diff --git a/packages/mock-providers/package.json b/packages/mock-providers/package.json index 64310f0695cc..f5fba6c3b74b 100644 --- a/packages/mock-providers/package.json +++ b/packages/mock-providers/package.json @@ -17,7 +17,7 @@ "@types/use-sync-external-store": "^0.0.5", "eslint": "~8.45.0", "react": "~17.0.2", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "peerDependencies": { "@tanstack/react-query": "*", diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index f96764fa49af..13ee8c08b727 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -6,7 +6,7 @@ "@types/node-rsa": "^1.1.3", "eslint": "~8.45.0", "mongodb": "^4.17.2", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/models/package.json b/packages/models/package.json index 19f1f28438f6..6b0d1c0a6fe7 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -7,7 +7,7 @@ "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "^29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "dependencies": { "@rocket.chat/model-typings": "workspace:~" diff --git a/packages/node-poplib/package.json b/packages/node-poplib/package.json index a232d6b4c476..1d0c4c462e46 100644 --- a/packages/node-poplib/package.json +++ b/packages/node-poplib/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "main": "./src/index.js", "typings": "./dist/index.d.ts" diff --git a/packages/password-policies/package.json b/packages/password-policies/package.json index d53ffa1f5249..a2fef4ae0543 100644 --- a/packages/password-policies/package.json +++ b/packages/password-policies/package.json @@ -7,7 +7,7 @@ "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "rm -rf dist && tsc", diff --git a/packages/patch-injection/package.json b/packages/patch-injection/package.json index 99f676bff831..8dabf2fb3f2a 100644 --- a/packages/patch-injection/package.json +++ b/packages/patch-injection/package.json @@ -7,7 +7,7 @@ "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "rm -rf dist && tsc", diff --git a/packages/peggy-loader/package.json b/packages/peggy-loader/package.json index 5fa014da7f29..f0ac6d915567 100644 --- a/packages/peggy-loader/package.json +++ b/packages/peggy-loader/package.json @@ -50,7 +50,7 @@ "peggy": "3.0.2", "prettier": "~2.8.7", "rimraf": "^3.0.2", - "typescript": "~5.3.3", + "typescript": "~5.5.4", "webpack": "~5.78.0" }, "volta": { diff --git a/packages/random/package.json b/packages/random/package.json index 72fc8c5c566a..498e218338d9 100644 --- a/packages/random/package.json +++ b/packages/random/package.json @@ -23,7 +23,7 @@ "@typescript-eslint/parser": "~5.60.1", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "volta": { "extends": "../../package.json" diff --git a/packages/release-action/package.json b/packages/release-action/package.json index 0d17e4fb4221..e633ef69d06f 100644 --- a/packages/release-action/package.json +++ b/packages/release-action/package.json @@ -11,7 +11,7 @@ "packageManager": "yarn@3.5.1", "devDependencies": { "@types/node": "^16.18.60", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "dependencies": { "@actions/core": "^1.10.1", diff --git a/packages/release-changelog/package.json b/packages/release-changelog/package.json index 9e48d015b321..f183d00b550b 100644 --- a/packages/release-changelog/package.json +++ b/packages/release-changelog/package.json @@ -12,7 +12,7 @@ "@rocket.chat/eslint-config": "workspace:^", "@types/node": "^14.18.63", "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "dependencies": { "dataloader": "^1.4.0", diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 53bd1d2f5cb2..b5846800ad69 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -7,7 +7,7 @@ "eslint": "~8.45.0", "jest": "~29.7.0", "mongodb": "^4.17.2", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "rm -rf dist && tsc", diff --git a/packages/server-cloud-communication/package.json b/packages/server-cloud-communication/package.json index 8c970687ab8b..35e67a2c0638 100644 --- a/packages/server-cloud-communication/package.json +++ b/packages/server-cloud-communication/package.json @@ -5,7 +5,7 @@ "devDependencies": { "@rocket.chat/license": "workspace:^", "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "volta": { "extends": "../../package.json" diff --git a/packages/server-fetch/package.json b/packages/server-fetch/package.json index c98b4ba99e54..27f957758520 100644 --- a/packages/server-fetch/package.json +++ b/packages/server-fetch/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "eslint": "~8.45.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/sha256/package.json b/packages/sha256/package.json index 6d10f5b80d65..fb9e0d0d7f26 100644 --- a/packages/sha256/package.json +++ b/packages/sha256/package.json @@ -22,7 +22,7 @@ "@typescript-eslint/parser": "~5.60.1", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "volta": { "extends": "../../package.json" diff --git a/packages/tools/package.json b/packages/tools/package.json index d1301efb7055..11dade3ac5c8 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -7,7 +7,7 @@ "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 1c2dc6dabbc4..d315553b8d83 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -15,7 +15,7 @@ "eslint-plugin-storybook": "~0.6.15", "eslint-plugin-testing-library": "~5.11.1", "react": "^17.0.2", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index f43b2d8622b8..31492399dee9 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -37,7 +37,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-hook-form": "~7.45.4", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "scripts": { "build": "rm -rf dist && tsc -p tsconfig.build.json", diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index d854a6ffea86..a051bc16db23 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -38,7 +38,7 @@ "react": "~17.0.2", "react-docgen-typescript-plugin": "~1.0.5", "react-dom": "~17.0.2", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "peerDependencies": { "@react-aria/toolbar": "*", diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 513aebd86a30..b2954e61c9ec 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -16,7 +16,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "mongodb": "^4.17.2", "react": "~17.0.2", - "typescript": "~5.3.3", + "typescript": "~5.5.4", "use-sync-external-store": "^1.2.0" }, "peerDependencies": { diff --git a/packages/ui-contexts/src/DeviceContext.ts b/packages/ui-contexts/src/DeviceContext.ts index 483f03707f95..5bbda60cfcd5 100644 --- a/packages/ui-contexts/src/DeviceContext.ts +++ b/packages/ui-contexts/src/DeviceContext.ts @@ -6,10 +6,6 @@ export type Device = { type: string; }; -export interface IExperimentalHTMLAudioElement extends HTMLAudioElement { - setSinkId: (sinkId: string) => void; -} - type EnabledDeviceContextValue = { enabled: true; availableAudioOutputDevices: Device[]; @@ -18,7 +14,7 @@ type EnabledDeviceContextValue = { selectedAudioOutputDevice?: Device; selectedAudioInputDevice?: Device; // selectedVideoInputDevice?: Device; - setAudioOutputDevice: (data: { outputDevice: Device; HTMLAudioElement: IExperimentalHTMLAudioElement }) => void; + setAudioOutputDevice: (data: { outputDevice: Device; HTMLAudioElement: HTMLAudioElement }) => void; setAudioInputDevice: (device: Device) => void; // setVideoInputDevice: (device: Device) => void; }; diff --git a/packages/ui-contexts/src/hooks/useEndpoint.ts b/packages/ui-contexts/src/hooks/useEndpoint.ts index a0b7c977f2c6..3d29917c63e2 100644 --- a/packages/ui-contexts/src/hooks/useEndpoint.ts +++ b/packages/ui-contexts/src/hooks/useEndpoint.ts @@ -14,7 +14,7 @@ export type EndpointFunction( method: TMethod, pathPattern: TPathPattern, - ...[keys]: undefined extends UrlParams ? [keys?: UrlParams] : [keys: UrlParams] + ...[keys]: NoInfer ? [keys?: UrlParams] : [keys: UrlParams]> ): EndpointFunction { const { callEndpoint } = useContext(ServerContext); const keysRef = useRef(keys); diff --git a/packages/ui-contexts/src/hooks/useSetOutputMediaDevice.ts b/packages/ui-contexts/src/hooks/useSetOutputMediaDevice.ts index 7a68d7b10e0d..c3d6b9425876 100644 --- a/packages/ui-contexts/src/hooks/useSetOutputMediaDevice.ts +++ b/packages/ui-contexts/src/hooks/useSetOutputMediaDevice.ts @@ -1,17 +1,11 @@ import { useContext } from 'react'; -import type { Device, IExperimentalHTMLAudioElement } from '../DeviceContext'; +import type { Device } from '../DeviceContext'; import { DeviceContext, isDeviceContextEnabled } from '../DeviceContext'; // This allows different places to set the output device by providing a HTMLAudioElement -type setOutputMediaDevice = ({ - outputDevice, - HTMLAudioElement, -}: { - outputDevice: Device; - HTMLAudioElement: IExperimentalHTMLAudioElement; -}) => void; +type setOutputMediaDevice = ({ outputDevice, HTMLAudioElement }: { outputDevice: Device; HTMLAudioElement: HTMLAudioElement }) => void; export const useSetOutputMediaDevice = (): setOutputMediaDevice => { const context = useContext(DeviceContext); diff --git a/packages/ui-contexts/src/index.ts b/packages/ui-contexts/src/index.ts index e021eb840aa0..313710bbfd4e 100644 --- a/packages/ui-contexts/src/index.ts +++ b/packages/ui-contexts/src/index.ts @@ -14,7 +14,7 @@ export { ToastMessagesContext, ToastMessagesContextValue } from './ToastMessages export { TooltipContext, TooltipContextValue } from './TooltipContext'; export { TranslationContext, TranslationContextValue } from './TranslationContext'; export { UserContext, UserContextValue } from './UserContext'; -export { DeviceContext, Device, IExperimentalHTMLAudioElement, DeviceContextValue } from './DeviceContext'; +export { DeviceContext, Device, DeviceContextValue } from './DeviceContext'; export { ActionManagerContext, IActionManager } from './ActionManagerContext'; export { useAbsoluteUrl } from './hooks/useAbsoluteUrl'; diff --git a/packages/ui-kit/package.json b/packages/ui-kit/package.json index c7e8159d457d..ae42ec71b2a0 100644 --- a/packages/ui-kit/package.json +++ b/packages/ui-kit/package.json @@ -52,11 +52,11 @@ "ts-jest": "~29.1.1", "ts-loader": "~9.4.2", "ts-node": "~10.9.1", - "ts-patch": "~3.0.2", - "typescript": "~5.3.3" + "ts-patch": "~3.2.1", + "typescript": "~5.5.4" }, "dependencies": { - "typia": "~5.3.3" + "typia": "~6.9.0" }, "peerDependencies": { "@rocket.chat/icons": "*" diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 5e7d114a3576..befa3514509f 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -32,7 +32,7 @@ "jest": "~29.7.0", "jest-axe": "~9.0.0", "react-docgen-typescript-plugin": "~1.0.5", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "peerDependencies": { "@rocket.chat/css-in-js": "*", diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index f46f139a66f4..e29be5287b65 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -50,7 +50,7 @@ "eslint": "~8.45.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", - "typescript": "~5.3.3", + "typescript": "~5.5.4", "vite": "^4.3.9" }, "volta": { diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index ba3dc31423a6..4a9b4ac82a9c 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -42,7 +42,7 @@ "react-hook-form": "~7.45.4", "react-i18next": "~13.2.2", "storybook-dark-mode": "~3.0.1", - "typescript": "~5.3.3" + "typescript": "~5.5.4" }, "peerDependencies": { "@rocket.chat/layout": "*", diff --git a/yarn.lock b/yarn.lock index f2e902295848..7ef356f54646 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8433,7 +8433,7 @@ __metadata: pino: ^8.15.0 polka: ^0.5.2 ts-node: ^10.9.1 - typescript: ~5.3.3 + typescript: ~5.5.4 uuid: ^9.0.1 languageName: unknown linkType: soft @@ -8443,7 +8443,7 @@ __metadata: resolution: "@rocket.chat/account-utils@workspace:packages/account-utils" dependencies: eslint: ~8.45.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8459,7 +8459,7 @@ __metadata: human-interval: ^2.0.1 moment-timezone: ~0.5.43 mongodb: ^4.17.2 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8479,7 +8479,7 @@ __metadata: query-string: ^7.1.3 split-on-first: ^3.0.0 strict-uri-encode: ^2.0.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8513,7 +8513,7 @@ __metadata: "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/model-typings": "workspace:^" eslint: ~8.45.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8545,7 +8545,7 @@ __metadata: pino: ^8.15.0 polka: ^0.5.2 ts-node: ^10.9.1 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8561,7 +8561,7 @@ __metadata: "@typescript-eslint/parser": ~5.60.1 eslint: ~8.45.0 jest: ~29.7.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8571,7 +8571,7 @@ __metadata: dependencies: cheerio: 1.0.0-rc.10 eslint: ~8.45.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8601,7 +8601,7 @@ __metadata: jest: ~29.7.0 mongodb: ^4.17.2 prettier: ~2.8.8 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8617,7 +8617,7 @@ __metadata: eslint: ~8.45.0 mongodb: ^4.17.2 prettier: ~2.8.8 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8631,7 +8631,7 @@ __metadata: "@rocket.chat/random": "workspace:^" eslint: ~8.45.0 mongodb: ^4.17.2 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8670,7 +8670,7 @@ __metadata: eslint: ~8.45.0 jest: ~29.7.0 jest-websocket-mock: ~2.5.0 - typescript: ~5.3.3 + typescript: ~5.5.4 ws: ^8.13.0 peerDependencies: "@rocket.chat/emitter": "*" @@ -8718,7 +8718,7 @@ __metadata: polka: ^0.5.2 sharp: ^0.32.6 ts-node: ^10.9.1 - typescript: ~5.3.3 + typescript: ~5.5.4 underscore: ^1.13.6 uuid: ^7.0.3 ws: ^8.8.1 @@ -8758,7 +8758,7 @@ __metadata: resolution: "@rocket.chat/favicon@workspace:packages/favicon" dependencies: eslint: ~8.45.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8923,7 +8923,7 @@ __metadata: rimraf: ^3.0.2 storybook-dark-mode: ~3.0.1 tslib: ^2.5.3 - typescript: ~5.3.3 + typescript: ~5.5.4 peerDependencies: "@rocket.chat/apps-engine": "*" "@rocket.chat/eslint-config": 0.7.0 @@ -9012,7 +9012,7 @@ __metadata: react-docgen-typescript-plugin: ~1.0.5 react-dom: ~17.0.2 react-error-boundary: ^3.1.4 - typescript: ~5.3.3 + typescript: ~5.5.4 peerDependencies: "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/css-in-js": "*" @@ -9035,7 +9035,7 @@ __metadata: eslint: ~8.45.0 jest: ~29.7.0 tsup: ^6.7.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9055,7 +9055,7 @@ __metadata: eslint: ~8.45.0 mongodb: ^4.17.2 prettier: ~2.8.8 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9077,7 +9077,7 @@ __metadata: jest-axe: ~9.0.0 jest-environment-jsdom: ~29.7.0 jest-environment-node: ~29.7.0 - typescript: ~5.4.5 + typescript: ~5.5.4 uuid: ~9.0.1 languageName: unknown linkType: soft @@ -9091,7 +9091,7 @@ __metadata: eslint: ~8.45.0 jest: ~29.7.0 jose: ^4.14.4 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9122,7 +9122,7 @@ __metadata: eslint: ~8.45.0 jest: ~29.7.0 jest-websocket-mock: ~2.5.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9210,7 +9210,7 @@ __metadata: stylelint-order: ^5.0.0 svg-loader: ^0.0.2 terser-webpack-plugin: ~4.2.3 - typescript: ~5.3.3 + typescript: ~5.5.4 url-loader: ^4.1.1 webpack: ^5.89.0 webpack-bundle-analyzer: ^4.9.1 @@ -9232,7 +9232,7 @@ __metadata: chalk: ^4.0.0 ejson: ^2.2.3 eslint: ~8.45.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9243,7 +9243,7 @@ __metadata: "@rocket.chat/emitter": ~0.31.25 eslint: ~8.45.0 pino: ^8.15.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9292,7 +9292,7 @@ __metadata: tldts: ~5.7.112 ts-loader: ~9.4.2 typedoc: ~0.24.1 - typescript: ~5.3.3 + typescript: ~5.5.4 webpack: ~5.78.0 webpack-cli: ~5.0.1 languageName: unknown @@ -9665,8 +9665,8 @@ __metadata: turndown: ^7.1.2 twilio: ^3.76.1 twit: ^2.2.11 - typescript: ~5.3.3 - typia: ^5.3.3 + typescript: ~5.5.4 + typia: ~6.9.0 ua-parser-js: ^1.0.37 underscore: ^1.13.6 universal-perf-hooks: ^1.0.1 @@ -9698,7 +9698,7 @@ __metadata: i18next: ~23.4.9 react: ~17.0.2 react-i18next: ~13.2.2 - typescript: ~5.3.3 + typescript: ~5.5.4 use-sync-external-store: ~1.2.2 peerDependencies: "@tanstack/react-query": "*" @@ -9714,7 +9714,7 @@ __metadata: "@types/node-rsa": ^1.1.3 eslint: ~8.45.0 mongodb: ^4.17.2 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9727,7 +9727,7 @@ __metadata: "@types/jest": ~29.5.12 eslint: ~8.45.0 jest: ^29.7.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9770,7 +9770,7 @@ __metadata: mongo-message-queue: ^1.0.0 mongodb: ^4.17.2 pino: ^8.15.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9808,7 +9808,7 @@ __metadata: pino: ^8.15.0 polka: ^0.5.2 ts-node: ^10.9.1 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9841,7 +9841,7 @@ __metadata: "@types/jest": ~29.5.12 eslint: ~8.45.0 jest: ~29.7.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9853,7 +9853,7 @@ __metadata: "@types/jest": ~29.5.12 eslint: ~8.45.0 jest: ~29.7.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9880,7 +9880,7 @@ __metadata: moment-timezone: ^0.5.43 react: ~18.3.1 react-dom: ~18.3.1 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9896,7 +9896,7 @@ __metadata: peggy: 3.0.2 prettier: ~2.8.7 rimraf: ^3.0.2 - typescript: ~5.3.3 + typescript: ~5.5.4 webpack: ~5.78.0 peerDependencies: peggy: "*" @@ -9909,7 +9909,7 @@ __metadata: resolution: "@rocket.chat/poplib@workspace:packages/node-poplib" dependencies: eslint: ~8.45.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9941,7 +9941,7 @@ __metadata: pino: ^8.15.0 polka: ^0.5.2 ts-node: ^10.9.1 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9963,7 +9963,7 @@ __metadata: eslint: ~8.45.0 jest: ~29.7.0 mongodb: ^4.17.2 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10008,7 +10008,7 @@ __metadata: pino: ^8.15.0 polka: ^0.5.2 ts-node: ^10.9.1 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10024,7 +10024,7 @@ __metadata: "@typescript-eslint/parser": ~5.60.1 eslint: ~8.45.0 jest: ~29.7.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10043,7 +10043,7 @@ __metadata: remark-parse: 9.0.0 remark-stringify: 9.0.1 semver: ^7.5.2 - typescript: ~5.3.3 + typescript: ~5.5.4 unified: 9.2.2 languageName: unknown linkType: soft @@ -10058,7 +10058,7 @@ __metadata: dataloader: ^1.4.0 eslint: ~8.45.0 node-fetch: ^2 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10077,7 +10077,7 @@ __metadata: eslint: ~8.45.0 jest: ~29.7.0 mongodb: ^4.17.2 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10100,7 +10100,7 @@ __metadata: dependencies: "@rocket.chat/license": "workspace:^" eslint: ~8.45.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10114,7 +10114,7 @@ __metadata: https-proxy-agent: ^5.0.1 node-fetch: 2.3.0 proxy-from-env: ^1.1.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10130,7 +10130,7 @@ __metadata: "@typescript-eslint/parser": ~5.60.1 eslint: ~8.45.0 jest: ~29.7.0 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10164,7 +10164,7 @@ __metadata: pino: ^8.15.0 polka: ^0.5.2 ts-node: ^10.9.1 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10204,7 +10204,7 @@ __metadata: eslint: ~8.45.0 jest: ~29.7.0 moment-timezone: ^0.5.43 - typescript: ~5.3.3 + typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10224,7 +10224,7 @@ __metadata: eslint-plugin-storybook: ~0.6.15 eslint-plugin-testing-library: ~5.11.1 react: ^17.0.2 - typescript: ~5.3.3 + typescript: ~5.5.4 peerDependencies: "@rocket.chat/fuselage": "*" "@rocket.chat/ui-contexts": 9.0.0 @@ -10270,7 +10270,7 @@ __metadata: react: ^17.0.2 react-dom: ^17.0.2 react-hook-form: ~7.45.4 - typescript: ~5.3.3 + typescript: ~5.5.4 peerDependencies: "@react-aria/toolbar": "*" "@rocket.chat/css-in-js": "*" @@ -10308,7 +10308,7 @@ __metadata: react: ~17.0.2 react-docgen-typescript-plugin: ~1.0.5 react-dom: ~17.0.2 - typescript: ~5.3.3 + typescript: ~5.5.4 peerDependencies: "@react-aria/toolbar": "*" "@rocket.chat/fuselage": "*" @@ -10336,7 +10336,7 @@ __metadata: eslint-plugin-react-hooks: ^4.6.0 mongodb: ^4.17.2 react: ~17.0.2 - typescript: ~5.3.3 + typescript: ~5.5.4 use-sync-external-store: ^1.2.0 peerDependencies: "@rocket.chat/core-typings": "workspace:^" @@ -10371,9 +10371,9 @@ __metadata: ts-jest: ~29.1.1 ts-loader: ~9.4.2 ts-node: ~10.9.1 - ts-patch: ~3.0.2 - typescript: ~5.3.3 - typia: ~5.3.3 + ts-patch: ~3.2.1 + typescript: ~5.5.4 + typia: ~6.9.0 peerDependencies: "@rocket.chat/icons": "*" languageName: unknown @@ -10396,7 +10396,7 @@ __metadata: eslint-plugin-testing-library: ^5.11.1 react: ~17.0.2 react-docgen-typescript-plugin: ~1.0.5 - typescript: ~5.3.3 + typescript: ~5.5.4 peerDependencies: "@rocket.chat/css-in-js": "*" "@rocket.chat/fuselage": "*" @@ -10440,7 +10440,7 @@ __metadata: jest: ~29.7.0 jest-axe: ~9.0.0 react-docgen-typescript-plugin: ~1.0.5 - typescript: ~5.3.3 + typescript: ~5.5.4 peerDependencies: "@rocket.chat/css-in-js": "*" "@rocket.chat/fuselage": "*" @@ -10495,7 +10495,7 @@ __metadata: react-split-pane: ^0.1.92 react-virtuoso: ^4.7.1 reactflow: ^11.7.2 - typescript: ~5.3.3 + typescript: ~5.5.4 use-subscription: ^1.8.0 vite: ^4.3.9 languageName: unknown @@ -10531,7 +10531,7 @@ __metadata: react-hook-form: ~7.45.4 react-i18next: ~13.2.2 storybook-dark-mode: ~3.0.1 - typescript: ~5.3.3 + typescript: ~5.5.4 peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 @@ -10543,6 +10543,13 @@ __metadata: languageName: unknown linkType: soft +"@samchon/openapi@npm:^0.4.6": + version: 0.4.9 + resolution: "@samchon/openapi@npm:0.4.9" + checksum: a6fd35db27ebf3223c4793bd9a6669fc0e48ccbe522fa8eb26519073b897fb774cd652777e8d7d414bc19bf47ae03be227dfc2b65e2e1a5869c9723c5adad2e0 + languageName: node + linkType: hard + "@selderee/plugin-htmlparser2@npm:^0.6.0": version: 0.6.0 resolution: "@selderee/plugin-htmlparser2@npm:0.6.0" @@ -36734,7 +36741,7 @@ __metadata: sodium-native: ^3.3.0 sodium-plus: ^0.9.0 ts-node: ^10.9.1 - typescript: ~5.3.3 + typescript: ~5.5.4 uuid: ^8.3.2 ws: ^8.8.1 languageName: unknown @@ -37200,7 +37207,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.2, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4": +"semver@npm:^7.2, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4": version: 7.5.4 resolution: "semver@npm:7.5.4" dependencies: @@ -40047,20 +40054,20 @@ __metadata: languageName: node linkType: hard -"ts-patch@npm:~3.0.2": - version: 3.0.2 - resolution: "ts-patch@npm:3.0.2" +"ts-patch@npm:~3.2.1": + version: 3.2.1 + resolution: "ts-patch@npm:3.2.1" dependencies: chalk: ^4.1.2 global-prefix: ^3.0.0 minimist: ^1.2.8 resolve: ^1.22.2 - semver: ^7.3.8 + semver: ^7.5.4 strip-ansi: ^6.0.1 bin: ts-patch: bin/ts-patch.js tspc: bin/tspc.js - checksum: 09cdc54bf517b11d4b0de64515e9a0d7e71e238d6065b3c02a04280dc2683143cd810a9065046228571af0865a7d876a4a852ff9a909cb2cae8fe33b41e4eb81 + checksum: 8da4472dcd67b561a6299b54e30ab96181598edb90a97bc8dbe0066b28d706ec7402fee73496d25a281e2c4c94cb8e86d3b1592b1ca7591ea0b6cb48617ed19c languageName: node linkType: hard @@ -40544,75 +40551,57 @@ __metadata: languageName: node linkType: hard -"typescript@npm:~5.3.3": - version: 5.3.3 - resolution: "typescript@npm:5.3.3" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 2007ccb6e51bbbf6fde0a78099efe04dc1c3dfbdff04ca3b6a8bc717991862b39fd6126c0c3ebf2d2d98ac5e960bcaa873826bb2bb241f14277034148f41f6a2 - languageName: node - linkType: hard - -"typescript@npm:~5.4.5": - version: 5.4.5 - resolution: "typescript@npm:5.4.5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 53c879c6fa1e3bcb194b274d4501ba1985894b2c2692fa079db03c5a5a7140587a1e04e1ba03184605d35f439b40192d9e138eb3279ca8eee313c081c8bcd9b0 - languageName: node - linkType: hard - -"typescript@patch:typescript@~5.3.3#~builtin": - version: 5.3.3 - resolution: "typescript@patch:typescript@npm%3A5.3.3#~builtin::version=5.3.3&hash=85af82" +"typescript@npm:~5.5.4": + version: 5.5.4 + resolution: "typescript@npm:5.5.4" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: f61375590b3162599f0f0d5b8737877ac0a7bc52761dbb585d67e7b8753a3a4c42d9a554c4cc929f591ffcf3a2b0602f65ae3ce74714fd5652623a816862b610 + checksum: b309040f3a1cd91c68a5a58af6b9fdd4e849b8c42d837b2c2e73f9a4f96a98c4f1ed398a9aab576ee0a4748f5690cf594e6b99dbe61de7839da748c41e6d6ca8 languageName: node linkType: hard -"typescript@patch:typescript@~5.4.5#~builtin": - version: 5.4.5 - resolution: "typescript@patch:typescript@npm%3A5.4.5#~builtin::version=5.4.5&hash=85af82" +"typescript@patch:typescript@~5.5.4#~builtin": + version: 5.5.4 + resolution: "typescript@patch:typescript@npm%3A5.5.4#~builtin::version=5.5.4&hash=85af82" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 2373c693f3b328f3b2387c3efafe6d257b057a142f9a79291854b14ff4d5367d3d730810aee981726b677ae0fd8329b23309da3b6aaab8263dbdccf1da07a3ba + checksum: fc52962f31a5bcb716d4213bef516885e4f01f30cea797a831205fc9ef12b405a40561c40eae3127ab85ba1548e7df49df2bcdee6b84a94bfbe3a0d7eff16b14 languageName: node linkType: hard -"typia@npm:5.3.3, typia@npm:^5.3.3": - version: 5.3.3 - resolution: "typia@npm:5.3.3" +"typia@npm:6.9.0": + version: 6.9.0 + resolution: "typia@npm:6.9.0" dependencies: + "@samchon/openapi": ^0.4.6 commander: ^10.0.0 comment-json: ^4.2.3 inquirer: ^8.2.5 randexp: ^0.5.3 peerDependencies: - typescript: ">=4.8.0 <5.4.0" + typescript: ">=4.8.0 <5.6.0" bin: typia: lib/executable/typia.js - checksum: 6e6c9f4c1382deda6ee91fb42f0adbfa57c5b73541a2e411474108d1deac9dd2f590fbbe48399c0357064a6298b5ab17324aa521195cf8e470057171ce868a64 + checksum: 1d5ab0d331ff29b84914f5c8c5655fe3b1d17fae45ac3a76d30690de8414e8c45a27c189662896730c3211a436373e8c2eb3fc55d2eeb6ac8d15a1f50218a2e9 languageName: node linkType: hard -"typia@patch:typia@npm%3A5.3.3#./.yarn/patches/typia-npm-5.3.3-21d3e18463.patch::locator=rocket.chat%40workspace%3A.": - version: 5.3.3 - resolution: "typia@patch:typia@npm%3A5.3.3#./.yarn/patches/typia-npm-5.3.3-21d3e18463.patch::version=5.3.3&hash=777cd5&locator=rocket.chat%40workspace%3A." +"typia@patch:typia@npm%3A6.9.0#./.yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch::locator=rocket.chat%40workspace%3A.": + version: 6.9.0 + resolution: "typia@patch:typia@npm%3A6.9.0#./.yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch::version=6.9.0&hash=71fcee&locator=rocket.chat%40workspace%3A." dependencies: + "@samchon/openapi": ^0.4.6 commander: ^10.0.0 comment-json: ^4.2.3 inquirer: ^8.2.5 randexp: ^0.5.3 peerDependencies: - typescript: ">=4.8.0 <5.4.0" + typescript: ">=4.8.0 <5.6.0" bin: typia: lib/executable/typia.js - checksum: 256a670f6d3265135090a493c9519cd97466444188766ce9f4e434d2bfe29ec88c3a4ac3ac39938921e116873694ac526136957cbed5710109525d4d0d2425da + checksum: d87f150a526959f92ac9bafe7ad88121e69a2807c7aeb01a625cb845e0614fb09c54bbdbd68d0c90bce37072c2da5e153daa2ccd1f5ff7ca92eca4b5edf9e8a9 languageName: node linkType: hard From 037128cc55d9f3293f6f73adcbedd74f41125f8a Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Mon, 2 Sep 2024 13:00:47 -0300 Subject: [PATCH 028/170] test: Add some unit tests for `useRetentionPolicy` (#33196) --- .../room/hooks/useRetentionPolicy.spec.ts | 87 +++++++++++++++++++ apps/meteor/tests/mocks/data.ts | 2 +- 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 apps/meteor/client/views/room/hooks/useRetentionPolicy.spec.ts diff --git a/apps/meteor/client/views/room/hooks/useRetentionPolicy.spec.ts b/apps/meteor/client/views/room/hooks/useRetentionPolicy.spec.ts new file mode 100644 index 000000000000..9b99d6e4d781 --- /dev/null +++ b/apps/meteor/client/views/room/hooks/useRetentionPolicy.spec.ts @@ -0,0 +1,87 @@ +import { mockAppRoot } from '@rocket.chat/mock-providers'; +import { renderHook } from '@testing-library/react'; + +import { createFakeRoom } from '../../../../tests/mocks/data'; +import { useRetentionPolicy } from './useRetentionPolicy'; + +const getGlobalSettings = ({ + enabled = false, + filesOnly = false, + doNotPrunePinned = false, + ignoreThreads = false, + appliesToChannels = false, + appliesToGroups = false, + appliesToDMs = false, +}) => { + return mockAppRoot() + .withSetting('RetentionPolicy_Enabled', enabled) + .withSetting('RetentionPolicy_FilesOnly', filesOnly) + .withSetting('RetentionPolicy_DoNotPrunePinned', doNotPrunePinned) + .withSetting('RetentionPolicy_DoNotPruneThreads', ignoreThreads) + .withSetting('RetentionPolicy_AppliesToChannels', appliesToChannels) + .withSetting('RetentionPolicy_AppliesToGroups', appliesToGroups) + .withSetting('RetentionPolicy_AppliesToDMs', appliesToDMs); +}; + +const defaultValue = { + enabled: false, + isActive: false, + filesOnly: false, + excludePinned: false, + ignoreThreads: false, +}; + +const roomTypeConfig = { + c: { appliesToChannels: true }, + p: { appliesToGroups: true }, + d: { appliesToDMs: true }, +}; + +const CHANNELS_TYPE = 'c'; + +it('should return the default value if global retention is not enabled', async () => { + const fakeRoom = createFakeRoom({ t: CHANNELS_TYPE }); + + const { result } = renderHook(() => useRetentionPolicy(fakeRoom), { + legacyRoot: true, + wrapper: getGlobalSettings({}).build(), + }); + + expect(result.current).toEqual(expect.objectContaining(defaultValue)); +}); + +it('should return enabled true if global retention is enabled', async () => { + const fakeRoom = createFakeRoom({ t: CHANNELS_TYPE }); + + const { result } = renderHook(() => useRetentionPolicy(fakeRoom), { + legacyRoot: true, + wrapper: getGlobalSettings({ enabled: true }).build(), + }); + + expect(result.current).toEqual(expect.objectContaining({ ...defaultValue, enabled: true })); +}); + +it('should return enabled and active true global retention is active for rooms of the type', async () => { + const fakeRoom = createFakeRoom({ t: CHANNELS_TYPE }); + + const { result } = renderHook(() => useRetentionPolicy(fakeRoom), { + legacyRoot: true, + wrapper: getGlobalSettings({ enabled: true, ...roomTypeConfig[CHANNELS_TYPE] }).build(), + }); + + expect(result.current).toEqual(expect.objectContaining({ ...defaultValue, enabled: true, isActive: true })); +}); + +it.failing( + 'should isActive be false if global retention is active for rooms of the type and room has retention.enabled false', + async () => { + const fakeRoom = createFakeRoom({ t: CHANNELS_TYPE, retention: { enabled: false } }); + + const { result } = renderHook(() => useRetentionPolicy(fakeRoom), { + legacyRoot: true, + wrapper: getGlobalSettings({ enabled: true, ...roomTypeConfig[CHANNELS_TYPE] }).build(), + }); + + expect(result.current?.isActive).toBe(false); + }, +); diff --git a/apps/meteor/tests/mocks/data.ts b/apps/meteor/tests/mocks/data.ts index 14f03a6bd9ab..fd6a0ce91123 100644 --- a/apps/meteor/tests/mocks/data.ts +++ b/apps/meteor/tests/mocks/data.ts @@ -21,7 +21,7 @@ export function createFakeUser(overrides?: Partial): IUser { }; } -export const createFakeRoom = (overrides?: Partial): IRoom => ({ +export const createFakeRoom = (overrides?: Partial): IRoom => ({ _id: faker.database.mongodbObjectId(), _updatedAt: faker.date.recent(), t: faker.helpers.arrayElement(['c', 'p', 'd']), From 833880737fab6b02ba611541e309a483d13a8c50 Mon Sep 17 00:00:00 2001 From: Rafael Tapia Date: Mon, 2 Sep 2024 15:20:57 -0300 Subject: [PATCH 029/170] feat: email bridge (#33160) --- .changeset/tame-mayflies-press.md | 5 ++++ .../meteor/app/apps/server/bridges/bridges.js | 6 +++++ apps/meteor/app/apps/server/bridges/email.ts | 16 ++++++++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/ddp-streamer/package.json | 2 +- ee/packages/presence/package.json | 2 +- packages/apps/package.json | 2 +- packages/core-services/package.json | 2 +- packages/core-typings/package.json | 2 +- packages/fuselage-ui-kit/package.json | 2 +- packages/rest-typings/package.json | 2 +- yarn.lock | 26 +++++++++---------- 13 files changed, 49 insertions(+), 22 deletions(-) create mode 100644 .changeset/tame-mayflies-press.md create mode 100644 apps/meteor/app/apps/server/bridges/email.ts diff --git a/.changeset/tame-mayflies-press.md b/.changeset/tame-mayflies-press.md new file mode 100644 index 000000000000..e470306cbc25 --- /dev/null +++ b/.changeset/tame-mayflies-press.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": minor +--- + +Implemented sending email via apps diff --git a/apps/meteor/app/apps/server/bridges/bridges.js b/apps/meteor/app/apps/server/bridges/bridges.js index 6d52a1d8e56d..aeab9f191039 100644 --- a/apps/meteor/app/apps/server/bridges/bridges.js +++ b/apps/meteor/app/apps/server/bridges/bridges.js @@ -5,6 +5,7 @@ import { AppApisBridge } from './api'; import { AppCloudBridge } from './cloud'; import { AppCommandsBridge } from './commands'; import { AppDetailChangesBridge } from './details'; +import { AppEmailBridge } from './email'; import { AppEnvironmentalVariableBridge } from './environmental'; import { AppHttpBridge } from './http'; import { AppInternalBridge } from './internal'; @@ -53,6 +54,7 @@ export class RealAppBridges extends AppBridges { this._moderationBridge = new AppModerationBridge(orch); this._threadBridge = new AppThreadBridge(orch); this._roleBridge = new AppRoleBridge(orch); + this._emailBridge = new AppEmailBridge(orch); } getCommandBridge() { @@ -150,4 +152,8 @@ export class RealAppBridges extends AppBridges { getRoleBridge() { return this._roleBridge; } + + getEmailBridge() { + return this._emailBridge; + } } diff --git a/apps/meteor/app/apps/server/bridges/email.ts b/apps/meteor/app/apps/server/bridges/email.ts new file mode 100644 index 000000000000..4c9cb9a93ed6 --- /dev/null +++ b/apps/meteor/app/apps/server/bridges/email.ts @@ -0,0 +1,16 @@ +import type { IAppServerOrchestrator } from '@rocket.chat/apps'; +import type { IEmail } from '@rocket.chat/apps-engine/definition/email'; +import { EmailBridge } from '@rocket.chat/apps-engine/server/bridges'; + +import * as Mailer from '../../../mailer/server/api'; + +export class AppEmailBridge extends EmailBridge { + constructor(private readonly orch: IAppServerOrchestrator) { + super(); + } + + protected async sendEmail(email: IEmail, appId: string): Promise { + this.orch.debugLog(`The app ${appId} is sending an email.`); + await Mailer.send(email); + } +} diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 27794da80e16..5d7039d0962f 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -18,7 +18,7 @@ "author": "Rocket.Chat", "license": "MIT", "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.866", + "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", diff --git a/apps/meteor/package.json b/apps/meteor/package.json index b1230a0fa813..f0fbd66c087d 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -230,7 +230,7 @@ "@rocket.chat/agenda": "workspace:^", "@rocket.chat/api-client": "workspace:^", "@rocket.chat/apps": "workspace:^", - "@rocket.chat/apps-engine": "1.45.0-alpha.866", + "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/base64": "workspace:^", "@rocket.chat/cas-validate": "workspace:^", "@rocket.chat/core-services": "workspace:^", diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index fab1967867da..e776c1a573b8 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -15,7 +15,7 @@ ], "author": "Rocket.Chat", "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.866", + "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 997f80c60dd7..f7c195678dd6 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@babel/preset-env": "~7.22.20", "@babel/preset-typescript": "~7.22.15", - "@rocket.chat/apps-engine": "1.45.0-alpha.866", + "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@types/node": "^14.18.63", diff --git a/packages/apps/package.json b/packages/apps/package.json index 4491237dc047..b970a7d8cc20 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -18,7 +18,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.866", + "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/model-typings": "workspace:^" } diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 281982a62c57..191240062908 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -34,7 +34,7 @@ "extends": "../../package.json" }, "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.866", + "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/message-parser": "workspace:^", diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 98d496c05054..485dec1d88ed 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -22,7 +22,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.866", + "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/ui-kit": "workspace:~" diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 688033a1a7dc..75684f3f9fb5 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -63,7 +63,7 @@ "@babel/preset-env": "~7.22.20", "@babel/preset-react": "~7.22.15", "@babel/preset-typescript": "~7.22.15", - "@rocket.chat/apps-engine": "1.45.0-alpha.866", + "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/fuselage": "^0.57.0", diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index b5846800ad69..2c676f04a07f 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -23,7 +23,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.866", + "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/ui-kit": "workspace:~", diff --git a/yarn.lock b/yarn.lock index 7ef356f54646..6578c3ba2410 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8483,9 +8483,9 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/apps-engine@npm:1.45.0-alpha.866": - version: 1.45.0-alpha.866 - resolution: "@rocket.chat/apps-engine@npm:1.45.0-alpha.866" +"@rocket.chat/apps-engine@npm:1.45.0-alpha.868": + version: 1.45.0-alpha.868 + resolution: "@rocket.chat/apps-engine@npm:1.45.0-alpha.868" dependencies: "@msgpack/msgpack": 3.0.0-beta2 adm-zip: ^0.5.9 @@ -8501,7 +8501,7 @@ __metadata: uuid: ~8.3.2 peerDependencies: "@rocket.chat/ui-kit": "*" - checksum: 04abb4f712fcca206c6791322b52e2a3d97f3db06f606cd1f58fdda4e63d2123d7004bb445ad7582c52808c3ec4433d465d8855e24f3ab2f8457dafa6b017c5b + checksum: 3ac41e3de76be67e856e4bca888f113360628e510f9d4c66d70ed71d84f25bda6ca6659ead6c7a87d21c117c47bfa090b4508cce66e8630d2e935d3ed3158835 languageName: node linkType: hard @@ -8509,7 +8509,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/apps@workspace:packages/apps" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.866 + "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/model-typings": "workspace:^" eslint: ~8.45.0 @@ -8582,7 +8582,7 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": 1.45.0-alpha.866 + "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/icons": ~0.38.0 @@ -8609,7 +8609,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/core-typings@workspace:packages/core-typings" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.866 + "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/icons": ~0.38.0 "@rocket.chat/message-parser": "workspace:^" @@ -8681,7 +8681,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/ddp-streamer@workspace:ee/apps/ddp-streamer" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.866 + "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/ddp-client": "workspace:~" @@ -8879,7 +8879,7 @@ __metadata: "@babel/preset-env": ~7.22.20 "@babel/preset-react": ~7.22.15 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": 1.45.0-alpha.866 + "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/fuselage": ^0.57.0 @@ -9329,7 +9329,7 @@ __metadata: "@rocket.chat/agenda": "workspace:^" "@rocket.chat/api-client": "workspace:^" "@rocket.chat/apps": "workspace:^" - "@rocket.chat/apps-engine": 1.45.0-alpha.866 + "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/base64": "workspace:^" "@rocket.chat/cas-validate": "workspace:^" "@rocket.chat/core-services": "workspace:^" @@ -9952,7 +9952,7 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": 1.45.0-alpha.866 + "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" @@ -10066,7 +10066,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/rest-typings@workspace:packages/rest-typings" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.866 + "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:~" "@rocket.chat/message-parser": "workspace:^" @@ -36701,7 +36701,7 @@ __metadata: version: 0.0.0-use.local resolution: "rocketchat-services@workspace:apps/meteor/ee/server/services" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.866 + "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/emitter": ~0.31.25 From 9e7cc89e48e8b237a189cded88e243153be1c9ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9ssica=20Souza?= Date: Mon, 2 Sep 2024 17:06:10 -0300 Subject: [PATCH 030/170] test: create tests for omnichannel queue management (#33149) --- ...ichannel-livechat-queue-management.spec.ts | 120 ++++++++++++++++++ .../e2e/page-objects/omnichannel-livechat.ts | 13 ++ 2 files changed, 133 insertions(+) create mode 100644 apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management.spec.ts diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management.spec.ts new file mode 100644 index 000000000000..ee91c49bfb16 --- /dev/null +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management.spec.ts @@ -0,0 +1,120 @@ +import { createFakeVisitor } from '../../mocks/data'; +import { IS_EE } from '../config/constants'; +import { createAuxContext } from '../fixtures/createAuxContext'; +import { Users } from '../fixtures/userStates'; +import { HomeOmnichannel, OmnichannelLiveChat } from '../page-objects'; +import { test, expect } from '../utils/test'; + +const firstVisitor = createFakeVisitor(); + +const secondVisitor = createFakeVisitor(); + +test.use({ storageState: Users.user1.state }); + +test.describe('OC - Livechat - Queue Management', () => { + test.skip(!IS_EE, 'Enterprise Only'); + + let poHomeOmnichannel: HomeOmnichannel; + let poLiveChat: OmnichannelLiveChat; + + const waitingQueueMessage = 'This is a message from Waiting Queue'; + const queuePosition1 = 'Your spot is #1'; + const queuePosition2 = 'Your spot is #2'; + + test.beforeAll(async ({ api, browser }) => { + await Promise.all([ + api.post('/settings/Livechat_Routing_Method', { value: 'Manual_Selection' }), + api.post('/settings/Livechat_waiting_queue', { value: true }), + api.post('/settings/Livechat_waiting_queue_message', { value: waitingQueueMessage }), + api.post('/livechat/users/agent', { username: 'user1' }), + ]); + + const { page: omniPage } = await createAuxContext(browser, Users.user1, '/', true); + poHomeOmnichannel = new HomeOmnichannel(omniPage); + }); + + test.beforeEach(async ({ browser, api }) => { + const context = await browser.newContext(); + const page2 = await context.newPage(); + + poLiveChat = new OmnichannelLiveChat(page2, api); + await poLiveChat.page.goto('/livechat'); + }); + + test.afterAll(async ({ api }) => { + await Promise.all([ + api.post('/settings/Livechat_Routing_Method', { value: 'Auto_Selection' }), + api.post('/settings/Livechat_waiting_queue', { value: false }), + api.post('/settings/Livechat_waiting_queue_message', { value: '' }), + api.delete('/livechat/users/agent/user1'), + ]); + await poHomeOmnichannel.page.close(); + }); + + test.afterEach(async () => { + await poLiveChat.closeChat(); + await poLiveChat.page.close(); + }); + + test('OC - Queue Management - Waiting Queue Message enabled', async () => { + await test.step('should start livechat session', async () => { + await poLiveChat.openAnyLiveChatAndSendMessage({ + liveChatUser: firstVisitor, + message: 'Test message', + isOffline: false, + }); + }); + await test.step('expect to receive Waiting Queue message on chat', async () => { + await expect(poLiveChat.page.locator(`div >> text=${waitingQueueMessage}`)).toBeVisible(); + }); + }); + + test.describe('OC - Queue Management - Update Queue Position', () => { + let poLiveChat2: OmnichannelLiveChat; + + test.beforeEach(async ({ browser, api }) => { + const context = await browser.newContext(); + const page = await context.newPage(); + poLiveChat2 = new OmnichannelLiveChat(page, api); + await poLiveChat2.page.goto('/livechat'); + }); + + test.afterEach(async () => { + await poLiveChat2.closeChat(); + await poLiveChat2.page.close(); + }); + + test('Update user position on Queue', async () => { + await test.step('should start secondary livechat session', async () => { + await poLiveChat2.openAnyLiveChatAndSendMessage({ + liveChatUser: secondVisitor, + message: 'Test message', + isOffline: false, + }); + }); + + await test.step('should start primary livechat session', async () => { + await poLiveChat.openAnyLiveChatAndSendMessage({ + liveChatUser: firstVisitor, + message: 'Test message', + isOffline: false, + }); + }); + + await test.step('should verify the queue position of the primary user', async () => { + await expect(poLiveChat.page.locator(`div[role='alert'] >> text=${queuePosition2}`)).toBeVisible(); + }); + + await test.step('should allow the agent to take the secondary user chat', async () => { + await poHomeOmnichannel.sidenav.getQueuedChat(secondVisitor.name).click(); + await expect(poHomeOmnichannel.content.btnTakeChat).toBeVisible(); + await poHomeOmnichannel.content.btnTakeChat.click(); + await expect(poHomeOmnichannel.content.lastSystemMessageBody).toHaveText('joined the channel'); + }); + + await test.step('expect the queue position of the primary user to update after the secondary users chat is taken', async () => { + await expect(poLiveChat.page.locator(`div[role='alert'] >> text=${queuePosition1}`)).toBeVisible(); + }); + }); + }); +}); diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts index 330fc981237f..e52ae45782c8 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts @@ -88,6 +88,19 @@ export class OmnichannelLiveChat { await this.btnNewChat.click(); } + async openAnyLiveChatAndSendMessage(params: { + liveChatUser: { name: string; email: string }; + message: string; + isOffline?: boolean; + department?: string; + }): Promise { + const { liveChatUser, message, isOffline, department } = params; + await this.openAnyLiveChat(); + await this.sendMessage(liveChatUser, isOffline, department); + await this.onlineAgentMessage.fill(message); + await this.btnSendMessageToOnlineAgent.click(); + } + unreadMessagesBadge(count: number): Locator { const name = count === 1 ? `${count} unread message` : `${count} unread messages`; From a71352063b906848010359ad8f005b43d5d1cfe2 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 2 Sep 2024 19:24:23 -0300 Subject: [PATCH 031/170] regression: fix subscription counter for DMs (#33200) --- apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts index 7551cabb6e63..7d727ab49685 100644 --- a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts +++ b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts @@ -111,7 +111,7 @@ async function updateUsersSubscriptions(message: IMessage, room: IRoom): Promise roomId: room._id, uidsExclude: [message.u._id], uidsInclude: userIds, - onlyRead: !toAll && !toHere, + onlyRead: !toAll && !toHere && unreadCount !== 'all_messages', }).forEach((sub) => { const hasUserMention = userIds.includes(sub.u._id); const shouldIncUnread = hasUserMention || toAll || toHere || unreadCount === 'all_messages'; From 304bc6d5ad7be7d1371190277abd53cd96a17a15 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 2 Sep 2024 21:49:40 -0300 Subject: [PATCH 032/170] chore: improve omni queue metrics query (#33159) --- .changeset/cool-actors-sin.md | 5 + .../meteor/server/models/raw/LivechatRooms.ts | 80 +++-- .../tests/end-to-end/api/livechat/00-rooms.ts | 4 + .../tests/end-to-end/api/livechat/07-queue.ts | 322 +++++++++++++++++- 4 files changed, 375 insertions(+), 36 deletions(-) create mode 100644 .changeset/cool-actors-sin.md diff --git a/.changeset/cool-actors-sin.md b/.changeset/cool-actors-sin.md new file mode 100644 index 000000000000..e53b8f136ebb --- /dev/null +++ b/.changeset/cool-actors-sin.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Improves Omnichannel queue page performance diff --git a/apps/meteor/server/models/raw/LivechatRooms.ts b/apps/meteor/server/models/raw/LivechatRooms.ts index b01d7e62c5ff..ae03d67251ec 100644 --- a/apps/meteor/server/models/raw/LivechatRooms.ts +++ b/apps/meteor/server/models/raw/LivechatRooms.ts @@ -91,22 +91,31 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive options?: { offset?: number; count?: number; sort?: { [k: string]: number } }; }) { const match: Document = { $match: { t: 'l', open: true, servedBy: { $exists: true } } }; - const matchUsers: Document = { $match: {} }; + if (departmentId && departmentId !== 'undefined') { match.$match.departmentId = departmentId; } - if (agentId) { - matchUsers.$match['user._id'] = agentId; - } - if (!includeOfflineAgents) { - matchUsers.$match['user.status'] = { $ne: 'offline' }; - matchUsers.$match['user.statusLivechat'] = { $eq: 'available' }; - } + const departmentsLookup = { $lookup: { from: 'rocketchat_livechat_department', - localField: 'departmentId', - foreignField: '_id', + let: { + deptId: '$departmentId', + }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$deptId'], + }, + }, + }, + { + $project: { + name: 1, + }, + }, + ], as: 'departments', }, }; @@ -116,27 +125,40 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive preserveNullAndEmptyArrays: true, }, }; - const departmentsGroup = { - $group: { - _id: { - departmentId: '$departmentId', - name: '$departments.name', - room: '$$ROOT', - }, - }, - }; + const usersLookup = { $lookup: { from: 'users', - localField: '_id.room.servedBy._id', - foreignField: '_id', + let: { + servedById: '$servedBy._id', + }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$servedById'], + }, + ...(!includeOfflineAgents && { + status: { $ne: 'offline' }, + statusLivechat: 'available', + }), + ...(agentId && { _id: agentId }), + }, + }, + { + $project: { + _id: 1, + username: 1, + status: 1, + }, + }, + ], as: 'user', }, }; const usersUnwind = { $unwind: { path: '$user', - preserveNullAndEmptyArrays: true, }, }; const usersGroup = { @@ -145,8 +167,8 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive userId: '$user._id', username: '$user.username', status: '$user.status', - departmentId: '$_id.departmentId', - departmentName: '$_id.name', + departmentId: '$departmentId', + departmentName: '$departments.name', }, chats: { $sum: 1 }, }, @@ -160,16 +182,13 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive status: '$_id.status', }, department: { - _id: { $ifNull: ['$_id.departmentId', null] }, - name: { $ifNull: ['$_id.departmentName', null] }, + _id: '$_id.departmentId', + name: '$_id.departmentName', }, chats: 1, }, }; - const firstParams = [match, departmentsLookup, departmentsUnwind, departmentsGroup, usersLookup, usersUnwind]; - if (Object.keys(matchUsers.$match)) { - firstParams.push(matchUsers); - } + const firstParams = [match, departmentsLookup, departmentsUnwind, usersLookup, usersUnwind]; const sort: Document = { $sort: options.sort || { chats: -1 } }; const pagination = [sort]; @@ -188,6 +207,7 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive }; const params = [...firstParams, usersGroup, project, facet]; + return this.col.aggregate(params, { readPreference: readSecondaryPreferred(), allowDiskUse: true }).toArray(); } diff --git a/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts b/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts index f3ae205c7090..7142725a1d99 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts @@ -2468,6 +2468,10 @@ describe('LIVECHAT - rooms', () => { await updateSetting('Unread_Count_Omni', 'all_messages'); }); + after(async () => { + await deleteDepartment(departmentWithAgent.department._id); + }); + it('it should prepare the required data for further tests', async () => { departmentWithAgent = await createDepartmentWithAnOnlineAgent(); visitor = await createVisitor(departmentWithAgent.department._id); diff --git a/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts b/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts index 1d5ef110d308..4e2128b682a6 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts @@ -1,27 +1,58 @@ /* eslint-env mocha */ +import { faker } from '@faker-js/faker'; +import type { ILivechatDepartment, ILivechatVisitor, IOmnichannelRoom, IUser } from '@rocket.chat/core-typings'; import { expect } from 'chai'; -import { before, describe, it } from 'mocha'; +import { after, before, describe, it } from 'mocha'; import type { Response } from 'supertest'; import { getCredentials, api, request, credentials } from '../../../data/api-data'; +import { createDepartmentWithAnOnlineAgent, deleteDepartment, addOrRemoveAgentFromDepartment } from '../../../data/livechat/department'; +import { createVisitor, createLivechatRoom, closeOmnichannelRoom, deleteVisitor } from '../../../data/livechat/rooms'; +import { createAnOnlineAgent } from '../../../data/livechat/users'; import { updatePermission, updateSetting } from '../../../data/permissions.helper'; +import { deleteUser } from '../../../data/users.helper'; +import { IS_EE } from '../../../e2e/config/constants'; + +const cleanupRooms = async () => { + const response = await request.get(api('livechat/queue')).set(credentials).expect('Content-Type', 'application/json').expect(200); + + const { queue } = response.body; + + for await (const item of queue) { + const { + body: { rooms }, + } = await request.get(api('livechat/rooms')).query({ 'agents[]': item.user._id }).set(credentials); + + await Promise.all( + rooms.map((room: IOmnichannelRoom) => + request.post(api('livechat/room.closeByUser')).set(credentials).send({ rid: room._id, comment: faker.lorem.sentence() }), + ), + ); + } +}; describe('LIVECHAT - Queue', () => { before((done) => getCredentials(done)); - before(async () => { - await updateSetting('Livechat_enabled', true); - }); + before(async () => + Promise.all([ + updateSetting('Livechat_enabled', true), + updateSetting('Livechat_Routing_Method', 'Auto_Selection'), + + // this cleanup is required since previous tests left the DB dirty + cleanupRooms(), + ]), + ); describe('livechat/queue', () => { it('should return an "unauthorized error" when the user does not have the necessary permission', async () => { await updatePermission('view-l-room', []); await request.get(api('livechat/queue')).set(credentials).expect('Content-Type', 'application/json').expect(403); + await updatePermission('view-l-room', ['admin']); }); it('should return an array of queued metrics', async () => { - await updatePermission('view-l-room', ['admin']); await request .get(api('livechat/queue')) .set(credentials) @@ -36,7 +67,6 @@ describe('LIVECHAT - Queue', () => { }); }); it('should return an array of queued metrics even requested with count and offset params', async () => { - await updatePermission('view-l-room', ['admin']); await request .get(api('livechat/queue')) .set(credentials) @@ -55,4 +85,284 @@ describe('LIVECHAT - Queue', () => { }); }); }); + + describe('queue position', () => { + let agent1: { user: IUser }; + let agent2: { user: IUser }; + let agent3: { user: IUser }; + let deptd1: ILivechatDepartment; + let deptd2: ILivechatDepartment; + + const roomsToClose: IOmnichannelRoom[] = []; + const visitors: ILivechatVisitor[] = []; + const usersToDelete: IUser[] = []; + + before(async () => { + const { department, agent } = await createDepartmentWithAnOnlineAgent(); + + deptd1 = department; + agent1 = agent; + + usersToDelete.push(agent.user); + + const newVisitor = await createVisitor(deptd1._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + roomsToClose.push(newRoom); + visitors.push(newVisitor); + }); + + after(async () => { + await deleteDepartment(deptd1._id); + + if (deptd2) { + await deleteDepartment(deptd2._id); + } + + await Promise.all(roomsToClose.map((room) => closeOmnichannelRoom(room._id))); + await Promise.all(visitors.map((visitor) => deleteVisitor(visitor.token))); + await Promise.all(usersToDelete.map((user) => deleteUser(user))); + }); + + it('should have one item in the queue', async () => { + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(1); + + const [queue] = res.body.queue; + + expect(queue).to.have.property('chats', 1); + expect(queue).to.have.nested.property('user._id', agent1.user._id); + expect(queue).to.have.nested.property('department._id', deptd1._id); + }); + }); + + it('should return empty results when filtering by another agent', async () => { + await request + .get(api('livechat/queue')) + .query({ agentId: 'another-agent' }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total', 0); + expect(res.body).to.have.property('count', 0); + expect(res.body.queue).to.be.an('array').of.length(0); + }); + }); + + it('should increase chats when a new room for same department is created', async () => { + const newVisitor = await createVisitor(); + const newRoom = await createLivechatRoom(newVisitor.token); + + roomsToClose.push(newRoom); + visitors.push(newVisitor); + + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(1); + + const [queue] = res.body.queue; + + expect(queue).to.have.property('chats', 2); + expect(queue).to.have.nested.property('user._id', agent1.user._id); + expect(queue).to.have.nested.property('department._id', deptd1._id); + }); + }); + + it('should have two items when create room for another agent', async () => { + const { user } = await createAnOnlineAgent(); + await addOrRemoveAgentFromDepartment(deptd1._id, { agentId: user._id, username: user.username }, true); + + agent2 = { user }; + + usersToDelete.push(user); + + const newVisitor = await createVisitor(deptd1._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + roomsToClose.push(newRoom); + visitors.push(newVisitor); + + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(2); + + const [queue1, queue2] = res.body.queue; + + expect(queue1).to.have.property('chats', 2); + expect(queue1).to.have.nested.property('user._id', agent1.user._id); + expect(queue1).to.have.nested.property('department._id', deptd1._id); + + expect(queue2).to.have.property('chats', 1); + expect(queue2).to.have.nested.property('user._id', agent2.user._id); + expect(queue2).to.have.nested.property('department._id', deptd1._id); + }); + }); + + it('should be able to filter for second agent only', async () => { + await request + .get(api('livechat/queue')) + .query({ agentId: agent2.user._id }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(1); + + const [queue1] = res.body.queue; + + expect(queue1).to.have.property('chats', 1); + expect(queue1).to.have.nested.property('user._id', agent2.user._id); + expect(queue1).to.have.nested.property('department._id', deptd1._id); + }); + }); + + it('should return empty if filter for a department without chats', async () => { + await request + .get(api('livechat/queue')) + .query({ departmentId: 'no-chats' }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total', 0); + expect(res.body).to.have.property('count', 0); + expect(res.body.queue).to.be.an('array').of.length(0); + }); + }); + + it('should be able to filter for first department only', async () => { + await request + .get(api('livechat/queue')) + .query({ departmentId: deptd1._id }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(2); + + const [queue1] = res.body.queue; + + expect(queue1).to.have.property('chats', 2); + expect(queue1).to.have.nested.property('user._id', agent1.user._id); + expect(queue1).to.have.nested.property('department._id', deptd1._id); + }); + }); + + (IS_EE ? it : it.skip)('should have three items when create room for another department', async () => { + const { department: dep2, agent: ag3 } = await createDepartmentWithAnOnlineAgent(); + + agent3 = ag3; + + usersToDelete.push(ag3.user); + + deptd2 = dep2; + + const newVisitor = await createVisitor(deptd2._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + roomsToClose.push(newRoom); + visitors.push(newVisitor); + + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(3); + + const [queue1, queue2, queue3] = res.body.queue; + + expect(queue1).to.have.property('chats', 2); + expect(queue1).to.have.nested.property('user._id', agent1.user._id); + expect(queue1).to.have.nested.property('department._id', deptd1._id); + + expect(queue2).to.have.property('chats', 1); + expect(queue3).to.have.property('chats', 1); + }); + }); + + (IS_EE ? it : it.skip)('should change the order when second department gets more rooms', async () => { + const newVisitor1 = await createVisitor(deptd2._id); + const newRoom1 = await createLivechatRoom(newVisitor1.token); + + roomsToClose.push(newRoom1); + visitors.push(newVisitor1); + + const newVisitor2 = await createVisitor(deptd2._id); + const newRoom2 = await createLivechatRoom(newVisitor2.token); + + roomsToClose.push(newRoom2); + visitors.push(newVisitor2); + + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(3); + + const [queue1, queue2, queue3] = res.body.queue; + + expect(queue1).to.have.property('chats', 3); + expect(queue1).to.have.nested.property('user._id', agent3.user._id); + expect(queue1).to.have.nested.property('department._id', deptd2._id); + + expect(queue2).to.have.property('chats', 2); + expect(queue2).to.have.nested.property('user._id', agent1.user._id); + expect(queue2).to.have.nested.property('department._id', deptd1._id); + + expect(queue3).to.have.property('chats', 1); + expect(queue3).to.have.nested.property('user._id', agent2.user._id); + expect(queue3).to.have.nested.property('department._id', deptd1._id); + }); + }); + }); }); From 2d7f6dc3e845fd29587cf012bce601423ff1f2ef Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 2 Sep 2024 21:49:40 -0300 Subject: [PATCH 033/170] chore: improve omni queue metrics query (#33159) --- .changeset/cool-actors-sin.md | 5 + .../meteor/server/models/raw/LivechatRooms.ts | 80 +++-- .../tests/end-to-end/api/livechat/00-rooms.ts | 4 + .../tests/end-to-end/api/livechat/07-queue.ts | 322 +++++++++++++++++- 4 files changed, 375 insertions(+), 36 deletions(-) create mode 100644 .changeset/cool-actors-sin.md diff --git a/.changeset/cool-actors-sin.md b/.changeset/cool-actors-sin.md new file mode 100644 index 000000000000..e53b8f136ebb --- /dev/null +++ b/.changeset/cool-actors-sin.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Improves Omnichannel queue page performance diff --git a/apps/meteor/server/models/raw/LivechatRooms.ts b/apps/meteor/server/models/raw/LivechatRooms.ts index b01d7e62c5ff..ae03d67251ec 100644 --- a/apps/meteor/server/models/raw/LivechatRooms.ts +++ b/apps/meteor/server/models/raw/LivechatRooms.ts @@ -91,22 +91,31 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive options?: { offset?: number; count?: number; sort?: { [k: string]: number } }; }) { const match: Document = { $match: { t: 'l', open: true, servedBy: { $exists: true } } }; - const matchUsers: Document = { $match: {} }; + if (departmentId && departmentId !== 'undefined') { match.$match.departmentId = departmentId; } - if (agentId) { - matchUsers.$match['user._id'] = agentId; - } - if (!includeOfflineAgents) { - matchUsers.$match['user.status'] = { $ne: 'offline' }; - matchUsers.$match['user.statusLivechat'] = { $eq: 'available' }; - } + const departmentsLookup = { $lookup: { from: 'rocketchat_livechat_department', - localField: 'departmentId', - foreignField: '_id', + let: { + deptId: '$departmentId', + }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$deptId'], + }, + }, + }, + { + $project: { + name: 1, + }, + }, + ], as: 'departments', }, }; @@ -116,27 +125,40 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive preserveNullAndEmptyArrays: true, }, }; - const departmentsGroup = { - $group: { - _id: { - departmentId: '$departmentId', - name: '$departments.name', - room: '$$ROOT', - }, - }, - }; + const usersLookup = { $lookup: { from: 'users', - localField: '_id.room.servedBy._id', - foreignField: '_id', + let: { + servedById: '$servedBy._id', + }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$servedById'], + }, + ...(!includeOfflineAgents && { + status: { $ne: 'offline' }, + statusLivechat: 'available', + }), + ...(agentId && { _id: agentId }), + }, + }, + { + $project: { + _id: 1, + username: 1, + status: 1, + }, + }, + ], as: 'user', }, }; const usersUnwind = { $unwind: { path: '$user', - preserveNullAndEmptyArrays: true, }, }; const usersGroup = { @@ -145,8 +167,8 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive userId: '$user._id', username: '$user.username', status: '$user.status', - departmentId: '$_id.departmentId', - departmentName: '$_id.name', + departmentId: '$departmentId', + departmentName: '$departments.name', }, chats: { $sum: 1 }, }, @@ -160,16 +182,13 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive status: '$_id.status', }, department: { - _id: { $ifNull: ['$_id.departmentId', null] }, - name: { $ifNull: ['$_id.departmentName', null] }, + _id: '$_id.departmentId', + name: '$_id.departmentName', }, chats: 1, }, }; - const firstParams = [match, departmentsLookup, departmentsUnwind, departmentsGroup, usersLookup, usersUnwind]; - if (Object.keys(matchUsers.$match)) { - firstParams.push(matchUsers); - } + const firstParams = [match, departmentsLookup, departmentsUnwind, usersLookup, usersUnwind]; const sort: Document = { $sort: options.sort || { chats: -1 } }; const pagination = [sort]; @@ -188,6 +207,7 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive }; const params = [...firstParams, usersGroup, project, facet]; + return this.col.aggregate(params, { readPreference: readSecondaryPreferred(), allowDiskUse: true }).toArray(); } diff --git a/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts b/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts index f3ae205c7090..7142725a1d99 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts @@ -2468,6 +2468,10 @@ describe('LIVECHAT - rooms', () => { await updateSetting('Unread_Count_Omni', 'all_messages'); }); + after(async () => { + await deleteDepartment(departmentWithAgent.department._id); + }); + it('it should prepare the required data for further tests', async () => { departmentWithAgent = await createDepartmentWithAnOnlineAgent(); visitor = await createVisitor(departmentWithAgent.department._id); diff --git a/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts b/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts index 1d5ef110d308..4e2128b682a6 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts @@ -1,27 +1,58 @@ /* eslint-env mocha */ +import { faker } from '@faker-js/faker'; +import type { ILivechatDepartment, ILivechatVisitor, IOmnichannelRoom, IUser } from '@rocket.chat/core-typings'; import { expect } from 'chai'; -import { before, describe, it } from 'mocha'; +import { after, before, describe, it } from 'mocha'; import type { Response } from 'supertest'; import { getCredentials, api, request, credentials } from '../../../data/api-data'; +import { createDepartmentWithAnOnlineAgent, deleteDepartment, addOrRemoveAgentFromDepartment } from '../../../data/livechat/department'; +import { createVisitor, createLivechatRoom, closeOmnichannelRoom, deleteVisitor } from '../../../data/livechat/rooms'; +import { createAnOnlineAgent } from '../../../data/livechat/users'; import { updatePermission, updateSetting } from '../../../data/permissions.helper'; +import { deleteUser } from '../../../data/users.helper'; +import { IS_EE } from '../../../e2e/config/constants'; + +const cleanupRooms = async () => { + const response = await request.get(api('livechat/queue')).set(credentials).expect('Content-Type', 'application/json').expect(200); + + const { queue } = response.body; + + for await (const item of queue) { + const { + body: { rooms }, + } = await request.get(api('livechat/rooms')).query({ 'agents[]': item.user._id }).set(credentials); + + await Promise.all( + rooms.map((room: IOmnichannelRoom) => + request.post(api('livechat/room.closeByUser')).set(credentials).send({ rid: room._id, comment: faker.lorem.sentence() }), + ), + ); + } +}; describe('LIVECHAT - Queue', () => { before((done) => getCredentials(done)); - before(async () => { - await updateSetting('Livechat_enabled', true); - }); + before(async () => + Promise.all([ + updateSetting('Livechat_enabled', true), + updateSetting('Livechat_Routing_Method', 'Auto_Selection'), + + // this cleanup is required since previous tests left the DB dirty + cleanupRooms(), + ]), + ); describe('livechat/queue', () => { it('should return an "unauthorized error" when the user does not have the necessary permission', async () => { await updatePermission('view-l-room', []); await request.get(api('livechat/queue')).set(credentials).expect('Content-Type', 'application/json').expect(403); + await updatePermission('view-l-room', ['admin']); }); it('should return an array of queued metrics', async () => { - await updatePermission('view-l-room', ['admin']); await request .get(api('livechat/queue')) .set(credentials) @@ -36,7 +67,6 @@ describe('LIVECHAT - Queue', () => { }); }); it('should return an array of queued metrics even requested with count and offset params', async () => { - await updatePermission('view-l-room', ['admin']); await request .get(api('livechat/queue')) .set(credentials) @@ -55,4 +85,284 @@ describe('LIVECHAT - Queue', () => { }); }); }); + + describe('queue position', () => { + let agent1: { user: IUser }; + let agent2: { user: IUser }; + let agent3: { user: IUser }; + let deptd1: ILivechatDepartment; + let deptd2: ILivechatDepartment; + + const roomsToClose: IOmnichannelRoom[] = []; + const visitors: ILivechatVisitor[] = []; + const usersToDelete: IUser[] = []; + + before(async () => { + const { department, agent } = await createDepartmentWithAnOnlineAgent(); + + deptd1 = department; + agent1 = agent; + + usersToDelete.push(agent.user); + + const newVisitor = await createVisitor(deptd1._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + roomsToClose.push(newRoom); + visitors.push(newVisitor); + }); + + after(async () => { + await deleteDepartment(deptd1._id); + + if (deptd2) { + await deleteDepartment(deptd2._id); + } + + await Promise.all(roomsToClose.map((room) => closeOmnichannelRoom(room._id))); + await Promise.all(visitors.map((visitor) => deleteVisitor(visitor.token))); + await Promise.all(usersToDelete.map((user) => deleteUser(user))); + }); + + it('should have one item in the queue', async () => { + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(1); + + const [queue] = res.body.queue; + + expect(queue).to.have.property('chats', 1); + expect(queue).to.have.nested.property('user._id', agent1.user._id); + expect(queue).to.have.nested.property('department._id', deptd1._id); + }); + }); + + it('should return empty results when filtering by another agent', async () => { + await request + .get(api('livechat/queue')) + .query({ agentId: 'another-agent' }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total', 0); + expect(res.body).to.have.property('count', 0); + expect(res.body.queue).to.be.an('array').of.length(0); + }); + }); + + it('should increase chats when a new room for same department is created', async () => { + const newVisitor = await createVisitor(); + const newRoom = await createLivechatRoom(newVisitor.token); + + roomsToClose.push(newRoom); + visitors.push(newVisitor); + + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(1); + + const [queue] = res.body.queue; + + expect(queue).to.have.property('chats', 2); + expect(queue).to.have.nested.property('user._id', agent1.user._id); + expect(queue).to.have.nested.property('department._id', deptd1._id); + }); + }); + + it('should have two items when create room for another agent', async () => { + const { user } = await createAnOnlineAgent(); + await addOrRemoveAgentFromDepartment(deptd1._id, { agentId: user._id, username: user.username }, true); + + agent2 = { user }; + + usersToDelete.push(user); + + const newVisitor = await createVisitor(deptd1._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + roomsToClose.push(newRoom); + visitors.push(newVisitor); + + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(2); + + const [queue1, queue2] = res.body.queue; + + expect(queue1).to.have.property('chats', 2); + expect(queue1).to.have.nested.property('user._id', agent1.user._id); + expect(queue1).to.have.nested.property('department._id', deptd1._id); + + expect(queue2).to.have.property('chats', 1); + expect(queue2).to.have.nested.property('user._id', agent2.user._id); + expect(queue2).to.have.nested.property('department._id', deptd1._id); + }); + }); + + it('should be able to filter for second agent only', async () => { + await request + .get(api('livechat/queue')) + .query({ agentId: agent2.user._id }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(1); + + const [queue1] = res.body.queue; + + expect(queue1).to.have.property('chats', 1); + expect(queue1).to.have.nested.property('user._id', agent2.user._id); + expect(queue1).to.have.nested.property('department._id', deptd1._id); + }); + }); + + it('should return empty if filter for a department without chats', async () => { + await request + .get(api('livechat/queue')) + .query({ departmentId: 'no-chats' }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total', 0); + expect(res.body).to.have.property('count', 0); + expect(res.body.queue).to.be.an('array').of.length(0); + }); + }); + + it('should be able to filter for first department only', async () => { + await request + .get(api('livechat/queue')) + .query({ departmentId: deptd1._id }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(2); + + const [queue1] = res.body.queue; + + expect(queue1).to.have.property('chats', 2); + expect(queue1).to.have.nested.property('user._id', agent1.user._id); + expect(queue1).to.have.nested.property('department._id', deptd1._id); + }); + }); + + (IS_EE ? it : it.skip)('should have three items when create room for another department', async () => { + const { department: dep2, agent: ag3 } = await createDepartmentWithAnOnlineAgent(); + + agent3 = ag3; + + usersToDelete.push(ag3.user); + + deptd2 = dep2; + + const newVisitor = await createVisitor(deptd2._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + roomsToClose.push(newRoom); + visitors.push(newVisitor); + + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(3); + + const [queue1, queue2, queue3] = res.body.queue; + + expect(queue1).to.have.property('chats', 2); + expect(queue1).to.have.nested.property('user._id', agent1.user._id); + expect(queue1).to.have.nested.property('department._id', deptd1._id); + + expect(queue2).to.have.property('chats', 1); + expect(queue3).to.have.property('chats', 1); + }); + }); + + (IS_EE ? it : it.skip)('should change the order when second department gets more rooms', async () => { + const newVisitor1 = await createVisitor(deptd2._id); + const newRoom1 = await createLivechatRoom(newVisitor1.token); + + roomsToClose.push(newRoom1); + visitors.push(newVisitor1); + + const newVisitor2 = await createVisitor(deptd2._id); + const newRoom2 = await createLivechatRoom(newVisitor2.token); + + roomsToClose.push(newRoom2); + visitors.push(newVisitor2); + + await request + .get(api('livechat/queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('count'); + expect(res.body.queue).to.be.an('array').of.length(3); + + const [queue1, queue2, queue3] = res.body.queue; + + expect(queue1).to.have.property('chats', 3); + expect(queue1).to.have.nested.property('user._id', agent3.user._id); + expect(queue1).to.have.nested.property('department._id', deptd2._id); + + expect(queue2).to.have.property('chats', 2); + expect(queue2).to.have.nested.property('user._id', agent1.user._id); + expect(queue2).to.have.nested.property('department._id', deptd1._id); + + expect(queue3).to.have.property('chats', 1); + expect(queue3).to.have.nested.property('user._id', agent2.user._id); + expect(queue3).to.have.nested.property('department._id', deptd1._id); + }); + }); + }); }); From 2aa343d79deb8385f45ef0b7c49ed25c21fc440c Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 3 Sep 2024 01:14:30 +0000 Subject: [PATCH 034/170] Release 6.12.0-rc.3 [no ci] --- .changeset/bump-patch-1725326060827.md | 5 +++ .changeset/pre.json | 2 ++ apps/meteor/CHANGELOG.md | 34 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 +++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 +++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 +++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 14 ++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 ++++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 +++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 +++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 +++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 +++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 ++++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 +++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 ++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/api-client/CHANGELOG.md | 10 ++++++ packages/api-client/package.json | 2 +- packages/apps/CHANGELOG.md | 10 ++++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 ++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 ++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 ++++++ packages/cron/package.json | 2 +- packages/ddp-client/CHANGELOG.md | 11 ++++++ packages/ddp-client/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 +++++++ packages/fuselage-ui-kit/package.json | 8 ++--- packages/gazzodown/CHANGELOG.md | 11 ++++++ packages/gazzodown/package.json | 6 ++-- packages/instance-status/CHANGELOG.md | 9 +++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 +++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 +++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 +++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 +++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 +++++ packages/ui-avatar/package.json | 4 +-- packages/ui-client/CHANGELOG.md | 9 +++++ packages/ui-client/package.json | 4 +-- packages/ui-contexts/CHANGELOG.md | 11 ++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 ++++++ packages/ui-video-conf/package.json | 6 ++-- packages/uikit-playground/CHANGELOG.md | 11 ++++++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 9 +++++ packages/web-ui-registration/package.json | 4 +-- yarn.lock | 20 +++++------ 69 files changed, 425 insertions(+), 54 deletions(-) create mode 100644 .changeset/bump-patch-1725326060827.md diff --git a/.changeset/bump-patch-1725326060827.md b/.changeset/bump-patch-1725326060827.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1725326060827.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/pre.json b/.changeset/pre.json index b16c34f330cd..947aecb92f25 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -67,7 +67,9 @@ "brown-crabs-chew", "bump-patch-1724712948901", "bump-patch-1724977971712", + "bump-patch-1725326060827", "calm-tigers-peel", + "cool-actors-sin", "cool-rocks-remember", "empty-toys-smell", "fast-lobsters-turn", diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index 862232d77787..2f6758c0dd90 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,39 @@ # @rocket.chat/meteor +## 6.12.0-rc.3 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- ([#33159](https://github.com/RocketChat/Rocket.Chat/pull/33159)) Improves Omnichannel queue page performance + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/license@0.2.5-rc.3 + - @rocket.chat/omnichannel-services@0.3.2-rc.3 + - @rocket.chat/pdf-worker@0.2.2-rc.3 + - @rocket.chat/presence@0.2.5-rc.3 + - @rocket.chat/api-client@0.2.5-rc.3 + - @rocket.chat/apps@0.1.5-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/cron@0.1.5-rc.3 + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.3 + - @rocket.chat/gazzodown@10.0.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/ui-contexts@10.0.0-rc.3 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.2-rc.3 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.3 + - @rocket.chat/ui-client@10.0.0-rc.3 + - @rocket.chat/ui-video-conf@10.0.0-rc.3 + - @rocket.chat/web-ui-registration@10.0.0-rc.3 + - @rocket.chat/instance-status@0.1.5-rc.3 +
+ ## 6.12.0-rc.2 ### Patch Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index b88a04d76851..1bca0bac5765 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.12.0-rc.2" + "version": "6.12.0-rc.3" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 1d6a25b73776..abf8d5228b29 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.3.2-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 1.3.2-rc.2 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 8d9679014361..83c091192c61 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.2-rc.2", + "version": "1.3.2-rc.3", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index ab76940fee8a..f81fca6618aa 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.12.0-rc.2", + "version": "6.12.0-rc.3", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 630cb593da8a..38c443cf3a4b 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.4.5-rc.2 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 5a4b896658f0..536cef003036 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.5-rc.2", + "version": "0.4.5-rc.3", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index 1c86327bd7c0..45d15fd042a5 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.4.5-rc.2 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index f814e9e423ab..1a71691c0a14 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.5-rc.2", + "version": "0.4.5-rc.3", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index a8f4bf3e076b..3a5f74b87852 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/ddp-streamer +## 0.3.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 + - @rocket.chat/instance-status@0.1.5-rc.3 +
+ ## 0.3.5-rc.2 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 25203f96d8c3..38581e470022 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.5-rc.2", + "version": "0.3.5-rc.3", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index fa7eb91835b5..7be9afcd9559 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/omnichannel-services@0.3.2-rc.3 + - @rocket.chat/pdf-worker@0.2.2-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.4.5-rc.2 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 80e7c5456bd6..404a7aca3441 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.5-rc.2", + "version": "0.4.5-rc.3", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 80a6bc702eff..30a99e7b8e55 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/presence@0.2.5-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.4.5-rc.2 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 83e816c9f0b4..6bb81a60e6cb 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.5-rc.2", + "version": "0.4.5-rc.3", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 6e075a3b50f4..71d6c295cb38 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/omnichannel-services@0.3.2-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.4.5-rc.2 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 0c8281eaec2b..335e656f4f8a 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.5-rc.2", + "version": "0.4.5-rc.3", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 7a6d5fa93c67..392d9a2e9b9b 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.4.5-rc.2 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 125ba400991c..d3b12e730262 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.5-rc.2", + "version": "0.4.5-rc.3", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index a3fb453b888f..3c8436ca82e6 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 +
+ ## 0.2.5-rc.2 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index d357d2e85243..2a86ce9f12a7 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.5-rc.2", + "version": "0.2.5-rc.3", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 51dd515e5a3a..6ca6e78c68ba 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.2-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/pdf-worker@0.2.2-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.3.2-rc.2 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 676576e42b3c..91937d884f5d 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.2-rc.2", + "version": "0.3.2-rc.3", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index f9881b0273ff..d050ccf77ea0 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.2-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 +
+ ## 0.2.2-rc.2 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 8724b3d4d6e1..0405b1530dc8 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.2-rc.2", + "version": "0.2.2-rc.3", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index f211e5812b68..989426b15d05 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/core-services@0.6.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.2.5-rc.2 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 530d53767c7a..eab9e4050f3a 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.5-rc.2", + "version": "0.2.5-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index fd4f9abcfc2f..6012e87ef2ca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.12.0-rc.2", + "version": "6.12.0-rc.3", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md index 3694ba19c009..a80e5a7e0900 100644 --- a/packages/api-client/CHANGELOG.md +++ b/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 +
+ ## 0.2.5-rc.2 ### Patch Changes diff --git a/packages/api-client/package.json b/packages/api-client/package.json index d2f203161cb7..68b249942c1f 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.5-rc.2", + "version": "0.2.5-rc.3", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index bc6dd6e55408..3e6c5ef39e4f 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/model-typings@0.7.0-rc.3 +
+ ## 0.1.5-rc.2 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 7b23ba55bcf9..7919ee2f3f6f 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.5-rc.2", + "version": "0.1.5-rc.3", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index 8f62112c8922..bb87268b8e8f 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.6.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.6.0-rc.2 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index a4e8ada23f19..d6db1dfdc31f 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.6.0-rc.2", + "version": "0.6.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index f9bb8458f37a..bfa83d392816 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.12.0-rc.3 + ## 6.12.0-rc.2 ## 6.12.0-rc.1 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index eb9c2a47866a..43cbc3a6292f 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.12.0-rc.2", + "version": "6.12.0-rc.3", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 6f684940f3c1..a4bc7615db55 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.1.5-rc.2 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index 78e1579405ec..7d243266bc25 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.5-rc.2", + "version": "0.1.5-rc.3", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/ddp-client/CHANGELOG.md b/packages/ddp-client/CHANGELOG.md index 9dcb8a73d04c..0ec02a88ff69 100644 --- a/packages/ddp-client/CHANGELOG.md +++ b/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ddp-client +## 0.3.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/api-client@0.2.5-rc.3 +
+ ## 0.3.5-rc.2 ### Patch Changes diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index 89db267343fe..2484f6b3b99f 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.5-rc.2", + "version": "0.3.5-rc.3", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 30c34bf191b7..9da6098482ea 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 10.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/gazzodown@10.0.0-rc.3 + - @rocket.chat/ui-contexts@10.0.0-rc.3 + - @rocket.chat/ui-avatar@6.0.0-rc.3 + - @rocket.chat/ui-video-conf@10.0.0-rc.3 +
+ ## 10.0.0-rc.2 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 2dcfab40ce11..cbc2e9c29d62 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "10.0.0-rc.2", + "version": "10.0.0-rc.3", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0-rc.2", - "@rocket.chat/ui-contexts": "10.0.0-rc.2", + "@rocket.chat/ui-avatar": "6.0.0-rc.3", + "@rocket.chat/ui-contexts": "10.0.0-rc.3", "@rocket.chat/ui-kit": "0.36.1-rc.0", - "@rocket.chat/ui-video-conf": "10.0.0-rc.2", + "@rocket.chat/ui-video-conf": "10.0.0-rc.3", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index bfdcc3cf881f..4c2f98d560b1 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 10.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/ui-contexts@10.0.0-rc.3 + - @rocket.chat/ui-client@10.0.0-rc.3 +
+ ## 10.0.0-rc.2 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 64f33c6bbfd1..2716d57f0250 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "10.0.0-rc.2", + "version": "10.0.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -66,8 +66,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "10.0.0-rc.2", - "@rocket.chat/ui-contexts": "10.0.0-rc.2", + "@rocket.chat/ui-client": "10.0.0-rc.3", + "@rocket.chat/ui-contexts": "10.0.0-rc.3", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index a654321650cf..0be6adf6cc59 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.5-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.2.2-rc.3 +
+ ## 0.1.5-rc.2 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 0e385002d153..04683fad8ce4 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.5-rc.2", + "version": "0.1.5-rc.3", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index c4b6702ce273..9df991bae547 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.19.2-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@10.0.0-rc.3 +
+ ## 1.19.2-rc.2 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 8204d6478f4b..6112165c723e 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.2-rc.2", + "version": "1.19.2-rc.3", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 1e52e3e6f005..566249984b5f 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.7.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 +
+ ## 0.7.0-rc.2 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index 524d012e41a5..bb45b3a08ba6 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.7.0-rc.2", + "version": "0.7.0-rc.3", "private": true, "devDependencies": { "@types/node-rsa": "^1.1.3", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index f7995184602a..206a949666e0 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.2.2-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.7.0-rc.3 +
+ ## 0.2.2-rc.2 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index 4f32e1edbffa..cd7f2c743876 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.2-rc.2", + "version": "0.2.2-rc.3", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index fab8b499954d..a850f0e0ec90 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.12.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 +
+ ## 6.12.0-rc.2 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index c11dc05cd6c2..c248c18267f9 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.12.0-rc.2", + "version": "6.12.0-rc.3", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index 52845ddff3be..dc5e70097220 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 6.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.3 +
+ ## 6.0.0-rc.2 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index b34b9e4891f4..78d9ffe249d3 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "6.0.0-rc.2", + "version": "6.0.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "10.0.0-rc.2", + "@rocket.chat/ui-contexts": "10.0.0-rc.3", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index a3d0b59dc6d9..364b71169f1f 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 10.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.3 +
+ ## 10.0.0-rc.2 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 13119376a79b..025db00782a7 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "10.0.0-rc.2", + "version": "10.0.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -60,7 +60,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "10.0.0-rc.2", + "@rocket.chat/ui-contexts": "10.0.0-rc.3", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index 37c1e0a5431c..f311763386b1 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 10.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.3 + - @rocket.chat/rest-typings@6.12.0-rc.3 + - @rocket.chat/ddp-client@0.3.5-rc.3 +
+ ## 10.0.0-rc.2 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 0a5fbf4a83f2..7f82271d1d30 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "10.0.0-rc.2", + "version": "10.0.0-rc.3", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index e7f617bb3c07..9e28fff148a4 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 10.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.3 + - @rocket.chat/ui-avatar@6.0.0-rc.3 +
+ ## 10.0.0-rc.2 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index f89db00eae82..50b5f67c5a8b 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "10.0.0-rc.2", + "version": "10.0.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -40,8 +40,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0-rc.2", - "@rocket.chat/ui-contexts": "10.0.0-rc.2", + "@rocket.chat/ui-avatar": "6.0.0-rc.3", + "@rocket.chat/ui-contexts": "10.0.0-rc.3", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index 0154c2a5d005..6b1b3cb0c981 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.4.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.3 + - @rocket.chat/ui-contexts@10.0.0-rc.3 + - @rocket.chat/ui-avatar@6.0.0-rc.3 +
+ ## 0.4.0-rc.2 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 6a91a7681572..5ba9ceebb62e 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.4.0-rc.2", + "version": "0.4.0-rc.3", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 56bf9390b687..c475eb1607c2 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 10.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.3 +
+ ## 10.0.0-rc.2 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index cb9c41903091..54d67b89dbbe 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "10.0.0-rc.2", + "version": "10.0.0-rc.3", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -47,7 +47,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "10.0.0-rc.2", + "@rocket.chat/ui-contexts": "10.0.0-rc.3", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", diff --git a/yarn.lock b/yarn.lock index 2dadeaa4d3d9..a948ba3748ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8934,10 +8934,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 6.0.0-rc.1 - "@rocket.chat/ui-contexts": 10.0.0-rc.1 + "@rocket.chat/ui-avatar": 6.0.0-rc.2 + "@rocket.chat/ui-contexts": 10.0.0-rc.2 "@rocket.chat/ui-kit": 0.36.1-rc.0 - "@rocket.chat/ui-video-conf": 10.0.0-rc.1 + "@rocket.chat/ui-video-conf": 10.0.0-rc.2 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9021,8 +9021,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 10.0.0-rc.1 - "@rocket.chat/ui-contexts": 10.0.0-rc.1 + "@rocket.chat/ui-client": 10.0.0-rc.2 + "@rocket.chat/ui-contexts": 10.0.0-rc.2 katex: "*" react: "*" languageName: unknown @@ -10228,7 +10228,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 10.0.0-rc.1 + "@rocket.chat/ui-contexts": 10.0.0-rc.2 react: ~17.0.2 languageName: unknown linkType: soft @@ -10278,7 +10278,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 10.0.0-rc.1 + "@rocket.chat/ui-contexts": 10.0.0-rc.2 react: ~17.0.2 languageName: unknown linkType: soft @@ -10448,8 +10448,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 6.0.0-rc.1 - "@rocket.chat/ui-contexts": 10.0.0-rc.1 + "@rocket.chat/ui-avatar": 6.0.0-rc.2 + "@rocket.chat/ui-contexts": 10.0.0-rc.2 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10536,7 +10536,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 - "@rocket.chat/ui-contexts": 10.0.0-rc.1 + "@rocket.chat/ui-contexts": 10.0.0-rc.2 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 9eaefdc892cb89d2f0c7296d805b93d742f73f0c Mon Sep 17 00:00:00 2001 From: Rafael Tapia Date: Tue, 3 Sep 2024 10:16:56 -0300 Subject: [PATCH 035/170] feat: update contact endpoint (#32729) --- .changeset/heavy-snails-help.md | 6 + .../server/constant/permissions.ts | 4 + .../app/livechat/server/api/v1/contact.ts | 19 +- .../app/livechat/server/lib/Contacts.ts | 61 +++- .../server/models/raw/LivechatContacts.ts | 9 + .../tests/end-to-end/api/livechat/contacts.ts | 285 +++++++++++++++++- .../app/livechat/server/lib/Contacts.spec.ts | 70 ++++- packages/i18n/src/locales/en.i18n.json | 3 + packages/i18n/src/locales/pt-BR.i18n.json | 3 + .../src/models/ILivechatContactsModel.ts | 4 +- packages/rest-typings/src/v1/omnichannel.ts | 53 ++++ 11 files changed, 499 insertions(+), 18 deletions(-) create mode 100644 .changeset/heavy-snails-help.md diff --git a/.changeset/heavy-snails-help.md b/.changeset/heavy-snails-help.md new file mode 100644 index 000000000000..fb10bac9ea8f --- /dev/null +++ b/.changeset/heavy-snails-help.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/rest-typings": minor +--- + +Implemented "omnichannel/contacts.update" endpoint to update contacts diff --git a/apps/meteor/app/authorization/server/constant/permissions.ts b/apps/meteor/app/authorization/server/constant/permissions.ts index d9ae4133e49e..e5e8f7fb05dd 100644 --- a/apps/meteor/app/authorization/server/constant/permissions.ts +++ b/apps/meteor/app/authorization/server/constant/permissions.ts @@ -97,6 +97,10 @@ export const permissions = [ _id: 'create-livechat-contact', roles: ['livechat-manager', 'livechat-monitor', 'livechat-agent', 'admin'], }, + { + _id: 'update-livechat-contact', + roles: ['livechat-manager', 'livechat-monitor', 'livechat-agent', 'admin'], + }, { _id: 'view-livechat-manager', roles: ['livechat-manager', 'livechat-monitor', 'admin'] }, { _id: 'view-omnichannel-contact-center', diff --git a/apps/meteor/app/livechat/server/api/v1/contact.ts b/apps/meteor/app/livechat/server/api/v1/contact.ts index 91b18a6b21af..94bd5ed3e11c 100644 --- a/apps/meteor/app/livechat/server/api/v1/contact.ts +++ b/apps/meteor/app/livechat/server/api/v1/contact.ts @@ -1,11 +1,11 @@ import { LivechatCustomField, LivechatVisitors } from '@rocket.chat/models'; -import { isPOSTOmnichannelContactsProps } from '@rocket.chat/rest-typings'; +import { isPOSTOmnichannelContactsProps, isPOSTUpdateOmnichannelContactsProps } from '@rocket.chat/rest-typings'; import { escapeRegExp } from '@rocket.chat/string-helpers'; import { Match, check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; import { API } from '../../../../api/server'; -import { Contacts, createContact } from '../../lib/Contacts'; +import { Contacts, createContact, updateContact } from '../../lib/Contacts'; API.v1.addRoute( 'omnichannel/contact', @@ -101,3 +101,18 @@ API.v1.addRoute( }, }, ); +API.v1.addRoute( + 'omnichannel/contacts.update', + { authRequired: true, permissionsRequired: ['update-livechat-contact'], validateParams: isPOSTUpdateOmnichannelContactsProps }, + { + async post() { + if (!process.env.TEST_MODE) { + throw new Meteor.Error('error-not-allowed', 'This endpoint is only allowed in test mode'); + } + + const contact = await updateContact({ ...this.bodyParams }); + + return API.v1.success({ contact }); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/lib/Contacts.ts b/apps/meteor/app/livechat/server/lib/Contacts.ts index 4f4a33ee61b2..58404ce27584 100644 --- a/apps/meteor/app/livechat/server/lib/Contacts.ts +++ b/apps/meteor/app/livechat/server/lib/Contacts.ts @@ -1,4 +1,11 @@ -import type { ILivechatContactChannel, ILivechatCustomField, ILivechatVisitor, IOmnichannelRoom, IUser } from '@rocket.chat/core-typings'; +import type { + ILivechatContact, + ILivechatContactChannel, + ILivechatCustomField, + ILivechatVisitor, + IOmnichannelRoom, + IUser, +} from '@rocket.chat/core-typings'; import { LivechatVisitors, Users, @@ -45,6 +52,16 @@ type CreateContactParams = { channels?: ILivechatContactChannel[]; }; +type UpdateContactParams = { + contactId: string; + name?: string; + emails?: string[]; + phones?: string[]; + customFields?: Record; + contactManager?: string; + channels?: ILivechatContactChannel[]; +}; + export const Contacts = { async registerContact({ token, @@ -189,10 +206,7 @@ export async function createContact(params: CreateContactParams): Promise>(contactManager, { projection: { roles: 1 } }); - if (!contactManagerUser) { - throw new Error('error-contact-manager-not-found'); - } + await validateContactManager(contactManager); } const allowedCustomFields = await getAllowedCustomFields(); @@ -211,6 +225,29 @@ export async function createContact(params: CreateContactParams): Promise { + const { contactId, name, emails, phones, customFields, contactManager, channels } = params; + + const contact = await LivechatContacts.findOneById>(contactId, { projection: { _id: 1 } }); + + if (!contact) { + throw new Error('error-contact-not-found'); + } + + if (contactManager) { + await validateContactManager(contactManager); + } + + if (customFields) { + const allowedCustomFields = await getAllowedCustomFields(); + validateCustomFields(allowedCustomFields, customFields); + } + + const updatedContact = await LivechatContacts.updateContact(contactId, { name, emails, phones, contactManager, channels, customFields }); + + return updatedContact; +} + async function getAllowedCustomFields(): Promise { return LivechatCustomField.findByScope( 'visitor', @@ -245,4 +282,18 @@ export function validateCustomFields(allowedCustomFields: ILivechatCustomField[] } } } + + const allowedCustomFieldIds = new Set(allowedCustomFields.map((cf) => cf._id)); + for (const key in customFields) { + if (!allowedCustomFieldIds.has(key)) { + throw new Error(i18n.t('error-custom-field-not-allowed', { key })); + } + } +} + +export async function validateContactManager(contactManagerUserId: string) { + const contactManagerUser = await Users.findOneAgentById>(contactManagerUserId, { projection: { _id: 1 } }); + if (!contactManagerUser) { + throw new Error('error-contact-manager-not-found'); + } } diff --git a/apps/meteor/server/models/raw/LivechatContacts.ts b/apps/meteor/server/models/raw/LivechatContacts.ts index 1f5f29a3cc78..88dac1b9f5c1 100644 --- a/apps/meteor/server/models/raw/LivechatContacts.ts +++ b/apps/meteor/server/models/raw/LivechatContacts.ts @@ -8,4 +8,13 @@ export class LivechatContactsRaw extends BaseRaw implements IL constructor(db: Db, trash?: Collection>) { super(db, 'livechat_contact', trash); } + + async updateContact(contactId: string, data: Partial): Promise { + const updatedValue = await this.findOneAndUpdate( + { _id: contactId }, + { $set: { ...data, unknown: false } }, + { returnDocument: 'after' }, + ); + return updatedValue.value as ILivechatContact; + } } diff --git a/apps/meteor/tests/end-to-end/api/livechat/contacts.ts b/apps/meteor/tests/end-to-end/api/livechat/contacts.ts index 21eced5ee7e9..957d22ba92ae 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/contacts.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/contacts.ts @@ -1,27 +1,42 @@ import { faker } from '@faker-js/faker'; +import type { ILivechatAgent, IUser } from '@rocket.chat/core-typings'; import { expect } from 'chai'; import { before, after, describe, it } from 'mocha'; import { getCredentials, api, request, credentials } from '../../../data/api-data'; import { createCustomField, deleteCustomField } from '../../../data/livechat/custom-fields'; import { createAgent } from '../../../data/livechat/rooms'; +import { removeAgent } from '../../../data/livechat/users'; import { removePermissionFromAllRoles, restorePermissionToRoles, updatePermission, updateSetting } from '../../../data/permissions.helper'; import { createUser, deleteUser } from '../../../data/users.helper'; describe('LIVECHAT - contacts', () => { + let agentUser: IUser; + let livechatAgent: ILivechatAgent; before((done) => getCredentials(done)); before(async () => { await updateSetting('Livechat_enabled', true); - await updatePermission('create-livechat-contact', ['admin']); + agentUser = await createUser(); + livechatAgent = await createAgent(agentUser.username); }); after(async () => { + await removeAgent(livechatAgent._id); + await deleteUser(agentUser); await restorePermissionToRoles('create-livechat-contact'); await updateSetting('Livechat_enabled', true); }); describe('[POST] omnichannel/contacts', () => { + before(async () => { + await updatePermission('create-livechat-contact', ['admin']); + }); + + after(async () => { + await restorePermissionToRoles('create-livechat-contact'); + }); + it('should be able to create a new contact', async () => { const res = await request .post(api('omnichannel/contacts')) @@ -92,9 +107,6 @@ describe('LIVECHAT - contacts', () => { }); it('should be able to create a new contact with a contact manager', async () => { - const user = await createUser(); - const livechatAgent = await createAgent(user.username); - const res = await request .post(api('omnichannel/contacts')) .set(credentials) @@ -108,8 +120,6 @@ describe('LIVECHAT - contacts', () => { expect(res.body).to.have.property('success', true); expect(res.body).to.have.property('contactId'); expect(res.body.contactId).to.be.an('string'); - - await deleteUser(user); }); describe('Custom Fields', () => { @@ -296,4 +306,267 @@ describe('LIVECHAT - contacts', () => { }); }); }); + + describe('[POST] omnichannel/contacts.update', () => { + let contactId: string; + + before(async () => { + const { body } = await request + .post(api('omnichannel/contacts')) + .set(credentials) + .send({ + name: faker.person.fullName(), + emails: [faker.internet.email().toLowerCase()], + phones: [faker.phone.number()], + }); + contactId = body.contactId; + }); + + after(async () => { + await restorePermissionToRoles('update-livechat-contact'); + }); + + it('should be able to update a contact', async () => { + const name = faker.person.fullName(); + const emails = [faker.internet.email().toLowerCase()]; + const phones = [faker.phone.number()]; + + const res = await request.post(api('omnichannel/contacts.update')).set(credentials).send({ + contactId, + name, + emails, + phones, + }); + + expect(res.status).to.be.equal(200); + expect(res.body).to.have.property('success', true); + expect(res.body.contact._id).to.be.equal(contactId); + expect(res.body.contact.name).to.be.equal(name); + expect(res.body.contact.emails).to.be.deep.equal(emails); + expect(res.body.contact.phones).to.be.deep.equal(phones); + }); + + it('should set the unknown field to false when updating a contact', async () => { + const res = await request.post(api('omnichannel/contacts.update')).set(credentials).send({ + contactId, + name: faker.person.fullName(), + }); + + expect(res.status).to.be.equal(200); + expect(res.body).to.have.property('success', true); + expect(res.body.contact._id).to.be.equal(contactId); + expect(res.body.contact.unknown).to.be.equal(false); + }); + + it('should be able to update the contact manager', async () => { + const res = await request.post(api('omnichannel/contacts.update')).set(credentials).send({ + contactId, + contactManager: livechatAgent._id, + }); + + expect(res.status).to.be.equal(200); + expect(res.body).to.have.property('success', true); + expect(res.body.contact._id).to.be.equal(contactId); + expect(res.body.contact.contactManager).to.be.equal(livechatAgent._id); + }); + + it('should return an error if contact does not exist', async () => { + const res = await request + .post(api('omnichannel/contacts.update')) + .set(credentials) + .send({ + contactId: 'invalid', + name: faker.person.fullName(), + emails: [faker.internet.email().toLowerCase()], + phones: [faker.phone.number()], + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('error-contact-not-found'); + }); + + it('should return an error if contact manager not exists', async () => { + const res = await request.post(api('omnichannel/contacts.update')).set(credentials).send({ + contactId, + contactManager: 'invalid', + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('error-contact-manager-not-found'); + }); + + describe('Permissions', () => { + before(async () => { + await removePermissionFromAllRoles('update-livechat-contact'); + }); + + after(async () => { + await restorePermissionToRoles('update-livechat-contact'); + }); + + it("should return an error if user doesn't have 'update-livechat-contact' permission", async () => { + const res = await request.post(api('omnichannel/contacts.update')).set(credentials).send({ + contactId, + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + + describe('Custom Fields', () => { + before(async () => { + await createCustomField({ + field: 'cf1', + label: 'Custom Field 1', + scope: 'visitor', + visibility: 'public', + type: 'input', + required: true, + regexp: '^[0-9]+$', + searchable: true, + public: true, + }); + }); + + after(async () => { + await deleteCustomField('cf1'); + }); + + it('should validate custom fields correctly', async () => { + const res = await request + .post(api('omnichannel/contacts.update')) + .set(credentials) + .send({ + contactId, + customFields: { + cf1: '123', + }, + }); + + expect(res.status).to.be.equal(200); + expect(res.body).to.have.property('success', true); + expect(res.body.contact._id).to.be.equal(contactId); + }); + + it('should return an error for invalid custom field value', async () => { + const res = await request + .post(api('omnichannel/contacts.update')) + .set(credentials) + .send({ + contactId, + customFields: { + cf1: 'invalid', + }, + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('Invalid value for Custom Field 1 field'); + }); + + it('should return an error if additional custom fields are provided', async () => { + const res = await request + .post(api('omnichannel/contacts.update')) + .set(credentials) + .send({ + contactId, + customFields: { + cf1: '123', + cf2: 'invalid', + }, + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('Custom field cf2 is not allowed'); + }); + }); + + describe('Fields Validation', () => { + it('should return an error if contactId is missing', async () => { + const res = await request + .post(api('omnichannel/contacts.update')) + .set(credentials) + .send({ + emails: [faker.internet.email().toLowerCase()], + phones: [faker.phone.number()], + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal("must have required property 'contactId' [invalid-params]"); + expect(res.body.errorType).to.be.equal('invalid-params'); + }); + + it('should return an error if emails is not an array', async () => { + const res = await request.post(api('omnichannel/contacts.update')).set(credentials).send({ + contactId, + emails: 'invalid', + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('must be array [invalid-params]'); + expect(res.body.errorType).to.be.equal('invalid-params'); + }); + + it('should return an error if emails is not an array of strings', async () => { + const res = await request + .post(api('omnichannel/contacts.update')) + .set(credentials) + .send({ + contactId, + emails: [{ invalid: true }], + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('must be string [invalid-params]'); + expect(res.body.errorType).to.be.equal('invalid-params'); + }); + + it('should return an error if phones is not an array', async () => { + const res = await request.post(api('omnichannel/contacts.update')).set(credentials).send({ + contactId, + phones: 'invalid', + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('must be array [invalid-params]'); + expect(res.body.errorType).to.be.equal('invalid-params'); + }); + + it('should return an error if phones is not an array of strings', async () => { + const res = await request + .post(api('omnichannel/contacts.update')) + .set(credentials) + .send({ + contactId, + phones: [{ invalid: true }], + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('must be string [invalid-params]'); + expect(res.body.errorType).to.be.equal('invalid-params'); + }); + + it('should return an error if additional fields are provided', async () => { + const res = await request.post(api('omnichannel/contacts.update')).set(credentials).send({ + contactId, + unknown: true, + }); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal('must NOT have additional properties [invalid-params]'); + expect(res.body.errorType).to.be.equal('invalid-params'); + }); + }); + }); }); diff --git a/apps/meteor/tests/unit/app/livechat/server/lib/Contacts.spec.ts b/apps/meteor/tests/unit/app/livechat/server/lib/Contacts.spec.ts index 9ff2019ffca5..fef3c59469f8 100644 --- a/apps/meteor/tests/unit/app/livechat/server/lib/Contacts.spec.ts +++ b/apps/meteor/tests/unit/app/livechat/server/lib/Contacts.spec.ts @@ -2,10 +2,22 @@ import { expect } from 'chai'; import proxyquire from 'proxyquire'; import sinon from 'sinon'; -const { validateCustomFields } = proxyquire.noCallThru().load('../../../../../../app/livechat/server/lib/Contacts', { - 'meteor/check': sinon.stub(), - 'meteor/meteor': sinon.stub(), -}); +const modelsMock = { + Users: { + findOneAgentById: sinon.stub(), + }, + LivechatContacts: { + findOneById: sinon.stub(), + updateContact: sinon.stub(), + }, +}; +const { validateCustomFields, validateContactManager, updateContact } = proxyquire + .noCallThru() + .load('../../../../../../app/livechat/server/lib/Contacts', { + 'meteor/check': sinon.stub(), + 'meteor/meteor': sinon.stub(), + '@rocket.chat/models': modelsMock, + }); describe('[OC] Contacts', () => { describe('validateCustomFields', () => { @@ -36,5 +48,55 @@ describe('[OC] Contacts', () => { expect(() => validateCustomFields(allowedCustomFields, customFields)).not.to.throw(); }); + + it('should throw an error if a extra custom field is passed', () => { + const allowedCustomFields = [{ _id: 'field1', label: 'Field 1', required: false }]; + const customFields = { field2: 'value' }; + + expect(() => validateCustomFields(allowedCustomFields, customFields)).to.throw(); + }); + }); + + describe('validateContactManager', () => { + beforeEach(() => { + modelsMock.Users.findOneAgentById.reset(); + }); + + it('should throw an error if the user does not exist', async () => { + modelsMock.Users.findOneAgentById.resolves(undefined); + await expect(validateContactManager('any_id')).to.be.rejectedWith('error-contact-manager-not-found'); + }); + + it('should not throw an error if the user has the "livechat-agent" role', async () => { + const user = { _id: 'userId' }; + modelsMock.Users.findOneAgentById.resolves(user); + + await expect(validateContactManager('userId')).to.not.be.rejected; + expect(modelsMock.Users.findOneAgentById.getCall(0).firstArg).to.be.equal('userId'); + }); + }); + + describe('updateContact', () => { + beforeEach(() => { + modelsMock.LivechatContacts.findOneById.reset(); + modelsMock.LivechatContacts.updateContact.reset(); + }); + + it('should throw an error if the contact does not exist', async () => { + modelsMock.LivechatContacts.findOneById.resolves(undefined); + await expect(updateContact('any_id')).to.be.rejectedWith('error-contact-not-found'); + expect(modelsMock.LivechatContacts.updateContact.getCall(0)).to.be.null; + }); + + it('should update the contact with correct params', async () => { + modelsMock.LivechatContacts.findOneById.resolves({ _id: 'contactId' }); + modelsMock.LivechatContacts.updateContact.resolves({ _id: 'contactId', name: 'John Doe' } as any); + + const updatedContact = await updateContact({ contactId: 'contactId', name: 'John Doe' }); + + expect(modelsMock.LivechatContacts.updateContact.getCall(0).args[0]).to.be.equal('contactId'); + expect(modelsMock.LivechatContacts.updateContact.getCall(0).args[1]).to.be.deep.contain({ name: 'John Doe' }); + expect(updatedContact).to.be.deep.equal({ _id: 'contactId', name: 'John Doe' }); + }); }); }); diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index b28b1fc2bfde..ea7e31422cb1 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -2082,6 +2082,7 @@ "error-invalid-custom-field": "Invalid custom field", "error-invalid-custom-field-name": "Invalid custom field name. Use only letters, numbers, hyphens and underscores.", "error-invalid-custom-field-value": "Invalid value for {{field}} field", + "error-custom-field-not-allowed": "Custom field {{key}} is not allowed", "error-invalid-date": "Invalid date provided.", "error-invalid-dates": "From date cannot be after To date", "error-invalid-description": "Invalid description", @@ -5842,6 +5843,8 @@ "view-joined-room": "View Joined Room", "view-joined-room_description": "Permission to view the currently joined channels", "view-l-room": "View Omnichannel Rooms", + "create-livechat-contact": "Create Omnichannel contacts", + "update-livechat-contact": "Update Omnichannel contacts", "view-l-room_description": "Permission to view Omnichannel rooms", "view-livechat-analytics": "View Omnichannel Analytics", "onboarding.page.awaitingConfirmation.subtitle": "We have sent you an email to {{emailAddress}} with a confirmation link. Please verify that the security code below matches the one in the email.", diff --git a/packages/i18n/src/locales/pt-BR.i18n.json b/packages/i18n/src/locales/pt-BR.i18n.json index f072bc626270..dc62318cb230 100644 --- a/packages/i18n/src/locales/pt-BR.i18n.json +++ b/packages/i18n/src/locales/pt-BR.i18n.json @@ -1736,6 +1736,7 @@ "error-invalid-custom-field": "Campo personalizado inválido", "error-invalid-custom-field-name": "Nome inválido para o campo personalizado. Use apenas letras, números, hífens e travessão.", "error-invalid-custom-field-value": "Valor inválido para o campo {{field}}", + "error-custom-field-not-allowed": "O campo personalizado {{key}} não é permitido", "error-invalid-date": "Data fornecida inválida", "error-invalid-description": "Descrição inválida", "error-invalid-domain": "Domínio inválido", @@ -4678,6 +4679,8 @@ "view-joined-room": "Ver sala incorporada", "view-joined-room_description": "Permissão para ver os canais atualmente associados", "view-l-room": "Ver salas de omnichannel", + "create-livechat-contact": "Criar contatos do omnichannel", + "update-livechat-contact": "Atualizar contatos do omnichannel", "view-l-room_description": "Permissão para ver salas de omnichannel", "view-livechat-analytics": "Ver a análise do omnichannel", "onboarding.page.awaitingConfirmation.subtitle": "Enviamos um e-mail para {{emailAddress}} com um link de confirmação. Verifique se o código de segurança abaixo coincide com o do e-mail.", diff --git a/packages/model-typings/src/models/ILivechatContactsModel.ts b/packages/model-typings/src/models/ILivechatContactsModel.ts index bcf48a837400..f94216830884 100644 --- a/packages/model-typings/src/models/ILivechatContactsModel.ts +++ b/packages/model-typings/src/models/ILivechatContactsModel.ts @@ -2,4 +2,6 @@ import type { ILivechatContact } from '@rocket.chat/core-typings'; import type { IBaseModel } from './IBaseModel'; -export type ILivechatContactsModel = IBaseModel; +export interface ILivechatContactsModel extends IBaseModel { + updateContact(contactId: string, data: Partial): Promise; +} diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index c15e94030de3..1ed249f5dd55 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -27,6 +27,7 @@ import type { ReportWithUnmatchingElements, SMSProviderResponse, ILivechatTriggerActionResponse, + ILivechatContact, } from '@rocket.chat/core-typings'; import { ILivechatAgentStatus } from '@rocket.chat/core-typings'; import Ajv from 'ajv'; @@ -1254,6 +1255,55 @@ const POSTOmnichannelContactsSchema = { export const isPOSTOmnichannelContactsProps = ajv.compile(POSTOmnichannelContactsSchema); +type POSTUpdateOmnichannelContactsProps = { + contactId: string; + name?: string; + emails?: string[]; + phones?: string[]; + customFields?: Record; + contactManager?: string; +}; + +const POSTUpdateOmnichannelContactsSchema = { + type: 'object', + properties: { + contactId: { + type: 'string', + }, + name: { + type: 'string', + }, + emails: { + type: 'array', + items: { + type: 'string', + }, + uniqueItems: true, + nullable: true, + }, + phones: { + type: 'array', + items: { + type: 'string', + }, + uniqueItems: true, + nullable: true, + }, + customFields: { + type: 'object', + nullable: true, + }, + contactManager: { + type: 'string', + nullable: true, + }, + }, + required: ['contactId'], + additionalProperties: false, +}; + +export const isPOSTUpdateOmnichannelContactsProps = ajv.compile(POSTUpdateOmnichannelContactsSchema); + type GETOmnichannelContactProps = { contactId: string }; const GETOmnichannelContactSchema = { @@ -3695,6 +3745,9 @@ export type OmnichannelEndpoints = { '/v1/omnichannel/contacts': { POST: (params: POSTOmnichannelContactsProps) => { contactId: string }; }; + '/v1/omnichannel/contacts.update': { + POST: (params: POSTUpdateOmnichannelContactsProps) => { contact: ILivechatContact }; + }; '/v1/omnichannel/contact.search': { GET: (params: GETOmnichannelContactSearchProps) => { contact: ILivechatVisitor | null }; From 4dc145f1a1d9d076b70f87455245932f1bb62c61 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 3 Sep 2024 16:50:24 +0000 Subject: [PATCH 036/170] Release 6.11.2 [no ci] --- .changeset/bump-patch-1724077277110.md | 5 -- .changeset/gentle-bugs-think.md | 5 -- .changeset/orange-clocks-wait.md | 5 -- .changeset/strong-rings-rush.md | 5 -- .changeset/two-bikes-crash.md | 7 --- .changeset/wise-avocados-taste.md | 5 -- apps/meteor/CHANGELOG.md | 46 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 ++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 ++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 ++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 15 ++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 ++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 ++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 ++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 +++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/api-client/CHANGELOG.md | 10 ++++ ee/packages/api-client/package.json | 2 +- ee/packages/ddp-client/CHANGELOG.md | 10 ++++ ee/packages/ddp-client/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 ++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 ++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 ++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 +++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/apps/CHANGELOG.md | 10 ++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 +++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 + packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 ++++ packages/cron/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 ++++++ packages/fuselage-ui-kit/package.json | 8 ++-- packages/gazzodown/CHANGELOG.md | 11 +++++ packages/gazzodown/package.json | 6 +-- packages/instance-status/CHANGELOG.md | 9 ++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 ++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 ++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 ++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 ++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 ++++ packages/ui-avatar/package.json | 4 +- packages/ui-client/CHANGELOG.md | 9 ++++ packages/ui-client/package.json | 4 +- packages/ui-contexts/CHANGELOG.md | 11 +++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 ++++ packages/ui-video-conf/package.json | 6 +-- packages/uikit-playground/CHANGELOG.md | 11 +++++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 9 ++++ packages/web-ui-registration/package.json | 4 +- 72 files changed, 420 insertions(+), 76 deletions(-) delete mode 100644 .changeset/bump-patch-1724077277110.md delete mode 100644 .changeset/gentle-bugs-think.md delete mode 100644 .changeset/orange-clocks-wait.md delete mode 100644 .changeset/strong-rings-rush.md delete mode 100644 .changeset/two-bikes-crash.md delete mode 100644 .changeset/wise-avocados-taste.md diff --git a/.changeset/bump-patch-1724077277110.md b/.changeset/bump-patch-1724077277110.md deleted file mode 100644 index e1eaa7980afb..000000000000 --- a/.changeset/bump-patch-1724077277110.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Bump @rocket.chat/meteor version. diff --git a/.changeset/gentle-bugs-think.md b/.changeset/gentle-bugs-think.md deleted file mode 100644 index fc4738f3043a..000000000000 --- a/.changeset/gentle-bugs-think.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Prevent `processRoomAbandonment` callback from erroring out when a room was inactive during a day Business Hours was not configured for. diff --git a/.changeset/orange-clocks-wait.md b/.changeset/orange-clocks-wait.md deleted file mode 100644 index eacb88108a0f..000000000000 --- a/.changeset/orange-clocks-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/.changeset/strong-rings-rush.md b/.changeset/strong-rings-rush.md deleted file mode 100644 index 5125f47dcb3b..000000000000 --- a/.changeset/strong-rings-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Restored tooltips to the unit edit department field selected options diff --git a/.changeset/two-bikes-crash.md b/.changeset/two-bikes-crash.md deleted file mode 100644 index a120435e4a48..000000000000 --- a/.changeset/two-bikes-crash.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixed an issue related to setting Accounts_ForgetUserSessionOnWindowClose, this setting was not working as expected. - -The new meteor 2.16 release introduced a new option to configure the Accounts package and choose between the local storage or session storage. They also changed how Meteor.\_localstorage works internally. Due to these changes in Meteor, our setting to use session storage wasn't working as expected. This PR fixes this issue and configures the Accounts package according to the workspace settings. diff --git a/.changeset/wise-avocados-taste.md b/.changeset/wise-avocados-taste.md deleted file mode 100644 index c4c9bce010b8..000000000000 --- a/.changeset/wise-avocados-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes an issue where multi-step modals were closing unexpectedly diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index aa58cd1ba36a..4a5a8c760a8c 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,51 @@ # @rocket.chat/meteor +## 6.11.2 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- Bump @rocket.chat/meteor version. + +- ([#33084](https://github.com/RocketChat/Rocket.Chat/pull/33084) by [@dionisio-bot](https://github.com/dionisio-bot)) Prevent `processRoomAbandonment` callback from erroring out when a room was inactive during a day Business Hours was not configured for. + +- ([#33153](https://github.com/RocketChat/Rocket.Chat/pull/33153) by [@dionisio-bot](https://github.com/dionisio-bot)) Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) + +- ([#33185](https://github.com/RocketChat/Rocket.Chat/pull/33185) by [@dionisio-bot](https://github.com/dionisio-bot)) Restored tooltips to the unit edit department field selected options + +- ([#33129](https://github.com/RocketChat/Rocket.Chat/pull/33129) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixed an issue related to setting Accounts_ForgetUserSessionOnWindowClose, this setting was not working as expected. + + The new meteor 2.16 release introduced a new option to configure the Accounts package and choose between the local storage or session storage. They also changed how Meteor.\_localstorage works internally. Due to these changes in Meteor, our setting to use session storage wasn't working as expected. This PR fixes this issue and configures the Accounts package according to the workspace settings. + +- ([#33178](https://github.com/RocketChat/Rocket.Chat/pull/33178) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixes an issue where multi-step modals were closing unexpectedly + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/api-client@0.2.5 + - @rocket.chat/license@0.2.5 + - @rocket.chat/omnichannel-services@0.3.2 + - @rocket.chat/pdf-worker@0.2.2 + - @rocket.chat/presence@0.2.5 + - @rocket.chat/apps@0.1.5 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/cron@0.1.5 + - @rocket.chat/fuselage-ui-kit@9.0.2 + - @rocket.chat/gazzodown@9.0.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/ui-contexts@9.0.2 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.2 + - @rocket.chat/ui-theming@0.2.0 + - @rocket.chat/ui-avatar@5.0.2 + - @rocket.chat/ui-client@9.0.2 + - @rocket.chat/ui-video-conf@9.0.2 + - @rocket.chat/web-ui-registration@9.0.2 + - @rocket.chat/instance-status@0.1.5 +
+ ## 6.11.1 ### Patch Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index 74c84a88cef2..0604041b61c7 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.11.1" + "version": "6.11.2" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 87dd221531e1..7e9c69fc3a8f 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.3.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/models@0.2.2 +
+ ## 1.3.1 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 59f351444031..34d57e65ab1a 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.1", + "version": "1.3.2", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 044bb765e2db..be520ecf6fa1 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.11.1", + "version": "6.11.2", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index c72b16bd401f..f289dbe21329 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.4.4 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 895d955510fd..73ff677d29f5 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.4", + "version": "0.4.5", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index 03f7cb62a50b..08efe1cb2e77 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.4.4 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 7c6783838a84..f3ade2612149 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.4", + "version": "0.4.5", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 22ddcea338a5..3b8ce871f86a 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/ddp-streamer +## 0.3.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/ui-contexts@9.0.2 + - @rocket.chat/models@0.2.2 + - @rocket.chat/instance-status@0.1.5 +
+ ## 0.3.4 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index e2d4fd6320b0..1307dde1d7c1 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.4", + "version": "0.3.5", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index b9837882510c..12831f929366 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/omnichannel-services@0.3.2 + - @rocket.chat/pdf-worker@0.2.2 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.4.4 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 293e5c1be775..cf3801bdd513 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.4", + "version": "0.4.5", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 614c49928415..a6e47fc6f9af 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/presence@0.2.5 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.4.4 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 457eb9225b6c..f0d43ab5fe84 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.4", + "version": "0.4.5", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 53be288ed34d..ff37f0acf2dd 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/omnichannel-services@0.3.2 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.4.4 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 72bc5d688e36..1903ef994958 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.4", + "version": "0.4.5", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 284e853f4737..41efb8e4a8bd 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.4.4 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index d1f2e64acfc0..96b2f95197bd 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.4", + "version": "0.4.5", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/api-client/CHANGELOG.md b/ee/packages/api-client/CHANGELOG.md index 7430778db198..a78f2c6b738f 100644 --- a/ee/packages/api-client/CHANGELOG.md +++ b/ee/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 +
+ ## 0.2.4 ### Patch Changes diff --git a/ee/packages/api-client/package.json b/ee/packages/api-client/package.json index d5744d456a46..07e141691f0d 100644 --- a/ee/packages/api-client/package.json +++ b/ee/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.4", + "version": "0.2.5", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/ddp-client/CHANGELOG.md b/ee/packages/ddp-client/CHANGELOG.md index c26b0c47f6cb..ad4c010470c4 100644 --- a/ee/packages/ddp-client/CHANGELOG.md +++ b/ee/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ddp-client +## 0.3.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/api-client@0.2.5 +
+ ## 0.3.4 ### Patch Changes diff --git a/ee/packages/ddp-client/package.json b/ee/packages/ddp-client/package.json index 192ea63af72d..4e9a7b8564c6 100644 --- a/ee/packages/ddp-client/package.json +++ b/ee/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.4", + "version": "0.3.5", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 9dce96a0310d..958a23f152ad 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 +
+ ## 0.2.4 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index e5317dc08bcc..22e54c3d5cc9 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.4", + "version": "0.2.5", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index d3bbf0b00655..a8f12d64def3 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/pdf-worker@0.2.2 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/model-typings@0.6.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.3.1 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index f6c66eba4550..5958ccdf131b 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.1", + "version": "0.3.2", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index a67dc8eafd21..95479cecb74e 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 +
+ ## 0.2.1 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index d2a0e3029eff..726de909bc17 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.1", + "version": "0.2.2", "private": true, "devDependencies": { "@storybook/addon-essentials": "~6.5.16", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index 93d927c5bc5c..b186efdfd733 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/core-services@0.5.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.2.4 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index a01538b8de6c..a7213ab2c793 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.4", + "version": "0.2.5", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index edc1f5da7e54..5679d4f1a101 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.11.1", + "version": "6.11.2", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index e9efd36ae6bc..ea366e23cef1 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/model-typings@0.6.2 +
+ ## 0.1.4 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 254e1566e120..076601f770af 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.4", + "version": "0.1.5", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index 9871852c0245..0a2f604faabf 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.5.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.5.1 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 072157066bcf..bc2c7c9b5d3c 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.5.1", + "version": "0.5.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index 42bcd35326fa..8760abdf06a0 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.11.2 + ## 6.11.1 ## 6.11.0 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 16e17d410ad5..aca37032fd82 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.11.1", + "version": "6.11.2", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index b2b06e586370..64e5823dea43 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/models@0.2.2 +
+ ## 0.1.4 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index ede7f521da8c..ff7cb93469c8 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.4", + "version": "0.1.5", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 0b1435f47f1b..f5185a744fad 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 9.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/gazzodown@9.0.2 + - @rocket.chat/ui-contexts@9.0.2 + - @rocket.chat/ui-avatar@5.0.2 + - @rocket.chat/ui-video-conf@9.0.2 +
+ ## 9.0.1 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 32d18d782968..492ec6799e61 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "9.0.1", + "version": "9.0.2", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.1", - "@rocket.chat/ui-contexts": "9.0.1", + "@rocket.chat/ui-avatar": "5.0.2", + "@rocket.chat/ui-contexts": "9.0.2", "@rocket.chat/ui-kit": "0.36.0", - "@rocket.chat/ui-video-conf": "9.0.1", + "@rocket.chat/ui-video-conf": "9.0.2", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 48b701cbeb54..f418d2055016 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 9.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/ui-contexts@9.0.2 + - @rocket.chat/ui-client@9.0.2 +
+ ## 9.0.1 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 7341d79bba85..8d33aadcb2e3 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "9.0.1", + "version": "9.0.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -71,8 +71,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "9.0.1", - "@rocket.chat/ui-contexts": "9.0.1", + "@rocket.chat/ui-client": "9.0.2", + "@rocket.chat/ui-contexts": "9.0.2", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index d314c504721c..1ffe17fc3fbf 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.2.2 +
+ ## 0.1.4 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 2037a3cf5f61..7d86bf07dc01 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.4", + "version": "0.1.5", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index 87cdaae78911..f7554d380b02 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.19.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@9.0.2 +
+ ## 1.19.1 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 6974bd1a2acd..c61496d9420c 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.1", + "version": "1.19.2", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 6b27e4ad4ab1..6f367165df67 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.6.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 +
+ ## 0.6.1 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index edc79f10e2df..0e4df28c7ad5 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.6.1", + "version": "0.6.2", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 772805da3b8f..a74d88f3161d 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.2.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.6.2 +
+ ## 0.2.1 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index c09d8cea307f..f0c0a0fe4e5a 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.1", + "version": "0.2.2", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 9f0e3a01cd21..c9c3fd7652b3 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.11.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 +
+ ## 6.11.1 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index a7a8275dd276..4a4388f814bd 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.11.1", + "version": "6.11.2", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "@types/jest": "~29.5.7", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index 927a3463e069..f059f62949b5 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 5.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.2 +
+ ## 5.0.1 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 92d1382de36e..ac528e7cf4ad 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "5.0.1", + "version": "5.0.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "9.0.1", + "@rocket.chat/ui-contexts": "9.0.2", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 8dee0ec12c50..b0bf87281f0b 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 9.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.2 +
+ ## 9.0.1 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 43743f37339f..71c80e9fd8e6 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "9.0.1", + "version": "9.0.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -63,7 +63,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "9.0.1", + "@rocket.chat/ui-contexts": "9.0.2", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index 4e21589c1388..14bd6d6514d2 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 9.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.2 + - @rocket.chat/rest-typings@6.11.2 + - @rocket.chat/ddp-client@0.3.5 +
+ ## 9.0.1 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 85d6df1b93e6..bc3bb0daba3f 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "9.0.1", + "version": "9.0.2", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index feb33d9679e0..27dacec94f8c 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 9.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.2 + - @rocket.chat/ui-avatar@5.0.2 +
+ ## 9.0.1 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 861da958667c..489cd82cd363 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "9.0.1", + "version": "9.0.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -36,8 +36,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.1", - "@rocket.chat/ui-contexts": "9.0.1", + "@rocket.chat/ui-avatar": "5.0.2", + "@rocket.chat/ui-contexts": "9.0.2", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index 7515e3005bc6..a098342b1427 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.3.5 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@9.0.2 + - @rocket.chat/ui-contexts@9.0.2 + - @rocket.chat/ui-avatar@5.0.2 +
+ ## 0.3.4 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 2923804daa48..f9850b9052a9 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.3.4", + "version": "0.3.5", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index ab10df1e8c58..f115425281a4 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 9.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.2 +
+ ## 9.0.1 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 3e0a0483eb86..8909fa91b65a 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "9.0.1", + "version": "9.0.2", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -51,7 +51,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "9.0.1", + "@rocket.chat/ui-contexts": "9.0.2", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From 75041350a5cd6c93affd99959f5025fef44b3ce3 Mon Sep 17 00:00:00 2001 From: Debdut Chakraborty Date: Tue, 3 Sep 2024 22:58:47 +0530 Subject: [PATCH 037/170] ci: change release repository (#32923) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 514dd6d1c518..40260f71d21f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -824,7 +824,7 @@ jobs: with: token: ${{ secrets.DISTRIBUTION_TOKEN }} event-type: new_release - repository: RocketChat/Release.Distributions + repository: RocketChat/public-releases client-payload: '{"tag": "${{ github.ref_name }}"}' docs-update: From e04a6d19b21a74d5bc6fe135d739aeb6de19d188 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 3 Sep 2024 18:13:40 +0000 Subject: [PATCH 038/170] Release 6.12.0-rc.4 [no ci] --- .changeset/bump-patch-1725387211812.md | 5 +++ .changeset/pre.json | 1 + apps/meteor/CHANGELOG.md | 35 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 +++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 15 ++++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 26 ++++++++++---- ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 17 +++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 19 ++++++++-- ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 15 +++++++- ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 14 ++++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 16 ++++++++- ee/apps/stream-hub-service/package.json | 2 +- ee/packages/license/CHANGELOG.md | 12 ++++++- ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 17 +++++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 15 +++++++- ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 14 ++++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/api-client/CHANGELOG.md | 11 ++++++ packages/api-client/package.json | 2 +- packages/apps/CHANGELOG.md | 13 +++++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 ++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 3 ++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 11 ++++++ packages/cron/package.json | 2 +- packages/ddp-client/CHANGELOG.md | 13 +++++++ packages/ddp-client/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 15 ++++++++ packages/fuselage-ui-kit/package.json | 8 ++--- packages/gazzodown/CHANGELOG.md | 13 +++++++ packages/gazzodown/package.json | 6 ++-- packages/instance-status/CHANGELOG.md | 12 ++++++- packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 10 ++++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 10 ++++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 13 ++++++- packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 11 ++++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 12 +++++++ packages/ui-avatar/package.json | 4 +-- packages/ui-client/CHANGELOG.md | 11 ++++++ packages/ui-client/package.json | 4 +-- packages/ui-contexts/CHANGELOG.md | 15 ++++++-- packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 14 +++++++- packages/ui-video-conf/package.json | 6 ++-- packages/uikit-playground/CHANGELOG.md | 15 +++++++- packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 11 ++++++ packages/web-ui-registration/package.json | 4 +-- 68 files changed, 483 insertions(+), 63 deletions(-) create mode 100644 .changeset/bump-patch-1725387211812.md diff --git a/.changeset/bump-patch-1725387211812.md b/.changeset/bump-patch-1725387211812.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1725387211812.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/pre.json b/.changeset/pre.json index 947aecb92f25..6aa4b3dd5bf9 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -68,6 +68,7 @@ "bump-patch-1724712948901", "bump-patch-1724977971712", "bump-patch-1725326060827", + "bump-patch-1725387211812", "calm-tigers-peel", "cool-actors-sin", "cool-rocks-remember", diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index 754ffaa5686c..a3c6f38176ac 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,11 +1,45 @@ # @rocket.chat/meteor +## 6.12.0-rc.4 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/license@0.2.6-rc.4 + - @rocket.chat/omnichannel-services@0.3.3-rc.4 + - @rocket.chat/pdf-worker@0.2.3-rc.4 + - @rocket.chat/presence@0.2.6-rc.4 + - @rocket.chat/api-client@0.2.6-rc.4 + - @rocket.chat/apps@0.1.6-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/cron@0.1.6-rc.4 + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.4 + - @rocket.chat/gazzodown@10.0.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/ui-contexts@10.0.0-rc.4 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.3-rc.4 + - @rocket.chat/ui-theming@0.2.1-rc.0 + - @rocket.chat/ui-avatar@6.0.0-rc.4 + - @rocket.chat/ui-client@10.0.0-rc.4 + - @rocket.chat/ui-video-conf@10.0.0-rc.4 + - @rocket.chat/web-ui-registration@10.0.0-rc.4 + - @rocket.chat/instance-status@0.1.6-rc.4 +
+ ## 6.11.2 + ### Patch Changes - Bump @rocket.chat/meteor version. ## 6.12.0-rc.3 + ### Patch Changes - Bump @rocket.chat/meteor version. @@ -218,6 +252,7 @@ - @rocket.chat/instance-status@0.1.4-rc.0 - @rocket.chat/server-cloud-communication@0.0.2 + - Bump @rocket.chat/meteor version. - ([#33084](https://github.com/RocketChat/Rocket.Chat/pull/33084) by [@dionisio-bot](https://github.com/dionisio-bot)) Prevent `processRoomAbandonment` callback from erroring out when a room was inactive during a day Business Hours was not configured for. diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index 1bca0bac5765..77fdbe3d6942 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.12.0-rc.3" + "version": "6.12.0-rc.4" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index d4ad4a47d8b8..8ff59eaabd3e 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,17 @@ # rocketchat-services +## 1.3.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
## 1.3.2 @@ -8,6 +20,7 @@ -
Updated dependencies []: ## 1.3.3-rc.3 + ### Patch Changes -
Updated dependencies []: diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 687c00eb676f..5ef1b16af1c2 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.3-rc.3", + "version": "1.3.3-rc.4", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index f81fca6618aa..b1d00dd1b931 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.12.0-rc.3", + "version": "6.12.0-rc.4", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 0febefd2e0b7..ab5fcbb3f11d 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,6 +1,20 @@ # @rocket.chat/account-service +## 0.4.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
+ ## 0.4.5 + ### Patch Changes -
Updated dependencies []: @@ -12,6 +26,7 @@
## 0.4.6-rc.3 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 710f1b064c1a..16d72db9844e 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.6-rc.3", + "version": "0.4.6-rc.4", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index ebc00c17b413..6d82edcf5808 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,20 +1,32 @@ # @rocket.chat/authorization-service - -## 0.4.5 +## 0.4.6-rc.4 ### Patch Changes -
Updated dependencies []: - - @rocket.chat/core-typings@6.11.2 - - @rocket.chat/rest-typings@6.11.2 - - @rocket.chat/core-services@0.5.2 - - @rocket.chat/model-typings@0.6.2 - - @rocket.chat/models@0.2.2 + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4
+## 0.4.5 + +### Patch Changes + +-
Updated dependencies []: +- @rocket.chat/core-typings@6.11.2 +- @rocket.chat/rest-typings@6.11.2 +- @rocket.chat/core-services@0.5.2 +- @rocket.chat/model-typings@0.6.2 +- @rocket.chat/models@0.2.2 +
## 0.4.6-rc.3 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 60ced4f57d26..b247e6f5dbb5 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.6-rc.3", + "version": "0.4.6-rc.4", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 5d97da181d36..1c9c37bf3400 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,6 +1,21 @@ # @rocket.chat/ddp-streamer +## 0.3.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 + - @rocket.chat/instance-status@0.1.6-rc.4 +
+ ## 0.3.6-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -54,7 +69,9 @@ - @rocket.chat/models@0.2.1-rc.0 - @rocket.chat/instance-status@0.1.4-rc.0
+ ## 0.3.5 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 438afa9791de..fbe9173b32db 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.6-rc.3", + "version": "0.3.6-rc.4", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 33d1b880524f..bfb8ca03b676 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,11 +1,24 @@ # @rocket.chat/omnichannel-transcript +## 0.4.6-rc.4 -## 0.4.6-rc.3 ### Patch Changes -
Updated dependencies []: + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/omnichannel-services@0.3.3-rc.4 + - @rocket.chat/pdf-worker@0.2.3-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
+ +## 0.4.6-rc.3 + +### Patch Changes + +-
Updated dependencies []: - @rocket.chat/core-typings@6.12.0-rc.3 - @rocket.chat/omnichannel-services@0.3.2-rc.3 @@ -55,8 +68,10 @@ - @rocket.chat/omnichannel-services@0.3.1-rc.0 - @rocket.chat/models@0.2.1-rc.0 - @rocket.chat/pdf-worker@0.2.1-rc.0 -
+
+ ## 0.4.5 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 40cfb3667ef4..6ce61b7e1a71 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.6-rc.3", + "version": "0.4.6-rc.4", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 5258a6aa180e..238f5b922e4d 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/presence@0.2.6-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
+ ## 0.4.6-rc.3 ### Patch Changes @@ -50,8 +63,8 @@ - @rocket.chat/models@0.2.1-rc.0 - @rocket.chat/presence@0.2.4-rc.0
-## 0.4.5 +## 0.4.5 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 7cd653e0969d..958b1da5293b 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.6-rc.3", + "version": "0.4.6-rc.4", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 3335455fe454..9fd9667e3115 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,7 +1,20 @@ # @rocket.chat/queue-worker +## 0.4.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/omnichannel-services@0.3.3-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
## 0.4.6-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -53,6 +66,7 @@
## 0.4.5 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index a07d9784deea..262787811e43 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.6-rc.3", + "version": "0.4.6-rc.4", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index aad9d0186738..fe29a82ffbba 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,7 +1,19 @@ # @rocket.chat/stream-hub-service +## 0.4.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
## 0.4.6-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -46,8 +58,10 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/core-services@0.6.0-rc.0 - @rocket.chat/models@0.2.1-rc.0 -
+
+ ## 0.4.5 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index c00be846e78a..80ce39023626 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.6-rc.3", + "version": "0.4.6-rc.4", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 3909267868b5..0c857093c129 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,8 +1,16 @@ # @rocket.chat/license +## 0.2.6-rc.4 +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 +
## 0.2.6-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -35,8 +43,10 @@ -
Updated dependencies [7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: - @rocket.chat/core-typings@6.12.0-rc.0 -
+
+ ## 0.2.5 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 8d083ed4d47b..694e6faaee5c 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.6-rc.3", + "version": "0.2.6-rc.4", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 49a904ae5535..752cb9a7d8c2 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,6 +1,21 @@ # @rocket.chat/omnichannel-services +## 0.3.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/pdf-worker@0.2.3-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
+ ## 0.3.3-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -54,7 +69,9 @@ - @rocket.chat/models@0.2.1-rc.0 - @rocket.chat/pdf-worker@0.2.1-rc.0
+ ## 0.3.2 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index aee66810ed7c..10da64e14995 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.3-rc.3", + "version": "0.3.3-rc.4", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index a2f4d8471002..c2fbbdf3c0cf 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,11 +1,22 @@ # @rocket.chat/pdf-worker +## 0.2.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 +
+ ## 0.2.2 + ### Patch Changes -
Updated dependencies []: ## 0.2.3-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -38,8 +49,10 @@ -
Updated dependencies [7937ff741a, 58c0efc732, e28be46db7, 58c0efc732]: - @rocket.chat/core-typings@6.12.0-rc.0 -
+
+ ## 0.2.2 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 2c637c6421e3..037d976bb484 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.3-rc.3", + "version": "0.2.3-rc.4", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index 09713273474e..41d732348c84 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,6 +1,18 @@ # @rocket.chat/presence +## 0.2.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/core-services@0.6.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
+ ## 0.2.6-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -42,7 +54,9 @@ - @rocket.chat/core-services@0.6.0-rc.0 - @rocket.chat/models@0.2.1-rc.0
+ ## 0.2.5 + ### Patch Changes -
Updated dependencies []: diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 196446fcc7b0..f5e1bafa6747 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.6-rc.3", + "version": "0.2.6-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index 6012e87ef2ca..7b92d068451a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.12.0-rc.3", + "version": "6.12.0-rc.4", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md index cf34b109064a..f572a907479f 100644 --- a/packages/api-client/CHANGELOG.md +++ b/packages/api-client/CHANGELOG.md @@ -1,8 +1,17 @@ # @rocket.chat/api-client +## 0.2.6-rc.4 +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 +
## 0.2.6-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -39,7 +48,9 @@ - @rocket.chat/rest-typings@6.12.0-rc.0 - @rocket.chat/core-typings@6.12.0-rc.0
+ ## 0.2.5 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 75d7a0f00e39..8483d0eed41a 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.6-rc.3", + "version": "0.2.6-rc.4", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 584580544eb9..37eff88a3664 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,6 +1,17 @@ # @rocket.chat/apps +## 0.1.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/model-typings@0.7.0-rc.4 +
+ ## 0.1.6-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -38,7 +49,9 @@ - @rocket.chat/model-typings@0.7.0-rc.0 - @rocket.chat/core-typings@6.12.0-rc.0
+ ## 0.1.5 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/apps/package.json b/packages/apps/package.json index c18989113fec..3a36c524822c 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.6-rc.3", + "version": "0.1.6-rc.4", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index cbe5a476a772..d1bb14df9ada 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,7 +1,18 @@ # @rocket.chat/core-services +## 0.6.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
## 0.6.0-rc.3 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/core-services/package.json b/packages/core-services/package.json index d6db1dfdc31f..409952cc0c37 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.6.0-rc.3", + "version": "0.6.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index 30a859b84d2b..599b1cc5833e 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.12.0-rc.4 + ## 6.12.0-rc.3 ## 6.12.0-rc.2 @@ -32,6 +34,7 @@ - @rocket.chat/ui-kit@0.36.1-rc.0
+ ## 6.11.2 ## 6.11.1 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 43cbc3a6292f..75705fb91541 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.12.0-rc.3", + "version": "6.12.0-rc.4", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 7e136b7cde6f..3547dc00b3d5 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,7 +1,17 @@ # @rocket.chat/cron +## 0.1.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/models@0.2.3-rc.4 +
## 0.1.6-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -39,6 +49,7 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/models@0.2.1-rc.0
+ ## 0.1.5 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index 8fb41d605846..a91aac727d37 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.6-rc.3", + "version": "0.1.6-rc.4", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/ddp-client/CHANGELOG.md b/packages/ddp-client/CHANGELOG.md index 1e70d11ad1b3..f95d31c25370 100644 --- a/packages/ddp-client/CHANGELOG.md +++ b/packages/ddp-client/CHANGELOG.md @@ -1,7 +1,18 @@ # @rocket.chat/ddp-client +## 0.3.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/api-client@0.2.6-rc.4 +
## 0.3.6-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -43,7 +54,9 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/api-client@0.2.4-rc.0
+ ## 0.3.5 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index bb3c9f36a066..f477fc732ca4 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.6-rc.3", + "version": "0.3.6-rc.4", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index dfcd7c6bada3..d44f1c9c56ce 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,6 +1,20 @@ # Change Log +## 10.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/gazzodown@10.0.0-rc.4 + - @rocket.chat/ui-contexts@10.0.0-rc.4 + - @rocket.chat/ui-avatar@6.0.0-rc.4 + - @rocket.chat/ui-video-conf@10.0.0-rc.4 +
+ ## 10.0.0-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -54,6 +68,7 @@
## 9.0.2 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index cbc2e9c29d62..ab8dee206f07 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "10.0.0-rc.3", + "version": "10.0.0-rc.4", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0-rc.3", - "@rocket.chat/ui-contexts": "10.0.0-rc.3", + "@rocket.chat/ui-avatar": "6.0.0-rc.4", + "@rocket.chat/ui-contexts": "10.0.0-rc.4", "@rocket.chat/ui-kit": "0.36.1-rc.0", - "@rocket.chat/ui-video-conf": "10.0.0-rc.3", + "@rocket.chat/ui-video-conf": "10.0.0-rc.4", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 4c142863bf66..b29df6d2887b 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,7 +1,18 @@ # @rocket.chat/gazzodown +## 10.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/ui-contexts@10.0.0-rc.4 + - @rocket.chat/ui-client@10.0.0-rc.4 +
## 10.0.0-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -45,7 +56,9 @@ - @rocket.chat/core-typings@6.12.0-rc.0 - @rocket.chat/ui-contexts@10.0.0-rc.0
+ ## 9.0.2 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 2716d57f0250..bae2ed3fdb15 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "10.0.0-rc.3", + "version": "10.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -66,8 +66,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "10.0.0-rc.3", - "@rocket.chat/ui-contexts": "10.0.0-rc.3", + "@rocket.chat/ui-client": "10.0.0-rc.4", + "@rocket.chat/ui-contexts": "10.0.0-rc.4", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index 53c7dcf1de93..bcffe470bc5a 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,11 +1,20 @@ # @rocket.chat/instance-status +## 0.1.6-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.2.3-rc.4 +
## 0.1.6-rc.3 + ### Patch Changes -
Updated dependencies []: - + - @rocket.chat/models@0.2.2-rc.3
@@ -36,6 +45,7 @@
## 0.1.5 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 128759dcf044..aa8e0432c99b 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.6-rc.3", + "version": "0.1.6-rc.4", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index f306219ec318..08c7ccff3c86 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,6 +1,16 @@ # @rocket.chat/livechat Change Log +## 1.19.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@10.0.0-rc.4 +
+ ## 1.19.3-rc.3 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 7ba74445aec0..3153925ef531 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.3-rc.3", + "version": "1.19.3-rc.4", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 8a237189774f..e411eea4e61c 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,13 @@ # @rocket.chat/model-typings +## 0.7.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 +
## 0.6.2 @@ -9,7 +17,9 @@ - @rocket.chat/core-typings@6.11.2
+ ## 0.7.0-rc.3 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index bb45b3a08ba6..812ec223bd0f 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.7.0-rc.3", + "version": "0.7.0-rc.4", "private": true, "devDependencies": { "@types/node-rsa": "^1.1.3", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index fd8131004e2f..b45739ee48e8 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,7 +1,16 @@ # @rocket.chat/models +## 0.2.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.7.0-rc.4 +
## 0.2.3-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -34,8 +43,10 @@ -
Updated dependencies [7f88158036, a14c0678bb, e28be46db7]: - @rocket.chat/model-typings@0.7.0-rc.0 -
+
+ ## 0.2.2 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/models/package.json b/packages/models/package.json index f61f9c014fd3..74af2a1a3865 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.3-rc.3", + "version": "0.2.3-rc.4", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 9aebef66f43c..93c80293523d 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,7 +1,16 @@ # @rocket.chat/rest-typings +## 6.12.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 +
## 6.12.0-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -41,7 +50,9 @@ - @rocket.chat/ui-kit@0.36.1-rc.0 - @rocket.chat/core-typings@6.12.0-rc.0
+ ## 6.11.2 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index c248c18267f9..2c6b13e5dd29 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.12.0-rc.3", + "version": "6.12.0-rc.4", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.12", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index 18721b7d5314..ebd57cd5bcc9 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,6 +1,16 @@ # @rocket.chat/ui-avatar +## 6.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.4 +
+ ## 6.0.0-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -35,7 +45,9 @@ - @rocket.chat/ui-contexts@10.0.0-rc.0
+ ## 5.0.2 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 78d9ffe249d3..a31d61205759 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "6.0.0-rc.3", + "version": "6.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "10.0.0-rc.3", + "@rocket.chat/ui-contexts": "10.0.0-rc.4", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 37f8e5542051..037fd7e893b9 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,7 +1,16 @@ # @rocket.chat/ui-client +## 10.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.4 +
## 10.0.0-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -36,7 +45,9 @@ - @rocket.chat/ui-contexts@10.0.0-rc.0
+ ## 9.0.2 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 025db00782a7..9d1e1b2c356f 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "10.0.0-rc.3", + "version": "10.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -60,7 +60,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "10.0.0-rc.3", + "@rocket.chat/ui-contexts": "10.0.0-rc.4", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index c9d8e9e1647e..2a846d730bc0 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,12 +1,22 @@ # @rocket.chat/ui-contexts +## 10.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.12.0-rc.4 + - @rocket.chat/rest-typings@6.12.0-rc.4 + - @rocket.chat/ddp-client@0.3.6-rc.4 +
## 10.0.0-rc.3 + ### Patch Changes -
Updated dependencies []: - - + - @rocket.chat/core-typings@6.12.0-rc.3 - @rocket.chat/rest-typings@6.12.0-rc.3 - @rocket.chat/ddp-client@0.3.5-rc.3 @@ -47,6 +57,7 @@
## 9.0.2 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 7f82271d1d30..1a27dd1de101 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "10.0.0-rc.3", + "version": "10.0.0-rc.4", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index fa727d7a25fc..85c06375e2a0 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,11 +1,21 @@ # @rocket.chat/ui-video-conf +## 10.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.4 + - @rocket.chat/ui-avatar@6.0.0-rc.4 +
+ ## 10.0.0-rc.3 + ### Patch Changes -
Updated dependencies []: - - @rocket.chat/ui-contexts@10.0.0-rc.3 - @rocket.chat/ui-avatar@6.0.0-rc.3
@@ -41,7 +51,9 @@ - @rocket.chat/ui-avatar@6.0.0-rc.0 - @rocket.chat/ui-contexts@10.0.0-rc.0
+ ## 9.0.2 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 50b5f67c5a8b..0718e7ce8765 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "10.0.0-rc.3", + "version": "10.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -40,8 +40,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0-rc.3", - "@rocket.chat/ui-contexts": "10.0.0-rc.3", + "@rocket.chat/ui-avatar": "6.0.0-rc.4", + "@rocket.chat/ui-contexts": "10.0.0-rc.4", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index b46e958bffe3..ad7bfcc86739 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,6 +1,18 @@ # @rocket.chat/uikit-playground +## 0.4.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@10.0.0-rc.4 + - @rocket.chat/ui-contexts@10.0.0-rc.4 + - @rocket.chat/ui-avatar@6.0.0-rc.4 +
+ ## 0.4.0-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -49,6 +61,7 @@
## 0.3.5 + ### Patch Changes -
Updated dependencies []: @@ -56,7 +69,7 @@ - @rocket.chat/fuselage-ui-kit@9.0.2 - @rocket.chat/ui-contexts@9.0.2 - @rocket.chat/ui-avatar@5.0.2 -
+
## 0.3.4 diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 5ba9ceebb62e..008ebcbbdc62 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.4.0-rc.3", + "version": "0.4.0-rc.4", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index fc755af1cd97..c549e60d2d0a 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,6 +1,16 @@ # @rocket.chat/web-ui-registration +## 10.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@10.0.0-rc.4 +
+ ## 10.0.0-rc.3 + ### Patch Changes -
Updated dependencies []: @@ -38,6 +48,7 @@
## 9.0.2 + ### Patch Changes -
Updated dependencies []: diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 54d67b89dbbe..ec2ab7a9f089 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "10.0.0-rc.3", + "version": "10.0.0-rc.4", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -47,7 +47,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "10.0.0-rc.3", + "@rocket.chat/ui-contexts": "10.0.0-rc.4", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From efb41b43ffd3c72a9882e67251601d747b823d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrique=20Guimar=C3=A3es=20Ribeiro?= <43561537+rique223@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:23:04 -0300 Subject: [PATCH 039/170] regression: Add password verification to new user panel contextual bar (#33198) --- .../admin/users/AdminUserSetRandomPasswordContent.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordContent.tsx b/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordContent.tsx index 814ab8a22776..25d7a52a6ad4 100644 --- a/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordContent.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordContent.tsx @@ -1,6 +1,6 @@ import { Box, FieldError, FieldLabel, FieldRow, PasswordInput, ToggleSwitch } from '@rocket.chat/fuselage'; import { useUniqueId } from '@rocket.chat/fuselage-hooks'; -import { PasswordVerifier } from '@rocket.chat/ui-client'; +import { PasswordVerifier, useValidatePassword } from '@rocket.chat/ui-client'; import { useSetting, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; import type { Control, FieldErrors } from 'react-hook-form'; @@ -35,6 +35,8 @@ const AdminUserSetRandomPasswordContent = ({ const passwordPlaceholder = String(useSetting('Accounts_PasswordPlaceholder')); const passwordConfirmationPlaceholder = String(useSetting('Accounts_ConfirmPasswordPlaceholder')); + const passwordIsValid = useValidatePassword(password); + return ( <> @@ -53,7 +55,10 @@ const AdminUserSetRandomPasswordContent = ({ (password?.length && !passwordIsValid ? t('Password_must_meet_the_complexity_requirements') : true), + required: isNewUserPage && t('The_field_is_required', t('Password')), + }} render={({ field }) => ( (password === val ? true : t('Invalid_confirm_pass')), + validate: (confirmationPassword) => (password !== confirmationPassword ? t('Invalid_confirm_pass') : true), }} render={({ field }) => ( Date: Tue, 27 Aug 2024 17:20:40 -0300 Subject: [PATCH 040/170] test: Add e2e tests for teams multi-step modals (#33168) --- .../contextualBar/channels/TeamsChannels.tsx | 2 +- .../teams/contextualBar/info/TeamsInfo.tsx | 3 +- .../tests/e2e/channel-management.spec.ts | 32 +++--- .../page-objects/fragments/home-content.ts | 14 +++ .../fragments/home-flextab-channels.ts | 24 +++++ .../fragments/home-flextab-members.ts | 8 ++ .../fragments/home-flextab-room.ts | 40 +++++++ .../page-objects/fragments/home-flextab.ts | 4 + .../page-objects/fragments/home-sidenav.ts | 16 ++- .../tests/e2e/page-objects/home-channel.ts | 13 --- .../meteor/tests/e2e/retention-policy.spec.ts | 2 +- apps/meteor/tests/e2e/team-management.spec.ts | 102 +++++++++++++++--- 12 files changed, 210 insertions(+), 50 deletions(-) diff --git a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx index 8bad02c135c8..b1847825ffab 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx +++ b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx @@ -110,7 +110,7 @@ const TeamsChannels = ({ {t('Total')}: {total} - + - } + title='John Doe' subtitle={ diff --git a/apps/meteor/client/sidebarv2/Item/Extended.tsx b/apps/meteor/client/sidebarv2/Item/Extended.tsx index f288f5fd35c6..13112bc96cec 100644 --- a/apps/meteor/client/sidebarv2/Item/Extended.tsx +++ b/apps/meteor/client/sidebarv2/Item/Extended.tsx @@ -1,4 +1,14 @@ -import { Sidebar, IconButton } from '@rocket.chat/fuselage'; +import { + SidebarV2Item, + SidebarV2ItemAvatarWrapper, + SidebarV2ItemCol, + SidebarV2ItemRow, + SidebarV2ItemTitle, + SidebarV2ItemTimestamp, + SidebarV2ItemContent, + SidebarV2ItemMenu, + IconButton, +} from '@rocket.chat/fuselage'; import { useEffectEvent, usePrefersReducedMotion } from '@rocket.chat/fuselage-hooks'; import type { Keys as IconName } from '@rocket.chat/icons'; import React, { memo, useState } from 'react'; @@ -7,7 +17,7 @@ import { useShortTimeAgo } from '../../hooks/useTimeAgo'; type ExtendedProps = { icon?: IconName; - title?: React.ReactNode; + title: string; avatar?: React.ReactNode | boolean; actions?: React.ReactNode; href?: string; @@ -24,7 +34,7 @@ type ExtendedProps = { const Extended = ({ icon, - title = '', + title, avatar, actions, href, @@ -37,7 +47,6 @@ const Extended = ({ threadUnread: _threadUnread, unread, selected, - ...props }: ExtendedProps) => { const formatDate = useShortTimeAgo(); const [menuVisibility, setMenuVisibility] = useState(!!window.DISABLE_ANIMATION); @@ -47,42 +56,33 @@ const Extended = ({ const handleMenu = useEffectEvent((e) => { setMenuVisibility(e.target.offsetWidth > 0 && Boolean(menu)); }); - const handleMenuEvent = { [isReduceMotionEnabled ? 'onMouseEnter' : 'onTransitionEnd']: handleMenu, }; return ( - - {avatar && {avatar}} - - - - {icon} - - {title} - - {time && {formatDate(time)}} - - - - - {subtitle} - {badges} - {menu && ( - - {menuVisibility ? menu() : } - - )} - - - - {actions && ( - - {actions} - - )} - + + {avatar && {avatar}} + + + + {icon && icon} + {title} + {time && {formatDate(time)}} + + + + {subtitle} + {badges && badges} + {actions && actions} + {menu && ( + + {menuVisibility ? menu() : } + + )} + + + ); }; diff --git a/apps/meteor/client/sidebarv2/Item/Medium.tsx b/apps/meteor/client/sidebarv2/Item/Medium.tsx index ffc13047f66d..13d2305ad7d5 100644 --- a/apps/meteor/client/sidebarv2/Item/Medium.tsx +++ b/apps/meteor/client/sidebarv2/Item/Medium.tsx @@ -1,12 +1,13 @@ -import { Sidebar, IconButton } from '@rocket.chat/fuselage'; +import { IconButton, SidebarV2Item, SidebarV2ItemAvatarWrapper, SidebarV2ItemMenu, SidebarV2ItemTitle } from '@rocket.chat/fuselage'; import { useEffectEvent, usePrefersReducedMotion } from '@rocket.chat/fuselage-hooks'; +import type { Keys as IconName } from '@rocket.chat/icons'; import React, { memo, useState } from 'react'; type MediumProps = { - title: React.ReactNode; + title: string; titleIcon?: React.ReactNode; avatar: React.ReactNode | boolean; - icon?: string; + icon?: IconName; actions?: React.ReactNode; href?: string; unread?: boolean; @@ -16,7 +17,7 @@ type MediumProps = { menuOptions?: any; }; -const Medium = ({ icon, title = '', avatar, actions, href, badges, unread, menu, ...props }: MediumProps) => { +const Medium = ({ icon, title, avatar, actions, href, badges, unread, menu, selected }: MediumProps) => { const [menuVisibility, setMenuVisibility] = useState(!!window.DISABLE_ANIMATION); const isReduceMotionEnabled = usePrefersReducedMotion(); @@ -29,28 +30,18 @@ const Medium = ({ icon, title = '', avatar, actions, href, badges, unread, menu, }; return ( - - {avatar && {avatar}} - - - {icon} - - {title} - - - {badges && {badges}} - {menu && ( - - {menuVisibility ? menu() : } - - )} - - {actions && ( - - {actions} - + + {avatar} + {icon && icon} + {title} + {badges && badges} + {actions && actions} + {menu && ( + + {menuVisibility ? menu() : } + )} - + ); }; diff --git a/apps/meteor/client/sidebarv2/RoomList/RoomList.tsx b/apps/meteor/client/sidebarv2/RoomList/RoomList.tsx index 3f137d4709c7..5f6592210d65 100644 --- a/apps/meteor/client/sidebarv2/RoomList/RoomList.tsx +++ b/apps/meteor/client/sidebarv2/RoomList/RoomList.tsx @@ -1,11 +1,11 @@ -import type { IRoom } from '@rocket.chat/core-typings'; -import { css } from '@rocket.chat/css-in-js'; -import { Box } from '@rocket.chat/fuselage'; +/* eslint-disable react/no-multi-comp */ +import type { ISubscription, IRoom } from '@rocket.chat/core-typings'; +import { Box, SidebarV2GroupTitle } from '@rocket.chat/fuselage'; import { useResizeObserver } from '@rocket.chat/fuselage-hooks'; +import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useUserPreference, useUserId, useTranslation } from '@rocket.chat/ui-contexts'; -import type { ReactElement } from 'react'; import React, { useMemo } from 'react'; -import { Virtuoso } from 'react-virtuoso'; +import { GroupedVirtuoso } from 'react-virtuoso'; import { VirtuosoScrollbars } from '../../components/CustomScrollbars'; import { useOpenedRoom } from '../../lib/RoomManager'; @@ -18,7 +18,25 @@ import RoomListRow from './RoomListRow'; import RoomListRowWrapper from './RoomListRowWrapper'; import RoomListWrapper from './RoomListWrapper'; -const computeItemKey = (index: number, room: IRoom): IRoom['_id'] | number => room._id || index; +const getRoomsByGroup = (rooms: (ISubscription & IRoom)[]) => { + const groupCounts = rooms + .reduce((acc, item, index) => { + if (typeof item === 'string') { + acc.push(index); + } + return acc; + }, [] as number[]) + .map((item, index, arr) => (arr[index + 1] ? arr[index + 1] : rooms.length) - item - 1); + + const groupList = rooms.filter((item) => typeof item === 'string') as unknown as TranslationKey[]; + const roomList = rooms.filter((item) => typeof item !== 'string'); + + return { + groupCounts, + groupList, + roomList, + }; +}; const RoomList = () => { const t = useTranslation(); @@ -26,7 +44,7 @@ const RoomList = () => { const roomsList = useRoomList(); const avatarTemplate = useAvatarTemplate(); const sideBarItemTemplate = useTemplateByViewMode(); - const { ref } = useResizeObserver({ debounceDelay: 100 }); + const { ref } = useResizeObserver({ debounceDelay: 100 }); const openedRoom = useOpenedRoom() ?? ''; const sidebarViewMode = useUserPreference<'extended' | 'medium' | 'condensed'>('sidebarViewMode') || 'extended'; @@ -35,7 +53,7 @@ const RoomList = () => { () => ({ extended, t, - SideBarItemTemplate: sideBarItemTemplate, + SidebarItemTemplate: sideBarItemTemplate, AvatarTemplate: avatarTemplate, openedRoom, sidebarViewMode, @@ -47,87 +65,16 @@ const RoomList = () => { usePreventDefault(ref); useShortcutOpenMenu(ref); - const roomsListStyle = css` - position: relative; - - display: flex; - - overflow-x: hidden; - overflow-y: hidden; - - flex: 1 1 auto; - - height: 100%; - - &--embedded { - margin-top: 2rem; - } - - &__list:not(:last-child) { - margin-bottom: 22px; - } - - &__type { - display: flex; - - flex-direction: row; - - padding: 0 var(--sidebar-default-padding) 1rem var(--sidebar-default-padding); - - color: var(--rooms-list-title-color); - - font-size: var(--rooms-list-title-text-size); - align-items: center; - justify-content: space-between; - - &-text--livechat { - flex: 1; - } - } - - &__empty-room { - padding: 0 var(--sidebar-default-padding); - - color: var(--rooms-list-empty-text-color); - - font-size: var(--rooms-list-empty-text-size); - } - - &__toolbar-search { - position: absolute; - z-index: 10; - left: 0; - - overflow-y: scroll; - - height: 100%; - - background-color: var(--sidebar-background); - - padding-block-start: 12px; - } - - @media (max-width: 400px) { - padding: 0 calc(var(--sidebar-small-default-padding) - 4px); - - &__type, - &__empty-room { - padding: 0 calc(var(--sidebar-small-default-padding) - 4px) 0.5rem calc(var(--sidebar-small-default-padding) - 4px); - } - } - `; + const { groupCounts, groupList, roomList } = getRoomsByGroup(roomsList); return ( - - - } - /> - + + } + itemContent={(index) => } + components={{ Item: RoomListRowWrapper, List: RoomListWrapper, Scroller: VirtuosoScrollbars }} + /> ); }; diff --git a/apps/meteor/client/sidebarv2/RoomList/RoomListRow.tsx b/apps/meteor/client/sidebarv2/RoomList/RoomListRow.tsx index 64796d2e12e4..b520033056f3 100644 --- a/apps/meteor/client/sidebarv2/RoomList/RoomListRow.tsx +++ b/apps/meteor/client/sidebarv2/RoomList/RoomListRow.tsx @@ -1,18 +1,17 @@ import type { IRoom, ISubscription } from '@rocket.chat/core-typings'; -import { SidebarSection } from '@rocket.chat/fuselage'; import type { useTranslation } from '@rocket.chat/ui-contexts'; import React, { memo, useMemo } from 'react'; import { useVideoConfAcceptCall, useVideoConfRejectIncomingCall, useVideoConfIncomingCalls } from '../../contexts/VideoConfContext'; import type { useAvatarTemplate } from '../hooks/useAvatarTemplate'; import type { useTemplateByViewMode } from '../hooks/useTemplateByViewMode'; -import SideBarItemTemplateWithData from './SideBarItemTemplateWithData'; +import SidebarItemTemplateWithData from './SidebarItemTemplateWithData'; type RoomListRowProps = { data: { extended: boolean; t: ReturnType; - SideBarItemTemplate: ReturnType; + SidebarItemTemplate: ReturnType; AvatarTemplate: ReturnType; openedRoom: string; sidebarViewMode: 'extended' | 'condensed' | 'medium'; @@ -22,7 +21,7 @@ type RoomListRowProps = { }; const RoomListRow = ({ data, item }: RoomListRowProps) => { - const { extended, t, SideBarItemTemplate, AvatarTemplate, openedRoom, sidebarViewMode } = data; + const { extended, t, SidebarItemTemplate, AvatarTemplate, openedRoom, sidebarViewMode } = data; const acceptCall = useVideoConfAcceptCall(); const rejectCall = useVideoConfRejectIncomingCall(); @@ -38,22 +37,14 @@ const RoomListRow = ({ data, item }: RoomListRowProps) => { [acceptCall, rejectCall, currentCall], ); - if (typeof item === 'string') { - return ( - - {t(item)} - - ); - } - return ( - diff --git a/apps/meteor/client/sidebarv2/RoomList/RoomListRowWrapper.tsx b/apps/meteor/client/sidebarv2/RoomList/RoomListRowWrapper.tsx index b2cd75193466..a848c74ad1d5 100644 --- a/apps/meteor/client/sidebarv2/RoomList/RoomListRowWrapper.tsx +++ b/apps/meteor/client/sidebarv2/RoomList/RoomListRowWrapper.tsx @@ -1,10 +1,11 @@ +import { SidebarV2ListItem } from '@rocket.chat/fuselage'; import type { ForwardedRef, HTMLAttributes } from 'react'; import React, { forwardRef } from 'react'; type RoomListRoomWrapperProps = HTMLAttributes; const RoomListRoomWrapper = forwardRef(function RoomListRoomWrapper(props: RoomListRoomWrapperProps, ref: ForwardedRef) { - return
; + return ; }); export default RoomListRoomWrapper; diff --git a/apps/meteor/client/sidebarv2/RoomList/SideBarItemTemplateWithData.tsx b/apps/meteor/client/sidebarv2/RoomList/SidebarItemTemplateWithData.tsx similarity index 86% rename from apps/meteor/client/sidebarv2/RoomList/SideBarItemTemplateWithData.tsx rename to apps/meteor/client/sidebarv2/RoomList/SidebarItemTemplateWithData.tsx index 4eaba8cc37f0..51b8ce495af6 100644 --- a/apps/meteor/client/sidebarv2/RoomList/SideBarItemTemplateWithData.tsx +++ b/apps/meteor/client/sidebarv2/RoomList/SidebarItemTemplateWithData.tsx @@ -1,6 +1,6 @@ import type { IMessage, IRoom, ISubscription } from '@rocket.chat/core-typings'; import { isDirectMessageRoom, isMultipleDirectMessageRoom, isOmnichannelRoom, isVideoConfMessage } from '@rocket.chat/core-typings'; -import { Badge, Sidebar, SidebarItemAction, SidebarItemActions, Margins } from '@rocket.chat/fuselage'; +import { SidebarV2Action, SidebarV2Actions, SidebarV2ItemBadge, SidebarV2ItemIcon } from '@rocket.chat/fuselage'; import type { useTranslation } from '@rocket.chat/ui-contexts'; import { useLayout } from '@rocket.chat/ui-contexts'; import type { AllHTMLAttributes, ComponentType, ReactElement, ReactNode } from 'react'; @@ -15,7 +15,7 @@ import { OmnichannelBadges } from '../badges/OmnichannelBadges'; import type { useAvatarTemplate } from '../hooks/useAvatarTemplate'; import { normalizeSidebarMessage } from './normalizeSidebarMessage'; -const getMessage = (room: IRoom, lastMessage: IMessage | undefined, t: ReturnType): string | undefined => { +export const getMessage = (room: IRoom, lastMessage: IMessage | undefined, t: ReturnType): string | undefined => { if (!lastMessage) { return t('No_messages_yet'); } @@ -34,7 +34,7 @@ const getMessage = (room: IRoom, lastMessage: IMessage | undefined, t: ReturnTyp return `${lastMessage.u.name || lastMessage.u.username}: ${normalizeSidebarMessage(lastMessage, t)}`; }; -const getBadgeTitle = ( +export const getBadgeTitle = ( userMentions: number, threadUnread: number, groupMentions: number, @@ -61,7 +61,7 @@ const getBadgeTitle = ( type RoomListRowProps = { extended: boolean; t: ReturnType; - SideBarItemTemplate: ComponentType< + SidebarItemTemplate: ComponentType< { icon: ReactNode; title: ReactNode; @@ -98,13 +98,13 @@ type RoomListRowProps = { }; }; -const SideBarItemTemplateWithData = ({ +const SidebarItemTemplateWithData = ({ room, id, selected, style, extended, - SideBarItemTemplate, + SidebarItemTemplate, AvatarTemplate, t, isAnonymous, @@ -132,19 +132,19 @@ const SideBarItemTemplateWithData = ({ const highlighted = Boolean(!hideUnreadStatus && (alert || unread)); const icon = ( - // TODO: Remove icon='at' - - - + } + /> ); const actions = useMemo( () => videoConfActions && ( - - - - + + + + ), [videoConfActions], ); @@ -165,18 +165,18 @@ const SideBarItemTemplateWithData = ({ const badgeTitle = getBadgeTitle(userMentions, tunread.length, groupMentions, unread, t); const badges = ( - + <> {showBadge && isUnread && ( - + {unread + tunread?.length} - + )} {isOmnichannelRoom(room) && } - + ); return ( - { +export default memo(SidebarItemTemplateWithData, (prevProps, nextProps) => { if (keys.some((key) => prevProps[key] !== nextProps[key])) { return false; } diff --git a/apps/meteor/client/sidebarv2/RoomList/useSidebarListNavigation.ts b/apps/meteor/client/sidebarv2/RoomList/useSidebarListNavigation.ts index f5c2d00d4b2c..343df536c3f4 100644 --- a/apps/meteor/client/sidebarv2/RoomList/useSidebarListNavigation.ts +++ b/apps/meteor/client/sidebarv2/RoomList/useSidebarListNavigation.ts @@ -1,8 +1,8 @@ import { useFocusManager } from '@react-aria/focus'; import { useCallback } from 'react'; -const isListItem = (node: EventTarget) => (node as HTMLElement).classList.contains('rcx-sidebar-item'); -const isListItemMenu = (node: EventTarget) => (node as HTMLElement).classList.contains('rcx-sidebar-item__menu'); +const isListItem = (node: EventTarget) => (node as HTMLElement).classList.contains('rcx-sidebar-v2-item'); +const isListItemMenu = (node: EventTarget) => (node as HTMLElement).classList.contains('rcx-sidebar-v2-item__menu'); /** * Custom hook to provide the sidebar navigation by keyboard. diff --git a/apps/meteor/client/sidebarv2/Sidebar.tsx b/apps/meteor/client/sidebarv2/Sidebar.tsx index 573d90dd0d23..7209f51507d9 100644 --- a/apps/meteor/client/sidebarv2/Sidebar.tsx +++ b/apps/meteor/client/sidebarv2/Sidebar.tsx @@ -1,5 +1,4 @@ -import { css } from '@rocket.chat/css-in-js'; -import { Box } from '@rocket.chat/fuselage'; +import { SidebarV2 } from '@rocket.chat/fuselage'; import { useSessionStorage } from '@rocket.chat/fuselage-hooks'; import { useSetting, useUserPreference } from '@rocket.chat/ui-contexts'; import React, { memo } from 'react'; @@ -15,31 +14,18 @@ const Sidebar = () => { const [bannerDismissed, setBannerDismissed] = useSessionStorage('presence_cap_notifier', false); const presenceDisabled = useSetting('Presence_broadcast_disabled'); - const sidebarLink = css` - a { - text-decoration: none; - } - `; - return ( - {presenceDisabled && !bannerDismissed && setBannerDismissed(true)} />} - + ); }; diff --git a/apps/meteor/client/sidebarv2/header/SearchList.tsx b/apps/meteor/client/sidebarv2/header/SearchList.tsx index 70c666fead50..b132af80f674 100644 --- a/apps/meteor/client/sidebarv2/header/SearchList.tsx +++ b/apps/meteor/client/sidebarv2/header/SearchList.tsx @@ -34,7 +34,7 @@ const SearchList = ({ filterText, onEscSearch }: SearchListProps) => { () => ({ items, t, - SideBarItemTemplate: sideBarItemTemplate, + SidebarItemTemplate: sideBarItemTemplate, avatarTemplate, useRealName, extended, diff --git a/apps/meteor/client/sidebarv2/header/SearchSection.tsx b/apps/meteor/client/sidebarv2/header/SearchSection.tsx index c1f3f8cf8c21..660b8ee19cd5 100644 --- a/apps/meteor/client/sidebarv2/header/SearchSection.tsx +++ b/apps/meteor/client/sidebarv2/header/SearchSection.tsx @@ -1,5 +1,5 @@ import { css } from '@rocket.chat/css-in-js'; -import { Box, Icon, TextInput, Palette, Sidebar } from '@rocket.chat/fuselage'; +import { Box, Icon, TextInput, Palette, SidebarV2Section } from '@rocket.chat/fuselage'; import { useMergedRefs, useOutsideClick } from '@rocket.chat/fuselage-hooks'; import { useTranslation, useUser } from '@rocket.chat/ui-contexts'; import React, { useCallback, useEffect, useRef } from 'react'; @@ -70,15 +70,7 @@ const SearchSection = () => { return ( - + { )} - - + {isDirty && } ); diff --git a/apps/meteor/client/sidebarv2/header/actions/CreateRoom.tsx b/apps/meteor/client/sidebarv2/header/actions/CreateRoom.tsx index 478e7cce33e1..a80954c8b297 100644 --- a/apps/meteor/client/sidebarv2/header/actions/CreateRoom.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/CreateRoom.tsx @@ -1,4 +1,4 @@ -import { Sidebar } from '@rocket.chat/fuselage'; +import { SidebarV2Action } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; @@ -13,7 +13,7 @@ const CreateRoom = (props: CreateRoomProps) => { const sections = useCreateRoom(); - return ; + return ; }; export default CreateRoom; diff --git a/apps/meteor/client/sidebarv2/header/actions/Search.tsx b/apps/meteor/client/sidebarv2/header/actions/Search.tsx deleted file mode 100644 index 06d42114d76b..000000000000 --- a/apps/meteor/client/sidebarv2/header/actions/Search.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Sidebar } from '@rocket.chat/fuselage'; -import { useEffectEvent, useOutsideClick } from '@rocket.chat/fuselage-hooks'; -import type { HTMLAttributes } from 'react'; -import React, { useState, useEffect, useRef } from 'react'; -import tinykeys from 'tinykeys'; - -import SearchList from '../../search/SearchList'; - -type SearchProps = Omit, 'is'>; - -const Search = (props: SearchProps) => { - const [searchOpen, setSearchOpen] = useState(false); - - const ref = useRef(null); - const handleCloseSearch = useEffectEvent(() => { - setSearchOpen(false); - }); - - useOutsideClick([ref], handleCloseSearch); - - const openSearch = useEffectEvent(() => { - setSearchOpen(true); - }); - - useEffect(() => { - const unsubscribe = tinykeys(window, { - '$mod+K': (event) => { - event.preventDefault(); - openSearch(); - }, - '$mod+P': (event) => { - event.preventDefault(); - openSearch(); - }, - }); - - return (): void => { - unsubscribe(); - }; - }, [openSearch]); - - return ( - <> - - {searchOpen && } - - ); -}; - -export default Search; diff --git a/apps/meteor/client/sidebarv2/header/actions/Sort.tsx b/apps/meteor/client/sidebarv2/header/actions/Sort.tsx index e7f3b398e5f6..9956acf266b5 100644 --- a/apps/meteor/client/sidebarv2/header/actions/Sort.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/Sort.tsx @@ -1,4 +1,4 @@ -import { Sidebar } from '@rocket.chat/fuselage'; +import { SidebarV2Action } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; @@ -13,9 +13,7 @@ const Sort = (props: SortProps) => { const sections = useSortMenu(); - return ( - - ); + return ; }; export default Sort; diff --git a/apps/meteor/client/sidebarv2/hooks/useAvatarTemplate.tsx b/apps/meteor/client/sidebarv2/hooks/useAvatarTemplate.tsx index 9fd1023a32e7..e5bf780ee5b0 100644 --- a/apps/meteor/client/sidebarv2/hooks/useAvatarTemplate.tsx +++ b/apps/meteor/client/sidebarv2/hooks/useAvatarTemplate.tsx @@ -18,7 +18,7 @@ export const useAvatarTemplate = ( return null; } - const size = ((): 'x36' | 'x28' | 'x16' => { + const size = ((): 'x36' | 'x28' | 'x20' => { switch (viewMode) { case 'extended': return 'x36'; @@ -26,7 +26,7 @@ export const useAvatarTemplate = ( return 'x28'; case 'condensed': default: - return 'x16'; + return 'x20'; } })(); diff --git a/apps/meteor/client/sidebarv2/search/Row.tsx b/apps/meteor/client/sidebarv2/search/Row.tsx index 68ceecd2ad88..f8541546ec4b 100644 --- a/apps/meteor/client/sidebarv2/search/Row.tsx +++ b/apps/meteor/client/sidebarv2/search/Row.tsx @@ -2,7 +2,7 @@ import type { IRoom, ISubscription } from '@rocket.chat/core-typings'; import type { ReactElement } from 'react'; import React, { memo } from 'react'; -import SideBarItemTemplateWithData from '../RoomList/SideBarItemTemplateWithData'; +import SidebarItemTemplateWithData from '../RoomList/SidebarItemTemplateWithData'; import UserItem from './UserItem'; type RowProps = { @@ -11,7 +11,7 @@ type RowProps = { }; const Row = ({ item, data }: RowProps): ReactElement => { - const { t, SideBarItemTemplate, avatarTemplate: AvatarTemplate, useRealName, extended } = data; + const { t, SidebarItemTemplate, avatarTemplate: AvatarTemplate, useRealName, extended } = data; if (item.t === 'd' && !item.u) { return ( @@ -20,18 +20,18 @@ const Row = ({ item, data }: RowProps): ReactElement => { useRealName={useRealName} t={t} item={item} - SideBarItemTemplate={SideBarItemTemplate} + SidebarItemTemplate={SidebarItemTemplate} AvatarTemplate={AvatarTemplate} /> ); } return ( - ); diff --git a/apps/meteor/client/sidebarv2/search/SearchList.tsx b/apps/meteor/client/sidebarv2/search/SearchList.tsx deleted file mode 100644 index c43fe854ac30..000000000000 --- a/apps/meteor/client/sidebarv2/search/SearchList.tsx +++ /dev/null @@ -1,382 +0,0 @@ -import type { IRoom, ISubscription } from '@rocket.chat/core-typings'; -import { css } from '@rocket.chat/css-in-js'; -import { Sidebar, TextInput, Box, Icon } from '@rocket.chat/fuselage'; -import { useMutableCallback, useDebouncedValue, useAutoFocus, useUniqueId, useMergedRefs } from '@rocket.chat/fuselage-hooks'; -import { escapeRegExp } from '@rocket.chat/string-helpers'; -import { useUserPreference, useUserSubscriptions, useSetting, useTranslation, useMethod } from '@rocket.chat/ui-contexts'; -import type { UseQueryResult } from '@tanstack/react-query'; -import { useQuery } from '@tanstack/react-query'; -import type { - ReactElement, - MutableRefObject, - SetStateAction, - Dispatch, - FormEventHandler, - Ref, - MouseEventHandler, - ForwardedRef, -} from 'react'; -import React, { forwardRef, useState, useMemo, useEffect, useRef } from 'react'; -import type { VirtuosoHandle } from 'react-virtuoso'; -import { Virtuoso } from 'react-virtuoso'; -import tinykeys from 'tinykeys'; - -import { VirtuosoScrollbars } from '../../components/CustomScrollbars'; -import { getConfig } from '../../lib/utils/getConfig'; -import { useAvatarTemplate } from '../hooks/useAvatarTemplate'; -import { usePreventDefault } from '../hooks/usePreventDefault'; -import { useTemplateByViewMode } from '../hooks/useTemplateByViewMode'; -import Row from './Row'; - -const mobileCheck = function () { - let check = false; - (function (a: string) { - if ( - /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test( - a, - ) || - /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test( - a.substr(0, 4), - ) - ) - check = true; - })(navigator.userAgent || navigator.vendor || window.opera || ''); - return check; -}; - -declare global { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface Window { - opera?: string; - } - // eslint-disable-next-line @typescript-eslint/naming-convention - interface Navigator { - userAgentData?: { - mobile: boolean; - }; - } -} - -const shortcut = ((): string => { - if (navigator.userAgentData?.mobile || mobileCheck()) { - return ''; - } - if (window.navigator.platform.toLowerCase().includes('mac')) { - return '(\u2318+K)'; - } - return '(Ctrl+K)'; -})(); - -const LIMIT = parseInt(String(getConfig('Sidebar_Search_Spotlight_LIMIT', 20))); - -const options = { - sort: { - lm: -1, - name: 1, - }, - limit: LIMIT, -} as const; - -const useSearchItems = (filterText: string): UseQueryResult<(ISubscription & IRoom)[] | undefined, Error> => { - const [, mention, name] = useMemo(() => filterText.match(/(@|#)?(.*)/i) || [], [filterText]); - const query = useMemo(() => { - const filterRegex = new RegExp(escapeRegExp(name), 'i'); - - return { - $or: [{ name: filterRegex }, { fname: filterRegex }], - ...(mention && { - t: mention === '@' ? 'd' : { $ne: 'd' }, - }), - }; - }, [name, mention]); - - const localRooms = useUserSubscriptions(query, options); - - const usernamesFromClient = [...localRooms?.map(({ t, name }) => (t === 'd' ? name : null))].filter(Boolean) as string[]; - - const searchForChannels = mention === '#'; - const searchForDMs = mention === '@'; - - const type = useMemo(() => { - if (searchForChannels) { - return { users: false, rooms: true, includeFederatedRooms: true }; - } - if (searchForDMs) { - return { users: true, rooms: false }; - } - return { users: true, rooms: true, includeFederatedRooms: true }; - }, [searchForChannels, searchForDMs]); - - const getSpotlight = useMethod('spotlight'); - - return useQuery( - ['sidebar/search/spotlight', name, usernamesFromClient, type, localRooms.map(({ _id, name }) => _id + name)], - async () => { - if (localRooms.length === LIMIT) { - return localRooms; - } - - const spotlight = await getSpotlight(name, usernamesFromClient, type); - - const filterUsersUnique = ({ _id }: { _id: string }, index: number, arr: { _id: string }[]): boolean => - index === arr.findIndex((user) => _id === user._id); - - const roomFilter = (room: { t: string; uids?: string[]; _id: string; name?: string }): boolean => - !localRooms.find( - (item) => - (room.t === 'd' && room.uids && room.uids.length > 1 && room.uids?.includes(item._id)) || - [item.rid, item._id].includes(room._id), - ); - const usersFilter = (user: { _id: string }): boolean => - !localRooms.find((room) => room.t === 'd' && room.uids && room.uids?.length === 2 && room.uids.includes(user._id)); - - const userMap = (user: { - _id: string; - name: string; - username: string; - avatarETag?: string; - }): { - _id: string; - t: string; - name: string; - fname: string; - avatarETag?: string; - } => ({ - _id: user._id, - t: 'd', - name: user.username, - fname: user.name, - avatarETag: user.avatarETag, - }); - - type resultsFromServerType = { - _id: string; - t: string; - name: string; - teamMain?: boolean; - fname?: string; - avatarETag?: string | undefined; - uids?: string[] | undefined; - }[]; - - const resultsFromServer: resultsFromServerType = []; - resultsFromServer.push(...spotlight.users.filter(filterUsersUnique).filter(usersFilter).map(userMap)); - resultsFromServer.push(...spotlight.rooms.filter(roomFilter)); - - const exact = resultsFromServer?.filter((item) => [item.name, item.fname].includes(name)); - return Array.from(new Set([...exact, ...localRooms, ...resultsFromServer])); - }, - { - staleTime: 60_000, - keepPreviousData: true, - placeholderData: localRooms, - }, - ); -}; - -const useInput = (initial: string): { value: string; onChange: FormEventHandler; setValue: Dispatch> } => { - const [value, setValue] = useState(initial); - const onChange = useMutableCallback((e) => { - setValue(e.currentTarget.value); - }); - return { value, onChange, setValue }; -}; - -const toggleSelectionState = (next: HTMLElement, current: HTMLElement | undefined, input: HTMLElement | undefined): void => { - input?.setAttribute('aria-activedescendant', next.id); - next.setAttribute('aria-selected', 'true'); - next.classList.add('rcx-sidebar-item--selected'); - if (current) { - current.removeAttribute('aria-selected'); - current.classList.remove('rcx-sidebar-item--selected'); - } -}; - -type SearchListProps = { - onClose: () => void; -}; - -const SearchList = forwardRef(function SearchList({ onClose }: SearchListProps, ref: ForwardedRef) { - const listId = useUniqueId(); - const t = useTranslation(); - const { setValue: setFilterValue, ...filter } = useInput(''); - - const cursorRef = useRef(null); - const autofocus: Ref = useMergedRefs(useAutoFocus(), cursorRef); - - const listRef = useRef(null); - const boxRef = useRef(null); - - const selectedElement: MutableRefObject = useRef(null); - const itemIndexRef = useRef(0); - - const sidebarViewMode = useUserPreference('sidebarViewMode'); - const useRealName = useSetting('UI_Use_Real_Name'); - - const sideBarItemTemplate = useTemplateByViewMode(); - const avatarTemplate = useAvatarTemplate(); - - const extended = sidebarViewMode === 'extended'; - - const filterText = useDebouncedValue(filter.value, 100); - - const placeholder = [t('Search'), shortcut].filter(Boolean).join(' '); - - const { data: items = [], isLoading } = useSearchItems(filterText); - - const itemData = useMemo( - () => ({ - items, - t, - SideBarItemTemplate: sideBarItemTemplate, - avatarTemplate, - useRealName, - extended, - sidebarViewMode, - }), - [avatarTemplate, extended, items, useRealName, sideBarItemTemplate, sidebarViewMode, t], - ); - - const changeSelection = useMutableCallback((dir) => { - let nextSelectedElement = null; - - if (dir === 'up') { - const potentialElement = selectedElement.current?.parentElement?.previousSibling as HTMLElement; - if (potentialElement) { - nextSelectedElement = potentialElement.querySelector('a'); - } - } else { - const potentialElement = selectedElement.current?.parentElement?.nextSibling as HTMLElement; - if (potentialElement) { - nextSelectedElement = potentialElement.querySelector('a'); - } - } - - if (nextSelectedElement) { - toggleSelectionState(nextSelectedElement, selectedElement.current || undefined, cursorRef?.current || undefined); - return nextSelectedElement; - } - return selectedElement.current; - }); - - const resetCursor = useMutableCallback(() => { - setTimeout(() => { - itemIndexRef.current = 0; - listRef.current?.scrollToIndex({ index: itemIndexRef.current }); - selectedElement.current = boxRef.current?.querySelector('a.rcx-sidebar-item'); - if (selectedElement.current) { - toggleSelectionState(selectedElement.current, undefined, cursorRef?.current || undefined); - } - }, 0); - }); - - usePreventDefault(boxRef); - - useEffect(() => { - resetCursor(); - }); - - useEffect(() => { - resetCursor(); - }, [filterText, resetCursor]); - - useEffect(() => { - if (!cursorRef?.current) { - return; - } - return tinykeys(cursorRef?.current, { - Escape: (event) => { - event.preventDefault(); - setFilterValue((value) => { - if (!value) { - onClose(); - } - resetCursor(); - return ''; - }); - }, - Tab: onClose, - ArrowUp: () => { - const currentElement = changeSelection('up'); - itemIndexRef.current = Math.max(itemIndexRef.current - 1, 0); - listRef.current?.scrollToIndex({ index: itemIndexRef.current }); - selectedElement.current = currentElement; - }, - ArrowDown: () => { - const currentElement = changeSelection('down'); - itemIndexRef.current = Math.min(itemIndexRef.current + 1, items.length + 1); - listRef.current?.scrollToIndex({ index: itemIndexRef.current }); - selectedElement.current = currentElement; - }, - Enter: (event) => { - event.preventDefault(); - if (selectedElement.current && items.length > 0) { - selectedElement.current.click(); - } else { - onClose(); - } - }, - }); - }, [cursorRef, changeSelection, items.length, onClose, resetCursor, setFilterValue]); - - const handleClick: MouseEventHandler = (e): void => { - if (e.target instanceof Element && [e.target.tagName, e.target.parentElement?.tagName].includes('BUTTON')) { - return; - } - return onClose(); - }; - - return ( - - - } - /> - - - room._id} - itemContent={(_, data): ReactElement => } - ref={listRef} - /> - - - ); -}); - -export default SearchList; diff --git a/apps/meteor/client/sidebarv2/search/UserItem.tsx b/apps/meteor/client/sidebarv2/search/UserItem.tsx index 8b9667913311..9cfa97fd797c 100644 --- a/apps/meteor/client/sidebarv2/search/UserItem.tsx +++ b/apps/meteor/client/sidebarv2/search/UserItem.tsx @@ -1,5 +1,5 @@ import type { IUser } from '@rocket.chat/core-typings'; -import { Sidebar } from '@rocket.chat/fuselage'; +import { SidebarV2ItemIcon } from '@rocket.chat/fuselage'; import React, { memo } from 'react'; import { ReactiveUserStatus } from '../../components/UserStatus'; @@ -13,24 +13,20 @@ type UserItemProps = { t: string; }; t: (value: string) => string; - SideBarItemTemplate: any; + SidebarItemTemplate: any; AvatarTemplate: any; id: string; style?: CSSStyleRule; useRealName?: boolean; }; -const UserItem = ({ item, id, style, t, SideBarItemTemplate, AvatarTemplate, useRealName }: UserItemProps) => { +const UserItem = ({ item, id, style, t, SidebarItemTemplate, AvatarTemplate, useRealName }: UserItemProps) => { const title = useRealName ? item.fname || item.name : item.name || item.fname; - const icon = ( - - - - ); + const icon = } />; const href = roomCoordinator.getRouteLink(item.t, { name: item.name }); return ( - { const handleStatusDisabledModal = useStatusDisabledModal(); return ( - ); }; diff --git a/apps/meteor/package.json b/apps/meteor/package.json index e1f2eff94e07..43b62def0819 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -241,7 +241,7 @@ "@rocket.chat/favicon": "workspace:^", "@rocket.chat/forked-matrix-appservice-bridge": "^4.0.2", "@rocket.chat/forked-matrix-bot-sdk": "^0.6.0-beta.3", - "@rocket.chat/fuselage": "^0.57.1", + "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/fuselage-toastbar": "^0.33.0", diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json index 04b22e72aae3..5f3bb4977d7d 100644 --- a/ee/packages/ui-theming/package.json +++ b/ee/packages/ui-theming/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.57.1", + "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/ui-contexts": "workspace:~", diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 478502ebf93d..7c644744c3cf 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -66,7 +66,7 @@ "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.57.1", + "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/icons": "~0.38.0", diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 029dc0bfc606..8b751c895b0f 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.57.1", + "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/fuselage-tokens": "^0.33.1", "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/message-parser": "workspace:^", diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 84868f8ccb4e..66a50ce8c8e1 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@babel/core": "~7.22.20", - "@rocket.chat/fuselage": "^0.57.1", + "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/ui-contexts": "workspace:^", "@types/babel__core": "~7.20.3", "@types/react": "~17.0.69", diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 97fd45a4f1b5..d9cdb9f24ade 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@react-aria/toolbar": "^3.0.0-beta.1", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.57.1", + "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index f25571435fc5..55e22a79e34c 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -19,7 +19,7 @@ "@babel/core": "~7.22.20", "@react-aria/toolbar": "^3.0.0-beta.1", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.57.1", + "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/icons": "~0.38.0", "@storybook/addon-actions": "~6.5.16", "@storybook/addon-docs": "~6.5.16", diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index bfbb16eb682c..40253050d9bf 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@rocket.chat/css-in-js": "~0.31.25", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.57.1", + "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 1e842208211b..d309c2d54599 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -15,7 +15,7 @@ "@codemirror/tooltip": "^0.19.16", "@lezer/highlight": "^1.1.6", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.57.1", + "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/fuselage-toastbar": "^0.33.0", diff --git a/yarn.lock b/yarn.lock index 71d9ba0760ea..9197fbb0b63a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8883,7 +8883,7 @@ __metadata: "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.57.1 + "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/gazzodown": "workspace:^" @@ -8944,9 +8944,9 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/fuselage@npm:^0.57.1": - version: 0.57.1 - resolution: "@rocket.chat/fuselage@npm:0.57.1" +"@rocket.chat/fuselage@npm:^0.59.0": + version: 0.59.0 + resolution: "@rocket.chat/fuselage@npm:0.59.0" dependencies: "@rocket.chat/css-in-js": ^0.31.25 "@rocket.chat/css-supports": ^0.31.25 @@ -8964,7 +8964,7 @@ __metadata: react: ^17.0.2 react-dom: ^17.0.2 react-virtuoso: 1.2.4 - checksum: ed40c4e9ec6f6294e0e7c7a3912ae7c9eca026455506f3f1983483010d3d0c41169f9e38d173e5e63ed0e9824979edd607dda3c881202bf797a97b5b76e83a34 + checksum: 259dce5381a3c3e0d7c7f3dc7ab51346cb65a9f4906a5ca5d6a976627d05e01e7f8a3a940604d0ad1b2b4ed89c250a871ef3fb253f6bbb69d35bc931e193898d languageName: node linkType: hard @@ -8975,7 +8975,7 @@ __metadata: "@babel/core": ~7.22.20 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.57.1 + "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/fuselage-tokens": ^0.33.1 "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/message-parser": "workspace:^" @@ -9342,7 +9342,7 @@ __metadata: "@rocket.chat/favicon": "workspace:^" "@rocket.chat/forked-matrix-appservice-bridge": ^4.0.2 "@rocket.chat/forked-matrix-bot-sdk": ^0.6.0-beta.3 - "@rocket.chat/fuselage": ^0.57.1 + "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/fuselage-toastbar": ^0.33.0 @@ -10214,7 +10214,7 @@ __metadata: resolution: "@rocket.chat/ui-avatar@workspace:packages/ui-avatar" dependencies: "@babel/core": ~7.22.20 - "@rocket.chat/fuselage": ^0.57.1 + "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/ui-contexts": "workspace:^" "@types/babel__core": ~7.20.3 "@types/react": ~17.0.69 @@ -10240,7 +10240,7 @@ __metadata: "@babel/core": ~7.22.20 "@react-aria/toolbar": ^3.0.0-beta.1 "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.57.1 + "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/jest-presets": "workspace:~" @@ -10290,7 +10290,7 @@ __metadata: "@babel/core": ~7.22.20 "@react-aria/toolbar": ^3.0.0-beta.1 "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.57.1 + "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/icons": ~0.38.0 "@storybook/addon-actions": ~6.5.16 "@storybook/addon-docs": ~6.5.16 @@ -10385,7 +10385,7 @@ __metadata: resolution: "@rocket.chat/ui-theming@workspace:ee/packages/ui-theming" dependencies: "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.57.1 + "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/ui-contexts": "workspace:~" @@ -10415,7 +10415,7 @@ __metadata: "@rocket.chat/css-in-js": ~0.31.25 "@rocket.chat/emitter": ~0.31.25 "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.57.1 + "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/jest-presets": "workspace:~" @@ -10464,7 +10464,7 @@ __metadata: "@codemirror/tooltip": ^0.19.16 "@lezer/highlight": ^1.1.6 "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.57.1 + "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/fuselage-toastbar": ^0.33.0 From e0050c363bee1f0e037faefc060c0ff125e96117 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Fri, 6 Sep 2024 14:25:00 -0600 Subject: [PATCH 056/170] fix: NPS passing `startAt` as the expiration date when creating a banner (#33155) --- .changeset/nasty-tools-enjoy.md | 5 + apps/meteor/server/services/nps/service.ts | 5 +- .../unit/server/services/nps/spec.tests.ts | 103 ++++++++++++++++++ 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 .changeset/nasty-tools-enjoy.md create mode 100644 apps/meteor/tests/unit/server/services/nps/spec.tests.ts diff --git a/.changeset/nasty-tools-enjoy.md b/.changeset/nasty-tools-enjoy.md new file mode 100644 index 000000000000..b6e8dae3785a --- /dev/null +++ b/.changeset/nasty-tools-enjoy.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed a code issue on NPS service. It was passing `startAt` as the expiration date when creating a banner. diff --git a/apps/meteor/server/services/nps/service.ts b/apps/meteor/server/services/nps/service.ts index 9554a472fb0a..be5b44582a5a 100644 --- a/apps/meteor/server/services/nps/service.ts +++ b/apps/meteor/server/services/nps/service.ts @@ -21,7 +21,10 @@ export class NPSService extends ServiceClassInternal implements INPSService { const any = await Nps.findOne({}, { projection: { _id: 1 } }); if (!any) { - await Banner.create(getBannerForAdmins(nps.startAt)); + if (nps.expireAt < nps.startAt || nps.expireAt < new Date()) { + throw new Error('NPS already expired'); + } + await Banner.create(getBannerForAdmins(nps.expireAt)); await notifyAdmins(nps.startAt); } diff --git a/apps/meteor/tests/unit/server/services/nps/spec.tests.ts b/apps/meteor/tests/unit/server/services/nps/spec.tests.ts new file mode 100644 index 000000000000..21c5ecfe7c98 --- /dev/null +++ b/apps/meteor/tests/unit/server/services/nps/spec.tests.ts @@ -0,0 +1,103 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import p from 'proxyquire'; +import sinon from 'sinon'; + +const modelsMock = { + 'NpsVote': {}, + 'Nps': { + findOne: sinon.stub(), + save: sinon.stub(), + }, + 'Settings': { + getValueById: sinon.stub(), + }, + '@noCallThru': true, +}; + +const servicesMock = { + Banner: { + create: sinon.stub(), + }, +}; + +const getbannerforadminsMock = sinon.stub(); + +const { NPSService } = p('../../../../../server/services/nps/service.ts', { + '@rocket.chat/models': modelsMock, + '@rocket.chat/core-services': servicesMock, + './sendNpsResults': { 'sendNpsResults': sinon.stub(), '@noCallThru': true }, + '../../lib/logger/system': { 'SystemLogger': { error: sinon.stub() }, '@noCallThru': true }, + './notification': { 'notifyAdmins': sinon.stub(), 'getBannerForAdmins': getbannerforadminsMock, '@noCallThru': true }, +}); + +describe('NPS Service', () => { + it('should instantiate properly', () => { + expect(new NPSService()).to.be.an('object'); + }); + + describe('@create', () => { + beforeEach(() => { + modelsMock.Settings.getValueById.reset(); + modelsMock.Nps.findOne.reset(); + modelsMock.Nps.save.reset(); + servicesMock.Banner.create.reset(); + getbannerforadminsMock.reset(); + }); + it('should fail when user opted out of nps', async () => { + modelsMock.Settings.getValueById.withArgs('NPS_survey_enabled').resolves(false); + + await expect(new NPSService().create({})).to.be.rejectedWith('Server opted-out for NPS surveys'); + }); + it('should fail when nps expireDate is less than nps startAt', async () => { + modelsMock.Settings.getValueById.withArgs('NPS_survey_enabled').resolves(true); + modelsMock.Nps.findOne.resolves(null); + + await expect(new NPSService().create({ expireAt: new Date('2020-01-01'), startAt: new Date('2020-01-02') })).to.be.rejectedWith( + 'NPS already expired', + ); + }); + it('should fail when expireDate is less than current date', async () => { + modelsMock.Settings.getValueById.withArgs('NPS_survey_enabled').resolves(true); + modelsMock.Nps.findOne.resolves(null); + + await expect(new NPSService().create({ expireAt: new Date('2020-01-02'), startAt: new Date('2020-01-01') })).to.be.rejectedWith( + 'NPS already expired', + ); + }); + it('should try to create a banner when theres no nps saved', async () => { + modelsMock.Settings.getValueById.withArgs('NPS_survey_enabled').resolves(true); + modelsMock.Nps.findOne.resolves(null); + + const today = new Date(); + const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000); + + await new NPSService().create({ + expireAt: tomorrow, + startAt: today, + createdBy: { _id: 'tomorrow', username: 'tomorrow' }, + npsId: 'test', + }); + expect(getbannerforadminsMock.called).to.be.true; + expect(getbannerforadminsMock.calledWith(tomorrow)).to.be.true; + expect(modelsMock.Nps.save.called).to.be.true; + expect( + modelsMock.Nps.save.calledWith( + sinon.match({ + expireAt: tomorrow, + startAt: today, + status: 'open', + _id: 'test', + createdBy: { _id: 'tomorrow', username: 'tomorrow' }, + }), + ), + ).to.be.true; + }); + it('should fail if theres an error when saving the Nps', async () => { + modelsMock.Settings.getValueById.withArgs('NPS_survey_enabled').resolves(true); + modelsMock.Nps.findOne.resolves({ _id: 'test' }); + modelsMock.Nps.save.rejects(); + await expect(new NPSService().create({})).to.be.rejectedWith('Error creating NPS'); + }); + }); +}); From 06dbf725685d52c0514808b4c338e258d0571ddf Mon Sep 17 00:00:00 2001 From: Rafael Tapia Date: Mon, 9 Sep 2024 12:24:02 -0300 Subject: [PATCH 057/170] feat: unknown contacts (#32865) --- apps/meteor/app/livechat/server/api/v1/contact.ts | 4 ++-- apps/meteor/app/livechat/server/lib/Contacts.ts | 4 ++-- apps/meteor/app/livechat/server/lib/LivechatTyped.ts | 11 +++++++++++ .../tests/end-to-end/api/livechat/09-visitors.ts | 1 + packages/core-typings/src/ILivechatContact.ts | 4 ++-- packages/core-typings/src/ILivechatVisitor.ts | 1 + 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/meteor/app/livechat/server/api/v1/contact.ts b/apps/meteor/app/livechat/server/api/v1/contact.ts index 94bd5ed3e11c..7e9457d2f185 100644 --- a/apps/meteor/app/livechat/server/api/v1/contact.ts +++ b/apps/meteor/app/livechat/server/api/v1/contact.ts @@ -92,7 +92,7 @@ API.v1.addRoute( { authRequired: true, permissionsRequired: ['create-livechat-contact'], validateParams: isPOSTOmnichannelContactsProps }, { async post() { - if (!process.env.TEST_MODE) { + if (process.env.TEST_MODE?.toUpperCase() !== 'TRUE') { throw new Meteor.Error('error-not-allowed', 'This endpoint is only allowed in test mode'); } const contactId = await createContact({ ...this.bodyParams, unknown: false }); @@ -106,7 +106,7 @@ API.v1.addRoute( { authRequired: true, permissionsRequired: ['update-livechat-contact'], validateParams: isPOSTUpdateOmnichannelContactsProps }, { async post() { - if (!process.env.TEST_MODE) { + if (process.env.TEST_MODE?.toUpperCase() !== 'TRUE') { throw new Meteor.Error('error-not-allowed', 'This endpoint is only allowed in test mode'); } diff --git a/apps/meteor/app/livechat/server/lib/Contacts.ts b/apps/meteor/app/livechat/server/lib/Contacts.ts index 58404ce27584..f6f812ce8af8 100644 --- a/apps/meteor/app/livechat/server/lib/Contacts.ts +++ b/apps/meteor/app/livechat/server/lib/Contacts.ts @@ -44,8 +44,8 @@ type RegisterContactProps = { type CreateContactParams = { name: string; - emails: string[]; - phones: string[]; + emails?: string[]; + phones?: string[]; unknown: boolean; customFields?: Record; contactManager?: string; diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts index be79d565f6de..88f9494159a2 100644 --- a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts +++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts @@ -71,6 +71,7 @@ import * as Mailer from '../../../mailer/server/api'; import { metrics } from '../../../metrics/server'; import { settings } from '../../../settings/server'; import { businessHourManager } from '../business-hour'; +import { createContact } from './Contacts'; import { parseAgentCustomFields, updateDepartmentAgents, validateEmail, normalizeTransferredByData } from './Helper'; import { QueueManager } from './QueueManager'; import { RoutingManager } from './RoutingManager'; @@ -664,6 +665,16 @@ class LivechatClass { } } + if (process.env.TEST_MODE?.toUpperCase() === 'TRUE') { + const contactId = await createContact({ + name: name ?? (visitorDataToUpdate.username as string), + emails: email ? [email] : [], + phones: phone ? [phone.number] : [], + unknown: true, + }); + visitorDataToUpdate.contactId = contactId; + } + const upsertedLivechatVisitor = await LivechatVisitors.updateOneByIdOrToken(visitorDataToUpdate, { upsert: true, returnDocument: 'after', diff --git a/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts b/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts index 5bc961087efc..f02d9d1d1e95 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts @@ -56,6 +56,7 @@ describe('LIVECHAT - visitors', () => { expect(body).to.have.property('success', true); expect(body).to.have.property('visitor'); expect(body.visitor).to.have.property('token', 'test'); + expect(body.visitor).to.have.property('contactId'); // Ensure all new visitors are created as online :) expect(body.visitor).to.have.property('status', 'online'); diff --git a/packages/core-typings/src/ILivechatContact.ts b/packages/core-typings/src/ILivechatContact.ts index 149dab2b88b1..1e7bd4ff5399 100644 --- a/packages/core-typings/src/ILivechatContact.ts +++ b/packages/core-typings/src/ILivechatContact.ts @@ -14,8 +14,8 @@ export interface ILivechatContactConflictingField { export interface ILivechatContact extends IRocketChatRecord { name: string; - phones: string[]; - emails: string[]; + phones?: string[]; + emails?: string[]; contactManager?: string; unknown?: boolean; hasConflict?: boolean; diff --git a/packages/core-typings/src/ILivechatVisitor.ts b/packages/core-typings/src/ILivechatVisitor.ts index 21819cc23f24..eefb4ebd720c 100644 --- a/packages/core-typings/src/ILivechatVisitor.ts +++ b/packages/core-typings/src/ILivechatVisitor.ts @@ -49,6 +49,7 @@ export interface ILivechatVisitor extends IRocketChatRecord { }; activity?: string[]; disabled?: boolean; + contactId?: string; } export interface ILivechatVisitorDTO { From 7c14fd1a802a2f63f3dc6796e83192b54cbd4ff2 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 9 Sep 2024 13:12:34 -0600 Subject: [PATCH 058/170] feat: Allow admins to control if visitors can close omnichannel conversations (#33139) --- .changeset/healthy-rivers-nail.md | 8 +++ .../imports/server/rest/appearance.ts | 1 + .../app/livechat/server/api/lib/appearance.ts | 1 + .../app/livechat/server/api/lib/livechat.ts | 1 + .../meteor/app/livechat/server/api/v1/room.ts | 4 ++ .../app/livechat/server/lib/LivechatTyped.ts | 1 + .../omnichannel/appearance/AppearanceForm.tsx | 15 ++++++ .../omnichannel/appearance/AppearancePage.tsx | 1 + apps/meteor/server/settings/omnichannel.ts | 7 +++ .../omnichannel/omnichannel-livechat.spec.ts | 52 +++++++++++++++++++ .../tests/end-to-end/api/livechat/00-rooms.ts | 19 +++++++ packages/i18n/src/locales/en.i18n.json | 2 + .../livechat/src/routes/Chat/connector.tsx | 2 + .../livechat/src/routes/Chat/container.js | 4 +- packages/livechat/src/store/index.tsx | 1 + 15 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 .changeset/healthy-rivers-nail.md diff --git a/.changeset/healthy-rivers-nail.md b/.changeset/healthy-rivers-nail.md new file mode 100644 index 000000000000..a8da9bec846e --- /dev/null +++ b/.changeset/healthy-rivers-nail.md @@ -0,0 +1,8 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/i18n": minor +"@rocket.chat/livechat": minor +--- + +Added new setting `Allow visitors to finish conversations` that allows admins to decide if omnichannel visitors can close a conversation or not. This doesn't affect agent's capabilities of room closing, neither apps using the livechat bridge to close rooms. +However, if currently your integration relies on `livechat/room.close` endpoint for closing conversations, it's advised to use the authenticated version `livechat/room.closeByUser` of it before turning off this setting. diff --git a/apps/meteor/app/livechat/imports/server/rest/appearance.ts b/apps/meteor/app/livechat/imports/server/rest/appearance.ts index 48863fc9e5d3..7496b6243abe 100644 --- a/apps/meteor/app/livechat/imports/server/rest/appearance.ts +++ b/apps/meteor/app/livechat/imports/server/rest/appearance.ts @@ -51,6 +51,7 @@ API.v1.addRoute( 'Livechat_background', 'Livechat_widget_position', 'Livechat_hide_system_messages', + 'Omnichannel_allow_visitors_to_close_conversation', ]; const valid = settings.every((setting) => validSettingList.includes(setting._id)); diff --git a/apps/meteor/app/livechat/server/api/lib/appearance.ts b/apps/meteor/app/livechat/server/api/lib/appearance.ts index 785413ead9d1..0fc7d3547b2c 100644 --- a/apps/meteor/app/livechat/server/api/lib/appearance.ts +++ b/apps/meteor/app/livechat/server/api/lib/appearance.ts @@ -28,6 +28,7 @@ export async function findAppearance(): Promise<{ appearance: ISetting[] }> { 'Livechat_background', 'Livechat_widget_position', 'Livechat_hide_system_messages', + 'Omnichannel_allow_visitors_to_close_conversation', ], }, }; diff --git a/apps/meteor/app/livechat/server/api/lib/livechat.ts b/apps/meteor/app/livechat/server/api/lib/livechat.ts index a922edd40899..8041566d796e 100644 --- a/apps/meteor/app/livechat/server/api/lib/livechat.ts +++ b/apps/meteor/app/livechat/server/api/lib/livechat.ts @@ -142,6 +142,7 @@ export async function settings({ businessUnit = '' }: { businessUnit?: string } hiddenSystemMessages: initSettings.Livechat_hide_system_messages, livechatLogo: initSettings.Assets_livechat_widget_logo, hideWatermark: initSettings.Livechat_hide_watermark || false, + visitorsCanCloseChat: initSettings.Omnichannel_allow_visitors_to_close_conversation, }, theme: { title: initSettings.Livechat_title, diff --git a/apps/meteor/app/livechat/server/api/v1/room.ts b/apps/meteor/app/livechat/server/api/v1/room.ts index 565f8e0bb3f4..7aacfacb4476 100644 --- a/apps/meteor/app/livechat/server/api/v1/room.ts +++ b/apps/meteor/app/livechat/server/api/v1/room.ts @@ -107,6 +107,10 @@ API.v1.addRoute( async post() { const { rid, token } = this.bodyParams; + if (!rcSettings.get('Omnichannel_allow_visitors_to_close_conversation')) { + throw new Error('error-not-allowed-to-close-conversation'); + } + const visitor = await findGuest(token); if (!visitor) { throw new Error('invalid-token'); diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts index 88f9494159a2..89d125033977 100644 --- a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts +++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts @@ -1079,6 +1079,7 @@ class LivechatClass { 'Livechat_background', 'Assets_livechat_widget_logo', 'Livechat_hide_watermark', + 'Omnichannel_allow_visitors_to_close_conversation', ] as const; type SettingTypes = (typeof validSettings)[number] | 'Livechat_Show_Connecting'; diff --git a/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx b/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx index 4253ff023ee9..a4435398d9a9 100644 --- a/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx +++ b/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx @@ -52,6 +52,7 @@ const AppearanceForm = () => { const livechatWidgetPositionField = useUniqueId(); const livechatBackgroundField = useUniqueId(); const livechatHideSystemMessagesField = useUniqueId(); + const omnichannelVisitorsCanCloseConversationField = useUniqueId(); return ( @@ -140,6 +141,20 @@ const AppearanceForm = () => { /> + + + + {t('Omnichannel_allow_visitors_to_close_conversation')} + + ( + + )} + /> + + diff --git a/apps/meteor/client/views/omnichannel/appearance/AppearancePage.tsx b/apps/meteor/client/views/omnichannel/appearance/AppearancePage.tsx index a2cfb7b8103b..b90c32af6a7d 100644 --- a/apps/meteor/client/views/omnichannel/appearance/AppearancePage.tsx +++ b/apps/meteor/client/views/omnichannel/appearance/AppearancePage.tsx @@ -28,6 +28,7 @@ type LivechatAppearanceSettings = { Livechat_conversation_finished_text: string; Livechat_enable_message_character_limit: boolean; Livechat_message_character_limit: number; + Omnichannel_allow_visitors_to_close_conversation: boolean; }; type AppearanceSettings = Partial; diff --git a/apps/meteor/server/settings/omnichannel.ts b/apps/meteor/server/settings/omnichannel.ts index ed1daa8ce228..c86cd6674d4e 100644 --- a/apps/meteor/server/settings/omnichannel.ts +++ b/apps/meteor/server/settings/omnichannel.ts @@ -157,6 +157,13 @@ export const createOmniSettings = () => i18nLabel: 'Show_agent_email', }); + await this.add('Omnichannel_allow_visitors_to_close_conversation', true, { + type: 'boolean', + group: 'Omnichannel', + public: true, + enableQuery: omnichannelEnabledQuery, + }); + await this.add('Livechat_request_comment_when_closing_conversation', true, { type: 'boolean', group: 'Omnichannel', diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat.spec.ts index bf14584ed89f..405e7f82e3c4 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat.spec.ts @@ -2,6 +2,7 @@ import { createFakeVisitor } from '../../mocks/data'; import { createAuxContext } from '../fixtures/createAuxContext'; import { Users } from '../fixtures/userStates'; import { HomeOmnichannel, OmnichannelLiveChat } from '../page-objects'; +import { setSettingValueById } from '../utils'; import { createAgent } from '../utils/omnichannel/agents'; import { test, expect } from '../utils/test'; @@ -93,6 +94,57 @@ test.describe.serial('OC - Livechat', () => { }); }); +test.describe.serial('OC - Livechat - Visitors closing the room is disabled', () => { + let poLiveChat: OmnichannelLiveChat; + let poHomeOmnichannel: HomeOmnichannel; + + test.beforeAll(async ({ api }) => { + await api.post('/livechat/users/agent', { username: 'user1' }); + }); + + test.beforeAll(async ({ browser, api }) => { + const { page: livechatPage } = await createAuxContext(browser, Users.user1, '/livechat', false); + + poLiveChat = new OmnichannelLiveChat(livechatPage, api); + }); + + test.beforeAll(async ({ browser, api }) => { + await setSettingValueById(api, 'Livechat_allow_visitor_closing_chat', false); + const { page: omniPage } = await createAuxContext(browser, Users.user1, '/', true); + poHomeOmnichannel = new HomeOmnichannel(omniPage); + }); + + test.afterAll(async ({ api }) => { + await setSettingValueById(api, 'Livechat_allow_visitor_closing_chat', true); + await api.delete('/livechat/users/agent/user1'); + await poLiveChat.page.close(); + }); + + test('OC - Livechat - Close Chat disabled', async () => { + await poLiveChat.page.reload(); + await poLiveChat.openAnyLiveChat(); + await poLiveChat.sendMessage(firstVisitor, false); + await poLiveChat.onlineAgentMessage.fill('this_a_test_message_from_user'); + await poLiveChat.btnSendMessageToOnlineAgent.click(); + + await test.step('expect to close a livechat conversation', async () => { + await expect(poLiveChat.btnOptions).not.toBeVisible(); + await expect(poLiveChat.btnCloseChat).not.toBeVisible(); + }); + }); + + test('OC - Livechat - Close chat disabled, agents can close', async () => { + await poHomeOmnichannel.sidenav.openChat(firstVisitor.name); + + await test.step('expect livechat conversation to be closed by agent', async () => { + await poHomeOmnichannel.content.btnCloseChat.click(); + await poHomeOmnichannel.content.closeChatModal.inputComment.fill('this_is_a_test_comment'); + await poHomeOmnichannel.content.closeChatModal.btnConfirm.click(); + await expect(poHomeOmnichannel.toastSuccess).toBeVisible(); + }); + }); +}); + test.describe.serial('OC - Livechat - Resub after close room', () => { let poLiveChat: OmnichannelLiveChat; let poHomeOmnichannel: HomeOmnichannel; diff --git a/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts b/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts index 7142725a1d99..4388a4d24341 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts @@ -689,6 +689,25 @@ describe('LIVECHAT - rooms', () => { expect(latestRoom).to.not.have.property('pdfTranscriptFileId'); }, ); + + describe('Special case: visitors closing is disabled', () => { + before(async () => { + await updateSetting('Omnichannel_allow_visitors_to_close_conversation', false); + }); + after(async () => { + await updateSetting('Omnichannel_allow_visitors_to_close_conversation', true); + }); + it('should not allow visitor to close a conversation', async () => { + const { room, visitor } = await startANewLivechatRoomAndTakeIt(); + await request + .post(api('livechat/room.close')) + .send({ + token: visitor.token, + rid: room._id, + }) + .expect(400); + }); + }); }); describe('livechat/room.forward', () => { diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index ea7e31422cb1..d3324c6e749a 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -4037,6 +4037,8 @@ "Omnichannel_Reports_Summary": "Gain insights into your operation and export your metrics.", "Omnichannel_max_fallback_forward_depth": "Maximum fallback forward departments depth", "Omnichannel_max_fallback_forward_depth_Description": "Maximum number of hops that a room being transfered will do when the target department has a Fallback Forward Department set up. When limit is reached, chat won't be transferred and process will stop. Depending on your configuration, setting a high number may cause performance issues.", + "Omnichannel_allow_visitors_to_close_conversation": "Allow visitors to finish conversations", + "Omnichannel_allow_visitors_to_close_conversation_Description": "When disabled, visitors won't be able to finish an ongoing conversation either via UI or via API.", "On": "On", "on-hold-livechat-room": "On Hold Omnichannel Room", "on-hold-livechat-room_description": "Permission to on hold omnichannel room", diff --git a/packages/livechat/src/routes/Chat/connector.tsx b/packages/livechat/src/routes/Chat/connector.tsx index 36e574b246b1..3c72f9ae88cf 100644 --- a/packages/livechat/src/routes/Chat/connector.tsx +++ b/packages/livechat/src/routes/Chat/connector.tsx @@ -22,6 +22,7 @@ export const ChatConnector: FunctionalComponent<{ path: string; default: boolean nameFieldRegistrationForm, emailFieldRegistrationForm, limitTextLength, + visitorsCanCloseChat, }, messages: { conversationFinishedMessage }, theme: { title = '' } = {}, @@ -94,6 +95,7 @@ export const ChatConnector: FunctionalComponent<{ path: string; default: boolean ongoingCall={ongoingCall} messageListPosition={messageListPosition} theme={theme} + visitorsCanCloseChat={visitorsCanCloseChat} /> ); }; diff --git a/packages/livechat/src/routes/Chat/container.js b/packages/livechat/src/routes/Chat/container.js index 19172cc7fe5a..43ff281c6472 100644 --- a/packages/livechat/src/routes/Chat/container.js +++ b/packages/livechat/src/routes/Chat/container.js @@ -288,8 +288,8 @@ class ChatContainer extends Component { }; canFinishChat = () => { - const { room, connecting } = this.props; - return room !== undefined || connecting; + const { room, connecting, visitorsCanCloseChat } = this.props; + return visitorsCanCloseChat && (room !== undefined || connecting); }; canRemoveUserData = () => { diff --git a/packages/livechat/src/store/index.tsx b/packages/livechat/src/store/index.tsx index f8629ce693cc..e7d4b8caae17 100644 --- a/packages/livechat/src/store/index.tsx +++ b/packages/livechat/src/store/index.tsx @@ -59,6 +59,7 @@ export type StoreState = { hideWatermark?: boolean; livechatLogo?: { url: string }; transcript?: boolean; + visitorsCanCloseChat?: boolean; }; online?: boolean; departments: Department[]; From 4146c3956d6d8337b7a23232506f7796f113df17 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 9 Sep 2024 15:21:14 -0600 Subject: [PATCH 059/170] fix: Allow to use the token from `room.v` when requesting transcript instead of finding visitor (#33211) --- .changeset/four-cherries-kneel.md | 5 +++ .../app/livechat/server/lib/sendTranscript.ts | 17 +++---- apps/meteor/tests/data/livechat/rooms.ts | 4 +- .../end-to-end/api/livechat/11-livechat.ts | 21 +++++++++ .../server/lib/sendTranscript.spec.ts | 45 +++++++++++++------ 5 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 .changeset/four-cherries-kneel.md diff --git a/.changeset/four-cherries-kneel.md b/.changeset/four-cherries-kneel.md new file mode 100644 index 000000000000..095d5af0aa76 --- /dev/null +++ b/.changeset/four-cherries-kneel.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Allow to use the token from `room.v` when requesting transcript instead of visitor token. Visitors may change their tokens at any time, rendering old conversations impossible to access for them (or for APIs depending on token) as the visitor token won't match the `room.v` token. diff --git a/apps/meteor/app/livechat/server/lib/sendTranscript.ts b/apps/meteor/app/livechat/server/lib/sendTranscript.ts index 74032121ee50..bc7c06e0eaae 100644 --- a/apps/meteor/app/livechat/server/lib/sendTranscript.ts +++ b/apps/meteor/app/livechat/server/lib/sendTranscript.ts @@ -3,12 +3,13 @@ import { type IUser, type MessageTypesValues, type IOmnichannelSystemMessage, + type ILivechatVisitor, isFileAttachment, isFileImageAttachment, } from '@rocket.chat/core-typings'; import colors from '@rocket.chat/fuselage-tokens/colors'; import { Logger } from '@rocket.chat/logger'; -import { LivechatRooms, LivechatVisitors, Messages, Uploads, Users } from '@rocket.chat/models'; +import { LivechatRooms, Messages, Uploads, Users } from '@rocket.chat/models'; import { check } from 'meteor/check'; import moment from 'moment-timezone'; @@ -41,16 +42,12 @@ export async function sendTranscript({ const room = await LivechatRooms.findOneById(rid); - const visitor = await LivechatVisitors.getVisitorByToken(token, { - projection: { _id: 1, token: 1, language: 1, username: 1, name: 1 }, - }); - - if (!visitor) { - throw new Error('error-invalid-token'); + const visitor = room?.v as ILivechatVisitor; + if (token !== visitor?.token) { + throw new Error('error-invalid-visitor'); } - // @ts-expect-error - Visitor typings should include language? - const userLanguage = visitor?.language || settings.get('Language') || 'en'; + const userLanguage = settings.get('Language') || 'en'; const timezone = getTimezone(user); logger.debug(`Transcript will be sent using ${timezone} as timezone`); @@ -59,7 +56,7 @@ export async function sendTranscript({ } // allow to only user to send transcripts from their own chats - if (room.t !== 'l' || !room.v || room.v.token !== token) { + if (room.t !== 'l') { throw new Error('error-invalid-room'); } diff --git a/apps/meteor/tests/data/livechat/rooms.ts b/apps/meteor/tests/data/livechat/rooms.ts index 9532fd4214ab..b5d89762c614 100644 --- a/apps/meteor/tests/data/livechat/rooms.ts +++ b/apps/meteor/tests/data/livechat/rooms.ts @@ -33,10 +33,10 @@ export const createLivechatRoom = async (visitorToken: string, extraRoomParams?: return response.body.room; }; -export const createVisitor = (department?: string, visitorName?: string): Promise => +export const createVisitor = (department?: string, visitorName?: string, customEmail?: string): Promise => new Promise((resolve, reject) => { const token = getRandomVisitorToken(); - const email = `${token}@${token}.com`; + const email = customEmail || `${token}@${token}.com`; const phone = `${Math.floor(Math.random() * 10000000000)}`; void request.get(api(`livechat/visitor/${token}`)).end((err: Error, res: DummyResponse) => { if (!err && res && res.body && res.body.visitor) { diff --git a/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts b/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts index c07f7bcecc81..7ce582025538 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts @@ -283,6 +283,27 @@ describe('LIVECHAT - Utils', () => { .send({ token: visitor.token, rid: room._id, email: 'visitor@notadomain.com' }); expect(body).to.have.property('success', true); }); + it('should allow a visitor to get a transcript even if token changed by using an old token that matches room.v', async () => { + const visitor = await createVisitor(); + const room = await createLivechatRoom(visitor.token); + await closeOmnichannelRoom(room._id); + const visitor2 = await createVisitor(undefined, undefined, visitor.visitorEmails?.[0].address); + const room2 = await createLivechatRoom(visitor2.token); + await closeOmnichannelRoom(room2._id); + + expect(visitor.token !== visitor2.token).to.be.true; + const { body } = await request + .post(api('livechat/transcript')) + .set(credentials) + .send({ token: visitor.token, rid: room._id, email: 'visitor@notadomain.com' }); + expect(body).to.have.property('success', true); + + const { body: body2 } = await request + .post(api('livechat/transcript')) + .set(credentials) + .send({ token: visitor2.token, rid: room2._id, email: 'visitor@notadomain.com' }); + expect(body2).to.have.property('success', true); + }); }); describe('livechat/transcript/:rid', () => { diff --git a/apps/meteor/tests/unit/app/livechat/server/lib/sendTranscript.spec.ts b/apps/meteor/tests/unit/app/livechat/server/lib/sendTranscript.spec.ts index 64da050cfd88..ca39a64c21a9 100644 --- a/apps/meteor/tests/unit/app/livechat/server/lib/sendTranscript.spec.ts +++ b/apps/meteor/tests/unit/app/livechat/server/lib/sendTranscript.spec.ts @@ -6,9 +6,6 @@ const modelsMock = { LivechatRooms: { findOneById: sinon.stub(), }, - LivechatVisitors: { - getVisitorByToken: sinon.stub(), - }, Messages: { findLivechatClosingMessage: sinon.stub(), findVisibleByRoomIdNotContainingTypesBeforeTs: sinon.stub(), @@ -75,7 +72,6 @@ describe('Send transcript', () => { beforeEach(() => { checkMock.reset(); modelsMock.LivechatRooms.findOneById.reset(); - modelsMock.LivechatVisitors.getVisitorByToken.reset(); modelsMock.Messages.findLivechatClosingMessage.reset(); modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.reset(); modelsMock.Users.findOneById.reset(); @@ -87,11 +83,9 @@ describe('Send transcript', () => { await expect(sendTranscript({})).to.be.rejectedWith(Error); }); it('should throw error when visitor not found', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves(null); await expect(sendTranscript({ rid: 'rid', email: 'email', logger: mockLogger })).to.be.rejectedWith(Error); }); it('should attempt to send an email when params are valid using default subject', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'token' } }); modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.resolves([]); tStub.returns('Conversation Transcript'); @@ -117,7 +111,6 @@ describe('Send transcript', () => { ).to.be.true; }); it('should use provided subject', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'token' } }); modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.resolves([]); @@ -143,7 +136,6 @@ describe('Send transcript', () => { ).to.be.true; }); it('should use subject from setting (when configured) when no subject provided', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'token' } }); modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.resolves([]); mockSettingValues.Livechat_transcript_email_subject = 'A custom subject obtained from setting.get'; @@ -170,36 +162,63 @@ describe('Send transcript', () => { }); it('should fail if room provided is invalid', async () => { modelsMock.LivechatRooms.findOneById.resolves(null); - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); await expect(sendTranscript({ rid: 'rid', email: 'email', logger: mockLogger })).to.be.rejectedWith(Error); }); it('should fail if room provided is of different type', async () => { modelsMock.LivechatRooms.findOneById.resolves({ t: 'c' }); - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); await expect(sendTranscript({ rid: 'rid', email: 'email' })).to.be.rejectedWith(Error); }); it('should fail if room is of valid type, but doesnt doesnt have `v` property', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l' }); await expect(sendTranscript({ rid: 'rid', email: 'email' })).to.be.rejectedWith(Error); }); it('should fail if room is of valid type, has `v` prop, but it doesnt contain `token`', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { otherProp: 'xxx' } }); await expect(sendTranscript({ rid: 'rid', email: 'email' })).to.be.rejectedWith(Error); }); it('should fail if room is of valid type, has `v.token`, but its different from the one on param (room from another visitor)', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'xxx' } }); await expect(sendTranscript({ rid: 'rid', email: 'email', token: 'xveasdf' })).to.be.rejectedWith(Error); }); + + it('should throw an error when token is not the one on room.v', async () => { + modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'xxx' } }); + + await expect(sendTranscript({ rid: 'rid', email: 'email', token: 'xveasdf' })).to.be.rejectedWith(Error); + }); + it('should work when token matches room.v', async () => { + modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'token-123' } }); + modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.resolves([]); + delete mockSettingValues.Livechat_transcript_email_subject; + tStub.returns('Conversation Transcript'); + + await sendTranscript({ + rid: 'rid', + token: 'token-123', + email: 'email', + user: { _id: 'x', name: 'x', utcOffset: '-6', username: 'x' }, + }); + + expect(getTimezoneMock.calledWith({ _id: 'x', name: 'x', utcOffset: '-6', username: 'x' })).to.be.true; + expect(modelsMock.Messages.findLivechatClosingMessage.calledWith('rid', { projection: { ts: 1 } })).to.be.true; + expect(modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.called).to.be.true; + expect( + mailerMock.calledWith({ + to: 'email', + from: 'test@rocket.chat', + subject: 'Conversation Transcript', + replyTo: 'test@rocket.chat', + html: '

', + }), + ).to.be.true; + }); }); From 0f21fa01a3f1c9fcd533d696d001c2594ca38092 Mon Sep 17 00:00:00 2001 From: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:08:43 +0530 Subject: [PATCH 060/170] feat: Option to disable 2FA for OAuth users (#32945) --- .changeset/tiny-geckos-kiss.md | 6 ++ .../app/2fa/server/code/EmailCheck.spec.ts | 70 +++++++++++++++ apps/meteor/app/2fa/server/code/EmailCheck.ts | 6 +- apps/meteor/app/2fa/server/code/index.ts | 12 +-- apps/meteor/app/api/server/v1/misc.ts | 14 +-- .../server/functions/getBaseUserFields.ts | 34 ++++++++ .../server/functions/getDefaultUserFields.ts | 35 ++------ .../account/security/AccountSecurityPage.tsx | 12 ++- .../views/account/security/TwoFactorEmail.tsx | 4 +- apps/meteor/server/settings/accounts.ts | 12 +++ packages/core-typings/src/IUser.ts | 85 +++++++++++++------ packages/i18n/src/locales/en.i18n.json | 2 + 12 files changed, 217 insertions(+), 75 deletions(-) create mode 100644 .changeset/tiny-geckos-kiss.md create mode 100644 apps/meteor/app/2fa/server/code/EmailCheck.spec.ts create mode 100644 apps/meteor/app/utils/server/functions/getBaseUserFields.ts diff --git a/.changeset/tiny-geckos-kiss.md b/.changeset/tiny-geckos-kiss.md new file mode 100644 index 000000000000..d38150970310 --- /dev/null +++ b/.changeset/tiny-geckos-kiss.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/i18n': minor +'@rocket.chat/meteor': minor +--- + +Added a new setting which allows workspace admins to disable email two factor authentication for SSO (OAuth) users. If enabled, SSO users won't be asked for email two factor authentication. diff --git a/apps/meteor/app/2fa/server/code/EmailCheck.spec.ts b/apps/meteor/app/2fa/server/code/EmailCheck.spec.ts new file mode 100644 index 000000000000..5c3574f0b395 --- /dev/null +++ b/apps/meteor/app/2fa/server/code/EmailCheck.spec.ts @@ -0,0 +1,70 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import proxyquire from 'proxyquire'; +import sinon from 'sinon'; + +const settingsMock = sinon.stub(); + +const { EmailCheck } = proxyquire.noCallThru().load('./EmailCheck', { + '@rocket.chat/models': { + Users: {}, + }, + 'meteor/accounts-base': { + Accounts: { + _bcryptRounds: () => '123', + }, + }, + '../../../../server/lib/i18n': { + i18n: { + t: (key: string) => key, + }, + }, + '../../../mailer/server/api': { + send: () => undefined, + }, + '../../../settings/server': { + settings: { + get: settingsMock, + }, + }, +}); + +const normalUserMock = { services: { email2fa: { enabled: true } }, emails: [{ email: 'abc@gmail.com', verified: true }] }; +const normalUserWithUnverifiedEmailMock = { + services: { email2fa: { enabled: true } }, + emails: [{ email: 'abc@gmail.com', verified: false }], +}; +const OAuthUserMock = { services: { google: {} }, emails: [{ email: 'abc@gmail.com', verified: true }] }; + +describe('EmailCheck', () => { + let emailCheck: typeof EmailCheck; + beforeEach(() => { + settingsMock.reset(); + + emailCheck = new EmailCheck(); + }); + + it('should return EmailCheck is enabled for a normal user', () => { + settingsMock.returns(true); + + const isEmail2FAEnabled = emailCheck.isEnabled(normalUserMock); + + expect(isEmail2FAEnabled).to.be.equal(true); + }); + + it('should return EmailCheck is not enabled for a normal user with unverified email', () => { + settingsMock.returns(true); + + const isEmail2FAEnabled = emailCheck.isEnabled(normalUserWithUnverifiedEmailMock); + + expect(isEmail2FAEnabled).to.be.equal(false); + }); + + it('should return EmailCheck is not enabled for a OAuth user with setting being false', () => { + settingsMock.returns(true); + + const isEmail2FAEnabled = emailCheck.isEnabled(OAuthUserMock); + + expect(isEmail2FAEnabled).to.be.equal(false); + }); +}); diff --git a/apps/meteor/app/2fa/server/code/EmailCheck.ts b/apps/meteor/app/2fa/server/code/EmailCheck.ts index 123df96ee264..d947c1b30c2e 100644 --- a/apps/meteor/app/2fa/server/code/EmailCheck.ts +++ b/apps/meteor/app/2fa/server/code/EmailCheck.ts @@ -1,4 +1,4 @@ -import type { IUser } from '@rocket.chat/core-typings'; +import { isOAuthUser, type IUser } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; import { Random } from '@rocket.chat/random'; import bcrypt from 'bcrypt'; @@ -24,6 +24,10 @@ export class EmailCheck implements ICodeCheck { return false; } + if (!settings.get('Accounts_twoFactorAuthentication_email_available_for_OAuth_users') && isOAuthUser(user)) { + return false; + } + if (!user.services?.email2fa?.enabled) { return false; } diff --git a/apps/meteor/app/2fa/server/code/index.ts b/apps/meteor/app/2fa/server/code/index.ts index 1fbe658e5682..b05157416e31 100644 --- a/apps/meteor/app/2fa/server/code/index.ts +++ b/apps/meteor/app/2fa/server/code/index.ts @@ -45,14 +45,10 @@ function getAvailableMethodNames(user: IUser): string[] { export async function getUserForCheck(userId: string): Promise { return Users.findOneById(userId, { projection: { - 'emails': 1, - 'language': 1, - 'createdAt': 1, - 'services.totp': 1, - 'services.email2fa': 1, - 'services.emailCode': 1, - 'services.password': 1, - 'services.resume.loginTokens': 1, + emails: 1, + language: 1, + createdAt: 1, + services: 1, }, }); } diff --git a/apps/meteor/app/api/server/v1/misc.ts b/apps/meteor/app/api/server/v1/misc.ts index dd4da47bff05..8348b8429e4e 100644 --- a/apps/meteor/app/api/server/v1/misc.ts +++ b/apps/meteor/app/api/server/v1/misc.ts @@ -1,6 +1,6 @@ import crypto from 'crypto'; -import type { IUser } from '@rocket.chat/core-typings'; +import { isOAuthUser, type IUser } from '@rocket.chat/core-typings'; import { Settings, Users } from '@rocket.chat/models'; import { isShieldSvgProps, @@ -26,7 +26,7 @@ import { hasPermissionAsync } from '../../../authorization/server/functions/hasP import { passwordPolicy } from '../../../lib/server'; import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener'; import { settings } from '../../../settings/server'; -import { getDefaultUserFields } from '../../../utils/server/functions/getDefaultUserFields'; +import { getBaseUserFields } from '../../../utils/server/functions/getBaseUserFields'; import { isSMTPConfigured } from '../../../utils/server/functions/isSMTPConfigured'; import { getURL } from '../../../utils/server/getURL'; import { API } from '../api'; @@ -176,15 +176,19 @@ API.v1.addRoute( { authRequired: true }, { async get() { - const fields = getDefaultUserFields(); - const { services, ...user } = (await Users.findOneById(this.userId, { projection: fields })) as IUser; + const userFields = { ...getBaseUserFields(), services: 1 }; + const { services, ...user } = (await Users.findOneById(this.userId, { projection: userFields })) as IUser; return API.v1.success( await getUserInfo({ ...user, + isOAuthUser: isOAuthUser({ ...user, services }), ...(services && { services: { - ...services, + ...(services.github && { github: services.github }), + ...(services.gitlab && { gitlab: services.gitlab }), + ...(services.email2fa?.enabled && { email2fa: { enabled: services.email2fa.enabled } }), + ...(services.totp?.enabled && { totp: { enabled: services.totp.enabled } }), password: { // The password hash shouldn't be leaked but the client may need to know if it exists. exists: Boolean(services?.password?.bcrypt), diff --git a/apps/meteor/app/utils/server/functions/getBaseUserFields.ts b/apps/meteor/app/utils/server/functions/getBaseUserFields.ts new file mode 100644 index 000000000000..5e2a3bf2b4d7 --- /dev/null +++ b/apps/meteor/app/utils/server/functions/getBaseUserFields.ts @@ -0,0 +1,34 @@ +type UserFields = { + [k: string]: number; +}; + +export const getBaseUserFields = (): UserFields => ({ + 'name': 1, + 'username': 1, + 'nickname': 1, + 'emails': 1, + 'status': 1, + 'statusDefault': 1, + 'statusText': 1, + 'statusConnection': 1, + 'bio': 1, + 'avatarOrigin': 1, + 'utcOffset': 1, + 'language': 1, + 'settings': 1, + 'enableAutoAway': 1, + 'idleTimeLimit': 1, + 'roles': 1, + 'active': 1, + 'defaultRoom': 1, + 'customFields': 1, + 'requirePasswordChange': 1, + 'requirePasswordChangeReason': 1, + 'statusLivechat': 1, + 'banners': 1, + 'oauth.authorizedClients': 1, + '_updatedAt': 1, + 'avatarETag': 1, + 'extension': 1, + 'openBusinessHours': 1, +}); diff --git a/apps/meteor/app/utils/server/functions/getDefaultUserFields.ts b/apps/meteor/app/utils/server/functions/getDefaultUserFields.ts index 03d0cae77ab9..293eb8607342 100644 --- a/apps/meteor/app/utils/server/functions/getDefaultUserFields.ts +++ b/apps/meteor/app/utils/server/functions/getDefaultUserFields.ts @@ -1,39 +1,14 @@ -type DefaultUserFields = { +import { getBaseUserFields } from './getBaseUserFields'; + +type UserFields = { [k: string]: number; }; -export const getDefaultUserFields = (): DefaultUserFields => ({ - 'name': 1, - 'username': 1, - 'nickname': 1, - 'emails': 1, - 'status': 1, - 'statusDefault': 1, - 'statusText': 1, - 'statusConnection': 1, - 'bio': 1, - 'avatarOrigin': 1, - 'utcOffset': 1, - 'language': 1, - 'settings': 1, - 'enableAutoAway': 1, - 'idleTimeLimit': 1, - 'roles': 1, - 'active': 1, - 'defaultRoom': 1, - 'customFields': 1, - 'requirePasswordChange': 1, - 'requirePasswordChangeReason': 1, +export const getDefaultUserFields = (): UserFields => ({ + ...getBaseUserFields(), 'services.github': 1, 'services.gitlab': 1, 'services.password.bcrypt': 1, 'services.totp.enabled': 1, 'services.email2fa.enabled': 1, - 'statusLivechat': 1, - 'banners': 1, - 'oauth.authorizedClients': 1, - '_updatedAt': 1, - 'avatarETag': 1, - 'extension': 1, - 'openBusinessHours': 1, }); diff --git a/apps/meteor/client/views/account/security/AccountSecurityPage.tsx b/apps/meteor/client/views/account/security/AccountSecurityPage.tsx index 536ba8a04ef7..06619f0618f5 100644 --- a/apps/meteor/client/views/account/security/AccountSecurityPage.tsx +++ b/apps/meteor/client/views/account/security/AccountSecurityPage.tsx @@ -1,6 +1,6 @@ import { Box, Accordion, ButtonGroup, Button } from '@rocket.chat/fuselage'; import { useUniqueId } from '@rocket.chat/fuselage-hooks'; -import { useSetting, useTranslation } from '@rocket.chat/ui-contexts'; +import { useSetting, useTranslation, useUser } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; import { FormProvider, useForm } from 'react-hook-form'; @@ -15,6 +15,11 @@ const passwordDefaultValues = { password: '', confirmationPassword: '' }; const AccountSecurityPage = (): ReactElement => { const t = useTranslation(); + const user = useUser(); + + const isEmail2FAAvailableForOAuth = useSetting('Accounts_twoFactorAuthentication_email_available_for_OAuth_users'); + const isOAuthUser = user?.isOAuthUser; + const isEmail2FAAllowed = !isOAuthUser || isEmail2FAAvailableForOAuth; const methods = useForm({ defaultValues: passwordDefaultValues, @@ -30,6 +35,7 @@ const AccountSecurityPage = (): ReactElement => { const twoFactorByEmailEnabled = useSetting('Accounts_TwoFactorAuthentication_By_Email_Enabled'); const e2eEnabled = useSetting('E2E_Enable'); const allowPasswordChange = useSetting('Accounts_AllowPasswordChange'); + const showEmailTwoFactor = twoFactorByEmailEnabled && isEmail2FAAllowed; const passwordFormId = useUniqueId(); @@ -48,10 +54,10 @@ const AccountSecurityPage = (): ReactElement => { )} - {(twoFactorTOTP || twoFactorByEmailEnabled) && twoFactorEnabled && ( + {(twoFactorTOTP || showEmailTwoFactor) && twoFactorEnabled && ( {twoFactorTOTP && } - {twoFactorByEmailEnabled && } + {showEmailTwoFactor && } )} {e2eEnabled && ( diff --git a/apps/meteor/client/views/account/security/TwoFactorEmail.tsx b/apps/meteor/client/views/account/security/TwoFactorEmail.tsx index c890dc61e658..3654d17b5dec 100644 --- a/apps/meteor/client/views/account/security/TwoFactorEmail.tsx +++ b/apps/meteor/client/views/account/security/TwoFactorEmail.tsx @@ -1,11 +1,11 @@ import { Box, Button, Margins } from '@rocket.chat/fuselage'; import { useUser, useTranslation } from '@rocket.chat/ui-contexts'; -import type { ComponentProps, ReactElement } from 'react'; +import type { ComponentProps } from 'react'; import React, { useCallback } from 'react'; import { useEndpointAction } from '../../../hooks/useEndpointAction'; -const TwoFactorEmail = (props: ComponentProps): ReactElement => { +const TwoFactorEmail = (props: ComponentProps) => { const t = useTranslation(); const user = useUser(); diff --git a/apps/meteor/server/settings/accounts.ts b/apps/meteor/server/settings/accounts.ts index a744c47b2a41..b4da1cd913e9 100644 --- a/apps/meteor/server/settings/accounts.ts +++ b/apps/meteor/server/settings/accounts.ts @@ -31,6 +31,18 @@ export const createAccountSettings = () => public: true, }); + await this.add('Accounts_twoFactorAuthentication_email_available_for_OAuth_users', true, { + type: 'boolean', + enableQuery: [ + enable2FA, + { + _id: 'Accounts_TwoFactorAuthentication_By_Email_Enabled', + value: true, + }, + ], + public: true, + }); + await this.add('Accounts_TwoFactorAuthentication_By_Email_Auto_Opt_In', true, { type: 'boolean', enableQuery: [ diff --git a/packages/core-typings/src/IUser.ts b/packages/core-typings/src/IUser.ts index fa411c6f7e47..d6854bef7243 100644 --- a/packages/core-typings/src/IUser.ts +++ b/packages/core-typings/src/IUser.ts @@ -45,7 +45,35 @@ export type ILoginUsername = }; export type LoginUsername = string | ILoginUsername; -export interface IUserServices { +export interface IOAuthUserServices { + google?: any; + facebook?: any; + github?: any; + linkedin?: any; + twitter?: any; + gitlab?: any; + saml?: { + inResponseTo?: string; + provider?: string; + idp?: string; + idpSession?: string; + nameID?: string; + }; + ldap?: { + id: string; + idAttribute?: string; + }; + nextcloud?: { + accessToken: string; + refreshToken: string; + serverURL: string; + }; + dolphin?: { + NickName?: string; + }; +} + +export interface IUserServices extends IOAuthUserServices { password?: { exists?: boolean; bcrypt?: string; @@ -62,12 +90,6 @@ export interface IUserServices { refreshToken: string; expiresAt: Date; }; - google?: any; - facebook?: any; - github?: any; - linkedin?: any; - twitter?: any; - gitlab?: any; totp?: { enabled: boolean; hashedBackup: string[]; @@ -79,27 +101,37 @@ export interface IUserServices { changedAt: Date; }; emailCode?: IUserEmailCode; - saml?: { - inResponseTo?: string; - provider?: string; - idp?: string; - idpSession?: string; - nameID?: string; - }; - ldap?: { - id: string; - idAttribute?: string; - }; - nextcloud?: { - accessToken: string; - refreshToken: string; - serverURL: string; - }; - dolphin?: { - NickName?: string; - }; } +type IUserService = keyof IUserServices; +type IOAuthService = keyof IOAuthUserServices; + +const defaultOAuthKeys = [ + 'google', + 'dolphin', + 'facebook', + 'github', + 'gitlab', + 'google', + 'ldap', + 'linkedin', + 'nextcloud', + 'saml', + 'twitter', +] as IOAuthService[]; +const userServiceKeys = ['emailCode', 'email2fa', 'totp', 'resume', 'password', 'passwordHistory', 'cloud', 'email'] as IUserService[]; + +export const isUserServiceKey = (key: string): key is IUserService => + userServiceKeys.includes(key as IUserService) || defaultOAuthKeys.includes(key as IOAuthService); + +export const isDefaultOAuthUser = (user: IUser): boolean => + !!user.services && Object.keys(user.services).some((key) => defaultOAuthKeys.includes(key as IOAuthService)); + +export const isCustomOAuthUser = (user: IUser): boolean => + !!user.services && Object.keys(user.services).some((key) => !isUserServiceKey(key)); + +export const isOAuthUser = (user: IUser): boolean => isDefaultOAuthUser(user) || isCustomOAuthUser(user); + export interface IUserEmail { address: string; verified?: boolean; @@ -183,6 +215,7 @@ export interface IUser extends IRocketChatRecord { _pendingAvatarUrl?: string; requirePasswordChange?: boolean; requirePasswordChangeReason?: string; + isOAuthUser?: boolean; // client only field } export interface IRegisterUser extends IUser { diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index d3324c6e749a..e6867528ad4c 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -282,6 +282,8 @@ "Accounts_TwoFactorAuthentication_By_Email_Code_Expiration": "Time to expire the code sent via email in seconds", "Accounts_TwoFactorAuthentication_By_Email_Enabled": "Enable Two Factor Authentication via Email", "Accounts_TwoFactorAuthentication_By_Email_Enabled_Description": "Users with email verified and the option enabled in their profile page will receive an email with a temporary code to authorize certain actions like login, save the profile, etc.", + "Accounts_twoFactorAuthentication_email_available_for_OAuth_users": "Make two factor via email available for oAuth users", + "Accounts_twoFactorAuthentication_email_available_for_OAuth_users_Description": "People that use oAuth will receive an email with a temporary code to authorize actions like login, save profile, etc.", "Accounts_TwoFactorAuthentication_Enabled": "Enable Two Factor Authentication", "Accounts_TwoFactorAuthentication_Enabled_Description": "If deactivated, this setting will deactivate all Two Factor Authentication. \nTo force users to use Two Factor Authentication, the admin has to configure the 'user' role to enforce it.", "Accounts_TwoFactorAuthentication_Enforce_Password_Fallback": "Enforce password fallback", From f3e8b6b5082934c6d142df442ee42a5ce968c969 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 10 Sep 2024 18:59:26 +0000 Subject: [PATCH 061/170] Bump 6.12.1 --- .changeset/bump-patch-1725994766358.md | 5 +++++ yarn.lock | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 .changeset/bump-patch-1725994766358.md diff --git a/.changeset/bump-patch-1725994766358.md b/.changeset/bump-patch-1725994766358.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1725994766358.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/yarn.lock b/yarn.lock index d89ba8bce628..a4da870cdb2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8934,10 +8934,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 6.0.0-rc.6 - "@rocket.chat/ui-contexts": 10.0.0-rc.6 - "@rocket.chat/ui-kit": 0.36.1-rc.0 - "@rocket.chat/ui-video-conf": 10.0.0-rc.6 + "@rocket.chat/ui-avatar": 6.0.0 + "@rocket.chat/ui-contexts": 10.0.0 + "@rocket.chat/ui-kit": 0.36.1 + "@rocket.chat/ui-video-conf": 10.0.0 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9021,8 +9021,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 10.0.0-rc.6 - "@rocket.chat/ui-contexts": 10.0.0-rc.6 + "@rocket.chat/ui-client": 10.0.0 + "@rocket.chat/ui-contexts": 10.0.0 katex: "*" react: "*" languageName: unknown @@ -10228,7 +10228,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 10.0.0-rc.6 + "@rocket.chat/ui-contexts": 10.0.0 react: ~17.0.2 languageName: unknown linkType: soft @@ -10278,7 +10278,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 10.0.0-rc.6 + "@rocket.chat/ui-contexts": 10.0.0 react: ~17.0.2 languageName: unknown linkType: soft @@ -10448,8 +10448,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 6.0.0-rc.6 - "@rocket.chat/ui-contexts": 10.0.0-rc.6 + "@rocket.chat/ui-avatar": 6.0.0 + "@rocket.chat/ui-contexts": 10.0.0 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10536,7 +10536,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 - "@rocket.chat/ui-contexts": 10.0.0-rc.6 + "@rocket.chat/ui-contexts": 10.0.0 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 6730a3c9117fbb196ba36d5f1e10c752bd882112 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 10 Sep 2024 21:19:10 -0300 Subject: [PATCH 062/170] chore: fix ui-playground build (#33250) --- packages/password-policies/tsconfig.json | 3 +-- packages/uikit-playground/vite.config.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/password-policies/tsconfig.json b/packages/password-policies/tsconfig.json index f0a66c843c50..e2be47cf5499 100644 --- a/packages/password-policies/tsconfig.json +++ b/packages/password-policies/tsconfig.json @@ -2,8 +2,7 @@ "extends": "../../tsconfig.base.client.json", "compilerOptions": { "rootDir": "./src", - "outDir": "./dist", - "module": "commonjs" + "outDir": "./dist" }, "include": ["./src/**/*"] } diff --git a/packages/uikit-playground/vite.config.ts b/packages/uikit-playground/vite.config.ts index a18e01b590e8..61a5ab30e647 100644 --- a/packages/uikit-playground/vite.config.ts +++ b/packages/uikit-playground/vite.config.ts @@ -3,7 +3,7 @@ import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig(() => ({ - logLevel: 'info', + base: './', esbuild: {}, plugins: [react()], optimizeDeps: { From 79c16d315a40b3acb5135d2a334da6ab410703a3 Mon Sep 17 00:00:00 2001 From: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:20:42 -0300 Subject: [PATCH 063/170] fix: message parser being slow to process very long messages with too many symbols (#33227) --- .changeset/short-drinks-itch.md | 6 + packages/message-parser/src/grammar.pegjs | 126 ++++---- packages/message-parser/src/utils.ts | 36 ++- packages/message-parser/tests/abuse.test.ts | 268 ++++++++++++++++++ .../message-parser/tests/emphasis.test.ts | 62 ++++ packages/message-parser/tests/link.test.ts | 24 ++ 6 files changed, 453 insertions(+), 69 deletions(-) create mode 100644 .changeset/short-drinks-itch.md create mode 100644 packages/message-parser/tests/abuse.test.ts diff --git a/.changeset/short-drinks-itch.md b/.changeset/short-drinks-itch.md new file mode 100644 index 000000000000..ee57330ffc86 --- /dev/null +++ b/.changeset/short-drinks-itch.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/message-parser': patch +'@rocket.chat/peggy-loader': patch +--- + +Improved the performance of the message parser diff --git a/packages/message-parser/src/grammar.pegjs b/packages/message-parser/src/grammar.pegjs index 182653a9c664..a6cae97facbf 100644 --- a/packages/message-parser/src/grammar.pegjs +++ b/packages/message-parser/src/grammar.pegjs @@ -10,6 +10,7 @@ emoji, emojiUnicode, emoticon, + extractFirstResult, heading, image, inlineCode, @@ -33,6 +34,11 @@ unorderedList, timestamp, } = require('./utils'); + +let skipBold = false; +let skipItalic = false; +let skipStrikethrough = false; +let skipReferences = false; }} Start @@ -212,7 +218,7 @@ Inline = value:(InlineItem / Any)+ EndOfLine? { return reducePlainTexts(value); InlineItem = Whitespace / Timestamp - / References + / MaybeReferences / AutolinkedPhone / AutolinkedEmail / AutolinkedURL @@ -240,7 +246,7 @@ References = "[" title:LinkTitle* "](" href:LinkRef ")" { return title.length ? link(href, reducePlainTexts(title)) : link(href); } / "<" href:LinkRef "|" title:LinkTitle2 ">" { return link(href, [plain(title)]); } -LinkTitle = (Whitespace / EmphasisForReferences) / anyTitle:$(!("](" .) .) { return plain(anyTitle) } +LinkTitle = (Whitespace / Emphasis) / anyTitle:$(!("](" .) .) { return plain(anyTitle) } LinkTitle2 = $([\x20-\x3B\x3D\x3F-\x60\x61-\x7B\x7D-\xFF] / NonASCII)+ @@ -349,14 +355,7 @@ AutoLinkURLBody = !(Extra* (Whitespace / EndOfLine)) . * Emphasis * */ -Emphasis = Bold / Italic / Strikethrough - -/** - * - * Emphasis for References - * -*/ -EmphasisForReferences = BoldForReferences / ItalicForReferences / StrikethroughForReferences +Emphasis = MaybeBold / MaybeItalic / MaybeStrikethrough /** * @@ -365,6 +364,63 @@ EmphasisForReferences = BoldForReferences / ItalicForReferences / StrikethroughF * */ +// This rule is used inside expressions that have a JS code ensuring they always fail, +// Without any pattern to match, peggy will think the rule may end up succedding without consuming any input, which could cause infinite loops +// So this unreachable rule is added to them to satisfy peggy's requirement. +BlockedByJavascript = 'unreachable' + +MaybeBold + = result:( + & { + if (skipBold) { return false; } + skipBold = true; + return true; + } + ( + (text:Bold { skipBold = false; return text; }) + / (& { skipBold = false; return false; } BlockedByJavascript) + ) + ) { return extractFirstResult(result); } + +MaybeStrikethrough + = result:( + & { + if (skipStrikethrough) { return false; } + skipStrikethrough = true; + return true; + } + ( + (text:Strikethrough { skipStrikethrough = false; return text; }) + / (& { skipStrikethrough = false; return false; } BlockedByJavascript) + ) + ) { return extractFirstResult(result); } + +MaybeItalic + = result:( + & { + if (skipItalic) { return false; } + skipItalic = true; + return true; + } + ( + (text:Italic { skipItalic = false; return text; }) + / (& { skipItalic = false; return false; } BlockedByJavascript) + ) + ) { return extractFirstResult(result); } + +MaybeReferences + = result:( + & { + if (skipReferences) { return false; } + skipReferences = true; + return true; + } + ( + (text:References { skipReferences = false; return text; }) + / (& { skipReferences = false; return false; } BlockedByJavascript) + ) + ) { return extractFirstResult(result); } + /* Italic */ Italic = value:$([a-zA-Z0-9]+ [\x5F] [\x5F]?) { return plain(value); } @@ -384,11 +440,11 @@ ItalicContentItems = text:ItalicContentItem+ { return reducePlainTexts(text); } ItalicContentItem = Whitespace / InlineCode - / References + / MaybeReferences / UserMention / ChannelMention - / Bold - / Strikethrough + / MaybeBold + / MaybeStrikethrough / Emoji / Emoticon / AnyItalic @@ -399,52 +455,12 @@ Bold = [\x2A] [\x2A] @BoldContent [\x2A] [\x2A] / [\x2A] @BoldContent [\x2A] BoldContent = text:BoldContentItem+ { return bold(reducePlainTexts(text)); } -BoldContentItem = Whitespace / InlineCode / References / UserMention / ChannelMention / Italic / Strikethrough / Emoji / Emoticon / AnyBold / Line +BoldContentItem = Whitespace / InlineCode / MaybeReferences / UserMention / ChannelMention / MaybeItalic / MaybeStrikethrough / Emoji / Emoticon / AnyBold / Line /* Strike */ Strikethrough = [\x7E] [\x7E] @StrikethroughContent [\x7E] [\x7E] / [\x7E] @StrikethroughContent [\x7E] -StrikethroughContent = text:(Timestamp / InlineCode / Whitespace / References / UserMention / ChannelMention / Italic / Bold / Emoji / Emoticon / AnyStrike / Line)+ { - return strike(reducePlainTexts(text)); - } - -/* Italic for References */ -ItalicForReferences - = value:$([a-zA-Z0-9]+ [\x5F] [\x5F]?) { return plain(value); } - / [\x5F] [\x5F] i:ItalicContentItemsForReferences [\x5F] [\x5F] t:$[a-zA-Z0-9]+ { - return reducePlainTexts([plain('__'), ...i, plain('__'), plain(t)])[0]; - } - / [\x5F] i:ItalicContentItemsForReferences [\x5F] t:$[a-zA-Z]+ { - return reducePlainTexts([plain('_'), ...i, plain('_'), plain(t)])[0]; - } - / [\x5F] [\x5F] @ItalicContentForReferences [\x5F] [\x5F] - / [\x5F] @ItalicContentForReferences [\x5F] - -ItalicContentForReferences = text:ItalicContentItemsForReferences { return italic(text); } - -ItalicContentItemsForReferences = text:ItalicContentItemForReferences+ { return reducePlainTexts(text); } - -ItalicContentItemForReferences - = Whitespace - / UserMention - / ChannelMention - / BoldForReferences - / StrikethroughForReferences - / Emoji - / Emoticon - / AnyItalic - / Line - / InlineCode - -/* Bold for References */ -BoldForReferences = [\x2A] [\x2A] @BoldContentForReferences [\x2A] [\x2A] / [\x2A] @BoldContentForReferences [\x2A] - -BoldContentForReferences = text:(Whitespace / UserMention / ChannelMention / ItalicForReferences / StrikethroughForReferences / Emoji / Emoticon / AnyBold / Line / InlineCode)+ { return bold(reducePlainTexts(text)); } - -/* Strike for References */ -StrikethroughForReferences = [\x7E] [\x7E] @StrikethroughContentForReferences [\x7E] [\x7E] / [\x7E] @StrikethroughContentForReferences [\x7E] - -StrikethroughContentForReferences = text:(Whitespace / UserMention / ChannelMention / ItalicForReferences / BoldForReferences / Emoji / Emoticon / AnyStrike / Line / InlineCode)+ { +StrikethroughContent = text:(Timestamp / Whitespace / InlineCode / MaybeReferences / UserMention / ChannelMention / MaybeItalic / MaybeBold / Emoji / Emoticon / AnyStrike / Line)+ { return strike(reducePlainTexts(text)); } diff --git a/packages/message-parser/src/utils.ts b/packages/message-parser/src/utils.ts index 1f684b56d6ed..6c5d605c5c7a 100644 --- a/packages/message-parser/src/utils.ts +++ b/packages/message-parser/src/utils.ts @@ -198,21 +198,19 @@ const joinEmoji = ( export const reducePlainTexts = ( values: Paragraph['value'] ): Paragraph['value'] => - values - .flatMap((item) => item) - .reduce((result, item, index, values) => { - const next = values[index + 1]; - const current = joinEmoji(item, values[index - 1], next); - const previous: Inlines = result[result.length - 1]; - - if (previous) { - if (current.type === 'PLAIN_TEXT' && current.type === previous.type) { - previous.value += current.value; - return result; - } + values.flat().reduce((result, item, index, values) => { + const next = values[index + 1]; + const current = joinEmoji(item, values[index - 1], next); + const previous: Inlines = result[result.length - 1]; + + if (previous) { + if (current.type === 'PLAIN_TEXT' && current.type === previous.type) { + previous.value += current.value; + return result; } - return [...result, current]; - }, [] as Paragraph['value']); + } + return [...result, current]; + }, [] as Paragraph['value']); export const lineBreak = (): LineBreak => ({ type: 'LINE_BREAK', value: undefined, @@ -249,3 +247,13 @@ export const timestamp = ( fallback: plain(``), }; }; + +export const extractFirstResult = ( + value: Types[keyof Types]['value'] +): Types[keyof Types]['value'] => { + if (typeof value !== 'object' || !Array.isArray(value)) { + return value; + } + + return value.filter((item) => item).shift() as Types[keyof Types]['value']; +}; diff --git a/packages/message-parser/tests/abuse.test.ts b/packages/message-parser/tests/abuse.test.ts new file mode 100644 index 000000000000..c280ee75b4a0 --- /dev/null +++ b/packages/message-parser/tests/abuse.test.ts @@ -0,0 +1,268 @@ +import { parse } from '../src'; +import { paragraph, plain, bold, italic, strike } from '../src/utils'; + +test.each([ + [ + `This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. , REPEATx2 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. REPEAT x3 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. REPEAT x4 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. REPEATx 5 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. , REPEAT x6 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. this can go long for some time, repeat x7 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. ,repeat x8 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some.`, + [ + paragraph([ + plain( + 'This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&' + ), + bold([ + plain('()'), + italic([ + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + strike([ + plain( + `, from now on we repeat some. , REPEATx2 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + ]), + plain( + ', from now on we repeat some. REPEAT x3 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()' + ), + ]), + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + strike([ + plain( + ', from now on we repeat some. REPEAT x4 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()' + ), + italic([ + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. REPEATx 5 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()` + ), + ]), + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + ]), + plain( + `, from now on we repeat some. , REPEAT x6 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&` + ), + ]), + plain( + `()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + strike([ + plain( + `, from now on we repeat some. this can go long for some time, repeat x7 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()` + ), + italic([ + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. ,repeat x8 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()` + ), + ]), + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + ]), + plain(', from now on we repeat some.'), + ]), + ], + ], + [ + '**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__', + [ + paragraph([ + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + plain('__'), + ]), + ], + ], +])('parses %p', (input, output) => { + expect(parse(input)).toMatchObject(output); +}); diff --git a/packages/message-parser/tests/emphasis.test.ts b/packages/message-parser/tests/emphasis.test.ts index e8e72a5882f1..b035999204ce 100644 --- a/packages/message-parser/tests/emphasis.test.ts +++ b/packages/message-parser/tests/emphasis.test.ts @@ -185,6 +185,68 @@ test.each([ ]), ], ], + [ + '**bold ~~and strike~~** **not bold ~~but strike** ~~ not strike~~', + [ + paragraph([ + bold([plain('bold '), strike([plain('and strike')])]), + plain(' **not bold '), + strike([plain('but strike** ')]), + plain(' not strike~~'), + ]), + ], + ], + [ + '**bold** **another bold** ~~strike~~ ~~another strike~~ **bold ~~and strike~~** **not bold ~~but strike** ~~ not strike~~', + [ + paragraph([ + bold([plain('bold')]), + plain(' '), + bold([plain('another bold')]), + plain(' '), + strike([plain('strike')]), + plain(' '), + strike([plain('another strike')]), + plain(' '), + bold([plain('bold '), strike([plain('and strike')])]), + plain(' **not bold '), + strike([plain('but strike** ')]), + plain(' not strike~~'), + ]), + ], + ], + [ + 'some_snake_case_text and even_more', + [paragraph([plain('some_snake_case_text and even_more')])], + ], + [ + 'some_snake_case_text and some __italic__ text', + [ + paragraph([ + plain('some_snake_case_text and some '), + italic([plain('italic')]), + plain(' text'), + ]), + ], + ], + [ + 'some__double__snake__case__text and even_more', + [paragraph([plain('some__double__snake__case__text and even_more')])], + ], + [ + 'some__double__snake__case__text and some __italic__ text', + [ + paragraph([ + plain('some__double__snake__case__text and some '), + italic([plain('italic')]), + plain(' text'), + ]), + ], + ], + [ + 'something__ __and italic__', + [paragraph([plain('something__ '), italic([plain('and italic')])])], + ], ])('parses %p', (input, output) => { expect(parse(input)).toMatchObject(output); }); diff --git a/packages/message-parser/tests/link.test.ts b/packages/message-parser/tests/link.test.ts index 1e083fde5d70..fcf371474bf2 100644 --- a/packages/message-parser/tests/link.test.ts +++ b/packages/message-parser/tests/link.test.ts @@ -584,6 +584,30 @@ Text after line break`, ]), ], ], + [ + '[test **bold** and __italic__](https://rocket.chat)', + [ + paragraph([ + link('https://rocket.chat', [ + plain('test '), + bold([plain('bold')]), + plain(' and '), + italic([plain('italic')]), + ]), + ]), + ], + ], + [ + '[test **bold with __italic__**](https://rocket.chat)', + [ + paragraph([ + link('https://rocket.chat', [ + plain('test '), + bold([plain('bold with '), italic([plain('italic')])]), + ]), + ]), + ], + ], ])('parses %p', (input, output) => { expect(parse(input)).toMatchObject(output); }); From 249761607fc852dc32810d4ae965bc3a6aa714e9 Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Wed, 11 Sep 2024 10:28:01 -0300 Subject: [PATCH 064/170] chore: E2EE setting warning update (#33224) --- packages/i18n/src/locales/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index e6867528ad4c..849582f934b7 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -1800,7 +1800,7 @@ "Markdown_SupportSchemesForLink_Description": "Comma-separated list of allowed schemes", "E2E_enable": "Enable E2E", "E2E_disable": "Disable E2E", - "E2E_Enable_alert": "This feature is currently in beta! Please report bugs to github.com/RocketChat/Rocket.Chat/issues and be aware of:
- Encrypted messages of encrypted rooms will not be found by search operations.
- The mobile apps may not support the encrypted messages (they are implementing it).
- Bots may not be able to see encrypted messages until they implement support for it.
- Uploads will not be encrypted in this version.", + "E2E_Enable_alert": "This feature is currently in beta! Please report bugs to github.com/RocketChat/Rocket.Chat/issues and be aware of:
- Encrypted messages of encrypted rooms will not be found by search operations.
- Bots may not be able to see encrypted messages until they implement support for it.", "E2E_Enable_description": "Enable option to create encrypted groups and be able to change groups and direct messages to be encrypted", "E2E_Enabled": "E2E Enabled", "E2E_Enabled_Default_DirectRooms": "Enable encryption for Direct Rooms by default", From cbea8d492e03db406fdd32f40fb0c49843873567 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 11 Sep 2024 12:08:40 -0300 Subject: [PATCH 065/170] chore: move playground (#33260) --- {packages => apps}/uikit-playground/.eslintignore | 0 {packages => apps}/uikit-playground/.eslintrc.cjs | 0 {packages => apps}/uikit-playground/.gitignore | 0 {packages => apps}/uikit-playground/.prettierrc | 0 {packages => apps}/uikit-playground/CHANGELOG.md | 0 {packages => apps}/uikit-playground/index.html | 0 {packages => apps}/uikit-playground/package.json | 0 {packages => apps}/uikit-playground/postcss.config.js | 0 {packages => apps}/uikit-playground/public/vite.svg | 0 {packages => apps}/uikit-playground/src/App.css | 0 {packages => apps}/uikit-playground/src/App.tsx | 0 .../src/Components/CodeEditor/BlockEditor.tsx | 0 .../src/Components/CodeEditor/Extensions/Extensions.ts | 0 .../src/Components/CodeEditor/Extensions/HighlightStyle.ts | 0 .../src/Components/CodeEditor/Extensions/basicSetup.ts | 0 .../src/Components/CodeEditor/Extensions/index.ts | 0 .../src/Components/CodeEditor/Extensions/jsonLinter.ts | 0 .../src/Components/CodeEditor/Extensions/payloadLinter.ts | 0 .../src/Components/CodeEditor/Extensions/theme.ts | 0 .../src/Components/CodeEditor/Parser/index.ts | 0 .../src/Components/CodeEditor/Parser/parsePayload.ts | 0 .../src/Components/CodeEditor/PreviewEditor.tsx | 0 .../uikit-playground/src/Components/CodeEditor/index.tsx | 0 .../src/Components/ComponentSideBar/ScrollableSideBar.tsx | 0 .../src/Components/ComponentSideBar/SideBar.tsx | 0 .../src/Components/ComponentSideBar/SliderBtn.tsx | 0 .../src/Components/ComponentSideBar/index.tsx | 0 .../Components/CreateNewScreen/CreateNewScreenContainer.tsx | 0 .../src/Components/CreateNewScreen/ScreenThumbnail.tsx | 0 .../uikit-playground/src/Components/CreateNewScreen/index.ts | 0 .../src/Components/Draggable/DraggableList.tsx | 0 .../src/Components/Draggable/DraggableListItem.tsx | 0 .../uikit-playground/src/Components/DropDown/DropDown.tsx | 0 .../uikit-playground/src/Components/DropDown/Items.tsx | 0 .../uikit-playground/src/Components/DropDown/ItemsIcon.tsx | 0 .../uikit-playground/src/Components/DropDown/index.tsx | 0 .../uikit-playground/src/Components/DropDown/itemsStyle.ts | 0 .../uikit-playground/src/Components/DropDown/types.ts | 0 .../src/Components/FlowContainer/ConnectionLine.tsx | 0 .../FlowContainer/ControlButtons/ControlButtons.tsx | 0 .../src/Components/FlowContainer/ControlButtons/index.ts | 0 .../src/Components/FlowContainer/FlowContainer.tsx | 0 .../Components/FlowContainer/UIKitWrapper/UIKitWrapper.scss | 0 .../Components/FlowContainer/UIKitWrapper/UIKitWrapper.tsx | 0 .../src/Components/FlowContainer/UIKitWrapper/index.ts | 0 .../uikit-playground/src/Components/FlowContainer/index.ts | 0 .../uikit-playground/src/Components/FlowContainer/utils.ts | 0 .../src/Components/HomeContainer/HomeContainer.tsx | 0 .../Components/HomeContainer/ProjectsList/ProjectsList.tsx | 0 .../HomeContainer/ProjectsList/ProjectsThumbnail.tsx | 0 .../src/Components/HomeContainer/ProjectsList/index.ts | 0 .../uikit-playground/src/Components/HomeContainer/index.ts | 0 .../src/Components/NavBar/BurgerIcon/BurgerIcon.tsx | 0 .../src/Components/NavBar/BurgerIcon/Line.tsx | 0 .../src/Components/NavBar/BurgerIcon/Wrapper.tsx | 0 .../src/Components/NavBar/BurgerIcon/index.tsx | 0 .../uikit-playground/src/Components/NavBar/Divider.tsx | 0 .../uikit-playground/src/Components/NavBar/Logo.tsx | 0 .../uikit-playground/src/Components/NavBar/NavBar.tsx | 0 .../uikit-playground/src/Components/NavBar/RightNavBtn.tsx | 0 .../uikit-playground/src/Components/NavBar/index.tsx | 0 .../src/Components/PersistStore/PersistStore.tsx | 0 .../uikit-playground/src/Components/PersistStore/index.ts | 0 .../src/Components/Preview/Display/Display.tsx | 0 .../src/Components/Preview/Display/Surface/BannerSurface.tsx | 0 .../Preview/Display/Surface/ContextualBarSurface.tsx | 0 .../src/Components/Preview/Display/Surface/MessageSurface.tsx | 0 .../src/Components/Preview/Display/Surface/ModalSurface.tsx | 0 .../src/Components/Preview/Display/Surface/Reorder.ts | 0 .../src/Components/Preview/Display/Surface/Surface.tsx | 0 .../src/Components/Preview/Display/Surface/SurfaceRender.tsx | 0 .../src/Components/Preview/Display/Surface/constant.ts | 0 .../src/Components/Preview/Display/Surface/index.ts | 0 .../Preview/Display/UiKitElementWrapper/DeleteElementBtn.tsx | 0 .../Display/UiKitElementWrapper/UiKitElementWrapper.scss | 0 .../Display/UiKitElementWrapper/UiKitElementWrapper.tsx | 0 .../Components/Preview/Display/UiKitElementWrapper/index.ts | 0 .../uikit-playground/src/Components/Preview/Display/index.ts | 0 .../src/Components/Preview/Editor/ActionBlockEditor.tsx | 0 .../src/Components/Preview/Editor/ActionPreviewEditor.tsx | 0 .../src/Components/Preview/Editor/EditorPanel.tsx | 0 .../uikit-playground/src/Components/Preview/Editor/index.tsx | 0 .../src/Components/Preview/NavPanel/NavPanel.tsx | 0 .../src/Components/Preview/NavPanel/index.tsx | 0 .../uikit-playground/src/Components/Preview/Preview.tsx | 0 .../Preview/SplitPlaneContainer/SplitPlaneContainer.tsx | 0 .../src/Components/Preview/SplitPlaneContainer/index.ts | 0 .../src/Components/Preview/SplitPlaneContainer/splitPlane.css | 0 .../uikit-playground/src/Components/Preview/Wrapper.tsx | 0 .../uikit-playground/src/Components/Preview/index.tsx | 0 .../src/Components/PrototypeRender/PrototypeRender.scss | 0 .../src/Components/PrototypeRender/PrototypeRender.tsx | 0 .../uikit-playground/src/Components/PrototypeRender/index.ts | 0 .../src/Components/PtototypeContainer/PrototypeContainer.tsx | 0 .../src/Components/PtototypeContainer/index.ts | 0 .../src/Components/RenderPayload/RenderPayload.tsx | 0 .../uikit-playground/src/Components/RenderPayload/intex.ts | 0 .../uikit-playground/src/Components/Routes/HomeLayout.tsx | 0 .../src/Components/Routes/ProjectSpecificLayout.tsx | 0 .../src/Components/Routes/ProtectedLayout.tsx | 0 .../src/Components/ScreenThumbnail/CreateNewScreenButton.tsx | 0 .../src/Components/ScreenThumbnail/EditMenu/EditMenu.tsx | 0 .../src/Components/ScreenThumbnail/EditMenu/index.ts | 0 .../ScreenThumbnail/EditableLabel/EditableLabel.tsx | 0 .../ScreenThumbnail/EditableLabel/Editablelabel.scss | 0 .../src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx | 0 .../src/Components/ScreenThumbnail/Thumbnail.scss | 0 .../src/Components/ScreenThumbnail/Thumbnail.tsx | 0 .../src/Components/SurfaceSelect/SurfaceSelect.tsx | 0 .../uikit-playground/src/Components/SurfaceSelect/index.ts | 0 .../uikit-playground/src/Components/SurfaceSelect/options.ts | 0 .../src/Components/Templates/Container/Container.tsx | 0 .../src/Components/Templates/Container/Payload.tsx | 0 .../src/Components/Templates/Container/Section.tsx | 0 .../src/Components/Templates/Container/index.ts | 0 .../uikit-playground/src/Components/Templates/Templates.tsx | 0 .../uikit-playground/src/Components/Templates/index.ts | 0 .../uikit-playground/src/Components/ToggleTabs/index.tsx | 0 .../uikit-playground/src/Components/navMenu/Menu/MenuItem.tsx | 0 .../uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx | 0 .../uikit-playground/src/Components/navMenu/Menu/index.tsx | 0 .../uikit-playground/src/Components/navMenu/NavMenu.tsx | 0 .../uikit-playground/src/Components/navMenu/index.ts | 0 .../src/Context/action/actionPreviewAction.ts | 0 .../src/Context/action/activeProjectAction.ts | 0 .../uikit-playground/src/Context/action/activeScreenAction.ts | 0 .../src/Context/action/createNewProjectAction.ts | 0 .../src/Context/action/createNewScreenAction.ts | 0 .../src/Context/action/deleteProjectAction.ts | 0 .../uikit-playground/src/Context/action/deleteScreenAction.ts | 0 .../src/Context/action/duplicateProjectAction.ts | 0 .../src/Context/action/duplicateScreenAction.ts | 0 .../src/Context/action/editorTabsToggleAction.ts | 0 .../uikit-playground/src/Context/action/index.ts | 0 .../uikit-playground/src/Context/action/isMobileAction.ts | 0 .../uikit-playground/src/Context/action/isTabletAction.ts | 0 .../src/Context/action/navMenuToggleAction.ts | 0 .../src/Context/action/openCreateNewScreenAction.ts | 0 .../src/Context/action/previewTabsToggleAction.ts | 0 .../src/Context/action/renameProjectAction.ts | 0 .../uikit-playground/src/Context/action/renameScreenAction.ts | 0 .../src/Context/action/sidebarToggleAction.ts | 0 .../uikit-playground/src/Context/action/surfaceAction.ts | 0 .../uikit-playground/src/Context/action/tabsToggleAction.ts | 0 .../src/Context/action/templatesToggleAction.ts | 0 .../src/Context/action/updateFlowEdgesAction.ts | 0 .../src/Context/action/updateNodesAndViewPortAction.ts | 0 .../src/Context/action/updatePayloadAction.ts | 0 .../uikit-playground/src/Context/action/userAction.ts | 0 {packages => apps}/uikit-playground/src/Context/createCtx.tsx | 0 {packages => apps}/uikit-playground/src/Context/index.tsx | 0 .../uikit-playground/src/Context/initialState.ts | 0 {packages => apps}/uikit-playground/src/Context/reducer.ts | 0 {packages => apps}/uikit-playground/src/Pages/FlowDiagram.tsx | 0 {packages => apps}/uikit-playground/src/Pages/Home.tsx | 0 {packages => apps}/uikit-playground/src/Pages/Playground.tsx | 0 {packages => apps}/uikit-playground/src/Pages/Prototype.tsx | 0 .../uikit-playground/src/Pages/SignInSignUp.tsx | 0 .../uikit-playground/src/Payload/action/checkbox.ts | 0 .../uikit-playground/src/Payload/action/radioButton.ts | 0 .../uikit-playground/src/Payload/action/timePicker.ts | 0 .../uikit-playground/src/Payload/action/toggleSwitch.ts | 0 .../uikit-playground/src/Payload/actionBlock/BlocksTree.ts | 0 .../uikit-playground/src/Payload/actionBlock/action/button.ts | 0 .../src/Payload/actionBlock/action/datePicker.ts | 0 .../uikit-playground/src/Payload/actionBlock/action/image.ts | 0 .../uikit-playground/src/Payload/actionBlock/action/index.ts | 0 .../uikit-playground/src/Payload/actionBlock/action/input.ts | 0 .../src/Payload/actionBlock/action/linearScale.ts | 0 .../uikit-playground/src/Payload/actionBlock/action/menu.ts | 0 .../src/Payload/actionBlock/action/staticSelect.ts | 0 .../uikit-playground/src/Payload/actionBlock/context/index.ts | 0 .../uikit-playground/src/Payload/actionBlock/divider/index.ts | 0 .../uikit-playground/src/Payload/actionBlock/image/index.ts | 0 .../src/Payload/actionBlock/input/datePicker.ts | 0 .../uikit-playground/src/Payload/actionBlock/input/index.ts | 0 .../uikit-playground/src/Payload/actionBlock/input/input.ts | 0 .../src/Payload/actionBlock/input/linearScale.ts | 0 .../src/Payload/actionBlock/input/staticSelect.ts | 0 .../uikit-playground/src/Payload/actionBlock/preview/index.ts | 0 .../src/Payload/actionBlock/section/button.ts | 0 .../src/Payload/actionBlock/section/datePicker.ts | 0 .../uikit-playground/src/Payload/actionBlock/section/image.ts | 0 .../uikit-playground/src/Payload/actionBlock/section/index.ts | 0 .../uikit-playground/src/Payload/actionBlock/section/menu.ts | 0 .../uikit-playground/src/Payload/actionBlock/section/text.ts | 0 .../uikit-playground/src/Payload/actionPreview/container.ts | 0 .../src/Payload/actionPreview/generateActionPreview.ts | 0 .../uikit-playground/src/Payload/callout/index.ts | 0 {packages => apps}/uikit-playground/src/Payload/index.ts | 0 .../uikit-playground/src/Payload/tabNavigation/disabled.ts | 0 .../uikit-playground/src/Payload/tabNavigation/index.ts | 0 .../uikit-playground/src/Payload/tabNavigation/plain.ts | 0 .../uikit-playground/src/Payload/tabNavigation/selected.ts | 0 {packages => apps}/uikit-playground/src/Routes/Routes.ts | 0 {packages => apps}/uikit-playground/src/_global.css | 0 {packages => apps}/uikit-playground/src/cssVariables.css | 0 {packages => apps}/uikit-playground/src/hooks/useAuth.tsx | 0 .../uikit-playground/src/hooks/useCodeMirror.ts | 0 .../uikit-playground/src/hooks/useFormatCodeMirrorValue.ts | 0 .../uikit-playground/src/hooks/useHorizontalScroll.ts | 0 .../uikit-playground/src/hooks/useNodesAndEdges.ts | 0 {packages => apps}/uikit-playground/src/index.css | 0 {packages => apps}/uikit-playground/src/logo.svg | 0 {packages => apps}/uikit-playground/src/main.tsx | 0 {packages => apps}/uikit-playground/src/module.d.ts | 0 {packages => apps}/uikit-playground/src/utils/codePrettier.ts | 0 {packages => apps}/uikit-playground/src/utils/filterEdges.ts | 0 {packages => apps}/uikit-playground/src/utils/formatDate.ts | 0 {packages => apps}/uikit-playground/src/utils/getDate.ts | 0 {packages => apps}/uikit-playground/src/utils/getUniqueId.ts | 0 {packages => apps}/uikit-playground/src/utils/intendCode.ts | 0 {packages => apps}/uikit-playground/src/utils/persistStore.ts | 0 {packages => apps}/uikit-playground/src/utils/templates.ts | 0 .../uikit-playground/src/utils/uiKitRenderer.ts | 0 {packages => apps}/uikit-playground/src/vite-env.d.ts | 0 {packages => apps}/uikit-playground/tsconfig.json | 0 {packages => apps}/uikit-playground/vite.config.ts | 0 yarn.lock | 4 ++-- 219 files changed, 2 insertions(+), 2 deletions(-) rename {packages => apps}/uikit-playground/.eslintignore (100%) rename {packages => apps}/uikit-playground/.eslintrc.cjs (100%) rename {packages => apps}/uikit-playground/.gitignore (100%) rename {packages => apps}/uikit-playground/.prettierrc (100%) rename {packages => apps}/uikit-playground/CHANGELOG.md (100%) rename {packages => apps}/uikit-playground/index.html (100%) rename {packages => apps}/uikit-playground/package.json (100%) rename {packages => apps}/uikit-playground/postcss.config.js (100%) rename {packages => apps}/uikit-playground/public/vite.svg (100%) rename {packages => apps}/uikit-playground/src/App.css (100%) rename {packages => apps}/uikit-playground/src/App.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/BlockEditor.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/Extensions/Extensions.ts (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/Extensions/HighlightStyle.ts (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/Extensions/basicSetup.ts (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/Extensions/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/Extensions/jsonLinter.ts (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/Extensions/payloadLinter.ts (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/Extensions/theme.ts (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/Parser/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/Parser/parsePayload.ts (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/PreviewEditor.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/CodeEditor/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/ComponentSideBar/ScrollableSideBar.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/ComponentSideBar/SideBar.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/ComponentSideBar/SliderBtn.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/ComponentSideBar/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/CreateNewScreen/CreateNewScreenContainer.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/CreateNewScreen/ScreenThumbnail.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/CreateNewScreen/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Draggable/DraggableList.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Draggable/DraggableListItem.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/DropDown/DropDown.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/DropDown/Items.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/DropDown/ItemsIcon.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/DropDown/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/DropDown/itemsStyle.ts (100%) rename {packages => apps}/uikit-playground/src/Components/DropDown/types.ts (100%) rename {packages => apps}/uikit-playground/src/Components/FlowContainer/ConnectionLine.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/FlowContainer/ControlButtons/ControlButtons.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/FlowContainer/ControlButtons/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/FlowContainer/FlowContainer.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.scss (100%) rename {packages => apps}/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/FlowContainer/UIKitWrapper/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/FlowContainer/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/FlowContainer/utils.ts (100%) rename {packages => apps}/uikit-playground/src/Components/HomeContainer/HomeContainer.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsList.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsThumbnail.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/HomeContainer/ProjectsList/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/HomeContainer/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/NavBar/BurgerIcon/BurgerIcon.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/NavBar/BurgerIcon/Line.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/NavBar/BurgerIcon/Wrapper.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/NavBar/BurgerIcon/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/NavBar/Divider.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/NavBar/Logo.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/NavBar/NavBar.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/NavBar/RightNavBtn.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/NavBar/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/PersistStore/PersistStore.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/PersistStore/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Display.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Surface/BannerSurface.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Surface/ContextualBarSurface.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Surface/MessageSurface.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Surface/ModalSurface.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Surface/Reorder.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Surface/Surface.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Surface/SurfaceRender.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Surface/constant.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/Surface/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/DeleteElementBtn.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.scss (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Display/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Editor/ActionBlockEditor.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Editor/ActionPreviewEditor.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Editor/EditorPanel.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Editor/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/NavPanel/NavPanel.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/NavPanel/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Preview.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/SplitPlaneContainer/SplitPlaneContainer.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/SplitPlaneContainer/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/SplitPlaneContainer/splitPlane.css (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/Wrapper.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Preview/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/PrototypeRender/PrototypeRender.scss (100%) rename {packages => apps}/uikit-playground/src/Components/PrototypeRender/PrototypeRender.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/PrototypeRender/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/PtototypeContainer/PrototypeContainer.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/PtototypeContainer/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/RenderPayload/RenderPayload.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/RenderPayload/intex.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Routes/HomeLayout.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Routes/ProjectSpecificLayout.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Routes/ProtectedLayout.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/ScreenThumbnail/CreateNewScreenButton.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/ScreenThumbnail/EditMenu/EditMenu.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/ScreenThumbnail/EditMenu/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/EditableLabel.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/Editablelabel.scss (100%) rename {packages => apps}/uikit-playground/src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.scss (100%) rename {packages => apps}/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/SurfaceSelect/SurfaceSelect.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/SurfaceSelect/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/SurfaceSelect/options.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Templates/Container/Container.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Templates/Container/Payload.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Templates/Container/Section.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Templates/Container/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/Templates/Templates.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/Templates/index.ts (100%) rename {packages => apps}/uikit-playground/src/Components/ToggleTabs/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/navMenu/Menu/MenuItem.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/navMenu/Menu/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/navMenu/NavMenu.tsx (100%) rename {packages => apps}/uikit-playground/src/Components/navMenu/index.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/actionPreviewAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/activeProjectAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/activeScreenAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/createNewProjectAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/createNewScreenAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/deleteProjectAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/deleteScreenAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/duplicateProjectAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/duplicateScreenAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/editorTabsToggleAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/index.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/isMobileAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/isTabletAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/navMenuToggleAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/openCreateNewScreenAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/previewTabsToggleAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/renameProjectAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/renameScreenAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/sidebarToggleAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/surfaceAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/tabsToggleAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/templatesToggleAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/updateFlowEdgesAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/updateNodesAndViewPortAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/updatePayloadAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/action/userAction.ts (100%) rename {packages => apps}/uikit-playground/src/Context/createCtx.tsx (100%) rename {packages => apps}/uikit-playground/src/Context/index.tsx (100%) rename {packages => apps}/uikit-playground/src/Context/initialState.ts (100%) rename {packages => apps}/uikit-playground/src/Context/reducer.ts (100%) rename {packages => apps}/uikit-playground/src/Pages/FlowDiagram.tsx (100%) rename {packages => apps}/uikit-playground/src/Pages/Home.tsx (100%) rename {packages => apps}/uikit-playground/src/Pages/Playground.tsx (100%) rename {packages => apps}/uikit-playground/src/Pages/Prototype.tsx (100%) rename {packages => apps}/uikit-playground/src/Pages/SignInSignUp.tsx (100%) rename {packages => apps}/uikit-playground/src/Payload/action/checkbox.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/action/radioButton.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/action/timePicker.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/action/toggleSwitch.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/BlocksTree.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/action/button.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/action/datePicker.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/action/image.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/action/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/action/input.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/action/linearScale.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/action/menu.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/action/staticSelect.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/context/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/divider/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/image/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/input/datePicker.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/input/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/input/input.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/input/linearScale.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/input/staticSelect.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/preview/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/section/button.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/section/datePicker.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/section/image.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/section/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/section/menu.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionBlock/section/text.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionPreview/container.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/actionPreview/generateActionPreview.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/callout/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/tabNavigation/disabled.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/tabNavigation/index.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/tabNavigation/plain.ts (100%) rename {packages => apps}/uikit-playground/src/Payload/tabNavigation/selected.ts (100%) rename {packages => apps}/uikit-playground/src/Routes/Routes.ts (100%) rename {packages => apps}/uikit-playground/src/_global.css (100%) rename {packages => apps}/uikit-playground/src/cssVariables.css (100%) rename {packages => apps}/uikit-playground/src/hooks/useAuth.tsx (100%) rename {packages => apps}/uikit-playground/src/hooks/useCodeMirror.ts (100%) rename {packages => apps}/uikit-playground/src/hooks/useFormatCodeMirrorValue.ts (100%) rename {packages => apps}/uikit-playground/src/hooks/useHorizontalScroll.ts (100%) rename {packages => apps}/uikit-playground/src/hooks/useNodesAndEdges.ts (100%) rename {packages => apps}/uikit-playground/src/index.css (100%) rename {packages => apps}/uikit-playground/src/logo.svg (100%) rename {packages => apps}/uikit-playground/src/main.tsx (100%) rename {packages => apps}/uikit-playground/src/module.d.ts (100%) rename {packages => apps}/uikit-playground/src/utils/codePrettier.ts (100%) rename {packages => apps}/uikit-playground/src/utils/filterEdges.ts (100%) rename {packages => apps}/uikit-playground/src/utils/formatDate.ts (100%) rename {packages => apps}/uikit-playground/src/utils/getDate.ts (100%) rename {packages => apps}/uikit-playground/src/utils/getUniqueId.ts (100%) rename {packages => apps}/uikit-playground/src/utils/intendCode.ts (100%) rename {packages => apps}/uikit-playground/src/utils/persistStore.ts (100%) rename {packages => apps}/uikit-playground/src/utils/templates.ts (100%) rename {packages => apps}/uikit-playground/src/utils/uiKitRenderer.ts (100%) rename {packages => apps}/uikit-playground/src/vite-env.d.ts (100%) rename {packages => apps}/uikit-playground/tsconfig.json (100%) rename {packages => apps}/uikit-playground/vite.config.ts (100%) diff --git a/packages/uikit-playground/.eslintignore b/apps/uikit-playground/.eslintignore similarity index 100% rename from packages/uikit-playground/.eslintignore rename to apps/uikit-playground/.eslintignore diff --git a/packages/uikit-playground/.eslintrc.cjs b/apps/uikit-playground/.eslintrc.cjs similarity index 100% rename from packages/uikit-playground/.eslintrc.cjs rename to apps/uikit-playground/.eslintrc.cjs diff --git a/packages/uikit-playground/.gitignore b/apps/uikit-playground/.gitignore similarity index 100% rename from packages/uikit-playground/.gitignore rename to apps/uikit-playground/.gitignore diff --git a/packages/uikit-playground/.prettierrc b/apps/uikit-playground/.prettierrc similarity index 100% rename from packages/uikit-playground/.prettierrc rename to apps/uikit-playground/.prettierrc diff --git a/packages/uikit-playground/CHANGELOG.md b/apps/uikit-playground/CHANGELOG.md similarity index 100% rename from packages/uikit-playground/CHANGELOG.md rename to apps/uikit-playground/CHANGELOG.md diff --git a/packages/uikit-playground/index.html b/apps/uikit-playground/index.html similarity index 100% rename from packages/uikit-playground/index.html rename to apps/uikit-playground/index.html diff --git a/packages/uikit-playground/package.json b/apps/uikit-playground/package.json similarity index 100% rename from packages/uikit-playground/package.json rename to apps/uikit-playground/package.json diff --git a/packages/uikit-playground/postcss.config.js b/apps/uikit-playground/postcss.config.js similarity index 100% rename from packages/uikit-playground/postcss.config.js rename to apps/uikit-playground/postcss.config.js diff --git a/packages/uikit-playground/public/vite.svg b/apps/uikit-playground/public/vite.svg similarity index 100% rename from packages/uikit-playground/public/vite.svg rename to apps/uikit-playground/public/vite.svg diff --git a/packages/uikit-playground/src/App.css b/apps/uikit-playground/src/App.css similarity index 100% rename from packages/uikit-playground/src/App.css rename to apps/uikit-playground/src/App.css diff --git a/packages/uikit-playground/src/App.tsx b/apps/uikit-playground/src/App.tsx similarity index 100% rename from packages/uikit-playground/src/App.tsx rename to apps/uikit-playground/src/App.tsx diff --git a/packages/uikit-playground/src/Components/CodeEditor/BlockEditor.tsx b/apps/uikit-playground/src/Components/CodeEditor/BlockEditor.tsx similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/BlockEditor.tsx rename to apps/uikit-playground/src/Components/CodeEditor/BlockEditor.tsx diff --git a/packages/uikit-playground/src/Components/CodeEditor/Extensions/Extensions.ts b/apps/uikit-playground/src/Components/CodeEditor/Extensions/Extensions.ts similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/Extensions/Extensions.ts rename to apps/uikit-playground/src/Components/CodeEditor/Extensions/Extensions.ts diff --git a/packages/uikit-playground/src/Components/CodeEditor/Extensions/HighlightStyle.ts b/apps/uikit-playground/src/Components/CodeEditor/Extensions/HighlightStyle.ts similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/Extensions/HighlightStyle.ts rename to apps/uikit-playground/src/Components/CodeEditor/Extensions/HighlightStyle.ts diff --git a/packages/uikit-playground/src/Components/CodeEditor/Extensions/basicSetup.ts b/apps/uikit-playground/src/Components/CodeEditor/Extensions/basicSetup.ts similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/Extensions/basicSetup.ts rename to apps/uikit-playground/src/Components/CodeEditor/Extensions/basicSetup.ts diff --git a/packages/uikit-playground/src/Components/CodeEditor/Extensions/index.ts b/apps/uikit-playground/src/Components/CodeEditor/Extensions/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/Extensions/index.ts rename to apps/uikit-playground/src/Components/CodeEditor/Extensions/index.ts diff --git a/packages/uikit-playground/src/Components/CodeEditor/Extensions/jsonLinter.ts b/apps/uikit-playground/src/Components/CodeEditor/Extensions/jsonLinter.ts similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/Extensions/jsonLinter.ts rename to apps/uikit-playground/src/Components/CodeEditor/Extensions/jsonLinter.ts diff --git a/packages/uikit-playground/src/Components/CodeEditor/Extensions/payloadLinter.ts b/apps/uikit-playground/src/Components/CodeEditor/Extensions/payloadLinter.ts similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/Extensions/payloadLinter.ts rename to apps/uikit-playground/src/Components/CodeEditor/Extensions/payloadLinter.ts diff --git a/packages/uikit-playground/src/Components/CodeEditor/Extensions/theme.ts b/apps/uikit-playground/src/Components/CodeEditor/Extensions/theme.ts similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/Extensions/theme.ts rename to apps/uikit-playground/src/Components/CodeEditor/Extensions/theme.ts diff --git a/packages/uikit-playground/src/Components/CodeEditor/Parser/index.ts b/apps/uikit-playground/src/Components/CodeEditor/Parser/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/Parser/index.ts rename to apps/uikit-playground/src/Components/CodeEditor/Parser/index.ts diff --git a/packages/uikit-playground/src/Components/CodeEditor/Parser/parsePayload.ts b/apps/uikit-playground/src/Components/CodeEditor/Parser/parsePayload.ts similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/Parser/parsePayload.ts rename to apps/uikit-playground/src/Components/CodeEditor/Parser/parsePayload.ts diff --git a/packages/uikit-playground/src/Components/CodeEditor/PreviewEditor.tsx b/apps/uikit-playground/src/Components/CodeEditor/PreviewEditor.tsx similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/PreviewEditor.tsx rename to apps/uikit-playground/src/Components/CodeEditor/PreviewEditor.tsx diff --git a/packages/uikit-playground/src/Components/CodeEditor/index.tsx b/apps/uikit-playground/src/Components/CodeEditor/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/CodeEditor/index.tsx rename to apps/uikit-playground/src/Components/CodeEditor/index.tsx diff --git a/packages/uikit-playground/src/Components/ComponentSideBar/ScrollableSideBar.tsx b/apps/uikit-playground/src/Components/ComponentSideBar/ScrollableSideBar.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ComponentSideBar/ScrollableSideBar.tsx rename to apps/uikit-playground/src/Components/ComponentSideBar/ScrollableSideBar.tsx diff --git a/packages/uikit-playground/src/Components/ComponentSideBar/SideBar.tsx b/apps/uikit-playground/src/Components/ComponentSideBar/SideBar.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ComponentSideBar/SideBar.tsx rename to apps/uikit-playground/src/Components/ComponentSideBar/SideBar.tsx diff --git a/packages/uikit-playground/src/Components/ComponentSideBar/SliderBtn.tsx b/apps/uikit-playground/src/Components/ComponentSideBar/SliderBtn.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ComponentSideBar/SliderBtn.tsx rename to apps/uikit-playground/src/Components/ComponentSideBar/SliderBtn.tsx diff --git a/packages/uikit-playground/src/Components/ComponentSideBar/index.tsx b/apps/uikit-playground/src/Components/ComponentSideBar/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ComponentSideBar/index.tsx rename to apps/uikit-playground/src/Components/ComponentSideBar/index.tsx diff --git a/packages/uikit-playground/src/Components/CreateNewScreen/CreateNewScreenContainer.tsx b/apps/uikit-playground/src/Components/CreateNewScreen/CreateNewScreenContainer.tsx similarity index 100% rename from packages/uikit-playground/src/Components/CreateNewScreen/CreateNewScreenContainer.tsx rename to apps/uikit-playground/src/Components/CreateNewScreen/CreateNewScreenContainer.tsx diff --git a/packages/uikit-playground/src/Components/CreateNewScreen/ScreenThumbnail.tsx b/apps/uikit-playground/src/Components/CreateNewScreen/ScreenThumbnail.tsx similarity index 100% rename from packages/uikit-playground/src/Components/CreateNewScreen/ScreenThumbnail.tsx rename to apps/uikit-playground/src/Components/CreateNewScreen/ScreenThumbnail.tsx diff --git a/packages/uikit-playground/src/Components/CreateNewScreen/index.ts b/apps/uikit-playground/src/Components/CreateNewScreen/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/CreateNewScreen/index.ts rename to apps/uikit-playground/src/Components/CreateNewScreen/index.ts diff --git a/packages/uikit-playground/src/Components/Draggable/DraggableList.tsx b/apps/uikit-playground/src/Components/Draggable/DraggableList.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Draggable/DraggableList.tsx rename to apps/uikit-playground/src/Components/Draggable/DraggableList.tsx diff --git a/packages/uikit-playground/src/Components/Draggable/DraggableListItem.tsx b/apps/uikit-playground/src/Components/Draggable/DraggableListItem.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Draggable/DraggableListItem.tsx rename to apps/uikit-playground/src/Components/Draggable/DraggableListItem.tsx diff --git a/packages/uikit-playground/src/Components/DropDown/DropDown.tsx b/apps/uikit-playground/src/Components/DropDown/DropDown.tsx similarity index 100% rename from packages/uikit-playground/src/Components/DropDown/DropDown.tsx rename to apps/uikit-playground/src/Components/DropDown/DropDown.tsx diff --git a/packages/uikit-playground/src/Components/DropDown/Items.tsx b/apps/uikit-playground/src/Components/DropDown/Items.tsx similarity index 100% rename from packages/uikit-playground/src/Components/DropDown/Items.tsx rename to apps/uikit-playground/src/Components/DropDown/Items.tsx diff --git a/packages/uikit-playground/src/Components/DropDown/ItemsIcon.tsx b/apps/uikit-playground/src/Components/DropDown/ItemsIcon.tsx similarity index 100% rename from packages/uikit-playground/src/Components/DropDown/ItemsIcon.tsx rename to apps/uikit-playground/src/Components/DropDown/ItemsIcon.tsx diff --git a/packages/uikit-playground/src/Components/DropDown/index.tsx b/apps/uikit-playground/src/Components/DropDown/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/DropDown/index.tsx rename to apps/uikit-playground/src/Components/DropDown/index.tsx diff --git a/packages/uikit-playground/src/Components/DropDown/itemsStyle.ts b/apps/uikit-playground/src/Components/DropDown/itemsStyle.ts similarity index 100% rename from packages/uikit-playground/src/Components/DropDown/itemsStyle.ts rename to apps/uikit-playground/src/Components/DropDown/itemsStyle.ts diff --git a/packages/uikit-playground/src/Components/DropDown/types.ts b/apps/uikit-playground/src/Components/DropDown/types.ts similarity index 100% rename from packages/uikit-playground/src/Components/DropDown/types.ts rename to apps/uikit-playground/src/Components/DropDown/types.ts diff --git a/packages/uikit-playground/src/Components/FlowContainer/ConnectionLine.tsx b/apps/uikit-playground/src/Components/FlowContainer/ConnectionLine.tsx similarity index 100% rename from packages/uikit-playground/src/Components/FlowContainer/ConnectionLine.tsx rename to apps/uikit-playground/src/Components/FlowContainer/ConnectionLine.tsx diff --git a/packages/uikit-playground/src/Components/FlowContainer/ControlButtons/ControlButtons.tsx b/apps/uikit-playground/src/Components/FlowContainer/ControlButtons/ControlButtons.tsx similarity index 100% rename from packages/uikit-playground/src/Components/FlowContainer/ControlButtons/ControlButtons.tsx rename to apps/uikit-playground/src/Components/FlowContainer/ControlButtons/ControlButtons.tsx diff --git a/packages/uikit-playground/src/Components/FlowContainer/ControlButtons/index.ts b/apps/uikit-playground/src/Components/FlowContainer/ControlButtons/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/FlowContainer/ControlButtons/index.ts rename to apps/uikit-playground/src/Components/FlowContainer/ControlButtons/index.ts diff --git a/packages/uikit-playground/src/Components/FlowContainer/FlowContainer.tsx b/apps/uikit-playground/src/Components/FlowContainer/FlowContainer.tsx similarity index 100% rename from packages/uikit-playground/src/Components/FlowContainer/FlowContainer.tsx rename to apps/uikit-playground/src/Components/FlowContainer/FlowContainer.tsx diff --git a/packages/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.scss b/apps/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.scss similarity index 100% rename from packages/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.scss rename to apps/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.scss diff --git a/packages/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.tsx b/apps/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.tsx similarity index 100% rename from packages/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.tsx rename to apps/uikit-playground/src/Components/FlowContainer/UIKitWrapper/UIKitWrapper.tsx diff --git a/packages/uikit-playground/src/Components/FlowContainer/UIKitWrapper/index.ts b/apps/uikit-playground/src/Components/FlowContainer/UIKitWrapper/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/FlowContainer/UIKitWrapper/index.ts rename to apps/uikit-playground/src/Components/FlowContainer/UIKitWrapper/index.ts diff --git a/packages/uikit-playground/src/Components/FlowContainer/index.ts b/apps/uikit-playground/src/Components/FlowContainer/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/FlowContainer/index.ts rename to apps/uikit-playground/src/Components/FlowContainer/index.ts diff --git a/packages/uikit-playground/src/Components/FlowContainer/utils.ts b/apps/uikit-playground/src/Components/FlowContainer/utils.ts similarity index 100% rename from packages/uikit-playground/src/Components/FlowContainer/utils.ts rename to apps/uikit-playground/src/Components/FlowContainer/utils.ts diff --git a/packages/uikit-playground/src/Components/HomeContainer/HomeContainer.tsx b/apps/uikit-playground/src/Components/HomeContainer/HomeContainer.tsx similarity index 100% rename from packages/uikit-playground/src/Components/HomeContainer/HomeContainer.tsx rename to apps/uikit-playground/src/Components/HomeContainer/HomeContainer.tsx diff --git a/packages/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsList.tsx b/apps/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsList.tsx similarity index 100% rename from packages/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsList.tsx rename to apps/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsList.tsx diff --git a/packages/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsThumbnail.tsx b/apps/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsThumbnail.tsx similarity index 100% rename from packages/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsThumbnail.tsx rename to apps/uikit-playground/src/Components/HomeContainer/ProjectsList/ProjectsThumbnail.tsx diff --git a/packages/uikit-playground/src/Components/HomeContainer/ProjectsList/index.ts b/apps/uikit-playground/src/Components/HomeContainer/ProjectsList/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/HomeContainer/ProjectsList/index.ts rename to apps/uikit-playground/src/Components/HomeContainer/ProjectsList/index.ts diff --git a/packages/uikit-playground/src/Components/HomeContainer/index.ts b/apps/uikit-playground/src/Components/HomeContainer/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/HomeContainer/index.ts rename to apps/uikit-playground/src/Components/HomeContainer/index.ts diff --git a/packages/uikit-playground/src/Components/NavBar/BurgerIcon/BurgerIcon.tsx b/apps/uikit-playground/src/Components/NavBar/BurgerIcon/BurgerIcon.tsx similarity index 100% rename from packages/uikit-playground/src/Components/NavBar/BurgerIcon/BurgerIcon.tsx rename to apps/uikit-playground/src/Components/NavBar/BurgerIcon/BurgerIcon.tsx diff --git a/packages/uikit-playground/src/Components/NavBar/BurgerIcon/Line.tsx b/apps/uikit-playground/src/Components/NavBar/BurgerIcon/Line.tsx similarity index 100% rename from packages/uikit-playground/src/Components/NavBar/BurgerIcon/Line.tsx rename to apps/uikit-playground/src/Components/NavBar/BurgerIcon/Line.tsx diff --git a/packages/uikit-playground/src/Components/NavBar/BurgerIcon/Wrapper.tsx b/apps/uikit-playground/src/Components/NavBar/BurgerIcon/Wrapper.tsx similarity index 100% rename from packages/uikit-playground/src/Components/NavBar/BurgerIcon/Wrapper.tsx rename to apps/uikit-playground/src/Components/NavBar/BurgerIcon/Wrapper.tsx diff --git a/packages/uikit-playground/src/Components/NavBar/BurgerIcon/index.tsx b/apps/uikit-playground/src/Components/NavBar/BurgerIcon/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/NavBar/BurgerIcon/index.tsx rename to apps/uikit-playground/src/Components/NavBar/BurgerIcon/index.tsx diff --git a/packages/uikit-playground/src/Components/NavBar/Divider.tsx b/apps/uikit-playground/src/Components/NavBar/Divider.tsx similarity index 100% rename from packages/uikit-playground/src/Components/NavBar/Divider.tsx rename to apps/uikit-playground/src/Components/NavBar/Divider.tsx diff --git a/packages/uikit-playground/src/Components/NavBar/Logo.tsx b/apps/uikit-playground/src/Components/NavBar/Logo.tsx similarity index 100% rename from packages/uikit-playground/src/Components/NavBar/Logo.tsx rename to apps/uikit-playground/src/Components/NavBar/Logo.tsx diff --git a/packages/uikit-playground/src/Components/NavBar/NavBar.tsx b/apps/uikit-playground/src/Components/NavBar/NavBar.tsx similarity index 100% rename from packages/uikit-playground/src/Components/NavBar/NavBar.tsx rename to apps/uikit-playground/src/Components/NavBar/NavBar.tsx diff --git a/packages/uikit-playground/src/Components/NavBar/RightNavBtn.tsx b/apps/uikit-playground/src/Components/NavBar/RightNavBtn.tsx similarity index 100% rename from packages/uikit-playground/src/Components/NavBar/RightNavBtn.tsx rename to apps/uikit-playground/src/Components/NavBar/RightNavBtn.tsx diff --git a/packages/uikit-playground/src/Components/NavBar/index.tsx b/apps/uikit-playground/src/Components/NavBar/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/NavBar/index.tsx rename to apps/uikit-playground/src/Components/NavBar/index.tsx diff --git a/packages/uikit-playground/src/Components/PersistStore/PersistStore.tsx b/apps/uikit-playground/src/Components/PersistStore/PersistStore.tsx similarity index 100% rename from packages/uikit-playground/src/Components/PersistStore/PersistStore.tsx rename to apps/uikit-playground/src/Components/PersistStore/PersistStore.tsx diff --git a/packages/uikit-playground/src/Components/PersistStore/index.ts b/apps/uikit-playground/src/Components/PersistStore/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/PersistStore/index.ts rename to apps/uikit-playground/src/Components/PersistStore/index.ts diff --git a/packages/uikit-playground/src/Components/Preview/Display/Display.tsx b/apps/uikit-playground/src/Components/Preview/Display/Display.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Display.tsx rename to apps/uikit-playground/src/Components/Preview/Display/Display.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Display/Surface/BannerSurface.tsx b/apps/uikit-playground/src/Components/Preview/Display/Surface/BannerSurface.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Surface/BannerSurface.tsx rename to apps/uikit-playground/src/Components/Preview/Display/Surface/BannerSurface.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Display/Surface/ContextualBarSurface.tsx b/apps/uikit-playground/src/Components/Preview/Display/Surface/ContextualBarSurface.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Surface/ContextualBarSurface.tsx rename to apps/uikit-playground/src/Components/Preview/Display/Surface/ContextualBarSurface.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Display/Surface/MessageSurface.tsx b/apps/uikit-playground/src/Components/Preview/Display/Surface/MessageSurface.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Surface/MessageSurface.tsx rename to apps/uikit-playground/src/Components/Preview/Display/Surface/MessageSurface.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Display/Surface/ModalSurface.tsx b/apps/uikit-playground/src/Components/Preview/Display/Surface/ModalSurface.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Surface/ModalSurface.tsx rename to apps/uikit-playground/src/Components/Preview/Display/Surface/ModalSurface.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Display/Surface/Reorder.ts b/apps/uikit-playground/src/Components/Preview/Display/Surface/Reorder.ts similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Surface/Reorder.ts rename to apps/uikit-playground/src/Components/Preview/Display/Surface/Reorder.ts diff --git a/packages/uikit-playground/src/Components/Preview/Display/Surface/Surface.tsx b/apps/uikit-playground/src/Components/Preview/Display/Surface/Surface.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Surface/Surface.tsx rename to apps/uikit-playground/src/Components/Preview/Display/Surface/Surface.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Display/Surface/SurfaceRender.tsx b/apps/uikit-playground/src/Components/Preview/Display/Surface/SurfaceRender.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Surface/SurfaceRender.tsx rename to apps/uikit-playground/src/Components/Preview/Display/Surface/SurfaceRender.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Display/Surface/constant.ts b/apps/uikit-playground/src/Components/Preview/Display/Surface/constant.ts similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Surface/constant.ts rename to apps/uikit-playground/src/Components/Preview/Display/Surface/constant.ts diff --git a/packages/uikit-playground/src/Components/Preview/Display/Surface/index.ts b/apps/uikit-playground/src/Components/Preview/Display/Surface/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/Surface/index.ts rename to apps/uikit-playground/src/Components/Preview/Display/Surface/index.ts diff --git a/packages/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/DeleteElementBtn.tsx b/apps/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/DeleteElementBtn.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/DeleteElementBtn.tsx rename to apps/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/DeleteElementBtn.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.scss b/apps/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.scss similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.scss rename to apps/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.scss diff --git a/packages/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.tsx b/apps/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.tsx rename to apps/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/UiKitElementWrapper.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/index.ts b/apps/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/index.ts rename to apps/uikit-playground/src/Components/Preview/Display/UiKitElementWrapper/index.ts diff --git a/packages/uikit-playground/src/Components/Preview/Display/index.ts b/apps/uikit-playground/src/Components/Preview/Display/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Display/index.ts rename to apps/uikit-playground/src/Components/Preview/Display/index.ts diff --git a/packages/uikit-playground/src/Components/Preview/Editor/ActionBlockEditor.tsx b/apps/uikit-playground/src/Components/Preview/Editor/ActionBlockEditor.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Editor/ActionBlockEditor.tsx rename to apps/uikit-playground/src/Components/Preview/Editor/ActionBlockEditor.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Editor/ActionPreviewEditor.tsx b/apps/uikit-playground/src/Components/Preview/Editor/ActionPreviewEditor.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Editor/ActionPreviewEditor.tsx rename to apps/uikit-playground/src/Components/Preview/Editor/ActionPreviewEditor.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Editor/EditorPanel.tsx b/apps/uikit-playground/src/Components/Preview/Editor/EditorPanel.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Editor/EditorPanel.tsx rename to apps/uikit-playground/src/Components/Preview/Editor/EditorPanel.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Editor/index.tsx b/apps/uikit-playground/src/Components/Preview/Editor/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Editor/index.tsx rename to apps/uikit-playground/src/Components/Preview/Editor/index.tsx diff --git a/packages/uikit-playground/src/Components/Preview/NavPanel/NavPanel.tsx b/apps/uikit-playground/src/Components/Preview/NavPanel/NavPanel.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/NavPanel/NavPanel.tsx rename to apps/uikit-playground/src/Components/Preview/NavPanel/NavPanel.tsx diff --git a/packages/uikit-playground/src/Components/Preview/NavPanel/index.tsx b/apps/uikit-playground/src/Components/Preview/NavPanel/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/NavPanel/index.tsx rename to apps/uikit-playground/src/Components/Preview/NavPanel/index.tsx diff --git a/packages/uikit-playground/src/Components/Preview/Preview.tsx b/apps/uikit-playground/src/Components/Preview/Preview.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Preview.tsx rename to apps/uikit-playground/src/Components/Preview/Preview.tsx diff --git a/packages/uikit-playground/src/Components/Preview/SplitPlaneContainer/SplitPlaneContainer.tsx b/apps/uikit-playground/src/Components/Preview/SplitPlaneContainer/SplitPlaneContainer.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/SplitPlaneContainer/SplitPlaneContainer.tsx rename to apps/uikit-playground/src/Components/Preview/SplitPlaneContainer/SplitPlaneContainer.tsx diff --git a/packages/uikit-playground/src/Components/Preview/SplitPlaneContainer/index.ts b/apps/uikit-playground/src/Components/Preview/SplitPlaneContainer/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/Preview/SplitPlaneContainer/index.ts rename to apps/uikit-playground/src/Components/Preview/SplitPlaneContainer/index.ts diff --git a/packages/uikit-playground/src/Components/Preview/SplitPlaneContainer/splitPlane.css b/apps/uikit-playground/src/Components/Preview/SplitPlaneContainer/splitPlane.css similarity index 100% rename from packages/uikit-playground/src/Components/Preview/SplitPlaneContainer/splitPlane.css rename to apps/uikit-playground/src/Components/Preview/SplitPlaneContainer/splitPlane.css diff --git a/packages/uikit-playground/src/Components/Preview/Wrapper.tsx b/apps/uikit-playground/src/Components/Preview/Wrapper.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/Wrapper.tsx rename to apps/uikit-playground/src/Components/Preview/Wrapper.tsx diff --git a/packages/uikit-playground/src/Components/Preview/index.tsx b/apps/uikit-playground/src/Components/Preview/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Preview/index.tsx rename to apps/uikit-playground/src/Components/Preview/index.tsx diff --git a/packages/uikit-playground/src/Components/PrototypeRender/PrototypeRender.scss b/apps/uikit-playground/src/Components/PrototypeRender/PrototypeRender.scss similarity index 100% rename from packages/uikit-playground/src/Components/PrototypeRender/PrototypeRender.scss rename to apps/uikit-playground/src/Components/PrototypeRender/PrototypeRender.scss diff --git a/packages/uikit-playground/src/Components/PrototypeRender/PrototypeRender.tsx b/apps/uikit-playground/src/Components/PrototypeRender/PrototypeRender.tsx similarity index 100% rename from packages/uikit-playground/src/Components/PrototypeRender/PrototypeRender.tsx rename to apps/uikit-playground/src/Components/PrototypeRender/PrototypeRender.tsx diff --git a/packages/uikit-playground/src/Components/PrototypeRender/index.ts b/apps/uikit-playground/src/Components/PrototypeRender/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/PrototypeRender/index.ts rename to apps/uikit-playground/src/Components/PrototypeRender/index.ts diff --git a/packages/uikit-playground/src/Components/PtototypeContainer/PrototypeContainer.tsx b/apps/uikit-playground/src/Components/PtototypeContainer/PrototypeContainer.tsx similarity index 100% rename from packages/uikit-playground/src/Components/PtototypeContainer/PrototypeContainer.tsx rename to apps/uikit-playground/src/Components/PtototypeContainer/PrototypeContainer.tsx diff --git a/packages/uikit-playground/src/Components/PtototypeContainer/index.ts b/apps/uikit-playground/src/Components/PtototypeContainer/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/PtototypeContainer/index.ts rename to apps/uikit-playground/src/Components/PtototypeContainer/index.ts diff --git a/packages/uikit-playground/src/Components/RenderPayload/RenderPayload.tsx b/apps/uikit-playground/src/Components/RenderPayload/RenderPayload.tsx similarity index 100% rename from packages/uikit-playground/src/Components/RenderPayload/RenderPayload.tsx rename to apps/uikit-playground/src/Components/RenderPayload/RenderPayload.tsx diff --git a/packages/uikit-playground/src/Components/RenderPayload/intex.ts b/apps/uikit-playground/src/Components/RenderPayload/intex.ts similarity index 100% rename from packages/uikit-playground/src/Components/RenderPayload/intex.ts rename to apps/uikit-playground/src/Components/RenderPayload/intex.ts diff --git a/packages/uikit-playground/src/Components/Routes/HomeLayout.tsx b/apps/uikit-playground/src/Components/Routes/HomeLayout.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Routes/HomeLayout.tsx rename to apps/uikit-playground/src/Components/Routes/HomeLayout.tsx diff --git a/packages/uikit-playground/src/Components/Routes/ProjectSpecificLayout.tsx b/apps/uikit-playground/src/Components/Routes/ProjectSpecificLayout.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Routes/ProjectSpecificLayout.tsx rename to apps/uikit-playground/src/Components/Routes/ProjectSpecificLayout.tsx diff --git a/packages/uikit-playground/src/Components/Routes/ProtectedLayout.tsx b/apps/uikit-playground/src/Components/Routes/ProtectedLayout.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Routes/ProtectedLayout.tsx rename to apps/uikit-playground/src/Components/Routes/ProtectedLayout.tsx diff --git a/packages/uikit-playground/src/Components/ScreenThumbnail/CreateNewScreenButton.tsx b/apps/uikit-playground/src/Components/ScreenThumbnail/CreateNewScreenButton.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ScreenThumbnail/CreateNewScreenButton.tsx rename to apps/uikit-playground/src/Components/ScreenThumbnail/CreateNewScreenButton.tsx diff --git a/packages/uikit-playground/src/Components/ScreenThumbnail/EditMenu/EditMenu.tsx b/apps/uikit-playground/src/Components/ScreenThumbnail/EditMenu/EditMenu.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ScreenThumbnail/EditMenu/EditMenu.tsx rename to apps/uikit-playground/src/Components/ScreenThumbnail/EditMenu/EditMenu.tsx diff --git a/packages/uikit-playground/src/Components/ScreenThumbnail/EditMenu/index.ts b/apps/uikit-playground/src/Components/ScreenThumbnail/EditMenu/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/ScreenThumbnail/EditMenu/index.ts rename to apps/uikit-playground/src/Components/ScreenThumbnail/EditMenu/index.ts diff --git a/packages/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/EditableLabel.tsx b/apps/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/EditableLabel.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/EditableLabel.tsx rename to apps/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/EditableLabel.tsx diff --git a/packages/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/Editablelabel.scss b/apps/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/Editablelabel.scss similarity index 100% rename from packages/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/Editablelabel.scss rename to apps/uikit-playground/src/Components/ScreenThumbnail/EditableLabel/Editablelabel.scss diff --git a/packages/uikit-playground/src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx b/apps/uikit-playground/src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx rename to apps/uikit-playground/src/Components/ScreenThumbnail/ScreenThumbnailWrapper.tsx diff --git a/packages/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.scss b/apps/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.scss similarity index 100% rename from packages/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.scss rename to apps/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.scss diff --git a/packages/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.tsx b/apps/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.tsx rename to apps/uikit-playground/src/Components/ScreenThumbnail/Thumbnail.tsx diff --git a/packages/uikit-playground/src/Components/SurfaceSelect/SurfaceSelect.tsx b/apps/uikit-playground/src/Components/SurfaceSelect/SurfaceSelect.tsx similarity index 100% rename from packages/uikit-playground/src/Components/SurfaceSelect/SurfaceSelect.tsx rename to apps/uikit-playground/src/Components/SurfaceSelect/SurfaceSelect.tsx diff --git a/packages/uikit-playground/src/Components/SurfaceSelect/index.ts b/apps/uikit-playground/src/Components/SurfaceSelect/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/SurfaceSelect/index.ts rename to apps/uikit-playground/src/Components/SurfaceSelect/index.ts diff --git a/packages/uikit-playground/src/Components/SurfaceSelect/options.ts b/apps/uikit-playground/src/Components/SurfaceSelect/options.ts similarity index 100% rename from packages/uikit-playground/src/Components/SurfaceSelect/options.ts rename to apps/uikit-playground/src/Components/SurfaceSelect/options.ts diff --git a/packages/uikit-playground/src/Components/Templates/Container/Container.tsx b/apps/uikit-playground/src/Components/Templates/Container/Container.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Templates/Container/Container.tsx rename to apps/uikit-playground/src/Components/Templates/Container/Container.tsx diff --git a/packages/uikit-playground/src/Components/Templates/Container/Payload.tsx b/apps/uikit-playground/src/Components/Templates/Container/Payload.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Templates/Container/Payload.tsx rename to apps/uikit-playground/src/Components/Templates/Container/Payload.tsx diff --git a/packages/uikit-playground/src/Components/Templates/Container/Section.tsx b/apps/uikit-playground/src/Components/Templates/Container/Section.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Templates/Container/Section.tsx rename to apps/uikit-playground/src/Components/Templates/Container/Section.tsx diff --git a/packages/uikit-playground/src/Components/Templates/Container/index.ts b/apps/uikit-playground/src/Components/Templates/Container/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/Templates/Container/index.ts rename to apps/uikit-playground/src/Components/Templates/Container/index.ts diff --git a/packages/uikit-playground/src/Components/Templates/Templates.tsx b/apps/uikit-playground/src/Components/Templates/Templates.tsx similarity index 100% rename from packages/uikit-playground/src/Components/Templates/Templates.tsx rename to apps/uikit-playground/src/Components/Templates/Templates.tsx diff --git a/packages/uikit-playground/src/Components/Templates/index.ts b/apps/uikit-playground/src/Components/Templates/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/Templates/index.ts rename to apps/uikit-playground/src/Components/Templates/index.ts diff --git a/packages/uikit-playground/src/Components/ToggleTabs/index.tsx b/apps/uikit-playground/src/Components/ToggleTabs/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/ToggleTabs/index.tsx rename to apps/uikit-playground/src/Components/ToggleTabs/index.tsx diff --git a/packages/uikit-playground/src/Components/navMenu/Menu/MenuItem.tsx b/apps/uikit-playground/src/Components/navMenu/Menu/MenuItem.tsx similarity index 100% rename from packages/uikit-playground/src/Components/navMenu/Menu/MenuItem.tsx rename to apps/uikit-playground/src/Components/navMenu/Menu/MenuItem.tsx diff --git a/packages/uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx b/apps/uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx similarity index 100% rename from packages/uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx rename to apps/uikit-playground/src/Components/navMenu/Menu/Wrapper.tsx diff --git a/packages/uikit-playground/src/Components/navMenu/Menu/index.tsx b/apps/uikit-playground/src/Components/navMenu/Menu/index.tsx similarity index 100% rename from packages/uikit-playground/src/Components/navMenu/Menu/index.tsx rename to apps/uikit-playground/src/Components/navMenu/Menu/index.tsx diff --git a/packages/uikit-playground/src/Components/navMenu/NavMenu.tsx b/apps/uikit-playground/src/Components/navMenu/NavMenu.tsx similarity index 100% rename from packages/uikit-playground/src/Components/navMenu/NavMenu.tsx rename to apps/uikit-playground/src/Components/navMenu/NavMenu.tsx diff --git a/packages/uikit-playground/src/Components/navMenu/index.ts b/apps/uikit-playground/src/Components/navMenu/index.ts similarity index 100% rename from packages/uikit-playground/src/Components/navMenu/index.ts rename to apps/uikit-playground/src/Components/navMenu/index.ts diff --git a/packages/uikit-playground/src/Context/action/actionPreviewAction.ts b/apps/uikit-playground/src/Context/action/actionPreviewAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/actionPreviewAction.ts rename to apps/uikit-playground/src/Context/action/actionPreviewAction.ts diff --git a/packages/uikit-playground/src/Context/action/activeProjectAction.ts b/apps/uikit-playground/src/Context/action/activeProjectAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/activeProjectAction.ts rename to apps/uikit-playground/src/Context/action/activeProjectAction.ts diff --git a/packages/uikit-playground/src/Context/action/activeScreenAction.ts b/apps/uikit-playground/src/Context/action/activeScreenAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/activeScreenAction.ts rename to apps/uikit-playground/src/Context/action/activeScreenAction.ts diff --git a/packages/uikit-playground/src/Context/action/createNewProjectAction.ts b/apps/uikit-playground/src/Context/action/createNewProjectAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/createNewProjectAction.ts rename to apps/uikit-playground/src/Context/action/createNewProjectAction.ts diff --git a/packages/uikit-playground/src/Context/action/createNewScreenAction.ts b/apps/uikit-playground/src/Context/action/createNewScreenAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/createNewScreenAction.ts rename to apps/uikit-playground/src/Context/action/createNewScreenAction.ts diff --git a/packages/uikit-playground/src/Context/action/deleteProjectAction.ts b/apps/uikit-playground/src/Context/action/deleteProjectAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/deleteProjectAction.ts rename to apps/uikit-playground/src/Context/action/deleteProjectAction.ts diff --git a/packages/uikit-playground/src/Context/action/deleteScreenAction.ts b/apps/uikit-playground/src/Context/action/deleteScreenAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/deleteScreenAction.ts rename to apps/uikit-playground/src/Context/action/deleteScreenAction.ts diff --git a/packages/uikit-playground/src/Context/action/duplicateProjectAction.ts b/apps/uikit-playground/src/Context/action/duplicateProjectAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/duplicateProjectAction.ts rename to apps/uikit-playground/src/Context/action/duplicateProjectAction.ts diff --git a/packages/uikit-playground/src/Context/action/duplicateScreenAction.ts b/apps/uikit-playground/src/Context/action/duplicateScreenAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/duplicateScreenAction.ts rename to apps/uikit-playground/src/Context/action/duplicateScreenAction.ts diff --git a/packages/uikit-playground/src/Context/action/editorTabsToggleAction.ts b/apps/uikit-playground/src/Context/action/editorTabsToggleAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/editorTabsToggleAction.ts rename to apps/uikit-playground/src/Context/action/editorTabsToggleAction.ts diff --git a/packages/uikit-playground/src/Context/action/index.ts b/apps/uikit-playground/src/Context/action/index.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/index.ts rename to apps/uikit-playground/src/Context/action/index.ts diff --git a/packages/uikit-playground/src/Context/action/isMobileAction.ts b/apps/uikit-playground/src/Context/action/isMobileAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/isMobileAction.ts rename to apps/uikit-playground/src/Context/action/isMobileAction.ts diff --git a/packages/uikit-playground/src/Context/action/isTabletAction.ts b/apps/uikit-playground/src/Context/action/isTabletAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/isTabletAction.ts rename to apps/uikit-playground/src/Context/action/isTabletAction.ts diff --git a/packages/uikit-playground/src/Context/action/navMenuToggleAction.ts b/apps/uikit-playground/src/Context/action/navMenuToggleAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/navMenuToggleAction.ts rename to apps/uikit-playground/src/Context/action/navMenuToggleAction.ts diff --git a/packages/uikit-playground/src/Context/action/openCreateNewScreenAction.ts b/apps/uikit-playground/src/Context/action/openCreateNewScreenAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/openCreateNewScreenAction.ts rename to apps/uikit-playground/src/Context/action/openCreateNewScreenAction.ts diff --git a/packages/uikit-playground/src/Context/action/previewTabsToggleAction.ts b/apps/uikit-playground/src/Context/action/previewTabsToggleAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/previewTabsToggleAction.ts rename to apps/uikit-playground/src/Context/action/previewTabsToggleAction.ts diff --git a/packages/uikit-playground/src/Context/action/renameProjectAction.ts b/apps/uikit-playground/src/Context/action/renameProjectAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/renameProjectAction.ts rename to apps/uikit-playground/src/Context/action/renameProjectAction.ts diff --git a/packages/uikit-playground/src/Context/action/renameScreenAction.ts b/apps/uikit-playground/src/Context/action/renameScreenAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/renameScreenAction.ts rename to apps/uikit-playground/src/Context/action/renameScreenAction.ts diff --git a/packages/uikit-playground/src/Context/action/sidebarToggleAction.ts b/apps/uikit-playground/src/Context/action/sidebarToggleAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/sidebarToggleAction.ts rename to apps/uikit-playground/src/Context/action/sidebarToggleAction.ts diff --git a/packages/uikit-playground/src/Context/action/surfaceAction.ts b/apps/uikit-playground/src/Context/action/surfaceAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/surfaceAction.ts rename to apps/uikit-playground/src/Context/action/surfaceAction.ts diff --git a/packages/uikit-playground/src/Context/action/tabsToggleAction.ts b/apps/uikit-playground/src/Context/action/tabsToggleAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/tabsToggleAction.ts rename to apps/uikit-playground/src/Context/action/tabsToggleAction.ts diff --git a/packages/uikit-playground/src/Context/action/templatesToggleAction.ts b/apps/uikit-playground/src/Context/action/templatesToggleAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/templatesToggleAction.ts rename to apps/uikit-playground/src/Context/action/templatesToggleAction.ts diff --git a/packages/uikit-playground/src/Context/action/updateFlowEdgesAction.ts b/apps/uikit-playground/src/Context/action/updateFlowEdgesAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/updateFlowEdgesAction.ts rename to apps/uikit-playground/src/Context/action/updateFlowEdgesAction.ts diff --git a/packages/uikit-playground/src/Context/action/updateNodesAndViewPortAction.ts b/apps/uikit-playground/src/Context/action/updateNodesAndViewPortAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/updateNodesAndViewPortAction.ts rename to apps/uikit-playground/src/Context/action/updateNodesAndViewPortAction.ts diff --git a/packages/uikit-playground/src/Context/action/updatePayloadAction.ts b/apps/uikit-playground/src/Context/action/updatePayloadAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/updatePayloadAction.ts rename to apps/uikit-playground/src/Context/action/updatePayloadAction.ts diff --git a/packages/uikit-playground/src/Context/action/userAction.ts b/apps/uikit-playground/src/Context/action/userAction.ts similarity index 100% rename from packages/uikit-playground/src/Context/action/userAction.ts rename to apps/uikit-playground/src/Context/action/userAction.ts diff --git a/packages/uikit-playground/src/Context/createCtx.tsx b/apps/uikit-playground/src/Context/createCtx.tsx similarity index 100% rename from packages/uikit-playground/src/Context/createCtx.tsx rename to apps/uikit-playground/src/Context/createCtx.tsx diff --git a/packages/uikit-playground/src/Context/index.tsx b/apps/uikit-playground/src/Context/index.tsx similarity index 100% rename from packages/uikit-playground/src/Context/index.tsx rename to apps/uikit-playground/src/Context/index.tsx diff --git a/packages/uikit-playground/src/Context/initialState.ts b/apps/uikit-playground/src/Context/initialState.ts similarity index 100% rename from packages/uikit-playground/src/Context/initialState.ts rename to apps/uikit-playground/src/Context/initialState.ts diff --git a/packages/uikit-playground/src/Context/reducer.ts b/apps/uikit-playground/src/Context/reducer.ts similarity index 100% rename from packages/uikit-playground/src/Context/reducer.ts rename to apps/uikit-playground/src/Context/reducer.ts diff --git a/packages/uikit-playground/src/Pages/FlowDiagram.tsx b/apps/uikit-playground/src/Pages/FlowDiagram.tsx similarity index 100% rename from packages/uikit-playground/src/Pages/FlowDiagram.tsx rename to apps/uikit-playground/src/Pages/FlowDiagram.tsx diff --git a/packages/uikit-playground/src/Pages/Home.tsx b/apps/uikit-playground/src/Pages/Home.tsx similarity index 100% rename from packages/uikit-playground/src/Pages/Home.tsx rename to apps/uikit-playground/src/Pages/Home.tsx diff --git a/packages/uikit-playground/src/Pages/Playground.tsx b/apps/uikit-playground/src/Pages/Playground.tsx similarity index 100% rename from packages/uikit-playground/src/Pages/Playground.tsx rename to apps/uikit-playground/src/Pages/Playground.tsx diff --git a/packages/uikit-playground/src/Pages/Prototype.tsx b/apps/uikit-playground/src/Pages/Prototype.tsx similarity index 100% rename from packages/uikit-playground/src/Pages/Prototype.tsx rename to apps/uikit-playground/src/Pages/Prototype.tsx diff --git a/packages/uikit-playground/src/Pages/SignInSignUp.tsx b/apps/uikit-playground/src/Pages/SignInSignUp.tsx similarity index 100% rename from packages/uikit-playground/src/Pages/SignInSignUp.tsx rename to apps/uikit-playground/src/Pages/SignInSignUp.tsx diff --git a/packages/uikit-playground/src/Payload/action/checkbox.ts b/apps/uikit-playground/src/Payload/action/checkbox.ts similarity index 100% rename from packages/uikit-playground/src/Payload/action/checkbox.ts rename to apps/uikit-playground/src/Payload/action/checkbox.ts diff --git a/packages/uikit-playground/src/Payload/action/radioButton.ts b/apps/uikit-playground/src/Payload/action/radioButton.ts similarity index 100% rename from packages/uikit-playground/src/Payload/action/radioButton.ts rename to apps/uikit-playground/src/Payload/action/radioButton.ts diff --git a/packages/uikit-playground/src/Payload/action/timePicker.ts b/apps/uikit-playground/src/Payload/action/timePicker.ts similarity index 100% rename from packages/uikit-playground/src/Payload/action/timePicker.ts rename to apps/uikit-playground/src/Payload/action/timePicker.ts diff --git a/packages/uikit-playground/src/Payload/action/toggleSwitch.ts b/apps/uikit-playground/src/Payload/action/toggleSwitch.ts similarity index 100% rename from packages/uikit-playground/src/Payload/action/toggleSwitch.ts rename to apps/uikit-playground/src/Payload/action/toggleSwitch.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/BlocksTree.ts b/apps/uikit-playground/src/Payload/actionBlock/BlocksTree.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/BlocksTree.ts rename to apps/uikit-playground/src/Payload/actionBlock/BlocksTree.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/action/button.ts b/apps/uikit-playground/src/Payload/actionBlock/action/button.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/action/button.ts rename to apps/uikit-playground/src/Payload/actionBlock/action/button.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/action/datePicker.ts b/apps/uikit-playground/src/Payload/actionBlock/action/datePicker.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/action/datePicker.ts rename to apps/uikit-playground/src/Payload/actionBlock/action/datePicker.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/action/image.ts b/apps/uikit-playground/src/Payload/actionBlock/action/image.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/action/image.ts rename to apps/uikit-playground/src/Payload/actionBlock/action/image.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/action/index.ts b/apps/uikit-playground/src/Payload/actionBlock/action/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/action/index.ts rename to apps/uikit-playground/src/Payload/actionBlock/action/index.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/action/input.ts b/apps/uikit-playground/src/Payload/actionBlock/action/input.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/action/input.ts rename to apps/uikit-playground/src/Payload/actionBlock/action/input.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/action/linearScale.ts b/apps/uikit-playground/src/Payload/actionBlock/action/linearScale.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/action/linearScale.ts rename to apps/uikit-playground/src/Payload/actionBlock/action/linearScale.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/action/menu.ts b/apps/uikit-playground/src/Payload/actionBlock/action/menu.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/action/menu.ts rename to apps/uikit-playground/src/Payload/actionBlock/action/menu.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/action/staticSelect.ts b/apps/uikit-playground/src/Payload/actionBlock/action/staticSelect.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/action/staticSelect.ts rename to apps/uikit-playground/src/Payload/actionBlock/action/staticSelect.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/context/index.ts b/apps/uikit-playground/src/Payload/actionBlock/context/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/context/index.ts rename to apps/uikit-playground/src/Payload/actionBlock/context/index.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/divider/index.ts b/apps/uikit-playground/src/Payload/actionBlock/divider/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/divider/index.ts rename to apps/uikit-playground/src/Payload/actionBlock/divider/index.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/image/index.ts b/apps/uikit-playground/src/Payload/actionBlock/image/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/image/index.ts rename to apps/uikit-playground/src/Payload/actionBlock/image/index.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/input/datePicker.ts b/apps/uikit-playground/src/Payload/actionBlock/input/datePicker.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/input/datePicker.ts rename to apps/uikit-playground/src/Payload/actionBlock/input/datePicker.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/input/index.ts b/apps/uikit-playground/src/Payload/actionBlock/input/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/input/index.ts rename to apps/uikit-playground/src/Payload/actionBlock/input/index.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/input/input.ts b/apps/uikit-playground/src/Payload/actionBlock/input/input.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/input/input.ts rename to apps/uikit-playground/src/Payload/actionBlock/input/input.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/input/linearScale.ts b/apps/uikit-playground/src/Payload/actionBlock/input/linearScale.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/input/linearScale.ts rename to apps/uikit-playground/src/Payload/actionBlock/input/linearScale.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/input/staticSelect.ts b/apps/uikit-playground/src/Payload/actionBlock/input/staticSelect.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/input/staticSelect.ts rename to apps/uikit-playground/src/Payload/actionBlock/input/staticSelect.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/preview/index.ts b/apps/uikit-playground/src/Payload/actionBlock/preview/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/preview/index.ts rename to apps/uikit-playground/src/Payload/actionBlock/preview/index.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/section/button.ts b/apps/uikit-playground/src/Payload/actionBlock/section/button.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/section/button.ts rename to apps/uikit-playground/src/Payload/actionBlock/section/button.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/section/datePicker.ts b/apps/uikit-playground/src/Payload/actionBlock/section/datePicker.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/section/datePicker.ts rename to apps/uikit-playground/src/Payload/actionBlock/section/datePicker.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/section/image.ts b/apps/uikit-playground/src/Payload/actionBlock/section/image.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/section/image.ts rename to apps/uikit-playground/src/Payload/actionBlock/section/image.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/section/index.ts b/apps/uikit-playground/src/Payload/actionBlock/section/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/section/index.ts rename to apps/uikit-playground/src/Payload/actionBlock/section/index.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/section/menu.ts b/apps/uikit-playground/src/Payload/actionBlock/section/menu.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/section/menu.ts rename to apps/uikit-playground/src/Payload/actionBlock/section/menu.ts diff --git a/packages/uikit-playground/src/Payload/actionBlock/section/text.ts b/apps/uikit-playground/src/Payload/actionBlock/section/text.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionBlock/section/text.ts rename to apps/uikit-playground/src/Payload/actionBlock/section/text.ts diff --git a/packages/uikit-playground/src/Payload/actionPreview/container.ts b/apps/uikit-playground/src/Payload/actionPreview/container.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionPreview/container.ts rename to apps/uikit-playground/src/Payload/actionPreview/container.ts diff --git a/packages/uikit-playground/src/Payload/actionPreview/generateActionPreview.ts b/apps/uikit-playground/src/Payload/actionPreview/generateActionPreview.ts similarity index 100% rename from packages/uikit-playground/src/Payload/actionPreview/generateActionPreview.ts rename to apps/uikit-playground/src/Payload/actionPreview/generateActionPreview.ts diff --git a/packages/uikit-playground/src/Payload/callout/index.ts b/apps/uikit-playground/src/Payload/callout/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/callout/index.ts rename to apps/uikit-playground/src/Payload/callout/index.ts diff --git a/packages/uikit-playground/src/Payload/index.ts b/apps/uikit-playground/src/Payload/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/index.ts rename to apps/uikit-playground/src/Payload/index.ts diff --git a/packages/uikit-playground/src/Payload/tabNavigation/disabled.ts b/apps/uikit-playground/src/Payload/tabNavigation/disabled.ts similarity index 100% rename from packages/uikit-playground/src/Payload/tabNavigation/disabled.ts rename to apps/uikit-playground/src/Payload/tabNavigation/disabled.ts diff --git a/packages/uikit-playground/src/Payload/tabNavigation/index.ts b/apps/uikit-playground/src/Payload/tabNavigation/index.ts similarity index 100% rename from packages/uikit-playground/src/Payload/tabNavigation/index.ts rename to apps/uikit-playground/src/Payload/tabNavigation/index.ts diff --git a/packages/uikit-playground/src/Payload/tabNavigation/plain.ts b/apps/uikit-playground/src/Payload/tabNavigation/plain.ts similarity index 100% rename from packages/uikit-playground/src/Payload/tabNavigation/plain.ts rename to apps/uikit-playground/src/Payload/tabNavigation/plain.ts diff --git a/packages/uikit-playground/src/Payload/tabNavigation/selected.ts b/apps/uikit-playground/src/Payload/tabNavigation/selected.ts similarity index 100% rename from packages/uikit-playground/src/Payload/tabNavigation/selected.ts rename to apps/uikit-playground/src/Payload/tabNavigation/selected.ts diff --git a/packages/uikit-playground/src/Routes/Routes.ts b/apps/uikit-playground/src/Routes/Routes.ts similarity index 100% rename from packages/uikit-playground/src/Routes/Routes.ts rename to apps/uikit-playground/src/Routes/Routes.ts diff --git a/packages/uikit-playground/src/_global.css b/apps/uikit-playground/src/_global.css similarity index 100% rename from packages/uikit-playground/src/_global.css rename to apps/uikit-playground/src/_global.css diff --git a/packages/uikit-playground/src/cssVariables.css b/apps/uikit-playground/src/cssVariables.css similarity index 100% rename from packages/uikit-playground/src/cssVariables.css rename to apps/uikit-playground/src/cssVariables.css diff --git a/packages/uikit-playground/src/hooks/useAuth.tsx b/apps/uikit-playground/src/hooks/useAuth.tsx similarity index 100% rename from packages/uikit-playground/src/hooks/useAuth.tsx rename to apps/uikit-playground/src/hooks/useAuth.tsx diff --git a/packages/uikit-playground/src/hooks/useCodeMirror.ts b/apps/uikit-playground/src/hooks/useCodeMirror.ts similarity index 100% rename from packages/uikit-playground/src/hooks/useCodeMirror.ts rename to apps/uikit-playground/src/hooks/useCodeMirror.ts diff --git a/packages/uikit-playground/src/hooks/useFormatCodeMirrorValue.ts b/apps/uikit-playground/src/hooks/useFormatCodeMirrorValue.ts similarity index 100% rename from packages/uikit-playground/src/hooks/useFormatCodeMirrorValue.ts rename to apps/uikit-playground/src/hooks/useFormatCodeMirrorValue.ts diff --git a/packages/uikit-playground/src/hooks/useHorizontalScroll.ts b/apps/uikit-playground/src/hooks/useHorizontalScroll.ts similarity index 100% rename from packages/uikit-playground/src/hooks/useHorizontalScroll.ts rename to apps/uikit-playground/src/hooks/useHorizontalScroll.ts diff --git a/packages/uikit-playground/src/hooks/useNodesAndEdges.ts b/apps/uikit-playground/src/hooks/useNodesAndEdges.ts similarity index 100% rename from packages/uikit-playground/src/hooks/useNodesAndEdges.ts rename to apps/uikit-playground/src/hooks/useNodesAndEdges.ts diff --git a/packages/uikit-playground/src/index.css b/apps/uikit-playground/src/index.css similarity index 100% rename from packages/uikit-playground/src/index.css rename to apps/uikit-playground/src/index.css diff --git a/packages/uikit-playground/src/logo.svg b/apps/uikit-playground/src/logo.svg similarity index 100% rename from packages/uikit-playground/src/logo.svg rename to apps/uikit-playground/src/logo.svg diff --git a/packages/uikit-playground/src/main.tsx b/apps/uikit-playground/src/main.tsx similarity index 100% rename from packages/uikit-playground/src/main.tsx rename to apps/uikit-playground/src/main.tsx diff --git a/packages/uikit-playground/src/module.d.ts b/apps/uikit-playground/src/module.d.ts similarity index 100% rename from packages/uikit-playground/src/module.d.ts rename to apps/uikit-playground/src/module.d.ts diff --git a/packages/uikit-playground/src/utils/codePrettier.ts b/apps/uikit-playground/src/utils/codePrettier.ts similarity index 100% rename from packages/uikit-playground/src/utils/codePrettier.ts rename to apps/uikit-playground/src/utils/codePrettier.ts diff --git a/packages/uikit-playground/src/utils/filterEdges.ts b/apps/uikit-playground/src/utils/filterEdges.ts similarity index 100% rename from packages/uikit-playground/src/utils/filterEdges.ts rename to apps/uikit-playground/src/utils/filterEdges.ts diff --git a/packages/uikit-playground/src/utils/formatDate.ts b/apps/uikit-playground/src/utils/formatDate.ts similarity index 100% rename from packages/uikit-playground/src/utils/formatDate.ts rename to apps/uikit-playground/src/utils/formatDate.ts diff --git a/packages/uikit-playground/src/utils/getDate.ts b/apps/uikit-playground/src/utils/getDate.ts similarity index 100% rename from packages/uikit-playground/src/utils/getDate.ts rename to apps/uikit-playground/src/utils/getDate.ts diff --git a/packages/uikit-playground/src/utils/getUniqueId.ts b/apps/uikit-playground/src/utils/getUniqueId.ts similarity index 100% rename from packages/uikit-playground/src/utils/getUniqueId.ts rename to apps/uikit-playground/src/utils/getUniqueId.ts diff --git a/packages/uikit-playground/src/utils/intendCode.ts b/apps/uikit-playground/src/utils/intendCode.ts similarity index 100% rename from packages/uikit-playground/src/utils/intendCode.ts rename to apps/uikit-playground/src/utils/intendCode.ts diff --git a/packages/uikit-playground/src/utils/persistStore.ts b/apps/uikit-playground/src/utils/persistStore.ts similarity index 100% rename from packages/uikit-playground/src/utils/persistStore.ts rename to apps/uikit-playground/src/utils/persistStore.ts diff --git a/packages/uikit-playground/src/utils/templates.ts b/apps/uikit-playground/src/utils/templates.ts similarity index 100% rename from packages/uikit-playground/src/utils/templates.ts rename to apps/uikit-playground/src/utils/templates.ts diff --git a/packages/uikit-playground/src/utils/uiKitRenderer.ts b/apps/uikit-playground/src/utils/uiKitRenderer.ts similarity index 100% rename from packages/uikit-playground/src/utils/uiKitRenderer.ts rename to apps/uikit-playground/src/utils/uiKitRenderer.ts diff --git a/packages/uikit-playground/src/vite-env.d.ts b/apps/uikit-playground/src/vite-env.d.ts similarity index 100% rename from packages/uikit-playground/src/vite-env.d.ts rename to apps/uikit-playground/src/vite-env.d.ts diff --git a/packages/uikit-playground/tsconfig.json b/apps/uikit-playground/tsconfig.json similarity index 100% rename from packages/uikit-playground/tsconfig.json rename to apps/uikit-playground/tsconfig.json diff --git a/packages/uikit-playground/vite.config.ts b/apps/uikit-playground/vite.config.ts similarity index 100% rename from packages/uikit-playground/vite.config.ts rename to apps/uikit-playground/vite.config.ts diff --git a/yarn.lock b/yarn.lock index 9197fbb0b63a..aa2b104e5190 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10455,9 +10455,9 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/uikit-playground@workspace:packages/uikit-playground": +"@rocket.chat/uikit-playground@workspace:apps/uikit-playground": version: 0.0.0-use.local - resolution: "@rocket.chat/uikit-playground@workspace:packages/uikit-playground" + resolution: "@rocket.chat/uikit-playground@workspace:apps/uikit-playground" dependencies: "@codemirror/lang-javascript": ^6.1.9 "@codemirror/lang-json": ^6.0.1 From 9ef096fd9cca048cdda31d41f113650e2c6a25a3 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 11 Sep 2024 13:42:29 -0300 Subject: [PATCH 066/170] chore: publish preview github pages (#33248) --- .github/workflows/ci-preview.yml | 44 +++++++++++++++++++++++ .gitignore | 2 ++ _templates/package/new/package.json.ejs.t | 1 + apps/uikit-playground/package.json | 3 +- turbo.json | 8 +++++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci-preview.yml diff --git a/.github/workflows/ci-preview.yml b/.github/workflows/ci-preview.yml new file mode 100644 index 000000000000..18b4b0bef373 --- /dev/null +++ b/.github/workflows/ci-preview.yml @@ -0,0 +1,44 @@ +# .github/workflows/ci-preview.yml +name: Deploy PR previews +concurrency: preview-${{ github.ref }} +on: + pull_request: + types: + - opened + - reopened + - synchronize + - closed + push: + branches: + - main + - master + - develop +jobs: + deploy-preview: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: rharkor/caching-for-turbo@v1.5 + if: github.event.action != 'closed' + + - name: Setup NodeJS + uses: ./.github/actions/setup-node + if: github.event.action != 'closed' + with: + node-version: 14.21.3 + cache-modules: true + install: true + + - name: Build + if: github.event.action != 'closed' + run: | + yarn turbo run build-preview + yarn turbo run .:build-preview-move + + - uses: rossjrw/pr-preview-action@v1 + with: + source-dir: .preview + preview-branch: gh-pages + umbrella-dir: pr-preview + action: auto diff --git a/.gitignore b/.gitignore index 4e6e4bb29da9..dbad2c29a22c 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,8 @@ yarn-error.log* .history .envrc +.preview + *.sublime-workspace **/.vim/ diff --git a/_templates/package/new/package.json.ejs.t b/_templates/package/new/package.json.ejs.t index 6bee52f55927..b2827ee3fb89 100644 --- a/_templates/package/new/package.json.ejs.t +++ b/_templates/package/new/package.json.ejs.t @@ -19,6 +19,7 @@ to: packages/<%= name %>/package.json "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" + "build-preview": "mkdir -p ../../.preview && cp -r ./dist ../../.preview/<%= name.toLowerCase() %>" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/apps/uikit-playground/package.json b/apps/uikit-playground/package.json index d309c2d54599..233e71b719e5 100644 --- a/apps/uikit-playground/package.json +++ b/apps/uikit-playground/package.json @@ -5,7 +5,8 @@ "type": "module", "scripts": { "dev": "vite", - "build": "tsc && vite build", + "build-preview": "tsc && vite build", + ".:build-preview-move": "mkdir -p ../../.preview/ && cp -r ./dist ../../.preview/uikit-playground", "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" }, diff --git a/turbo.json b/turbo.json index 7ce868eb3707..0ae903f9250d 100644 --- a/turbo.json +++ b/turbo.json @@ -2,6 +2,14 @@ "$schema": "https://turborepo.org/schema.json", "globalDependencies": ["tsconfig.base.json", "tsconfig.base.server.json", "tsconfig.base.client.json"], "tasks": { + "build-preview": { + "dependsOn": ["^build"], + "outputs": ["storybook-static/**", ".storybook/**", "dist/**"] + }, + ".:build-preview-move": { + "dependsOn": ["^build-preview"], + "cache": false + }, "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] From fa8ac7aeaf5403720c2004cbae93a2ef3df51b78 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Wed, 11 Sep 2024 15:22:23 -0300 Subject: [PATCH 067/170] fix: Infinite loading when uploading a private app (#33181) --- .changeset/wet-hats-walk.md | 5 +++++ .../client/views/marketplace/hooks/useInstallApp.tsx | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .changeset/wet-hats-walk.md diff --git a/.changeset/wet-hats-walk.md b/.changeset/wet-hats-walk.md new file mode 100644 index 000000000000..4c3565e75523 --- /dev/null +++ b/.changeset/wet-hats-walk.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed issue that caused an infinite loading state when uploading a private app to Rocket.Chat diff --git a/apps/meteor/client/views/marketplace/hooks/useInstallApp.tsx b/apps/meteor/client/views/marketplace/hooks/useInstallApp.tsx index f10d3e989e0a..3b784e24c375 100644 --- a/apps/meteor/client/views/marketplace/hooks/useInstallApp.tsx +++ b/apps/meteor/client/views/marketplace/hooks/useInstallApp.tsx @@ -114,8 +114,11 @@ export const useInstallApp = (file: File, url: string): { install: () => void; i }; const extractManifestFromAppFile = async (appFile: File) => { - const manifest = await getManifestFromZippedApp(appFile); - return manifest; + try { + return getManifestFromZippedApp(appFile); + } catch (error) { + handleInstallError(error as Error); + } }; const install = async () => { @@ -158,6 +161,7 @@ export const useInstallApp = (file: File, url: string): { install: () => void; i handleEnableUnlimitedApps={() => { openExternalLink(manageSubscriptionUrl); setModal(null); + setInstalling(false); }} />, ); From 3cbb9f625292aa03fd30b48e44bd2bb8b3aaf0d9 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 19:15:29 +0000 Subject: [PATCH 068/170] fix: message parser being slow to process very long messages with too many symbols (#33254) Co-authored-by: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com> --- .changeset/short-drinks-itch.md | 6 + packages/message-parser/src/grammar.pegjs | 126 ++++---- packages/message-parser/src/utils.ts | 36 ++- packages/message-parser/tests/abuse.test.ts | 268 ++++++++++++++++++ .../message-parser/tests/emphasis.test.ts | 62 ++++ packages/message-parser/tests/link.test.ts | 24 ++ 6 files changed, 453 insertions(+), 69 deletions(-) create mode 100644 .changeset/short-drinks-itch.md create mode 100644 packages/message-parser/tests/abuse.test.ts diff --git a/.changeset/short-drinks-itch.md b/.changeset/short-drinks-itch.md new file mode 100644 index 000000000000..ee57330ffc86 --- /dev/null +++ b/.changeset/short-drinks-itch.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/message-parser': patch +'@rocket.chat/peggy-loader': patch +--- + +Improved the performance of the message parser diff --git a/packages/message-parser/src/grammar.pegjs b/packages/message-parser/src/grammar.pegjs index 182653a9c664..a6cae97facbf 100644 --- a/packages/message-parser/src/grammar.pegjs +++ b/packages/message-parser/src/grammar.pegjs @@ -10,6 +10,7 @@ emoji, emojiUnicode, emoticon, + extractFirstResult, heading, image, inlineCode, @@ -33,6 +34,11 @@ unorderedList, timestamp, } = require('./utils'); + +let skipBold = false; +let skipItalic = false; +let skipStrikethrough = false; +let skipReferences = false; }} Start @@ -212,7 +218,7 @@ Inline = value:(InlineItem / Any)+ EndOfLine? { return reducePlainTexts(value); InlineItem = Whitespace / Timestamp - / References + / MaybeReferences / AutolinkedPhone / AutolinkedEmail / AutolinkedURL @@ -240,7 +246,7 @@ References = "[" title:LinkTitle* "](" href:LinkRef ")" { return title.length ? link(href, reducePlainTexts(title)) : link(href); } / "<" href:LinkRef "|" title:LinkTitle2 ">" { return link(href, [plain(title)]); } -LinkTitle = (Whitespace / EmphasisForReferences) / anyTitle:$(!("](" .) .) { return plain(anyTitle) } +LinkTitle = (Whitespace / Emphasis) / anyTitle:$(!("](" .) .) { return plain(anyTitle) } LinkTitle2 = $([\x20-\x3B\x3D\x3F-\x60\x61-\x7B\x7D-\xFF] / NonASCII)+ @@ -349,14 +355,7 @@ AutoLinkURLBody = !(Extra* (Whitespace / EndOfLine)) . * Emphasis * */ -Emphasis = Bold / Italic / Strikethrough - -/** - * - * Emphasis for References - * -*/ -EmphasisForReferences = BoldForReferences / ItalicForReferences / StrikethroughForReferences +Emphasis = MaybeBold / MaybeItalic / MaybeStrikethrough /** * @@ -365,6 +364,63 @@ EmphasisForReferences = BoldForReferences / ItalicForReferences / StrikethroughF * */ +// This rule is used inside expressions that have a JS code ensuring they always fail, +// Without any pattern to match, peggy will think the rule may end up succedding without consuming any input, which could cause infinite loops +// So this unreachable rule is added to them to satisfy peggy's requirement. +BlockedByJavascript = 'unreachable' + +MaybeBold + = result:( + & { + if (skipBold) { return false; } + skipBold = true; + return true; + } + ( + (text:Bold { skipBold = false; return text; }) + / (& { skipBold = false; return false; } BlockedByJavascript) + ) + ) { return extractFirstResult(result); } + +MaybeStrikethrough + = result:( + & { + if (skipStrikethrough) { return false; } + skipStrikethrough = true; + return true; + } + ( + (text:Strikethrough { skipStrikethrough = false; return text; }) + / (& { skipStrikethrough = false; return false; } BlockedByJavascript) + ) + ) { return extractFirstResult(result); } + +MaybeItalic + = result:( + & { + if (skipItalic) { return false; } + skipItalic = true; + return true; + } + ( + (text:Italic { skipItalic = false; return text; }) + / (& { skipItalic = false; return false; } BlockedByJavascript) + ) + ) { return extractFirstResult(result); } + +MaybeReferences + = result:( + & { + if (skipReferences) { return false; } + skipReferences = true; + return true; + } + ( + (text:References { skipReferences = false; return text; }) + / (& { skipReferences = false; return false; } BlockedByJavascript) + ) + ) { return extractFirstResult(result); } + /* Italic */ Italic = value:$([a-zA-Z0-9]+ [\x5F] [\x5F]?) { return plain(value); } @@ -384,11 +440,11 @@ ItalicContentItems = text:ItalicContentItem+ { return reducePlainTexts(text); } ItalicContentItem = Whitespace / InlineCode - / References + / MaybeReferences / UserMention / ChannelMention - / Bold - / Strikethrough + / MaybeBold + / MaybeStrikethrough / Emoji / Emoticon / AnyItalic @@ -399,52 +455,12 @@ Bold = [\x2A] [\x2A] @BoldContent [\x2A] [\x2A] / [\x2A] @BoldContent [\x2A] BoldContent = text:BoldContentItem+ { return bold(reducePlainTexts(text)); } -BoldContentItem = Whitespace / InlineCode / References / UserMention / ChannelMention / Italic / Strikethrough / Emoji / Emoticon / AnyBold / Line +BoldContentItem = Whitespace / InlineCode / MaybeReferences / UserMention / ChannelMention / MaybeItalic / MaybeStrikethrough / Emoji / Emoticon / AnyBold / Line /* Strike */ Strikethrough = [\x7E] [\x7E] @StrikethroughContent [\x7E] [\x7E] / [\x7E] @StrikethroughContent [\x7E] -StrikethroughContent = text:(Timestamp / InlineCode / Whitespace / References / UserMention / ChannelMention / Italic / Bold / Emoji / Emoticon / AnyStrike / Line)+ { - return strike(reducePlainTexts(text)); - } - -/* Italic for References */ -ItalicForReferences - = value:$([a-zA-Z0-9]+ [\x5F] [\x5F]?) { return plain(value); } - / [\x5F] [\x5F] i:ItalicContentItemsForReferences [\x5F] [\x5F] t:$[a-zA-Z0-9]+ { - return reducePlainTexts([plain('__'), ...i, plain('__'), plain(t)])[0]; - } - / [\x5F] i:ItalicContentItemsForReferences [\x5F] t:$[a-zA-Z]+ { - return reducePlainTexts([plain('_'), ...i, plain('_'), plain(t)])[0]; - } - / [\x5F] [\x5F] @ItalicContentForReferences [\x5F] [\x5F] - / [\x5F] @ItalicContentForReferences [\x5F] - -ItalicContentForReferences = text:ItalicContentItemsForReferences { return italic(text); } - -ItalicContentItemsForReferences = text:ItalicContentItemForReferences+ { return reducePlainTexts(text); } - -ItalicContentItemForReferences - = Whitespace - / UserMention - / ChannelMention - / BoldForReferences - / StrikethroughForReferences - / Emoji - / Emoticon - / AnyItalic - / Line - / InlineCode - -/* Bold for References */ -BoldForReferences = [\x2A] [\x2A] @BoldContentForReferences [\x2A] [\x2A] / [\x2A] @BoldContentForReferences [\x2A] - -BoldContentForReferences = text:(Whitespace / UserMention / ChannelMention / ItalicForReferences / StrikethroughForReferences / Emoji / Emoticon / AnyBold / Line / InlineCode)+ { return bold(reducePlainTexts(text)); } - -/* Strike for References */ -StrikethroughForReferences = [\x7E] [\x7E] @StrikethroughContentForReferences [\x7E] [\x7E] / [\x7E] @StrikethroughContentForReferences [\x7E] - -StrikethroughContentForReferences = text:(Whitespace / UserMention / ChannelMention / ItalicForReferences / BoldForReferences / Emoji / Emoticon / AnyStrike / Line / InlineCode)+ { +StrikethroughContent = text:(Timestamp / Whitespace / InlineCode / MaybeReferences / UserMention / ChannelMention / MaybeItalic / MaybeBold / Emoji / Emoticon / AnyStrike / Line)+ { return strike(reducePlainTexts(text)); } diff --git a/packages/message-parser/src/utils.ts b/packages/message-parser/src/utils.ts index 1f684b56d6ed..6c5d605c5c7a 100644 --- a/packages/message-parser/src/utils.ts +++ b/packages/message-parser/src/utils.ts @@ -198,21 +198,19 @@ const joinEmoji = ( export const reducePlainTexts = ( values: Paragraph['value'] ): Paragraph['value'] => - values - .flatMap((item) => item) - .reduce((result, item, index, values) => { - const next = values[index + 1]; - const current = joinEmoji(item, values[index - 1], next); - const previous: Inlines = result[result.length - 1]; - - if (previous) { - if (current.type === 'PLAIN_TEXT' && current.type === previous.type) { - previous.value += current.value; - return result; - } + values.flat().reduce((result, item, index, values) => { + const next = values[index + 1]; + const current = joinEmoji(item, values[index - 1], next); + const previous: Inlines = result[result.length - 1]; + + if (previous) { + if (current.type === 'PLAIN_TEXT' && current.type === previous.type) { + previous.value += current.value; + return result; } - return [...result, current]; - }, [] as Paragraph['value']); + } + return [...result, current]; + }, [] as Paragraph['value']); export const lineBreak = (): LineBreak => ({ type: 'LINE_BREAK', value: undefined, @@ -249,3 +247,13 @@ export const timestamp = ( fallback: plain(``), }; }; + +export const extractFirstResult = ( + value: Types[keyof Types]['value'] +): Types[keyof Types]['value'] => { + if (typeof value !== 'object' || !Array.isArray(value)) { + return value; + } + + return value.filter((item) => item).shift() as Types[keyof Types]['value']; +}; diff --git a/packages/message-parser/tests/abuse.test.ts b/packages/message-parser/tests/abuse.test.ts new file mode 100644 index 000000000000..c280ee75b4a0 --- /dev/null +++ b/packages/message-parser/tests/abuse.test.ts @@ -0,0 +1,268 @@ +import { parse } from '../src'; +import { paragraph, plain, bold, italic, strike } from '../src/utils'; + +test.each([ + [ + `This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. , REPEATx2 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. REPEAT x3 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. REPEAT x4 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. REPEATx 5 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. , REPEAT x6 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. this can go long for some time, repeat x7 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. ,repeat x8 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some.`, + [ + paragraph([ + plain( + 'This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&' + ), + bold([ + plain('()'), + italic([ + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + strike([ + plain( + `, from now on we repeat some. , REPEATx2 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + ]), + plain( + ', from now on we repeat some. REPEAT x3 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()' + ), + ]), + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + strike([ + plain( + ', from now on we repeat some. REPEAT x4 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()' + ), + italic([ + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. REPEATx 5 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()` + ), + ]), + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + ]), + plain( + `, from now on we repeat some. , REPEAT x6 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&` + ), + ]), + plain( + `()_+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + strike([ + plain( + `, from now on we repeat some. this can go long for some time, repeat x7 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()` + ), + italic([ + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok~, from now on we repeat some. ,repeat x8 This a message designed to stress test the message parser, trying to force several rules to stack at the same time !!@#$%^&*()` + ), + ]), + plain( + `+, overloading the symbols {}:"|<>?, some more text ,./;'\\[], numbers too 1234567890-= let it call s o s ok` + ), + ]), + plain(', from now on we repeat some.'), + ]), + ], + ], + [ + '**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__**_**__', + [ + paragraph([ + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + italic([bold([plain('_')])]), + bold([italic([plain('**')]), italic([plain('**')])]), + plain('__'), + ]), + ], + ], +])('parses %p', (input, output) => { + expect(parse(input)).toMatchObject(output); +}); diff --git a/packages/message-parser/tests/emphasis.test.ts b/packages/message-parser/tests/emphasis.test.ts index e8e72a5882f1..b035999204ce 100644 --- a/packages/message-parser/tests/emphasis.test.ts +++ b/packages/message-parser/tests/emphasis.test.ts @@ -185,6 +185,68 @@ test.each([ ]), ], ], + [ + '**bold ~~and strike~~** **not bold ~~but strike** ~~ not strike~~', + [ + paragraph([ + bold([plain('bold '), strike([plain('and strike')])]), + plain(' **not bold '), + strike([plain('but strike** ')]), + plain(' not strike~~'), + ]), + ], + ], + [ + '**bold** **another bold** ~~strike~~ ~~another strike~~ **bold ~~and strike~~** **not bold ~~but strike** ~~ not strike~~', + [ + paragraph([ + bold([plain('bold')]), + plain(' '), + bold([plain('another bold')]), + plain(' '), + strike([plain('strike')]), + plain(' '), + strike([plain('another strike')]), + plain(' '), + bold([plain('bold '), strike([plain('and strike')])]), + plain(' **not bold '), + strike([plain('but strike** ')]), + plain(' not strike~~'), + ]), + ], + ], + [ + 'some_snake_case_text and even_more', + [paragraph([plain('some_snake_case_text and even_more')])], + ], + [ + 'some_snake_case_text and some __italic__ text', + [ + paragraph([ + plain('some_snake_case_text and some '), + italic([plain('italic')]), + plain(' text'), + ]), + ], + ], + [ + 'some__double__snake__case__text and even_more', + [paragraph([plain('some__double__snake__case__text and even_more')])], + ], + [ + 'some__double__snake__case__text and some __italic__ text', + [ + paragraph([ + plain('some__double__snake__case__text and some '), + italic([plain('italic')]), + plain(' text'), + ]), + ], + ], + [ + 'something__ __and italic__', + [paragraph([plain('something__ '), italic([plain('and italic')])])], + ], ])('parses %p', (input, output) => { expect(parse(input)).toMatchObject(output); }); diff --git a/packages/message-parser/tests/link.test.ts b/packages/message-parser/tests/link.test.ts index 1e083fde5d70..fcf371474bf2 100644 --- a/packages/message-parser/tests/link.test.ts +++ b/packages/message-parser/tests/link.test.ts @@ -584,6 +584,30 @@ Text after line break`, ]), ], ], + [ + '[test **bold** and __italic__](https://rocket.chat)', + [ + paragraph([ + link('https://rocket.chat', [ + plain('test '), + bold([plain('bold')]), + plain(' and '), + italic([plain('italic')]), + ]), + ]), + ], + ], + [ + '[test **bold with __italic__**](https://rocket.chat)', + [ + paragraph([ + link('https://rocket.chat', [ + plain('test '), + bold([plain('bold with '), italic([plain('italic')])]), + ]), + ]), + ], + ], ])('parses %p', (input, output) => { expect(parse(input)).toMatchObject(output); }); From ed7398d93067cf92b48791b4ca5f20cb94c89131 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 19:34:56 +0000 Subject: [PATCH 069/170] fix: Allow to use the token from `room.v` when requesting transcript instead of finding visitor (#33242) Co-authored-by: Kevin Aleman <11577696+KevLehman@users.noreply.github.com> --- .changeset/four-cherries-kneel.md | 5 +++ .../app/livechat/server/lib/sendTranscript.ts | 17 +++---- apps/meteor/tests/data/livechat/rooms.ts | 4 +- .../end-to-end/api/livechat/11-livechat.ts | 21 +++++++++ .../server/lib/sendTranscript.spec.ts | 45 +++++++++++++------ 5 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 .changeset/four-cherries-kneel.md diff --git a/.changeset/four-cherries-kneel.md b/.changeset/four-cherries-kneel.md new file mode 100644 index 000000000000..095d5af0aa76 --- /dev/null +++ b/.changeset/four-cherries-kneel.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Allow to use the token from `room.v` when requesting transcript instead of visitor token. Visitors may change their tokens at any time, rendering old conversations impossible to access for them (or for APIs depending on token) as the visitor token won't match the `room.v` token. diff --git a/apps/meteor/app/livechat/server/lib/sendTranscript.ts b/apps/meteor/app/livechat/server/lib/sendTranscript.ts index 74032121ee50..bc7c06e0eaae 100644 --- a/apps/meteor/app/livechat/server/lib/sendTranscript.ts +++ b/apps/meteor/app/livechat/server/lib/sendTranscript.ts @@ -3,12 +3,13 @@ import { type IUser, type MessageTypesValues, type IOmnichannelSystemMessage, + type ILivechatVisitor, isFileAttachment, isFileImageAttachment, } from '@rocket.chat/core-typings'; import colors from '@rocket.chat/fuselage-tokens/colors'; import { Logger } from '@rocket.chat/logger'; -import { LivechatRooms, LivechatVisitors, Messages, Uploads, Users } from '@rocket.chat/models'; +import { LivechatRooms, Messages, Uploads, Users } from '@rocket.chat/models'; import { check } from 'meteor/check'; import moment from 'moment-timezone'; @@ -41,16 +42,12 @@ export async function sendTranscript({ const room = await LivechatRooms.findOneById(rid); - const visitor = await LivechatVisitors.getVisitorByToken(token, { - projection: { _id: 1, token: 1, language: 1, username: 1, name: 1 }, - }); - - if (!visitor) { - throw new Error('error-invalid-token'); + const visitor = room?.v as ILivechatVisitor; + if (token !== visitor?.token) { + throw new Error('error-invalid-visitor'); } - // @ts-expect-error - Visitor typings should include language? - const userLanguage = visitor?.language || settings.get('Language') || 'en'; + const userLanguage = settings.get('Language') || 'en'; const timezone = getTimezone(user); logger.debug(`Transcript will be sent using ${timezone} as timezone`); @@ -59,7 +56,7 @@ export async function sendTranscript({ } // allow to only user to send transcripts from their own chats - if (room.t !== 'l' || !room.v || room.v.token !== token) { + if (room.t !== 'l') { throw new Error('error-invalid-room'); } diff --git a/apps/meteor/tests/data/livechat/rooms.ts b/apps/meteor/tests/data/livechat/rooms.ts index 9532fd4214ab..b5d89762c614 100644 --- a/apps/meteor/tests/data/livechat/rooms.ts +++ b/apps/meteor/tests/data/livechat/rooms.ts @@ -33,10 +33,10 @@ export const createLivechatRoom = async (visitorToken: string, extraRoomParams?: return response.body.room; }; -export const createVisitor = (department?: string, visitorName?: string): Promise => +export const createVisitor = (department?: string, visitorName?: string, customEmail?: string): Promise => new Promise((resolve, reject) => { const token = getRandomVisitorToken(); - const email = `${token}@${token}.com`; + const email = customEmail || `${token}@${token}.com`; const phone = `${Math.floor(Math.random() * 10000000000)}`; void request.get(api(`livechat/visitor/${token}`)).end((err: Error, res: DummyResponse) => { if (!err && res && res.body && res.body.visitor) { diff --git a/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts b/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts index c07f7bcecc81..7ce582025538 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts @@ -283,6 +283,27 @@ describe('LIVECHAT - Utils', () => { .send({ token: visitor.token, rid: room._id, email: 'visitor@notadomain.com' }); expect(body).to.have.property('success', true); }); + it('should allow a visitor to get a transcript even if token changed by using an old token that matches room.v', async () => { + const visitor = await createVisitor(); + const room = await createLivechatRoom(visitor.token); + await closeOmnichannelRoom(room._id); + const visitor2 = await createVisitor(undefined, undefined, visitor.visitorEmails?.[0].address); + const room2 = await createLivechatRoom(visitor2.token); + await closeOmnichannelRoom(room2._id); + + expect(visitor.token !== visitor2.token).to.be.true; + const { body } = await request + .post(api('livechat/transcript')) + .set(credentials) + .send({ token: visitor.token, rid: room._id, email: 'visitor@notadomain.com' }); + expect(body).to.have.property('success', true); + + const { body: body2 } = await request + .post(api('livechat/transcript')) + .set(credentials) + .send({ token: visitor2.token, rid: room2._id, email: 'visitor@notadomain.com' }); + expect(body2).to.have.property('success', true); + }); }); describe('livechat/transcript/:rid', () => { diff --git a/apps/meteor/tests/unit/app/livechat/server/lib/sendTranscript.spec.ts b/apps/meteor/tests/unit/app/livechat/server/lib/sendTranscript.spec.ts index 64da050cfd88..ca39a64c21a9 100644 --- a/apps/meteor/tests/unit/app/livechat/server/lib/sendTranscript.spec.ts +++ b/apps/meteor/tests/unit/app/livechat/server/lib/sendTranscript.spec.ts @@ -6,9 +6,6 @@ const modelsMock = { LivechatRooms: { findOneById: sinon.stub(), }, - LivechatVisitors: { - getVisitorByToken: sinon.stub(), - }, Messages: { findLivechatClosingMessage: sinon.stub(), findVisibleByRoomIdNotContainingTypesBeforeTs: sinon.stub(), @@ -75,7 +72,6 @@ describe('Send transcript', () => { beforeEach(() => { checkMock.reset(); modelsMock.LivechatRooms.findOneById.reset(); - modelsMock.LivechatVisitors.getVisitorByToken.reset(); modelsMock.Messages.findLivechatClosingMessage.reset(); modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.reset(); modelsMock.Users.findOneById.reset(); @@ -87,11 +83,9 @@ describe('Send transcript', () => { await expect(sendTranscript({})).to.be.rejectedWith(Error); }); it('should throw error when visitor not found', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves(null); await expect(sendTranscript({ rid: 'rid', email: 'email', logger: mockLogger })).to.be.rejectedWith(Error); }); it('should attempt to send an email when params are valid using default subject', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'token' } }); modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.resolves([]); tStub.returns('Conversation Transcript'); @@ -117,7 +111,6 @@ describe('Send transcript', () => { ).to.be.true; }); it('should use provided subject', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'token' } }); modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.resolves([]); @@ -143,7 +136,6 @@ describe('Send transcript', () => { ).to.be.true; }); it('should use subject from setting (when configured) when no subject provided', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'token' } }); modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.resolves([]); mockSettingValues.Livechat_transcript_email_subject = 'A custom subject obtained from setting.get'; @@ -170,36 +162,63 @@ describe('Send transcript', () => { }); it('should fail if room provided is invalid', async () => { modelsMock.LivechatRooms.findOneById.resolves(null); - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); await expect(sendTranscript({ rid: 'rid', email: 'email', logger: mockLogger })).to.be.rejectedWith(Error); }); it('should fail if room provided is of different type', async () => { modelsMock.LivechatRooms.findOneById.resolves({ t: 'c' }); - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); await expect(sendTranscript({ rid: 'rid', email: 'email' })).to.be.rejectedWith(Error); }); it('should fail if room is of valid type, but doesnt doesnt have `v` property', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l' }); await expect(sendTranscript({ rid: 'rid', email: 'email' })).to.be.rejectedWith(Error); }); it('should fail if room is of valid type, has `v` prop, but it doesnt contain `token`', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { otherProp: 'xxx' } }); await expect(sendTranscript({ rid: 'rid', email: 'email' })).to.be.rejectedWith(Error); }); it('should fail if room is of valid type, has `v.token`, but its different from the one on param (room from another visitor)', async () => { - modelsMock.LivechatVisitors.getVisitorByToken.resolves({ language: null }); modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'xxx' } }); await expect(sendTranscript({ rid: 'rid', email: 'email', token: 'xveasdf' })).to.be.rejectedWith(Error); }); + + it('should throw an error when token is not the one on room.v', async () => { + modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'xxx' } }); + + await expect(sendTranscript({ rid: 'rid', email: 'email', token: 'xveasdf' })).to.be.rejectedWith(Error); + }); + it('should work when token matches room.v', async () => { + modelsMock.LivechatRooms.findOneById.resolves({ t: 'l', v: { token: 'token-123' } }); + modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.resolves([]); + delete mockSettingValues.Livechat_transcript_email_subject; + tStub.returns('Conversation Transcript'); + + await sendTranscript({ + rid: 'rid', + token: 'token-123', + email: 'email', + user: { _id: 'x', name: 'x', utcOffset: '-6', username: 'x' }, + }); + + expect(getTimezoneMock.calledWith({ _id: 'x', name: 'x', utcOffset: '-6', username: 'x' })).to.be.true; + expect(modelsMock.Messages.findLivechatClosingMessage.calledWith('rid', { projection: { ts: 1 } })).to.be.true; + expect(modelsMock.Messages.findVisibleByRoomIdNotContainingTypesBeforeTs.called).to.be.true; + expect( + mailerMock.calledWith({ + to: 'email', + from: 'test@rocket.chat', + subject: 'Conversation Transcript', + replyTo: 'test@rocket.chat', + html: '

', + }), + ).to.be.true; + }); }); From cfc84ab29f8304e56858309e7ed14291f246634b Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 11 Sep 2024 17:35:47 -0300 Subject: [PATCH 070/170] chore: add index to preview page (#33261) Co-authored-by: Diego Sampaio --- ...iew.yml => ci-deploy-gh-pages-preview.yml} | 7 +--- .github/workflows/ci-deploy-gh-pages.yml | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) rename .github/workflows/{ci-preview.yml => ci-deploy-gh-pages-preview.yml} (91%) create mode 100644 .github/workflows/ci-deploy-gh-pages.yml diff --git a/.github/workflows/ci-preview.yml b/.github/workflows/ci-deploy-gh-pages-preview.yml similarity index 91% rename from .github/workflows/ci-preview.yml rename to .github/workflows/ci-deploy-gh-pages-preview.yml index 18b4b0bef373..17f247ddad94 100644 --- a/.github/workflows/ci-preview.yml +++ b/.github/workflows/ci-deploy-gh-pages-preview.yml @@ -8,11 +8,7 @@ on: - reopened - synchronize - closed - push: - branches: - - main - - master - - develop + jobs: deploy-preview: runs-on: ubuntu-latest @@ -35,6 +31,7 @@ jobs: run: | yarn turbo run build-preview yarn turbo run .:build-preview-move + npx indexifier .preview --html --extensions .html > .preview/index.html - uses: rossjrw/pr-preview-action@v1 with: diff --git a/.github/workflows/ci-deploy-gh-pages.yml b/.github/workflows/ci-deploy-gh-pages.yml new file mode 100644 index 000000000000..b381e05ae5d8 --- /dev/null +++ b/.github/workflows/ci-deploy-gh-pages.yml @@ -0,0 +1,38 @@ +# .github/workflows/ci-preview-deploy.yml +name: Deploy GitHub Pages +concurrency: preview-deploy-${{ github.ref }} +on: + push: + branches: + - main + - master + - develop +jobs: + deploy-preview: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: rharkor/caching-for-turbo@v1.5 + + - name: Setup NodeJS + uses: ./.github/actions/setup-node + with: + node-version: 14.21.3 + cache-modules: true + install: true + + - name: Build + run: | + yarn turbo run build-preview + yarn turbo run .:build-preview-move + npx indexifier .preview --html --extensions .html > .preview/index.html + mv .preview ${{ github.ref_name }} + mkdir .preview + mv ${{ github.ref_name }} .preview + + - name: Deploy + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: .preview + keep_files: true From 18b1b992a196c7ae8803380a0ddf4d67b8b08f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrique=20Guimar=C3=A3es=20Ribeiro?= <43561537+rique223@users.noreply.github.com> Date: Wed, 11 Sep 2024 18:56:50 -0300 Subject: [PATCH 071/170] refactor: Upgrade `Fuselage` and remove unnecessary `FieldError` styling (#33205) --- .../views/admin/users/AdminUserForm.tsx | 2 +- packages/fuselage-ui-kit/package.json | 8 +++---- packages/gazzodown/package.json | 4 ++-- packages/ui-avatar/package.json | 2 +- packages/ui-client/package.json | 2 +- packages/ui-video-conf/package.json | 4 ++-- packages/web-ui-registration/package.json | 2 +- yarn.lock | 22 +++++++++---------- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/meteor/client/views/admin/users/AdminUserForm.tsx b/apps/meteor/client/views/admin/users/AdminUserForm.tsx index 023d3df851e5..a55cc29eb648 100644 --- a/apps/meteor/client/views/admin/users/AdminUserForm.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserForm.tsx @@ -237,7 +237,7 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD /> {errors?.email && ( - + {errors.email.message} )} diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 7c644744c3cf..7277e183eae6 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0", - "@rocket.chat/ui-contexts": "10.0.0", - "@rocket.chat/ui-kit": "0.36.1", - "@rocket.chat/ui-video-conf": "10.0.0", + "@rocket.chat/ui-avatar": "*", + "@rocket.chat/ui-contexts": "*", + "@rocket.chat/ui-kit": "*", + "@rocket.chat/ui-video-conf": "*", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 8b751c895b0f..d4a18fb09a76 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -66,8 +66,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "10.0.0", - "@rocket.chat/ui-contexts": "10.0.0", + "@rocket.chat/ui-client": "*", + "@rocket.chat/ui-contexts": "*", "katex": "*", "react": "*" }, diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 66a50ce8c8e1..42860fd8692a 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "10.0.0", + "@rocket.chat/ui-contexts": "*", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index d9cdb9f24ade..0e969e173ca1 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -60,7 +60,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "10.0.0", + "@rocket.chat/ui-contexts": "*", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 40253050d9bf..d10c05edad2c 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -40,8 +40,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "6.0.0", - "@rocket.chat/ui-contexts": "10.0.0", + "@rocket.chat/ui-avatar": "*", + "@rocket.chat/ui-contexts": "*", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index e12b653ebfeb..2023641c15ab 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -47,7 +47,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "10.0.0", + "@rocket.chat/ui-contexts": "*", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", diff --git a/yarn.lock b/yarn.lock index aa2b104e5190..65ebae84019b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8934,10 +8934,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 6.0.0 - "@rocket.chat/ui-contexts": 10.0.0 - "@rocket.chat/ui-kit": 0.36.1 - "@rocket.chat/ui-video-conf": 10.0.0 + "@rocket.chat/ui-avatar": "*" + "@rocket.chat/ui-contexts": "*" + "@rocket.chat/ui-kit": "*" + "@rocket.chat/ui-video-conf": "*" "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9021,8 +9021,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 10.0.0 - "@rocket.chat/ui-contexts": 10.0.0 + "@rocket.chat/ui-client": "*" + "@rocket.chat/ui-contexts": "*" katex: "*" react: "*" languageName: unknown @@ -10228,7 +10228,7 @@ __metadata: typescript: ~5.5.4 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 10.0.0 + "@rocket.chat/ui-contexts": "*" react: ~17.0.2 languageName: unknown linkType: soft @@ -10278,7 +10278,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 10.0.0 + "@rocket.chat/ui-contexts": "*" react: ~17.0.2 languageName: unknown linkType: soft @@ -10448,8 +10448,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 6.0.0 - "@rocket.chat/ui-contexts": 10.0.0 + "@rocket.chat/ui-avatar": "*" + "@rocket.chat/ui-contexts": "*" react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10536,7 +10536,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 - "@rocket.chat/ui-contexts": 10.0.0 + "@rocket.chat/ui-contexts": "*" "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 41a1816e2e997b0e47d859f20b0fc25990d31d29 Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Thu, 12 Sep 2024 09:42:32 -0300 Subject: [PATCH 072/170] fix: Retention Policy cached settings not updated during upgrade procedure (#33237) --- .changeset/pink-swans-teach.md | 5 +++++ apps/meteor/server/startup/migrations/xrun.ts | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 .changeset/pink-swans-teach.md diff --git a/.changeset/pink-swans-teach.md b/.changeset/pink-swans-teach.md new file mode 100644 index 000000000000..7c85572a78d5 --- /dev/null +++ b/.changeset/pink-swans-teach.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +fixed retention policy max age settings not being respected after upgrade diff --git a/apps/meteor/server/startup/migrations/xrun.ts b/apps/meteor/server/startup/migrations/xrun.ts index 7f6c8a68ad55..0344649f9993 100644 --- a/apps/meteor/server/startup/migrations/xrun.ts +++ b/apps/meteor/server/startup/migrations/xrun.ts @@ -2,6 +2,7 @@ import { Settings } from '@rocket.chat/models'; import type { UpdateResult } from 'mongodb'; import { upsertPermissions } from '../../../app/authorization/server/functions/upsertPermissions'; +import { settings } from '../../../app/settings/server'; import { migrateDatabase, onServerVersionChange } from '../../lib/migrations'; import { ensureCloudWorkspaceRegistered } from '../cloudRegistration'; @@ -23,10 +24,13 @@ const moveRetentionSetting = async () => { { _id: { $in: Array.from(maxAgeSettingMap.keys()) }, value: { $ne: -1 } }, { projection: { _id: 1, value: 1 } }, ).forEach(({ _id, value }) => { - if (!maxAgeSettingMap.has(_id)) { + const newSettingId = maxAgeSettingMap.get(_id); + if (!newSettingId) { throw new Error(`moveRetentionSetting - Setting ${_id} equivalent does not exist`); } + const newValue = convertDaysToMs(Number(value)); + promises.push( Settings.updateOne( { @@ -34,11 +38,17 @@ const moveRetentionSetting = async () => { }, { $set: { - value: convertDaysToMs(Number(value)), + value: newValue, }, }, ), ); + + const currentCache = settings.getSetting(newSettingId); + if (!currentCache) { + return; + } + settings.set({ ...currentCache, value: newValue }); }); await Promise.all(promises); From 7cb6de00336dcec878edcb223e7bb6158a848565 Mon Sep 17 00:00:00 2001 From: "Julio A." <52619625+julio-cfa@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:06:20 +0200 Subject: [PATCH 073/170] fix: imported fixes (#33246) --- .changeset/many-rules-shout.md | 5 + .../server/functions/canDeleteMessage.ts | 28 +- .../app/otr/server/methods/updateOTRAck.ts | 38 +- .../tabs/AppDetails/AppDetails.tsx | 11 +- .../tabs/AppReleases/AppReleasesItem.tsx | 4 +- .../views/marketplace/lib/purifyOptions.ts | 50 ++ apps/meteor/server/models/raw/Rooms.ts | 4 + apps/meteor/tests/end-to-end/api/methods.ts | 454 ++++++++++++++++++ packages/gazzodown/package.json | 2 + .../gazzodown/src/emoji/EmojiRenderer.tsx | 11 +- packages/gazzodown/src/katex/KatexBlock.tsx | 1 + packages/gazzodown/src/katex/KatexElement.tsx | 1 + .../model-typings/src/models/IRoomsModel.ts | 1 + 13 files changed, 595 insertions(+), 15 deletions(-) create mode 100644 .changeset/many-rules-shout.md create mode 100644 apps/meteor/client/views/marketplace/lib/purifyOptions.ts diff --git a/.changeset/many-rules-shout.md b/.changeset/many-rules-shout.md new file mode 100644 index 000000000000..eacb88108a0f --- /dev/null +++ b/.changeset/many-rules-shout.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts b/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts index 7cd953a52bb2..fea37fd1c2a5 100644 --- a/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts +++ b/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts @@ -1,7 +1,8 @@ -import type { IUser } from '@rocket.chat/core-typings'; +import type { IUser, IRoom } from '@rocket.chat/core-typings'; import { Rooms } from '@rocket.chat/models'; import { getValue } from '../../../settings/server/raw'; +import { canAccessRoomAsync } from './canAccessRoom'; import { hasPermissionAsync } from './hasPermission'; const elapsedTime = (ts: Date): number => { @@ -13,6 +14,25 @@ export const canDeleteMessageAsync = async ( uid: string, { u, rid, ts }: { u: Pick; rid: string; ts: Date }, ): Promise => { + const room = await Rooms.findOneById>(rid, { + projection: { + _id: 1, + ro: 1, + unmuted: 1, + t: 1, + teamId: 1, + prid: 1, + }, + }); + + if (!room) { + return false; + } + + if (!(await canAccessRoomAsync(room, { _id: uid }))) { + return false; + } + const forceDelete = await hasPermissionAsync(uid, 'force-delete-message', rid); if (forceDelete) { @@ -45,12 +65,6 @@ export const canDeleteMessageAsync = async ( } } - const room = await Rooms.findOneById(rid, { projection: { ro: 1, unmuted: 1 } }); - - if (!room) { - return false; - } - if (room.ro === true && !(await hasPermissionAsync(uid, 'post-readonly', rid))) { // Unless the user was manually unmuted if (u.username && !(room.unmuted || []).includes(u.username)) { diff --git a/apps/meteor/app/otr/server/methods/updateOTRAck.ts b/apps/meteor/app/otr/server/methods/updateOTRAck.ts index 4fbd182e9d27..64e5e97fa4e5 100644 --- a/apps/meteor/app/otr/server/methods/updateOTRAck.ts +++ b/apps/meteor/app/otr/server/methods/updateOTRAck.ts @@ -1,8 +1,12 @@ import { api } from '@rocket.chat/core-services'; import type { IOTRMessage } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; +import { Rooms } from '@rocket.chat/models'; +import { check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; +import { canAccessRoomAsync } from '../../../authorization/server/functions/canAccessRoom'; + declare module '@rocket.chat/ddp-client' { // eslint-disable-next-line @typescript-eslint/naming-convention interface ServerMethods { @@ -11,10 +15,40 @@ declare module '@rocket.chat/ddp-client' { } Meteor.methods({ - updateOTRAck({ message, ack }) { - if (!Meteor.userId()) { + async updateOTRAck({ message, ack }) { + const uid = Meteor.userId(); + if (!uid) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'updateOTRAck' }); } + + check(ack, String); + check(message, { + _id: String, + rid: String, + msg: String, + t: String, + ts: Date, + u: { + _id: String, + username: String, + name: String, + }, + }); + + if (message?.t !== 'otr') { + throw new Meteor.Error('error-invalid-message', 'Invalid message type', { method: 'updateOTRAck' }); + } + + const room = await Rooms.findOneByIdAndType(message.rid, 'd', { projection: { t: 1, _id: 1, uids: 1 } }); + + if (!room) { + throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'updateOTRAck' }); + } + + if (!(await canAccessRoomAsync(room, { _id: uid })) || (room.uids && (!message.u._id || !room.uids.includes(message.u._id)))) { + throw new Meteor.Error('error-invalid-user', 'Invalid user, not in room', { method: 'updateOTRAck' }); + } + const acknowledgeMessage: IOTRMessage = { ...message, otrAck: ack }; void api.broadcast('otrAckUpdate', { roomId: message.rid, acknowledgeMessage }); }, diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx index 8d17f669db83..5f3e427b8391 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx @@ -2,10 +2,12 @@ import { Box, Callout, Chip, Margins } from '@rocket.chat/fuselage'; import { ExternalLink } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useTranslation } from '@rocket.chat/ui-contexts'; +import DOMPurify from 'dompurify'; import React from 'react'; import ScreenshotCarouselAnchor from '../../../components/ScreenshotCarouselAnchor'; import type { AppInfo } from '../../../definitions/AppInfo'; +import { purifyOptions } from '../../../lib/purifyOptions'; import AppDetailsAPIs from './AppDetailsAPIs'; import { normalizeUrl } from './normalizeUrl'; @@ -61,7 +63,14 @@ const AppDetails = ({ app }: AppDetailsProps) => { {t('Description')} - + diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleasesItem.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleasesItem.tsx index bc27053ea1d2..974b6d148e61 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleasesItem.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleasesItem.tsx @@ -1,9 +1,11 @@ import { Accordion, Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; +import DOMPurify from 'dompurify'; import type { ReactElement } from 'react'; import React from 'react'; import { useTimeAgo } from '../../../../../hooks/useTimeAgo'; +import { purifyOptions } from '../../../lib/purifyOptions'; type IRelease = { version: string; @@ -36,7 +38,7 @@ const AppReleasesItem = ({ release, ...props }: ReleaseItemProps): ReactElement return ( {release.detailedChangelog?.rendered ? ( - + ) : ( {t('No_release_information_provided')} )} diff --git a/apps/meteor/client/views/marketplace/lib/purifyOptions.ts b/apps/meteor/client/views/marketplace/lib/purifyOptions.ts new file mode 100644 index 000000000000..cef1a2c8c707 --- /dev/null +++ b/apps/meteor/client/views/marketplace/lib/purifyOptions.ts @@ -0,0 +1,50 @@ +export const purifyOptions = { + ALLOWED_TAGS: [ + 'b', + 'i', + 'em', + 'strong', + 'br', + 'p', + 'ul', + 'ol', + 'li', + 'article', + 'aside', + 'figure', + 'section', + 'summary', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'hgroup', + 'div', + 'hr', + 'span', + 'wbr', + 'abbr', + 'acronym', + 'cite', + 'code', + 'dfn', + 'figcaption', + 'mark', + 's', + 'samp', + 'sub', + 'sup', + 'var', + 'time', + 'q', + 'del', + 'ins', + 'rp', + 'rt', + 'ruby', + 'bdi', + 'bdo', + ], +}; diff --git a/apps/meteor/server/models/raw/Rooms.ts b/apps/meteor/server/models/raw/Rooms.ts index 96cd5a3a3acf..ec3bd6fe8d40 100644 --- a/apps/meteor/server/models/raw/Rooms.ts +++ b/apps/meteor/server/models/raw/Rooms.ts @@ -903,6 +903,10 @@ export class RoomsRaw extends BaseRaw implements IRoomsModel { return this.findOne(query, options); } + findOneByIdAndType(roomId: IRoom['_id'], type: IRoom['t'], options: FindOptions = {}): Promise { + return this.findOne({ _id: roomId, t: type }, options); + } + setCallStatus(_id: IRoom['_id'], status: IRoom['callStatus']): Promise { const query: Filter = { _id, diff --git a/apps/meteor/tests/end-to-end/api/methods.ts b/apps/meteor/tests/end-to-end/api/methods.ts index 197a71f8e8f2..08945994e438 100644 --- a/apps/meteor/tests/end-to-end/api/methods.ts +++ b/apps/meteor/tests/end-to-end/api/methods.ts @@ -2602,6 +2602,158 @@ describe('Meteor.methods', () => { updateSetting('Message_AllowEditing_BlockEditInMinutes', 0), ]); }); + + describe('message deletion when user is not part of the room', () => { + let ridTestRoom: IRoom['_id']; + let messageIdTestRoom: IMessage['_id']; + let testUser: TestUser; + let testUserCredentials: Credentials; + + before('create room, add new owner, and leave room', async () => { + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + const channelName = `methods-test-channel-${Date.now()}`; + + await request + .post(api('groups.create')) + .set(testUserCredentials) + .send({ + name: channelName, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('group._id'); + expect(res.body).to.have.nested.property('group.name', channelName); + expect(res.body).to.have.nested.property('group.t', 'p'); + expect(res.body).to.have.nested.property('group.msgs', 0); + ridTestRoom = res.body.group._id; + }); + + await request + .post(methodCall('sendMessage')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'sendMessage', + params: [ + { + _id: `${Date.now() + Math.random()}`, + rid: ridTestRoom, + msg: 'just a random test message', + }, + ], + id: 'id', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('result').that.is.an('object'); + messageIdTestRoom = data.result._id; + }); + + await request + .post(methodCall('addUsersToRoom')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'addUsersToRoom', + params: [ + { + rid: ridTestRoom, + users: ['rocket.cat'], + }, + ], + id: 'id', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('message').that.is.a('string'); + }); + + await request + .post(api('groups.addOwner')) + .set(testUserCredentials) + .send({ + roomId: ridTestRoom, + userId: 'rocket.cat', + }) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + }); + + await request + .post(api('groups.leave')) + .set(testUserCredentials) + .send({ + roomId: ridTestRoom, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + }); + }); + + it('should not delete a message if the user is no longer member of the room', async () => { + await request + .post(methodCall('deleteMessage')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'deleteMessage', + params: [{ _id: messageIdTestRoom, rid: ridTestRoom }], + id: 'id', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('msg', 'result'); + expect(data).to.have.a.property('id', 'id'); + expect(data.error).to.have.a.property('error', 'error-action-not-allowed'); + }); + }); + + it('should not delete a message if the user was never part of the room', async () => { + await request + .post(methodCall('deleteMessage')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'deleteMessage', + params: [{ _id: messageIdTestRoom, rid: ridTestRoom }], + id: 'id', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('msg', 'result'); + expect(data).to.have.a.property('id', 'id'); + expect(data.error).to.have.a.property('error', 'error-action-not-allowed'); + }); + }); + + after(() => Promise.all([deleteRoom({ type: 'p', roomId: ridTestRoom }), deleteUser(testUser)])); + }); }); describe('[@setUserActiveStatus]', () => { @@ -3348,6 +3500,7 @@ describe('Meteor.methods', () => { .end(done); }); }); + (IS_EE ? describe : describe.skip)('[@auditGetAuditions] EE', () => { let testUser: TestUser; let testUserCredentials: Credentials; @@ -3451,4 +3604,305 @@ describe('Meteor.methods', () => { }); }); }); + + describe('UpdateOTRAck', () => { + let testUser: TestUser; + let testUser2: TestUser; + let testUserCredentials: Credentials; + let dmTestId: IRoom['_id']; + + before(async () => { + testUser = await createUser(); + testUser2 = await createUser(); + testUserCredentials = await login(testUser.username, password); + }); + + before('create direct conversation between both users', (done) => { + void request + .post(methodCall('createDirectMessage')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'createDirectMessage', + params: [testUser2.username], + id: 'id', + msg: 'method', + }), + }) + .end((_err, res) => { + const result = JSON.parse(res.body.message); + expect(result.result).to.be.an('object'); + expect(result.result).to.have.property('rid').that.is.an('string'); + + dmTestId = result.result.rid; + done(); + }); + }); + + after(() => Promise.all([deleteRoom({ type: 'd', roomId: dmTestId }), deleteUser(testUser), deleteUser(testUser2)])); + + it('should fail if required parameters are not present', async () => { + await request + .post(methodCall('updateOTRAck')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'updateOTRAck', + params: [ + { + message: { + _id: 'czjFdkFab7H5bWxYq', + // rid: 'test', + msg: 'test', + t: 'otr', + ts: { $date: 1725447664093 }, + u: { + _id: 'test', + username: 'test', + name: 'test', + }, + }, + ack: 'test', + }, + ], + id: '18', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('message'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('error'); + expect(data.error).to.have.a.property('message', "Match error: Missing key 'rid'"); + }); + }); + + it('should fail if required parameters have a different type', async () => { + await request + .post(methodCall('updateOTRAck')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'updateOTRAck', + params: [ + { + message: { + _id: 'czjFdkFab7H5bWxYq', + rid: { $ne: 'test' }, + msg: 'test', + t: 'otr', + ts: { $date: 1725447664093 }, + u: { + _id: 'test', + username: 'test', + name: 'test', + }, + }, + ack: 'test', + }, + ], + id: '18', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('message'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('error'); + expect(data.error).to.have.a.property('message', 'Match error: Expected string, got object in field rid'); + }); + }); + + it('should fail if "t" is not "otr"', async () => { + await request + .post(methodCall('updateOTRAck')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'updateOTRAck', + params: [ + { + message: { + _id: 'czjFdkFab7H5bWxYq', + rid: 'test', + msg: 'test', + t: 'notOTR', + ts: { $date: 1725447664093 }, + u: { + _id: 'test', + username: 'test', + name: 'test', + }, + }, + ack: 'test', + }, + ], + id: '18', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('message'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('error'); + expect(data.error).to.have.a.property('message', 'Invalid message type [error-invalid-message]'); + }); + }); + + it('should fail if room does not exist', async () => { + await request + .post(methodCall('updateOTRAck')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'updateOTRAck', + params: [ + { + message: { + _id: 'czjFdkFab7H5bWxYq', + rid: 'test', + msg: 'test', + t: 'otr', + ts: { $date: 1725447664093 }, + u: { + _id: 'test', + username: 'test', + name: 'test', + }, + }, + ack: 'test', + }, + ], + id: '18', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('message'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('error'); + expect(data.error).to.have.a.property('message', 'Invalid room [error-invalid-room]'); + }); + }); + + it('should fail if room is not a DM', async () => { + await request + .post(methodCall('updateOTRAck')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'updateOTRAck', + params: [ + { + message: { + _id: 'czjFdkFab7H5bWxYq', + rid: 'GENERAL', + msg: 'test', + t: 'otr', + ts: { $date: 1725447664093 }, + u: { + _id: 'test', + username: 'test', + name: 'test', + }, + }, + ack: 'test', + }, + ], + id: '18', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('message'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('error'); + expect(data.error).to.have.a.property('message', 'Invalid room [error-invalid-room]'); + }); + }); + + it('should fail if user is not part of DM room', async () => { + await request + .post(methodCall('updateOTRAck')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'updateOTRAck', + params: [ + { + message: { + _id: 'czjFdkFab7H5bWxYq', + rid: dmTestId, + msg: 'test', + t: 'otr', + ts: { $date: 1725447664093 }, + u: { + _id: testUser._id, + username: testUser.username, + name: 'test', + }, + }, + ack: 'test', + }, + ], + id: '18', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('message'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('error'); + expect(data.error).to.have.a.property('message', 'Invalid user, not in room [error-invalid-user]'); + }); + }); + + it('should pass if all parameters are present and user is part of DM room', async () => { + await request + .post(methodCall('updateOTRAck')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'updateOTRAck', + params: [ + { + message: { + _id: 'czjFdkFab7H5bWxYq', + rid: dmTestId, + msg: 'test', + t: 'otr', + ts: { $date: 1725447664093 }, + u: { + _id: testUser._id, + username: testUser.username, + name: 'test', + }, + }, + ack: 'test', + }, + ], + id: '18', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('message'); + expect(res.body).to.have.a.property('success', true); + }); + }); + }); }); diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index d4a18fb09a76..f6c48c7f8e47 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -72,7 +72,9 @@ "react": "*" }, "dependencies": { + "@types/dompurify": "^3.0.5", "date-fns": "^3.3.1", + "dompurify": "^3.1.6", "highlight.js": "^11.5.1", "react-error-boundary": "^3.1.4" }, diff --git a/packages/gazzodown/src/emoji/EmojiRenderer.tsx b/packages/gazzodown/src/emoji/EmojiRenderer.tsx index 7a4ca5324930..84116361157c 100644 --- a/packages/gazzodown/src/emoji/EmojiRenderer.tsx +++ b/packages/gazzodown/src/emoji/EmojiRenderer.tsx @@ -1,5 +1,6 @@ import { MessageEmoji, ThreadMessageEmoji } from '@rocket.chat/fuselage'; import type * as MessageParser from '@rocket.chat/message-parser'; +import DOMPurify from 'dompurify'; import { ReactElement, useMemo, useContext, memo } from 'react'; import { MarkupInteractionContext } from '../MarkupInteractionContext'; @@ -14,10 +15,12 @@ const EmojiRenderer = ({ big = false, preview = false, ...emoji }: EmojiProps): const fallback = useMemo(() => ('unicode' in emoji ? emoji.unicode : `:${emoji.shortCode ?? emoji.value.value}:`), [emoji]); + const sanitizedFallback = DOMPurify.sanitize(fallback); + const descriptors = useMemo(() => { - const detected = detectEmoji?.(fallback); + const detected = detectEmoji?.(sanitizedFallback); return detected?.length !== 0 ? detected : undefined; - }, [detectEmoji, fallback]); + }, [detectEmoji, sanitizedFallback]); return ( <> @@ -34,8 +37,8 @@ const EmojiRenderer = ({ big = false, preview = false, ...emoji }: EmojiProps): )} )) ?? ( - - {fallback} + + {sanitizedFallback} )} diff --git a/packages/gazzodown/src/katex/KatexBlock.tsx b/packages/gazzodown/src/katex/KatexBlock.tsx index 5913185d3969..267b310b3897 100644 --- a/packages/gazzodown/src/katex/KatexBlock.tsx +++ b/packages/gazzodown/src/katex/KatexBlock.tsx @@ -15,6 +15,7 @@ const KatexBlock = ({ code }: KatexBlockProps): ReactElement => { macros: { '\\href': '\\@secondoftwo', }, + maxSize: 100, }), [code], ); diff --git a/packages/gazzodown/src/katex/KatexElement.tsx b/packages/gazzodown/src/katex/KatexElement.tsx index 3595f698f7ae..099c2f82cf8c 100644 --- a/packages/gazzodown/src/katex/KatexElement.tsx +++ b/packages/gazzodown/src/katex/KatexElement.tsx @@ -15,6 +15,7 @@ const KatexElement = ({ code }: KatexElementProps): ReactElement => { macros: { '\\href': '\\@secondoftwo', }, + maxSize: 100, }), [code], ); diff --git a/packages/model-typings/src/models/IRoomsModel.ts b/packages/model-typings/src/models/IRoomsModel.ts index 498a3c6b4bbc..9097a89c1413 100644 --- a/packages/model-typings/src/models/IRoomsModel.ts +++ b/packages/model-typings/src/models/IRoomsModel.ts @@ -192,6 +192,7 @@ export interface IRoomsModel extends IBaseModel { setE2eKeyId(roomId: string, e2eKeyId: string, options?: FindOptions): Promise; findOneByImportId(importId: string, options?: FindOptions): Promise; findOneByNameAndNotId(name: string, rid: string): Promise; + findOneByIdAndType(roomId: IRoom['_id'], type: IRoom['t'], options?: FindOptions): Promise; findOneByDisplayName(displayName: string, options?: FindOptions): Promise; findOneByNameAndType( name: string, From c2d7216c1c50254f028456f175675d909084b5ab Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:25:17 +0000 Subject: [PATCH 074/170] fix: Retention Policy cached settings not updated during upgrade procedure (#33265) Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com> --- .changeset/pink-swans-teach.md | 5 +++++ apps/meteor/server/startup/migrations/xrun.ts | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 .changeset/pink-swans-teach.md diff --git a/.changeset/pink-swans-teach.md b/.changeset/pink-swans-teach.md new file mode 100644 index 000000000000..7c85572a78d5 --- /dev/null +++ b/.changeset/pink-swans-teach.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +fixed retention policy max age settings not being respected after upgrade diff --git a/apps/meteor/server/startup/migrations/xrun.ts b/apps/meteor/server/startup/migrations/xrun.ts index 7f6c8a68ad55..0344649f9993 100644 --- a/apps/meteor/server/startup/migrations/xrun.ts +++ b/apps/meteor/server/startup/migrations/xrun.ts @@ -2,6 +2,7 @@ import { Settings } from '@rocket.chat/models'; import type { UpdateResult } from 'mongodb'; import { upsertPermissions } from '../../../app/authorization/server/functions/upsertPermissions'; +import { settings } from '../../../app/settings/server'; import { migrateDatabase, onServerVersionChange } from '../../lib/migrations'; import { ensureCloudWorkspaceRegistered } from '../cloudRegistration'; @@ -23,10 +24,13 @@ const moveRetentionSetting = async () => { { _id: { $in: Array.from(maxAgeSettingMap.keys()) }, value: { $ne: -1 } }, { projection: { _id: 1, value: 1 } }, ).forEach(({ _id, value }) => { - if (!maxAgeSettingMap.has(_id)) { + const newSettingId = maxAgeSettingMap.get(_id); + if (!newSettingId) { throw new Error(`moveRetentionSetting - Setting ${_id} equivalent does not exist`); } + const newValue = convertDaysToMs(Number(value)); + promises.push( Settings.updateOne( { @@ -34,11 +38,17 @@ const moveRetentionSetting = async () => { }, { $set: { - value: convertDaysToMs(Number(value)), + value: newValue, }, }, ), ); + + const currentCache = settings.getSetting(newSettingId); + if (!currentCache) { + return; + } + settings.set({ ...currentCache, value: newValue }); }); await Promise.all(promises); From ec6f6a650a552f39dec4af757ebefec3dbe54782 Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Thu, 12 Sep 2024 15:05:00 -0300 Subject: [PATCH 075/170] chore: moved UserAutoComplete to ui-client package (#33249) --- apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx | 2 +- .../client/views/omnichannel/agents/AgentsTable/AddAgent.tsx | 2 +- apps/meteor/client/views/omnichannel/managers/AddManager.tsx | 2 +- .../components/UserAutoComplete/UserAutoComplete.stories.tsx | 1 - .../src}/components/UserAutoComplete/UserAutoComplete.tsx | 2 +- .../ui-client/src}/components/UserAutoComplete/index.ts | 0 packages/ui-client/src/components/index.ts | 1 + 7 files changed, 5 insertions(+), 5 deletions(-) rename {apps/meteor/client => packages/ui-client/src}/components/UserAutoComplete/UserAutoComplete.stories.tsx (94%) rename {apps/meteor/client => packages/ui-client/src}/components/UserAutoComplete/UserAutoComplete.tsx (97%) rename {apps/meteor/client => packages/ui-client/src}/components/UserAutoComplete/index.ts (100%) diff --git a/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx b/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx index 62adc2a0405f..76a95cf4a0e7 100644 --- a/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx +++ b/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx @@ -13,6 +13,7 @@ import { StatesAction, } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; +import { UserAutoComplete } from '@rocket.chat/ui-client'; import { useTranslation, useToastMessageDispatch, useMethod, useEndpoint, useSetModal } from '@rocket.chat/ui-contexts'; import { useMutation, useQuery, hashQueryKey } from '@tanstack/react-query'; import React, { useMemo, useState } from 'react'; @@ -31,7 +32,6 @@ import { } from '../../components/GenericTable'; import { usePagination } from '../../components/GenericTable/hooks/usePagination'; import { useSort } from '../../components/GenericTable/hooks/useSort'; -import UserAutoComplete from '../../components/UserAutoComplete'; import { queryClient } from '../../lib/queryClient'; const MonitorsTable = () => { diff --git a/apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx b/apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx index 47d60b3d9958..4ad019281bbf 100644 --- a/apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx +++ b/apps/meteor/client/views/omnichannel/agents/AgentsTable/AddAgent.tsx @@ -1,10 +1,10 @@ import { Button, Box, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { UserAutoComplete } from '@rocket.chat/ui-client'; import { useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useState } from 'react'; -import UserAutoComplete from '../../../../components/UserAutoComplete'; import { useEndpointAction } from '../../../../hooks/useEndpointAction'; type AddAgentProps = { diff --git a/apps/meteor/client/views/omnichannel/managers/AddManager.tsx b/apps/meteor/client/views/omnichannel/managers/AddManager.tsx index e21896eef9fa..24817a03846e 100644 --- a/apps/meteor/client/views/omnichannel/managers/AddManager.tsx +++ b/apps/meteor/client/views/omnichannel/managers/AddManager.tsx @@ -1,10 +1,10 @@ import { Button, Box, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; import { useMutableCallback, useUniqueId } from '@rocket.chat/fuselage-hooks'; +import { UserAutoComplete } from '@rocket.chat/ui-client'; import { useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useState } from 'react'; -import UserAutoComplete from '../../../components/UserAutoComplete'; import { useEndpointAction } from '../../../hooks/useEndpointAction'; const AddManager = ({ reload }: { reload: () => void }): ReactElement => { diff --git a/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.stories.tsx b/packages/ui-client/src/components/UserAutoComplete/UserAutoComplete.stories.tsx similarity index 94% rename from apps/meteor/client/components/UserAutoComplete/UserAutoComplete.stories.tsx rename to packages/ui-client/src/components/UserAutoComplete/UserAutoComplete.stories.tsx index 757c10b35b86..b9baa3174dda 100644 --- a/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.stories.tsx +++ b/packages/ui-client/src/components/UserAutoComplete/UserAutoComplete.stories.tsx @@ -1,5 +1,4 @@ import type { ComponentMeta, ComponentStory } from '@storybook/react'; -import React from 'react'; import UserAutoComplete from '.'; diff --git a/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.tsx b/packages/ui-client/src/components/UserAutoComplete/UserAutoComplete.tsx similarity index 97% rename from apps/meteor/client/components/UserAutoComplete/UserAutoComplete.tsx rename to packages/ui-client/src/components/UserAutoComplete/UserAutoComplete.tsx index 3f61f421035c..72a8eecec4d0 100644 --- a/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.tsx +++ b/packages/ui-client/src/components/UserAutoComplete/UserAutoComplete.tsx @@ -4,7 +4,7 @@ import { UserAvatar } from '@rocket.chat/ui-avatar'; import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ComponentProps, ReactElement } from 'react'; -import React, { memo, useMemo, useState } from 'react'; +import { memo, useMemo, useState } from 'react'; const query = ( term = '', diff --git a/apps/meteor/client/components/UserAutoComplete/index.ts b/packages/ui-client/src/components/UserAutoComplete/index.ts similarity index 100% rename from apps/meteor/client/components/UserAutoComplete/index.ts rename to packages/ui-client/src/components/UserAutoComplete/index.ts diff --git a/packages/ui-client/src/components/index.ts b/packages/ui-client/src/components/index.ts index 1eccad1fd234..f78c32427cdb 100644 --- a/packages/ui-client/src/components/index.ts +++ b/packages/ui-client/src/components/index.ts @@ -13,3 +13,4 @@ export * from './HeaderV2'; export * from './MultiSelectCustom/MultiSelectCustom'; export * from './FeaturePreview/FeaturePreview'; export * from './RoomBanner'; +export { default as UserAutoComplete } from './UserAutoComplete'; From 811e2cb5762b126f6b7cb4709f822c80fd75bf54 Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Thu, 12 Sep 2024 16:24:15 -0300 Subject: [PATCH 076/170] chore: move GenericMenu to ui-client package (#33247) --- .../NavBarPagesToolbar/NavBarItemAuditMenu.tsx | 2 +- .../NavBarPagesToolbar/NavBarItemMarketPlaceMenu.tsx | 2 +- .../NavBarPagesToolbar/hooks/useAuditMenu.tsx | 2 +- .../NavBarPagesToolbar/hooks/useMarketPlaceMenu.tsx | 2 +- .../NavBarItemAdministrationMenu.tsx | 2 +- .../NavBarSettingsToolbar/UserMenu/UserMenu.tsx | 5 ++--- .../UserMenu/hooks/useAccountItems.tsx | 3 +-- .../UserMenu/hooks/useStatusItems.tsx | 2 +- .../UserMenu/hooks/useUserMenu.tsx | 2 +- .../hooks/useAdministrationMenu.tsx | 3 +-- .../components/message/toolbar/MessageActionMenu.tsx | 3 +-- apps/meteor/client/hooks/useAppActionButtons.ts | 2 +- .../navbar/actions/NavbarAdministrationAction.tsx | 3 +-- .../client/navbar/actions/NavbarAuditAction.tsx | 3 +-- .../navbar/actions/NavbarMarketplaceAction.tsx | 3 +-- apps/meteor/client/sidebar/header/UserMenu.tsx | 12 ++++++++---- .../client/sidebar/header/actions/Administration.tsx | 2 +- .../client/sidebar/header/actions/CreateRoom.tsx | 2 +- apps/meteor/client/sidebar/header/actions/Sort.tsx | 2 +- .../header/actions/hooks/useAdministrationItems.tsx | 3 +-- .../header/actions/hooks/useAdministrationMenu.tsx | 2 +- .../sidebar/header/actions/hooks/useAppsItems.tsx | 2 +- .../sidebar/header/actions/hooks/useAuditItems.tsx | 2 +- .../header/actions/hooks/useCreateRoomItems.tsx | 2 +- .../header/actions/hooks/useGroupingListItems.tsx | 3 +-- .../actions/hooks/useMatrixFederationItems.tsx.tsx | 2 +- .../header/actions/hooks/useSortModeItems.tsx | 2 +- .../header/actions/hooks/useViewModeItems.tsx | 3 +-- .../client/sidebar/header/hooks/useAccountItems.tsx | 3 +-- .../client/sidebar/header/hooks/useStatusItems.tsx | 2 +- .../client/sidebar/header/hooks/useUserMenu.tsx | 2 +- .../client/sidebarv2/header/actions/CreateRoom.tsx | 2 +- apps/meteor/client/sidebarv2/header/actions/Sort.tsx | 2 +- .../header/actions/hooks/useCreateRoomItems.tsx | 2 +- .../header/actions/hooks/useGroupingListItems.tsx | 3 +-- .../header/actions/hooks/useMatrixFederationItems.ts | 2 +- .../header/actions/hooks/useSortModeItems.tsx | 2 +- .../header/actions/hooks/useViewModeItems.tsx | 3 +-- .../views/admin/moderation/MessageContextFooter.tsx | 2 +- .../admin/moderation/ModerationConsoleActions.tsx | 2 +- .../moderation/UserReports/ModConsoleUserActions.tsx | 2 +- .../moderation/UserReports/UserContextFooter.tsx | 2 +- .../moderation/hooks/useDeactivateUserAction.tsx | 2 +- .../moderation/hooks/useDeleteMessagesAction.tsx | 2 +- .../admin/moderation/hooks/useDismissUserAction.tsx | 2 +- .../admin/moderation/hooks/useResetAvatarAction.tsx | 2 +- apps/meteor/client/views/marketplace/AppMenu.tsx | 2 +- .../views/room/Header/RoomToolbox/RoomToolbox.tsx | 4 ++-- .../views/room/HeaderV2/RoomToolbox/RoomToolbox.tsx | 4 ++-- .../client/views/room/UserCard/UserCardWithData.tsx | 2 +- .../MessageBoxActionsToolbar.tsx | 4 ++-- .../hooks/useAudioMessageAction.ts | 2 +- .../hooks/useCreateDiscussionAction.tsx | 2 +- .../hooks/useFileUploadAction.ts | 2 +- .../hooks/useShareLocationAction.tsx | 2 +- .../hooks/useVideoMessageAction.ts | 2 +- .../hooks/useWebdavActions.tsx | 2 +- .../FormattingToolbarDropdown.tsx | 4 ++-- .../room/contextualBar/Info/RoomInfo/RoomInfo.tsx | 2 +- .../contextualBar/RoomMembers/RoomMembersActions.tsx | 2 +- .../room/contextualBar/UserInfo/UserInfoActions.tsx | 2 +- .../hooks/useUserInfoActions/useUserInfoActions.ts | 2 +- .../contextualBar/channels/TeamsChannelItemMenu.tsx | 4 ++-- .../src}/components/GenericMenu/GenericMenu.spec.tsx | 1 - .../src}/components/GenericMenu/GenericMenu.tsx | 2 +- .../src}/components/GenericMenu/GenericMenuItem.tsx | 1 - .../GenericMenu/hooks/useHandleMenuAction.tsx | 5 ++--- .../ui-client/src/components/GenericMenu/index.ts | 3 +++ packages/ui-client/src/components/index.ts | 1 + 69 files changed, 83 insertions(+), 91 deletions(-) rename {apps/meteor/client => packages/ui-client/src}/components/GenericMenu/GenericMenu.spec.tsx (98%) rename {apps/meteor/client => packages/ui-client/src}/components/GenericMenu/GenericMenu.tsx (99%) rename {apps/meteor/client => packages/ui-client/src}/components/GenericMenu/GenericMenuItem.tsx (97%) rename {apps/meteor/client => packages/ui-client/src}/components/GenericMenu/hooks/useHandleMenuAction.tsx (81%) create mode 100644 packages/ui-client/src/components/GenericMenu/index.ts diff --git a/apps/meteor/client/NavBarV2/NavBarPagesToolbar/NavBarItemAuditMenu.tsx b/apps/meteor/client/NavBarV2/NavBarPagesToolbar/NavBarItemAuditMenu.tsx index 07936f6f4276..7c8a50338e7d 100644 --- a/apps/meteor/client/NavBarV2/NavBarPagesToolbar/NavBarItemAuditMenu.tsx +++ b/apps/meteor/client/NavBarV2/NavBarPagesToolbar/NavBarItemAuditMenu.tsx @@ -1,9 +1,9 @@ import { NavBarItem } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useCurrentRoutePath, useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../components/GenericMenu/GenericMenu'; import { useAuditMenu } from './hooks/useAuditMenu'; type NavBarItemAuditMenuProps = Omit, 'is'>; diff --git a/apps/meteor/client/NavBarV2/NavBarPagesToolbar/NavBarItemMarketPlaceMenu.tsx b/apps/meteor/client/NavBarV2/NavBarPagesToolbar/NavBarItemMarketPlaceMenu.tsx index 4a2bbc916b57..85687bb12a2e 100644 --- a/apps/meteor/client/NavBarV2/NavBarPagesToolbar/NavBarItemMarketPlaceMenu.tsx +++ b/apps/meteor/client/NavBarV2/NavBarPagesToolbar/NavBarItemMarketPlaceMenu.tsx @@ -1,9 +1,9 @@ import { NavBarItem } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useCurrentRoutePath, useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../components/GenericMenu/GenericMenu'; import { useMarketPlaceMenu } from './hooks/useMarketPlaceMenu'; type NavBarItemMarketPlaceMenuProps = Omit, 'is'>; diff --git a/apps/meteor/client/NavBarV2/NavBarPagesToolbar/hooks/useAuditMenu.tsx b/apps/meteor/client/NavBarV2/NavBarPagesToolbar/hooks/useAuditMenu.tsx index 88a2a5de31aa..97c8d7299497 100644 --- a/apps/meteor/client/NavBarV2/NavBarPagesToolbar/hooks/useAuditMenu.tsx +++ b/apps/meteor/client/NavBarV2/NavBarPagesToolbar/hooks/useAuditMenu.tsx @@ -1,6 +1,6 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { usePermission, useRouter, useTranslation } from '@rocket.chat/ui-contexts'; -import type { GenericMenuItemProps } from '../../../components/GenericMenu/GenericMenuItem'; import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule'; export const useAuditMenu = () => { diff --git a/apps/meteor/client/NavBarV2/NavBarPagesToolbar/hooks/useMarketPlaceMenu.tsx b/apps/meteor/client/NavBarV2/NavBarPagesToolbar/hooks/useMarketPlaceMenu.tsx index fd704ffafe1f..034ab0367e81 100644 --- a/apps/meteor/client/NavBarV2/NavBarPagesToolbar/hooks/useMarketPlaceMenu.tsx +++ b/apps/meteor/client/NavBarV2/NavBarPagesToolbar/hooks/useMarketPlaceMenu.tsx @@ -1,8 +1,8 @@ import { Badge, Skeleton } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation, usePermission, useRouter } from '@rocket.chat/ui-contexts'; import React from 'react'; -import type { GenericMenuItemProps } from '../../../components/GenericMenu/GenericMenuItem'; import { useUserDropdownAppsActionButtons } from '../../../hooks/useAppActionButtons'; import { useAppRequestStats } from '../../../views/marketplace/hooks/useAppRequestStats'; diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/NavBarItemAdministrationMenu.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/NavBarItemAdministrationMenu.tsx index 045b36425512..8236eec030e8 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/NavBarItemAdministrationMenu.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/NavBarItemAdministrationMenu.tsx @@ -1,9 +1,9 @@ import { NavBarItem } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useCurrentRoutePath, useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../components/GenericMenu/GenericMenu'; import { useAdministrationMenu } from './hooks/useAdministrationMenu'; type NavBarItemAdministrationMenuProps = Omit, 'is'>; diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenu.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenu.tsx index 531ff8a74b66..22895d55388f 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenu.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenu.tsx @@ -1,11 +1,10 @@ import type { IUser } from '@rocket.chat/core-typings'; +import { GenericMenu, useHandleMenuAction } from '@rocket.chat/ui-client'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import React, { memo, useState } from 'react'; -import GenericMenu from '../../../components/GenericMenu/GenericMenu'; -import type { GenericMenuItemProps } from '../../../components/GenericMenu/GenericMenuItem'; -import { useHandleMenuAction } from '../../../components/GenericMenu/hooks/useHandleMenuAction'; import UserMenuButton from './UserMenuButton'; import { useUserMenu } from './hooks/useUserMenu'; diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx index bf1b7e55f244..82c39c5c1b10 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx @@ -1,11 +1,10 @@ import { Badge } from '@rocket.chat/fuselage'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { defaultFeaturesPreview, useFeaturePreviewList } from '@rocket.chat/ui-client'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; - export const useAccountItems = (): GenericMenuItemProps[] => { const t = useTranslation(); const router = useRouter(); diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useStatusItems.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useStatusItems.tsx index 2957d22c5e32..1c9cf09e4610 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useStatusItems.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useStatusItems.tsx @@ -1,11 +1,11 @@ import { Box } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useSetting } from '@rocket.chat/ui-contexts'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import React, { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { callbacks } from '../../../../../lib/callbacks'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import MarkdownText from '../../../../components/MarkdownText'; import { UserStatus } from '../../../../components/UserStatus'; import { userStatuses } from '../../../../lib/userStatuses'; diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useUserMenu.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useUserMenu.tsx index a969c853d797..85a481f3e257 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useUserMenu.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useUserMenu.tsx @@ -1,9 +1,9 @@ import type { IUser } from '@rocket.chat/core-typings'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useLogout, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import UserMenuHeader from '../UserMenuHeader'; import { useAccountItems } from './useAccountItems'; import { useStatusItems } from './useStatusItems'; diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/hooks/useAdministrationMenu.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/hooks/useAdministrationMenu.tsx index 54d4818128ea..e3c4a358c7c1 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/hooks/useAdministrationMenu.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/hooks/useAdministrationMenu.tsx @@ -1,7 +1,6 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useAtLeastOnePermission, usePermission, useRouter, useTranslation } from '@rocket.chat/ui-contexts'; -import type { GenericMenuItemProps } from '../../../components/GenericMenu/GenericMenuItem'; - const ADMIN_PERMISSIONS = [ 'view-statistics', 'run-import', diff --git a/apps/meteor/client/components/message/toolbar/MessageActionMenu.tsx b/apps/meteor/client/components/message/toolbar/MessageActionMenu.tsx index 6c35f7b73dbd..155599c5b51d 100644 --- a/apps/meteor/client/components/message/toolbar/MessageActionMenu.tsx +++ b/apps/meteor/client/components/message/toolbar/MessageActionMenu.tsx @@ -1,11 +1,10 @@ import { useUniqueId } from '@rocket.chat/fuselage-hooks'; +import { GenericMenu, type GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { MouseEvent, ReactElement } from 'react'; import React from 'react'; import type { MessageActionConditionProps, MessageActionConfig } from '../../../../app/ui-utils/client/lib/MessageAction'; -import GenericMenu from '../../GenericMenu/GenericMenu'; -import type { GenericMenuItemProps } from '../../GenericMenu/GenericMenuItem'; type MessageActionConfigOption = Omit & { action: (e?: MouseEvent) => void; diff --git a/apps/meteor/client/hooks/useAppActionButtons.ts b/apps/meteor/client/hooks/useAppActionButtons.ts index 5ee20f7772bf..64c46f370a1f 100644 --- a/apps/meteor/client/hooks/useAppActionButtons.ts +++ b/apps/meteor/client/hooks/useAppActionButtons.ts @@ -1,5 +1,6 @@ import type { IUIActionButton, UIActionButtonContext } from '@rocket.chat/apps-engine/definition/ui'; import { useDebouncedCallback } from '@rocket.chat/fuselage-hooks'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useStream, useToastMessageDispatch, useUserId } from '@rocket.chat/ui-contexts'; import type { UseQueryResult } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query'; @@ -10,7 +11,6 @@ import { UiKitTriggerTimeoutError } from '../../app/ui-message/client/UiKitTrigg import type { MessageActionConfig, MessageActionContext } from '../../app/ui-utils/client/lib/MessageAction'; import type { MessageBoxAction } from '../../app/ui-utils/client/lib/messageBox'; import { Utilities } from '../../ee/lib/misc/Utilities'; -import type { GenericMenuItemProps } from '../components/GenericMenu/GenericMenuItem'; import { useUiKitActionManager } from '../uikit/hooks/useUiKitActionManager'; import { useApplyButtonFilters, useApplyButtonAuthFilter } from './useApplyButtonFilters'; diff --git a/apps/meteor/client/navbar/actions/NavbarAdministrationAction.tsx b/apps/meteor/client/navbar/actions/NavbarAdministrationAction.tsx index 3431b9e928ad..f3c34c333dc5 100644 --- a/apps/meteor/client/navbar/actions/NavbarAdministrationAction.tsx +++ b/apps/meteor/client/navbar/actions/NavbarAdministrationAction.tsx @@ -1,9 +1,8 @@ +import { GenericMenu, useHandleMenuAction } from '@rocket.chat/ui-client'; import { useTranslation, useRouter } from '@rocket.chat/ui-contexts'; import type { AllHTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../components/GenericMenu/GenericMenu'; -import { useHandleMenuAction } from '../../components/GenericMenu/hooks/useHandleMenuAction'; import { NavbarAction } from '../../components/Navbar'; import { useAdministrationItems } from '../../sidebar/header/actions/hooks/useAdministrationItems'; diff --git a/apps/meteor/client/navbar/actions/NavbarAuditAction.tsx b/apps/meteor/client/navbar/actions/NavbarAuditAction.tsx index fc613be29b99..7e679faf0ab2 100644 --- a/apps/meteor/client/navbar/actions/NavbarAuditAction.tsx +++ b/apps/meteor/client/navbar/actions/NavbarAuditAction.tsx @@ -1,9 +1,8 @@ +import { GenericMenu, useHandleMenuAction } from '@rocket.chat/ui-client'; import { useTranslation, useRouter } from '@rocket.chat/ui-contexts'; import type { AllHTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../components/GenericMenu/GenericMenu'; -import { useHandleMenuAction } from '../../components/GenericMenu/hooks/useHandleMenuAction'; import { NavbarAction } from '../../components/Navbar'; import { useAuditItems } from '../../sidebar/header/actions/hooks/useAuditItems'; diff --git a/apps/meteor/client/navbar/actions/NavbarMarketplaceAction.tsx b/apps/meteor/client/navbar/actions/NavbarMarketplaceAction.tsx index 8f54b8260b2b..92e3eccf592a 100644 --- a/apps/meteor/client/navbar/actions/NavbarMarketplaceAction.tsx +++ b/apps/meteor/client/navbar/actions/NavbarMarketplaceAction.tsx @@ -1,10 +1,9 @@ import { IconButton } from '@rocket.chat/fuselage'; +import { GenericMenu, useHandleMenuAction } from '@rocket.chat/ui-client'; import { useTranslation, useRouter } from '@rocket.chat/ui-contexts'; import type { AllHTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../components/GenericMenu/GenericMenu'; -import { useHandleMenuAction } from '../../components/GenericMenu/hooks/useHandleMenuAction'; import { NavbarAction } from '../../components/Navbar'; import { useAppsItems } from '../../sidebar/header/actions/hooks/useAppsItems'; diff --git a/apps/meteor/client/sidebar/header/UserMenu.tsx b/apps/meteor/client/sidebar/header/UserMenu.tsx index 592fc19656e9..b106caa20b16 100644 --- a/apps/meteor/client/sidebar/header/UserMenu.tsx +++ b/apps/meteor/client/sidebar/header/UserMenu.tsx @@ -1,11 +1,15 @@ import type { IUser } from '@rocket.chat/core-typings'; -import { FeaturePreview, FeaturePreviewOn, FeaturePreviewOff } from '@rocket.chat/ui-client'; +import { + FeaturePreview, + FeaturePreviewOn, + FeaturePreviewOff, + GenericMenu, + useHandleMenuAction, + type GenericMenuItemProps, +} from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { useState, memo } from 'react'; -import GenericMenu from '../../components/GenericMenu/GenericMenu'; -import type { GenericMenuItemProps } from '../../components/GenericMenu/GenericMenuItem'; -import { useHandleMenuAction } from '../../components/GenericMenu/hooks/useHandleMenuAction'; import UserAvatarWithStatus from './UserAvatarWithStatus'; import UserAvatarWithStatusUnstable from './UserAvatarWithStatusUnstable'; import { useUserMenu } from './hooks/useUserMenu'; diff --git a/apps/meteor/client/sidebar/header/actions/Administration.tsx b/apps/meteor/client/sidebar/header/actions/Administration.tsx index fbed4afec4cb..a0016db7e75c 100644 --- a/apps/meteor/client/sidebar/header/actions/Administration.tsx +++ b/apps/meteor/client/sidebar/header/actions/Administration.tsx @@ -1,9 +1,9 @@ import { Sidebar } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../../components/GenericMenu/GenericMenu'; import { useAdministrationMenu } from './hooks/useAdministrationMenu'; type AdministrationProps = Omit, 'is'>; diff --git a/apps/meteor/client/sidebar/header/actions/CreateRoom.tsx b/apps/meteor/client/sidebar/header/actions/CreateRoom.tsx index 478e7cce33e1..3392db4ed917 100644 --- a/apps/meteor/client/sidebar/header/actions/CreateRoom.tsx +++ b/apps/meteor/client/sidebar/header/actions/CreateRoom.tsx @@ -1,9 +1,9 @@ import { Sidebar } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../../components/GenericMenu/GenericMenu'; import { useCreateRoom } from './hooks/useCreateRoomMenu'; type CreateRoomProps = Omit, 'is'>; diff --git a/apps/meteor/client/sidebar/header/actions/Sort.tsx b/apps/meteor/client/sidebar/header/actions/Sort.tsx index e7f3b398e5f6..1fe4b947c661 100644 --- a/apps/meteor/client/sidebar/header/actions/Sort.tsx +++ b/apps/meteor/client/sidebar/header/actions/Sort.tsx @@ -1,9 +1,9 @@ import { Sidebar } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../../components/GenericMenu/GenericMenu'; import { useSortMenu } from './hooks/useSortMenu'; type SortProps = Omit, 'is'>; diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationItems.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationItems.tsx index 5e802c2d1851..9c74bacd23ce 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationItems.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationItems.tsx @@ -1,7 +1,6 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation, useRoute, useRouter, useAtLeastOnePermission, usePermission } from '@rocket.chat/ui-contexts'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; - const ADMIN_PERMISSIONS = [ 'view-statistics', 'run-import', diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationMenu.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationMenu.tsx index 5be021cf0b7e..cf71cf4223b9 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationMenu.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationMenu.tsx @@ -1,6 +1,6 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import { useAdministrationItems } from './useAdministrationItems'; import { useAppsItems } from './useAppsItems'; import { useAuditItems } from './useAuditItems'; diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useAppsItems.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useAppsItems.tsx index 3717f33fb195..f7b9cea0d56a 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useAppsItems.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useAppsItems.tsx @@ -1,8 +1,8 @@ import { Badge, Skeleton } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation, useRoute, usePermission } from '@rocket.chat/ui-contexts'; import React from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import { useUserDropdownAppsActionButtons } from '../../../../hooks/useAppActionButtons'; import { useAppRequestStats } from '../../../../views/marketplace/hooks/useAppRequestStats'; diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useAuditItems.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useAuditItems.tsx index 8e2640711347..cf53f1ffef03 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useAuditItems.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useAuditItems.tsx @@ -1,6 +1,6 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation, useRoute, usePermission } from '@rocket.chat/ui-contexts'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import { useHasLicenseModule } from '../../../../hooks/useHasLicenseModule'; /** diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx index 7b2770a60ab5..1bc64d1ba8d1 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx @@ -1,7 +1,7 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation, useSetting, useAtLeastOnePermission } from '@rocket.chat/ui-contexts'; import CreateDiscussion from '../../../../components/CreateDiscussion'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import CreateChannelWithData from '../../CreateChannel'; import CreateDirectMessage from '../../CreateDirectMessage'; import CreateTeam from '../../CreateTeam'; diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useGroupingListItems.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useGroupingListItems.tsx index 646b85c838be..5dcb53f2ad2f 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useGroupingListItems.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useGroupingListItems.tsx @@ -1,9 +1,8 @@ import { CheckBox } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useUserPreference, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useCallback } from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; - export const useGroupingListItems = (): GenericMenuItemProps[] => { const t = useTranslation(); diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useMatrixFederationItems.tsx.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useMatrixFederationItems.tsx.tsx index b3ac63f13773..7e628378749d 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useMatrixFederationItems.tsx.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useMatrixFederationItems.tsx.tsx @@ -1,6 +1,6 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import MatrixFederationSearch from '../../MatrixFederationSearch'; import { useCreateRoomModal } from '../../hooks/useCreateRoomModal'; diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useSortModeItems.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useSortModeItems.tsx index 56041ab4e571..0e2bf818a0bf 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useSortModeItems.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useSortModeItems.tsx @@ -1,8 +1,8 @@ import { RadioButton } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useUserPreference, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useCallback } from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import { OmnichannelSortingDisclaimer, useOmnichannelSortingDisclaimer, diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useViewModeItems.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useViewModeItems.tsx index ca2855d09db5..a33230a15729 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useViewModeItems.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useViewModeItems.tsx @@ -1,9 +1,8 @@ import { RadioButton, ToggleSwitch } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useUserPreference, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useCallback } from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; - export const useViewModeItems = (): GenericMenuItemProps[] => { const t = useTranslation(); diff --git a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx index 1f18d826843d..2be6b2b1dea2 100644 --- a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx @@ -1,11 +1,10 @@ import { Badge } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { defaultFeaturesPreview, useFeaturePreviewList } from '@rocket.chat/ui-client'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import type { GenericMenuItemProps } from '../../../components/GenericMenu/GenericMenuItem'; - export const useAccountItems = (): GenericMenuItemProps[] => { const t = useTranslation(); const router = useRouter(); diff --git a/apps/meteor/client/sidebar/header/hooks/useStatusItems.tsx b/apps/meteor/client/sidebar/header/hooks/useStatusItems.tsx index 026f7c80400e..dc3fa2a3b277 100644 --- a/apps/meteor/client/sidebar/header/hooks/useStatusItems.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useStatusItems.tsx @@ -1,11 +1,11 @@ import { Box } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useSetting } from '@rocket.chat/ui-contexts'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import React, { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { callbacks } from '../../../../lib/callbacks'; -import type { GenericMenuItemProps } from '../../../components/GenericMenu/GenericMenuItem'; import MarkdownText from '../../../components/MarkdownText'; import { UserStatus } from '../../../components/UserStatus'; import { userStatuses } from '../../../lib/userStatuses'; diff --git a/apps/meteor/client/sidebar/header/hooks/useUserMenu.tsx b/apps/meteor/client/sidebar/header/hooks/useUserMenu.tsx index de43d30306e9..c0c6f94a4ed8 100644 --- a/apps/meteor/client/sidebar/header/hooks/useUserMenu.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useUserMenu.tsx @@ -1,9 +1,9 @@ import type { IUser } from '@rocket.chat/core-typings'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useLogout, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import type { GenericMenuItemProps } from '../../../components/GenericMenu/GenericMenuItem'; import UserMenuHeader from '../UserMenuHeader'; import { useAccountItems } from './useAccountItems'; import { useStatusItems } from './useStatusItems'; diff --git a/apps/meteor/client/sidebarv2/header/actions/CreateRoom.tsx b/apps/meteor/client/sidebarv2/header/actions/CreateRoom.tsx index a80954c8b297..f12de10f19f9 100644 --- a/apps/meteor/client/sidebarv2/header/actions/CreateRoom.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/CreateRoom.tsx @@ -1,9 +1,9 @@ import { SidebarV2Action } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../../components/GenericMenu/GenericMenu'; import { useCreateRoom } from './hooks/useCreateRoomMenu'; type CreateRoomProps = Omit, 'is'>; diff --git a/apps/meteor/client/sidebarv2/header/actions/Sort.tsx b/apps/meteor/client/sidebarv2/header/actions/Sort.tsx index 9956acf266b5..d5394c28c6e6 100644 --- a/apps/meteor/client/sidebarv2/header/actions/Sort.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/Sort.tsx @@ -1,9 +1,9 @@ import { SidebarV2Action } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import React from 'react'; -import GenericMenu from '../../../components/GenericMenu/GenericMenu'; import { useSortMenu } from './hooks/useSortMenu'; type SortProps = Omit, 'is'>; diff --git a/apps/meteor/client/sidebarv2/header/actions/hooks/useCreateRoomItems.tsx b/apps/meteor/client/sidebarv2/header/actions/hooks/useCreateRoomItems.tsx index 3935ad0039df..4d313975d6f5 100644 --- a/apps/meteor/client/sidebarv2/header/actions/hooks/useCreateRoomItems.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/hooks/useCreateRoomItems.tsx @@ -1,7 +1,7 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation, useSetting, useAtLeastOnePermission } from '@rocket.chat/ui-contexts'; import CreateDiscussion from '../../../../components/CreateDiscussion'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import CreateChannelModal from '../../CreateChannelModal'; import CreateDirectMessage from '../../CreateDirectMessage'; import CreateTeamModal from '../../CreateTeamModal'; diff --git a/apps/meteor/client/sidebarv2/header/actions/hooks/useGroupingListItems.tsx b/apps/meteor/client/sidebarv2/header/actions/hooks/useGroupingListItems.tsx index 646b85c838be..5dcb53f2ad2f 100644 --- a/apps/meteor/client/sidebarv2/header/actions/hooks/useGroupingListItems.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/hooks/useGroupingListItems.tsx @@ -1,9 +1,8 @@ import { CheckBox } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useUserPreference, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useCallback } from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; - export const useGroupingListItems = (): GenericMenuItemProps[] => { const t = useTranslation(); diff --git a/apps/meteor/client/sidebarv2/header/actions/hooks/useMatrixFederationItems.ts b/apps/meteor/client/sidebarv2/header/actions/hooks/useMatrixFederationItems.ts index b3ac63f13773..7e628378749d 100644 --- a/apps/meteor/client/sidebarv2/header/actions/hooks/useMatrixFederationItems.ts +++ b/apps/meteor/client/sidebarv2/header/actions/hooks/useMatrixFederationItems.ts @@ -1,6 +1,6 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import MatrixFederationSearch from '../../MatrixFederationSearch'; import { useCreateRoomModal } from '../../hooks/useCreateRoomModal'; diff --git a/apps/meteor/client/sidebarv2/header/actions/hooks/useSortModeItems.tsx b/apps/meteor/client/sidebarv2/header/actions/hooks/useSortModeItems.tsx index 56041ab4e571..0e2bf818a0bf 100644 --- a/apps/meteor/client/sidebarv2/header/actions/hooks/useSortModeItems.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/hooks/useSortModeItems.tsx @@ -1,8 +1,8 @@ import { RadioButton } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useUserPreference, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useCallback } from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import { OmnichannelSortingDisclaimer, useOmnichannelSortingDisclaimer, diff --git a/apps/meteor/client/sidebarv2/header/actions/hooks/useViewModeItems.tsx b/apps/meteor/client/sidebarv2/header/actions/hooks/useViewModeItems.tsx index ca2855d09db5..a33230a15729 100644 --- a/apps/meteor/client/sidebarv2/header/actions/hooks/useViewModeItems.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/hooks/useViewModeItems.tsx @@ -1,9 +1,8 @@ import { RadioButton, ToggleSwitch } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useUserPreference, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useCallback } from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; - export const useViewModeItems = (): GenericMenuItemProps[] => { const t = useTranslation(); diff --git a/apps/meteor/client/views/admin/moderation/MessageContextFooter.tsx b/apps/meteor/client/views/admin/moderation/MessageContextFooter.tsx index 1cbe3c7c121b..878b4d84f507 100644 --- a/apps/meteor/client/views/admin/moderation/MessageContextFooter.tsx +++ b/apps/meteor/client/views/admin/moderation/MessageContextFooter.tsx @@ -1,8 +1,8 @@ import { Button, ButtonGroup, Box } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import GenericMenu from '../../../components/GenericMenu/GenericMenu'; import useDeactivateUserAction from './hooks/useDeactivateUserAction'; import useDeleteMessagesAction from './hooks/useDeleteMessagesAction'; import useDismissUserAction from './hooks/useDismissUserAction'; diff --git a/apps/meteor/client/views/admin/moderation/ModerationConsoleActions.tsx b/apps/meteor/client/views/admin/moderation/ModerationConsoleActions.tsx index 53615ad0321c..85d081e652da 100644 --- a/apps/meteor/client/views/admin/moderation/ModerationConsoleActions.tsx +++ b/apps/meteor/client/views/admin/moderation/ModerationConsoleActions.tsx @@ -1,8 +1,8 @@ // import { Menu, Option } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import GenericMenu from '../../../components/GenericMenu/GenericMenu'; import type { ModerationConsoleRowProps } from './ModerationConsoleTableRow'; import useDeactivateUserAction from './hooks/useDeactivateUserAction'; import useDeleteMessagesAction from './hooks/useDeleteMessagesAction'; diff --git a/apps/meteor/client/views/admin/moderation/UserReports/ModConsoleUserActions.tsx b/apps/meteor/client/views/admin/moderation/UserReports/ModConsoleUserActions.tsx index eb1ec183fcfe..13da70b48da2 100644 --- a/apps/meteor/client/views/admin/moderation/UserReports/ModConsoleUserActions.tsx +++ b/apps/meteor/client/views/admin/moderation/UserReports/ModConsoleUserActions.tsx @@ -1,7 +1,7 @@ +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import GenericMenu from '../../../../components/GenericMenu/GenericMenu'; import useDeactivateUserAction from '../hooks/useDeactivateUserAction'; import useDismissUserAction from '../hooks/useDismissUserAction'; import useResetAvatarAction from '../hooks/useResetAvatarAction'; diff --git a/apps/meteor/client/views/admin/moderation/UserReports/UserContextFooter.tsx b/apps/meteor/client/views/admin/moderation/UserReports/UserContextFooter.tsx index 601e403e7e74..c437746ad8ef 100644 --- a/apps/meteor/client/views/admin/moderation/UserReports/UserContextFooter.tsx +++ b/apps/meteor/client/views/admin/moderation/UserReports/UserContextFooter.tsx @@ -1,8 +1,8 @@ import { Button, ButtonGroup, Box } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import GenericMenu from '../../../../components/GenericMenu/GenericMenu'; import useDeactivateUserAction from '../hooks/useDeactivateUserAction'; import useDismissUserAction from '../hooks/useDismissUserAction'; import useResetAvatarAction from '../hooks/useResetAvatarAction'; diff --git a/apps/meteor/client/views/admin/moderation/hooks/useDeactivateUserAction.tsx b/apps/meteor/client/views/admin/moderation/hooks/useDeactivateUserAction.tsx index 2ac0eeffe131..ac046fe80633 100644 --- a/apps/meteor/client/views/admin/moderation/hooks/useDeactivateUserAction.tsx +++ b/apps/meteor/client/views/admin/moderation/hooks/useDeactivateUserAction.tsx @@ -1,9 +1,9 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useRouteParameter, useRouter, useSetModal, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import GenericModal from '../../../../components/GenericModal'; const useDeactivateUserAction = (userId: string, isUserReport?: boolean): GenericMenuItemProps => { diff --git a/apps/meteor/client/views/admin/moderation/hooks/useDeleteMessagesAction.tsx b/apps/meteor/client/views/admin/moderation/hooks/useDeleteMessagesAction.tsx index 4d5d5690492d..3fb22dfd0c5e 100644 --- a/apps/meteor/client/views/admin/moderation/hooks/useDeleteMessagesAction.tsx +++ b/apps/meteor/client/views/admin/moderation/hooks/useDeleteMessagesAction.tsx @@ -1,8 +1,8 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useRouteParameter, useRouter, useSetModal, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import React from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import GenericModal from '../../../../components/GenericModal'; const useDeleteMessagesAction = (userId: string): GenericMenuItemProps => { diff --git a/apps/meteor/client/views/admin/moderation/hooks/useDismissUserAction.tsx b/apps/meteor/client/views/admin/moderation/hooks/useDismissUserAction.tsx index 09a30358d737..72e5dc03fd95 100644 --- a/apps/meteor/client/views/admin/moderation/hooks/useDismissUserAction.tsx +++ b/apps/meteor/client/views/admin/moderation/hooks/useDismissUserAction.tsx @@ -1,9 +1,9 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useRouter, useSetModal, useToastMessageDispatch, useRouteParameter } from '@rocket.chat/ui-contexts'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import GenericModal from '../../../../components/GenericModal'; const useDismissUserAction = (userId: string, isUserReport?: boolean): GenericMenuItemProps => { diff --git a/apps/meteor/client/views/admin/moderation/hooks/useResetAvatarAction.tsx b/apps/meteor/client/views/admin/moderation/hooks/useResetAvatarAction.tsx index 377aad97b186..8e488234814b 100644 --- a/apps/meteor/client/views/admin/moderation/hooks/useResetAvatarAction.tsx +++ b/apps/meteor/client/views/admin/moderation/hooks/useResetAvatarAction.tsx @@ -1,8 +1,8 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useEndpoint, useSetModal, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import React from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import GenericModal from '../../../../components/GenericModal'; const useResetAvatarAction = (userId: string): GenericMenuItemProps => { diff --git a/apps/meteor/client/views/marketplace/AppMenu.tsx b/apps/meteor/client/views/marketplace/AppMenu.tsx index be1159ebd4e2..a1d3942ee304 100644 --- a/apps/meteor/client/views/marketplace/AppMenu.tsx +++ b/apps/meteor/client/views/marketplace/AppMenu.tsx @@ -1,9 +1,9 @@ import type { App } from '@rocket.chat/core-typings'; import { MenuItem, MenuItemContent, MenuSection, MenuV2, Skeleton } from '@rocket.chat/fuselage'; +import { useHandleMenuAction } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { memo } from 'react'; -import { useHandleMenuAction } from '../../components/GenericMenu/hooks/useHandleMenuAction'; import type { AppMenuOption } from './hooks/useAppMenu'; import { useAppMenu } from './hooks/useAppMenu'; diff --git a/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolbox.tsx b/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolbox.tsx index bdda6f33f0e3..ff9880ba1e84 100644 --- a/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolbox.tsx +++ b/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolbox.tsx @@ -1,11 +1,11 @@ import type { Box } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { GenericMenu } from '@rocket.chat/ui-client'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useLayout, useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import React, { memo } from 'react'; -import GenericMenu from '../../../../components/GenericMenu/GenericMenu'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import { HeaderToolbarAction, HeaderToolbarDivider } from '../../../../components/Header'; import { useRoomToolbox } from '../../contexts/RoomToolboxContext'; import type { RoomToolboxActionConfig } from '../../contexts/RoomToolboxContext'; diff --git a/apps/meteor/client/views/room/HeaderV2/RoomToolbox/RoomToolbox.tsx b/apps/meteor/client/views/room/HeaderV2/RoomToolbox/RoomToolbox.tsx index 5fda368711c1..abf9b41b89da 100644 --- a/apps/meteor/client/views/room/HeaderV2/RoomToolbox/RoomToolbox.tsx +++ b/apps/meteor/client/views/room/HeaderV2/RoomToolbox/RoomToolbox.tsx @@ -1,11 +1,11 @@ import type { Box } from '@rocket.chat/fuselage'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; +import { GenericMenu } from '@rocket.chat/ui-client'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useLayout, useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import React, { memo } from 'react'; -import GenericMenu from '../../../../components/GenericMenu/GenericMenu'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import { HeaderToolbarAction, HeaderToolbarDivider } from '../../../../components/Header'; import { useRoomToolbox } from '../../contexts/RoomToolboxContext'; import type { RoomToolboxActionConfig } from '../../contexts/RoomToolboxContext'; diff --git a/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx b/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx index a12e9a143cc2..a26b5f31e77d 100644 --- a/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx +++ b/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx @@ -1,11 +1,11 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useSetting, useRolesDescription, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useMemo } from 'react'; import { getUserDisplayName } from '../../../../lib/getUserDisplayName'; -import GenericMenu from '../../../components/GenericMenu/GenericMenu'; import LocalTime from '../../../components/LocalTime'; import { UserCard, UserCardAction, UserCardRole, UserCardSkeleton } from '../../../components/UserCard'; import { ReactiveUserStatus } from '../../../components/UserStatus'; diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/MessageBoxActionsToolbar.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/MessageBoxActionsToolbar.tsx index 90216f159069..38396844866b 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/MessageBoxActionsToolbar.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/MessageBoxActionsToolbar.tsx @@ -1,5 +1,7 @@ import type { IRoom, IMessage } from '@rocket.chat/core-typings'; import type { Icon } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { MessageComposerAction, MessageComposerActionsDivider } from '@rocket.chat/ui-composer'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useTranslation, useLayoutHiddenActions } from '@rocket.chat/ui-contexts'; @@ -8,8 +10,6 @@ import React, { memo } from 'react'; import { messageBox } from '../../../../../../app/ui-utils/client'; import { isTruthy } from '../../../../../../lib/isTruthy'; -import GenericMenu from '../../../../../components/GenericMenu/GenericMenu'; -import type { GenericMenuItemProps } from '../../../../../components/GenericMenu/GenericMenuItem'; import { useMessageboxAppsActionButtons } from '../../../../../hooks/useAppActionButtons'; import { useChat } from '../../../contexts/ChatContext'; import { useRoom } from '../../../contexts/RoomContext'; diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useAudioMessageAction.ts b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useAudioMessageAction.ts index 58cd7b72189b..9738f714fa97 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useAudioMessageAction.ts +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useAudioMessageAction.ts @@ -1,9 +1,9 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useSetting } from '@rocket.chat/ui-contexts'; import { useEffect, useMemo } from 'react'; import { AudioRecorder } from '../../../../../../../app/ui/client/lib/recorderjs/AudioRecorder'; -import type { GenericMenuItemProps } from '../../../../../../components/GenericMenu/GenericMenuItem'; import { useChat } from '../../../../contexts/ChatContext'; import { useMediaActionTitle } from '../../hooks/useMediaActionTitle'; import { useMediaPermissions } from '../../hooks/useMediaPermissions'; diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useCreateDiscussionAction.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useCreateDiscussionAction.tsx index 50702f6887aa..03bff48876f3 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useCreateDiscussionAction.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useCreateDiscussionAction.tsx @@ -1,10 +1,10 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { isRoomFederated } from '@rocket.chat/core-typings'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation, useSetting, usePermission, useSetModal } from '@rocket.chat/ui-contexts'; import React from 'react'; import CreateDiscussion from '../../../../../../components/CreateDiscussion'; -import type { GenericMenuItemProps } from '../../../../../../components/GenericMenu/GenericMenuItem'; export const useCreateDiscussionAction = (room?: IRoom): GenericMenuItemProps => { const t = useTranslation(); diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useFileUploadAction.ts b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useFileUploadAction.ts index f911b2b63b1f..f576aba9803c 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useFileUploadAction.ts +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useFileUploadAction.ts @@ -1,7 +1,7 @@ +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation, useSetting } from '@rocket.chat/ui-contexts'; import { useEffect } from 'react'; -import type { GenericMenuItemProps } from '../../../../../../components/GenericMenu/GenericMenuItem'; import { useFileInput } from '../../../../../../hooks/useFileInput'; import { useChat } from '../../../../contexts/ChatContext'; diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useShareLocationAction.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useShareLocationAction.tsx index bf44496b0d67..a49253c2744d 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useShareLocationAction.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useShareLocationAction.tsx @@ -1,9 +1,9 @@ import type { IMessage, IRoom } from '@rocket.chat/core-typings'; import { isRoomFederated } from '@rocket.chat/core-typings'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useSetting, useSetModal, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import type { GenericMenuItemProps } from '../../../../../../components/GenericMenu/GenericMenuItem'; import ShareLocationModal from '../../../../ShareLocation/ShareLocationModal'; export const useShareLocationAction = (room?: IRoom, tmid?: IMessage['tmid']): GenericMenuItemProps => { diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useVideoMessageAction.ts b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useVideoMessageAction.ts index cd7e2c5af6fc..2608597fb202 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useVideoMessageAction.ts +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useVideoMessageAction.ts @@ -1,9 +1,9 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useSetting } from '@rocket.chat/ui-contexts'; import { useEffect, useMemo } from 'react'; import { VideoRecorder } from '../../../../../../../app/ui/client/lib/recorderjs/videoRecorder'; -import type { GenericMenuItemProps } from '../../../../../../components/GenericMenu/GenericMenuItem'; import { useChat } from '../../../../contexts/ChatContext'; import { useMediaActionTitle } from '../../hooks/useMediaActionTitle'; import { useMediaPermissions } from '../../hooks/useMediaPermissions'; diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useWebdavActions.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useWebdavActions.tsx index ae80a7407851..806bebaa65e3 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useWebdavActions.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useWebdavActions.tsx @@ -1,9 +1,9 @@ import type { IWebdavAccountIntegration } from '@rocket.chat/core-typings'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useSetModal, useSetting } from '@rocket.chat/ui-contexts'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import type { GenericMenuItemProps } from '../../../../../../components/GenericMenu/GenericMenuItem'; import { useWebDAVAccountIntegrationsQuery } from '../../../../../../hooks/webdav/useWebDAVAccountIntegrationsQuery'; import { useChat } from '../../../../contexts/ChatContext'; import AddWebdavAccountModal from '../../../../webdav/AddWebdavAccountModal'; diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxFormattingToolbar/FormattingToolbarDropdown.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBoxFormattingToolbar/FormattingToolbarDropdown.tsx index b2ba79792e04..d39b74c079a2 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxFormattingToolbar/FormattingToolbarDropdown.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxFormattingToolbar/FormattingToolbarDropdown.tsx @@ -1,9 +1,9 @@ +import { GenericMenu } from '@rocket.chat/ui-client'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; import { isPromptButton, type FormattingButton } from '../../../../../../app/ui-message/client/messageBox/messageBoxFormatting'; -import GenericMenu from '../../../../../components/GenericMenu/GenericMenu'; -import type { GenericMenuItemProps } from '../../../../../components/GenericMenu/GenericMenuItem'; import type { ComposerAPI } from '../../../../../lib/chats/ChatAPI'; type FormattingToolbarDropdownProps = { diff --git a/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.tsx b/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.tsx index b0bf1d083a71..31f96a344677 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.tsx +++ b/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.tsx @@ -1,6 +1,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { Box, Callout, IconButton } from '@rocket.chat/fuselage'; import { RoomAvatar } from '@rocket.chat/ui-avatar'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; @@ -12,7 +13,6 @@ import { ContextualbarClose, ContextualbarTitle, } from '../../../../../components/Contextualbar'; -import GenericMenu from '../../../../../components/GenericMenu/GenericMenu'; import { InfoPanel, InfoPanelActionGroup, diff --git a/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersActions.tsx b/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersActions.tsx index 7df7c468bb01..c265a28cb284 100644 --- a/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersActions.tsx +++ b/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersActions.tsx @@ -1,9 +1,9 @@ import type { IUser, IRoom } from '@rocket.chat/core-typings'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; -import GenericMenu from '../../../../components/GenericMenu/GenericMenu'; import { useUserInfoActions } from '../../hooks/useUserInfoActions'; type RoomMembersActionsProps = { diff --git a/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoActions.tsx b/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoActions.tsx index 0b4f30fb1f29..17e8bd1470ba 100644 --- a/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoActions.tsx +++ b/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoActions.tsx @@ -1,11 +1,11 @@ /* eslint-disable react/display-name, react/no-multi-comp */ import type { IRoom, IUser } from '@rocket.chat/core-typings'; import { ButtonGroup, IconButton, Skeleton } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useMemo } from 'react'; -import GenericMenu from '../../../../components/GenericMenu/GenericMenu'; import { UserInfoAction } from '../../../../components/UserInfo'; import { useMemberExists } from '../../../hooks/useMemberExists'; import { useUserInfoActions } from '../../hooks/useUserInfoActions'; diff --git a/apps/meteor/client/views/room/hooks/useUserInfoActions/useUserInfoActions.ts b/apps/meteor/client/views/room/hooks/useUserInfoActions/useUserInfoActions.ts index 2a70ff55ee34..c04df6b7521a 100644 --- a/apps/meteor/client/views/room/hooks/useUserInfoActions/useUserInfoActions.ts +++ b/apps/meteor/client/views/room/hooks/useUserInfoActions/useUserInfoActions.ts @@ -1,10 +1,10 @@ import type { IRoom, IUser } from '@rocket.chat/core-typings'; import type { Icon } from '@rocket.chat/fuselage'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useLayoutHiddenActions } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import { useMemo } from 'react'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import { useEmbeddedLayout } from '../../../../hooks/useEmbeddedLayout'; import { useAddUserAction } from './actions/useAddUserAction'; import { useBlockUserAction } from './actions/useBlockUserAction'; diff --git a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItemMenu.tsx b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItemMenu.tsx index 97b1bdceb670..418883869a4a 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItemMenu.tsx +++ b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItemMenu.tsx @@ -1,10 +1,10 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { CheckBox } from '@rocket.chat/fuselage'; +import { GenericMenu } from '@rocket.chat/ui-client'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; -import GenericMenu from '../../../../components/GenericMenu/GenericMenu'; -import type { GenericMenuItemProps } from '../../../../components/GenericMenu/GenericMenuItem'; import { useDeleteRoom } from '../../../hooks/roomActions/useDeleteRoom'; import { useRemoveRoomFromTeam } from './hooks/useRemoveRoomFromTeam'; import { useToggleAutoJoin } from './hooks/useToggleAutoJoin'; diff --git a/apps/meteor/client/components/GenericMenu/GenericMenu.spec.tsx b/packages/ui-client/src/components/GenericMenu/GenericMenu.spec.tsx similarity index 98% rename from apps/meteor/client/components/GenericMenu/GenericMenu.spec.tsx rename to packages/ui-client/src/components/GenericMenu/GenericMenu.spec.tsx index 530bd1404dc7..bdd7f5fbda18 100644 --- a/apps/meteor/client/components/GenericMenu/GenericMenu.spec.tsx +++ b/packages/ui-client/src/components/GenericMenu/GenericMenu.spec.tsx @@ -1,6 +1,5 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import React from 'react'; import GenericMenu from './GenericMenu'; diff --git a/apps/meteor/client/components/GenericMenu/GenericMenu.tsx b/packages/ui-client/src/components/GenericMenu/GenericMenu.tsx similarity index 99% rename from apps/meteor/client/components/GenericMenu/GenericMenu.tsx rename to packages/ui-client/src/components/GenericMenu/GenericMenu.tsx index 294a98770523..3f65df59a6ca 100644 --- a/apps/meteor/client/components/GenericMenu/GenericMenu.tsx +++ b/packages/ui-client/src/components/GenericMenu/GenericMenu.tsx @@ -1,7 +1,6 @@ import { IconButton, MenuItem, MenuSection, MenuV2 } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactNode } from 'react'; -import React from 'react'; import type { GenericMenuItemProps } from './GenericMenuItem'; import GenericMenuItem from './GenericMenuItem'; @@ -13,6 +12,7 @@ type GenericMenuCommonProps = { disabled?: boolean; callbackAction?: () => void; }; + type GenericMenuConditionalProps = | { sections?: { diff --git a/apps/meteor/client/components/GenericMenu/GenericMenuItem.tsx b/packages/ui-client/src/components/GenericMenu/GenericMenuItem.tsx similarity index 97% rename from apps/meteor/client/components/GenericMenu/GenericMenuItem.tsx rename to packages/ui-client/src/components/GenericMenu/GenericMenuItem.tsx index c01a64d708a0..41576a2a40a6 100644 --- a/apps/meteor/client/components/GenericMenu/GenericMenuItem.tsx +++ b/packages/ui-client/src/components/GenericMenu/GenericMenuItem.tsx @@ -1,6 +1,5 @@ import { MenuItemColumn, MenuItemContent, MenuItemIcon, MenuItemInput } from '@rocket.chat/fuselage'; import type { ComponentProps, MouseEvent, ReactNode } from 'react'; -import React from 'react'; export type GenericMenuItemProps = { id: string; diff --git a/apps/meteor/client/components/GenericMenu/hooks/useHandleMenuAction.tsx b/packages/ui-client/src/components/GenericMenu/hooks/useHandleMenuAction.tsx similarity index 81% rename from apps/meteor/client/components/GenericMenu/hooks/useHandleMenuAction.tsx rename to packages/ui-client/src/components/GenericMenu/hooks/useHandleMenuAction.tsx index dd1115765194..fb423643b7c6 100644 --- a/apps/meteor/client/components/GenericMenu/hooks/useHandleMenuAction.tsx +++ b/packages/ui-client/src/components/GenericMenu/hooks/useHandleMenuAction.tsx @@ -2,12 +2,11 @@ import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { GenericMenuItemProps } from '../GenericMenuItem'; -export const useHandleMenuAction = (items: GenericMenuItemProps[], callbackAction?: () => void) => { - return useEffectEvent((id) => { +export const useHandleMenuAction = (items: GenericMenuItemProps[], callbackAction?: () => void) => + useEffectEvent((id) => { const item = items.find((item) => item.id === id && !!item.onClick); if (item) { item.onClick?.(); callbackAction?.(); } }); -}; diff --git a/packages/ui-client/src/components/GenericMenu/index.ts b/packages/ui-client/src/components/GenericMenu/index.ts new file mode 100644 index 000000000000..a0753e281481 --- /dev/null +++ b/packages/ui-client/src/components/GenericMenu/index.ts @@ -0,0 +1,3 @@ +export { default as GenericMenu } from './GenericMenu'; +export { default as GenericMenuItem, GenericMenuItemProps } from './GenericMenuItem'; +export { useHandleMenuAction } from './hooks/useHandleMenuAction'; diff --git a/packages/ui-client/src/components/index.ts b/packages/ui-client/src/components/index.ts index f78c32427cdb..8642983229aa 100644 --- a/packages/ui-client/src/components/index.ts +++ b/packages/ui-client/src/components/index.ts @@ -14,3 +14,4 @@ export * from './MultiSelectCustom/MultiSelectCustom'; export * from './FeaturePreview/FeaturePreview'; export * from './RoomBanner'; export { default as UserAutoComplete } from './UserAutoComplete'; +export * from './GenericMenu'; From 98b6a209013f2469deb1f405e30791c9481b145b Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Fri, 13 Sep 2024 09:01:28 -0300 Subject: [PATCH 077/170] refactor(i18n): Increase the adoption of `react-i18next` - Phase 1 (#33175) --- .../react-i18next-npm-15.0.1-0812bb73aa.patch | 99 +++++ apps/meteor/app/2fa/server/code/EmailCheck.ts | 2 +- .../app/2fa/server/functions/resetTOTP.ts | 2 +- .../app/lib/server/methods/addUsersToRoom.ts | 13 +- .../app/lib/server/methods/sendMessage.ts | 5 +- .../server/startup/mentionUserNotInChannel.ts | 8 +- .../modals/PlaceChatOnHoldModal.tsx | 4 +- .../meteor/app/livechat/server/api/v1/room.ts | 2 +- apps/meteor/app/livechat/server/lib/Helper.ts | 4 +- .../app/livechat/server/lib/QueueManager.ts | 4 +- .../messageBox/AddLinkComposerActionModal.tsx | 4 +- apps/meteor/app/utils/lib/i18n.ts | 3 +- .../NavBarItemOmniChannelCallDialPad.tsx | 4 +- .../NavBarItemOmnichannelCallToggleError.tsx | 4 +- ...NavBarItemOmnichannelCallToggleLoading.tsx | 4 +- .../NavBarItemOmnichannelCallToggleReady.tsx | 4 +- .../UserMenu/UserMenu.tsx | 4 +- .../apps/gameCenter/GameCenterContainer.tsx | 4 +- .../GameCenterInvitePlayersModal.tsx | 4 +- .../components/ActionManagerBusyState.tsx | 4 +- .../components/AutoCompleteDepartment.tsx | 4 +- .../AutoCompleteDepartmentMultiple.tsx | 4 +- .../components/ConfirmOwnerChangeModal.tsx | 4 +- .../Contextualbar/ContextualbarBack.tsx | 4 +- .../Contextualbar/ContextualbarClose.tsx | 4 +- .../meteor/client/components/FilterByText.tsx | 4 +- .../components/FingerprintChangeModal.tsx | 4 +- .../FingerprintChangeModalConfirmation.tsx | 4 +- .../components/GenericError/GenericError.tsx | 4 +- .../components/GenericModal/GenericModal.tsx | 4 +- .../GenericNoResults/GenericNoResults.tsx | 4 +- .../hooks/useItemsPerPageLabel.ts | 4 +- .../hooks/useShowingResultsLabel.ts | 10 +- .../GenericUpsellModal/GenericUpsellModal.tsx | 4 +- .../components/ImageGallery/ImageGallery.tsx | 4 +- .../ImageGallery/ImageGalleryError.tsx | 4 +- .../ImageGallery/ImageGalleryLoading.tsx | 4 +- .../InfoPanel/RetentionPolicyCallout.tsx | 4 +- apps/meteor/client/components/LocalTime.tsx | 4 +- .../meteor/client/components/MarkdownText.tsx | 4 +- .../modals/ReturnChatQueueModal.tsx | 4 +- .../Omnichannel/modals/TranscriptModal.tsx | 4 +- .../client/components/Sidebar/Header.tsx | 4 +- .../Sidebar/SidebarItemsAssembler.tsx | 6 +- .../SidebarToggler/SidebarTogglerButton.tsx | 4 +- apps/meteor/client/components/TextCopy.tsx | 4 +- .../TwoFactorModal/TwoFactorPasswordModal.tsx | 4 +- .../TwoFactorModal/TwoFactorTotpModal.tsx | 4 +- .../client/components/UrlChangeModal.tsx | 9 +- .../client/components/UserCard/UserCard.tsx | 4 +- .../client/components/UserInfo/UserInfo.tsx | 4 +- .../meteor/client/components/WarningModal.tsx | 4 +- .../components/dashboards/PeriodSelector.tsx | 6 +- .../client/components/dashboards/periods.ts | 23 +- .../components/dashboards/usePeriodLabel.ts | 6 +- .../DeviceManagementTable.tsx | 4 +- .../deviceManagement/LoggedOutBanner.tsx | 4 +- .../components/message/IgnoredContent.tsx | 4 +- .../components/message/MessageHeader.tsx | 4 +- .../message/ReadReceiptIndicator.tsx | 4 +- .../message/content/BroadcastMetrics.tsx | 4 +- .../message/content/DiscussionMetrics.tsx | 4 +- .../components/message/content/Reactions.tsx | 4 +- .../message/content/actions/MessageAction.tsx | 4 +- .../structure/AttachmentDownloadBase.tsx | 4 +- .../attachments/structure/image/Load.tsx | 4 +- .../attachments/structure/image/Retry.tsx | 4 +- .../collapsible/CollapsibleContent.tsx | 4 +- .../content/location/MapViewFallback.tsx | 4 +- .../message/content/location/MapViewImage.tsx | 4 +- .../content/reactions/ReactionTooltip.tsx | 4 +- .../content/urlPreviews/OEmbedCollapsible.tsx | 4 +- .../message/header/MessageRoles.tsx | 4 +- .../notification/MessageNotification.tsx | 4 +- .../message/toolbar/MessageActionMenu.tsx | 4 +- .../message/variants/SystemMessage.tsx | 4 +- .../message/variants/ThreadMessagePreview.tsx | 4 +- .../ThreadMessagePreviewBody.tsx | 4 +- .../components/voip/room/VoipRoomForeword.tsx | 4 +- .../client/hooks/useDecryptedMessage.ts | 4 +- .../hooks/useDownloadFromServiceWorker.ts | 3 +- apps/meteor/client/hooks/useFormatDuration.ts | 4 +- .../meteor/client/hooks/useHighlightedCode.ts | 4 +- .../additionalForms/BusinessHoursMultiple.tsx | 4 +- .../additionalForms/ContactManager.js | 4 +- .../CustomFieldsAdditionalForm.tsx | 4 +- .../additionalForms/DepartmentForwarding.tsx | 4 +- .../additionalForms/MaxChatsPerAgent.tsx | 4 +- .../MaxChatsPerAgentDisplay.tsx | 4 +- .../additionalForms/PrioritiesSelect.tsx | 4 +- .../CannedResponseEditWithDepartmentData.tsx | 4 +- .../cannedResponses/CannedResponseFilter.tsx | 4 +- .../InsertPlaceholderDropdown.tsx | 4 +- .../CannedResponse/CannedResponse.tsx | 4 +- .../CannedResponse/CannedResponseList.tsx | 4 +- .../contextualBar/CannedResponse/Item.tsx | 4 +- .../components/RoomActivityIcon/index.tsx | 4 +- .../client/omnichannel/hooks/useScopeDict.ts | 4 +- .../omnichannel/monitors/MonitorsPage.tsx | 4 +- .../priorities/PrioritiesResetModal.tsx | 4 +- .../priorities/PrioritiesTable.tsx | 4 +- .../priorities/PriorityEditFormWithData.tsx | 4 +- .../omnichannel/priorities/PriorityIcon.tsx | 4 +- .../omnichannel/priorities/PriorityList.tsx | 4 +- .../reports/components/AgentsTable.tsx | 4 +- .../components/ReportCardEmptyState.tsx | 4 +- .../components/ReportCardErrorState.tsx | 4 +- .../reports/hooks/useAgentsSection.tsx | 5 +- .../reports/hooks/useChannelsSection.tsx | 12 +- .../reports/hooks/useDefaultDownload.tsx | 4 +- .../reports/hooks/useDepartmentsSection.tsx | 5 +- .../reports/hooks/useStatusSection.tsx | 10 +- .../reports/hooks/useTagsSection.tsx | 5 +- .../reports/sections/AgentsSection.tsx | 4 +- .../reports/utils/formatPeriodDescription.tsx | 6 +- .../tags/AutoCompleteTagsMultiple.tsx | 4 +- .../sidebar/RoomList/RoomListWrapper.tsx | 4 +- .../sidebar/footer/SidebarFooterWatermark.tsx | 4 +- .../client/sidebar/footer/voip/VoipFooter.tsx | 4 +- .../FederatedRoomListEmptyPlaceholder.tsx | 4 +- .../FederatedRoomListErrorBoundary.tsx | 4 +- .../FederatedRoomListItem.tsx | 4 +- .../MatrixFederationSearch.tsx | 4 +- .../meteor/client/sidebar/header/UserMenu.tsx | 4 +- .../sidebar/header/actions/Administration.tsx | 4 +- .../sidebar/header/actions/CreateRoom.tsx | 4 +- .../client/sidebar/header/actions/Sort.tsx | 4 +- .../actions/hooks/useAdministrationMenu.tsx | 4 +- .../hooks/useMatrixFederationItems.tsx.tsx | 4 +- .../header/actions/hooks/useSortMenu.tsx | 4 +- .../sidebar/sections/OverMacLimitSection.tsx | 4 +- .../sections/StatusDisabledSection.tsx | 4 +- .../actions/OmnichannelCallDialPad.tsx | 4 +- .../actions/OmnichannelCallToggleError.tsx | 4 +- .../actions/OmnichannelCallToggleLoading.tsx | 4 +- .../actions/OmnichannelCallToggleReady.tsx | 4 +- .../sidebarv2/RoomList/RoomListWrapper.tsx | 4 +- .../footer/SidebarFooterWatermark.tsx | 4 +- .../sidebarv2/footer/voip/VoipFooter.tsx | 4 +- .../FederatedRoomListEmptyPlaceholder.tsx | 4 +- .../FederatedRoomListErrorBoundary.tsx | 4 +- .../FederatedRoomListItem.tsx | 4 +- .../MatrixFederationSearch.tsx | 4 +- .../sidebarv2/header/actions/CreateRoom.tsx | 4 +- .../client/sidebarv2/header/actions/Sort.tsx | 4 +- .../actions/hooks/useMatrixFederationItems.ts | 4 +- .../header/actions/hooks/useSortMenu.tsx | 4 +- .../sections/StatusDisabledSection.tsx | 4 +- .../contexts/TranslationContextMock.tsx | 3 +- .../DeviceManagementAccountPage.tsx | 4 +- .../DeviceManagementAccountRow.tsx | 4 +- .../DeviceManagementAccountTable.tsx | 4 +- .../AccountFeaturePreviewBadge.tsx | 4 +- .../omnichannel/PreferencesGeneral.tsx | 4 +- .../views/account/preferences/MyDataModal.tsx | 4 +- .../PreferencesHighlightsSection.tsx | 4 +- .../PreferencesMessagesSection.tsx | 4 +- .../PreferencesUserPresenceSection.tsx | 4 +- .../account/profile/ActionConfirmModal.tsx | 4 +- .../account/security/BackupCodesModal.tsx | 4 +- .../account/tokens/AccountTokensPage.tsx | 4 +- .../AccountTokensTable/AccountTokensRow.tsx | 4 +- .../admin/customEmoji/AddCustomEmoji.tsx | 4 +- .../CustomUserActiveConnections.tsx | 4 +- .../CustomUserStatusDisabledModal.tsx | 4 +- .../DeviceManagementAdminTable.tsx | 4 +- .../DeviceManagementInfoWithData.tsx | 4 +- .../EngagementDashboardCardErrorBoundary.tsx | 4 +- .../EngagementDashboardPage.tsx | 4 +- .../channels/ChannelsOverview.tsx | 9 +- .../messages/MessagesPerChannelSection.tsx | 4 +- .../messages/MessagesSentSection.tsx | 4 +- .../messages/MessagesTab.tsx | 4 +- .../users/ActiveUsersSection.tsx | 4 +- .../users/BusiestChatTimesSection.tsx | 4 +- .../users/ContentForHours.tsx | 4 +- .../users/NewUsersSection.tsx | 4 +- .../users/UsersByTimeOfTheDaySection.tsx | 4 +- .../engagementDashboard/users/UsersTab.tsx | 4 +- .../FederationDashboardPage.tsx | 4 +- .../views/admin/import/PrepareChannels.tsx | 10 +- .../views/admin/import/PrepareUsers.tsx | 10 +- .../views/admin/integrations/NewBot.tsx | 4 +- .../views/admin/integrations/NewZapier.tsx | 4 +- .../outgoing/OutgoingWebhookForm.tsx | 14 +- .../outgoing/history/HistoryContent.tsx | 4 +- .../admin/moderation/MessageContextFooter.tsx | 4 +- .../moderation/ModerationConsoleActions.tsx | 5 +- .../UserReports/ModConsoleUserActions.tsx | 4 +- .../UserReports/UserContextFooter.tsx | 4 +- .../moderation/helpers/DateRangePicker.tsx | 4 +- .../moderation/helpers/ModerationFilter.tsx | 4 +- .../helpers/ReportReasonCollapsible.tsx | 4 +- .../permissions/CustomRoleUpsellModal.tsx | 4 +- .../PermissionsTable/PermissionRow.tsx | 7 +- .../PermissionsTableFilter.tsx | 4 +- .../views/admin/permissions/RoleForm.tsx | 4 +- .../UsersInRoleTable/UsersInRoleTableRow.tsx | 4 +- .../views/admin/rooms/RoomsTableFilters.tsx | 4 +- .../ResetSettingButton/ResetSettingButton.tsx | 4 +- .../inputs/CodeMirror/CodeMirrorBox.tsx | 4 +- .../Setting/inputs/ColorSettingInput.tsx | 4 +- .../inputs/MultiSelectSettingInput.tsx | 4 +- .../Setting/inputs/SelectSettingInput.tsx | 4 +- .../inputs/TimespanSettingInput.spec.tsx | 11 +- .../Setting/inputs/TimespanSettingInput.tsx | 8 +- .../SettingsSection/SettingsSection.tsx | 4 +- .../OAuthGroupPage/CreateOAuthModal.tsx | 4 +- .../admin/settings/groups/TabbedGroupPage.tsx | 4 +- .../admin/subscription/SubscriptionPage.tsx | 2 +- .../admin/users/AdminUserFormWithData.tsx | 4 +- .../AdminUserSetRandomPasswordRadios.tsx | 4 +- .../users/SeatsCapUsage/SeatsCapUsage.tsx | 4 +- .../admin/users/UsersTable/UsersTableRow.tsx | 4 +- .../views/admin/viewLogs/AnalyticsReports.tsx | 4 +- .../views/admin/viewLogs/ViewLogsPage.tsx | 4 +- .../InstancesModal/InstancesModal.tsx | 4 +- .../MessagesRoomsCard/MessagesRoomsCard.tsx | 4 +- .../views/admin/workspace/WorkspacePage.tsx | 4 +- .../client/views/audit/AuditLogPage.tsx | 4 +- apps/meteor/client/views/audit/AuditPage.tsx | 4 +- .../audit/components/AuditFiltersDisplay.tsx | 4 +- .../views/audit/components/AuditForm.tsx | 4 +- .../views/audit/components/AuditLogEntry.tsx | 4 +- .../components/forms/DateRangePicker.tsx | 4 +- .../views/audit/components/tabs/DirectTab.tsx | 4 +- .../audit/components/tabs/OmnichannelTab.tsx | 4 +- .../views/audit/components/tabs/RoomsTab.tsx | 4 +- .../views/audit/components/tabs/UsersTab.tsx | 4 +- .../AudioMessageRecorder.tsx | 4 +- .../composer/EmojiPicker/EmojiCategoryRow.tsx | 4 +- .../EmojiPicker/EmojiPickerCategoryItem.tsx | 4 +- .../composer/EmojiPicker/SearchingResult.tsx | 4 +- .../client/views/directory/RoomTags.tsx | 4 +- .../views/e2e/EnterE2EPasswordModal.tsx | 4 +- .../client/views/e2e/SaveE2EPasswordModal.tsx | 4 +- .../views/home/cards/DesktopAppsCard.tsx | 4 +- .../views/home/cards/DocumentationCard.tsx | 4 +- .../views/home/cards/MobileAppsCard.tsx | 4 +- .../AppDetailsPage/AppDetailsPageHeader.tsx | 4 +- .../tabs/AppDetails/AppDetails.tsx | 4 +- .../AppDetailsPage/tabs/AppLogs/AppLogs.tsx | 4 +- .../tabs/AppLogs/AppLogsItem.tsx | 4 +- .../tabs/AppLogs/AppLogsItemEntry.tsx | 4 +- .../tabs/AppReleases/AppReleasesItem.tsx | 4 +- .../tabs/AppSecurity/AppSecurity.tsx | 4 +- .../tabs/AppSettings/AppSettings.tsx | 4 +- .../tabs/AppStatus/AppStatusPriceDisplay.tsx | 6 +- .../client/views/marketplace/AppMenu.tsx | 4 +- .../marketplace/AppPermissionsReviewModal.tsx | 4 +- .../views/marketplace/AppUpdateModal.tsx | 4 +- .../marketplace/AppsPage/AppsFilters.tsx | 4 +- .../AppsPage/AppsPageConnectionError.tsx | 4 +- .../AppsPage/AppsPageContentBody.tsx | 4 +- .../AppsPage/FeaturedAppsSections.tsx | 6 +- .../AppsPage/NoAppRequestsEmptyState.tsx | 4 +- .../NoInstalledAppMatchesEmptyState.tsx | 4 +- .../AppsPage/NoInstalledAppsEmptyState.tsx | 4 +- ...etplaceOrInstalledAppMatchesEmptyState.tsx | 4 +- .../AppsPage/PrivateEmptyState.tsx | 4 +- .../client/views/marketplace/BundleChips.tsx | 4 +- .../client/views/marketplace/IframeModal.tsx | 4 +- .../marketplace/UnlimitedAppsUpsellModal.tsx | 4 +- .../AppInstallModal/AppInstallModal.tsx | 4 +- .../components/AppPermissionsList.tsx | 4 +- .../CategoryFilter/CategoryDropDownAnchor.tsx | 4 +- .../components/EnabledAppsCount.tsx | 4 +- .../UninstallGrandfatheredAppModal.tsx | 4 +- .../views/marketplace/hooks/useCategories.ts | 4 +- .../views/notAuthorized/NotAuthorizedPage.tsx | 4 +- .../client/views/notFound/NotFoundPage.tsx | 4 +- .../agents/AgentsTable/AgentsTable.tsx | 4 +- .../omnichannel/analytics/AnalyticsPage.tsx | 6 +- .../omnichannel/analytics/DateRangePicker.tsx | 4 +- .../appearance/AppearanceFieldLabel.tsx | 4 +- .../omnichannel/appearance/AppearanceForm.tsx | 4 +- .../businessHours/BusinessHoursForm.tsx | 4 +- .../contactHistory/ContactHistoryItem.tsx | 4 +- .../contactHistory/ContactHistoryList.tsx | 4 +- .../MessageList/ContactHistoryMessage.tsx | 4 +- .../DepartmentAgentsTable/AgentRow.tsx | 4 +- .../DepartmentAgentsTable.tsx | 4 +- .../departments/DepartmentTags.tsx | 4 +- .../directory/calls/CallTableRow.tsx | 4 +- .../calls/contextualBar/VoipInfo.tsx | 4 +- .../contextualBar/VoipInfoCallButton.tsx | 4 +- .../chats/contextualBar/DepartmentField.tsx | 4 +- .../RoomEdit/RoomEditWithData.tsx | 4 +- .../chats/contextualBar/VisitorClientInfo.js | 4 +- .../components/CallDialpadButton.tsx | 4 +- .../directory/components/PriorityField.tsx | 4 +- .../directory/components/SlaField.tsx | 4 +- .../directory/components/SourceField.tsx | 4 +- .../contextualBar/ContactEditWithData.js | 4 +- .../omnichannel/queueList/QueueListFilter.tsx | 4 +- .../omnichannel/queueList/QueueListPage.tsx | 4 +- .../RealTimeMonitoringPage.js | 4 +- .../charts/AgentStatusChart.tsx | 9 +- .../charts/ChatDurationChart.js | 4 +- .../realTimeMonitoring/charts/ChatsChart.tsx | 9 +- .../charts/ChatsPerAgentChart.js | 4 +- .../charts/ChatsPerDepartmentChart.js | 4 +- .../charts/ResponseTimesChart.js | 4 +- .../charts/useUpdateChartData.ts | 6 +- .../counter/CounterContainer.tsx | 4 +- .../omnichannel/triggers/ConditionForm.tsx | 4 +- .../triggers/actions/ActionForm.tsx | 4 +- .../triggers/actions/ActionSender.tsx | 4 +- .../actions/ExternalServiceActionForm.tsx | 4 +- .../actions/SendMessageActionForm.tsx | 4 +- .../OutlookSettingItem.tsx | 4 +- .../views/room/E2EESetup/RoomE2EESetup.tsx | 4 +- .../QuickActions/QuickActionOptions.tsx | 4 +- .../Omnichannel/QuickActions/QuickActions.tsx | 4 +- .../client/views/room/Header/RoomHeader.tsx | 4 +- .../RoomToolbox/RoomToolboxE2EESetup.tsx | 4 +- .../QuickActions/QuickActionOptions.tsx | 4 +- .../Omnichannel/QuickActions/QuickActions.tsx | 4 +- .../client/views/room/HeaderV2/RoomHeader.tsx | 4 +- .../client/views/room/HeaderV2/RoomLeader.tsx | 4 +- .../RoomToolbox/RoomToolboxE2EESetup.tsx | 4 +- .../MessageList/MessageListErrorBoundary.tsx | 4 +- .../room/MessageList/MessageListItem.tsx | 4 +- .../views/room/body/DropTargetOverlay.tsx | 4 +- .../body/ErroredUploadProgressIndicator.tsx | 4 +- .../client/views/room/body/LeaderBar.tsx | 4 +- .../room/body/RetentionPolicyWarning.tsx | 4 +- .../room/body/RoomForeword/RoomForeword.tsx | 4 +- .../room/body/UnreadMessagesIndicator.tsx | 4 +- .../room/body/UploadProgressIndicator.tsx | 4 +- .../views/room/composer/ComposerArchived.tsx | 4 +- .../views/room/composer/ComposerBlocked.tsx | 4 +- .../views/room/composer/ComposerBoxPopup.tsx | 4 +- .../composer/ComposerBoxPopupSlashCommand.tsx | 4 +- .../room/composer/ComposerBoxPopupUser.tsx | 4 +- .../ComposerFederationDisabled.tsx | 4 +- .../ComposerFederationJoinRoomDisabled.tsx | 4 +- .../ComposerOmnichannelOnHold.tsx | 4 +- .../ComposerUserActionIndicator.tsx | 4 +- .../views/room/composer/ComposerVoIP.tsx | 4 +- .../FormattingToolbarDropdown.tsx | 4 +- .../MessageBoxFormattingToolbar.tsx | 4 +- .../messageBox/hooks/useMediaActionTitle.ts | 4 +- .../AutoTranslate/AutoTranslate.tsx | 4 +- .../Discussions/DiscussionsListRow.tsx | 4 +- .../components/DiscussionsListItem.tsx | 4 +- .../ExportMessages/ExportMessages.tsx | 4 +- .../ExportMessages/FileExport.tsx | 4 +- .../ExportMessages/MailExportForm.tsx | 4 +- .../ChannelToTeamConfirmation.tsx | 4 +- .../ChannelToTeamSelection.tsx | 4 +- .../contextualBar/Info/RoomInfo/RoomInfo.tsx | 4 +- .../Info/hooks/useRoomActions.ts | 4 +- .../KeyboardShortcuts/KeyboardShortcuts.tsx | 4 +- .../MessageSearchTab/MessageSearchTab.tsx | 4 +- .../components/MessageSearchForm.tsx | 4 +- .../NotificationPreferences.tsx | 4 +- .../NotificationPreferencesForm.tsx | 4 +- .../views/room/contextualBar/OTR/OTR.tsx | 4 +- .../OTR/components/OTREstablished.tsx | 4 +- .../OTR/components/OTRStates.tsx | 4 +- .../PruneMessages/PruneMessages.tsx | 4 +- .../contextualBar/RoomFiles/RoomFiles.tsx | 4 +- .../InviteUsers/EditInviteLink.tsx | 4 +- .../RoomMembers/InviteUsers/InviteLink.tsx | 4 +- .../RoomMembers/InviteUsers/InviteUsers.tsx | 4 +- .../RoomMembers/RoomMembersActions.tsx | 4 +- .../Threads/components/ThreadListMessage.tsx | 4 +- .../Threads/components/ThreadMessageItem.tsx | 4 +- .../UserInfo/UserInfoActions.tsx | 4 +- .../VideoConference/VideoConfConfigModal.tsx | 4 +- .../VideoConfList/VideoConfList.tsx | 4 +- .../VideoConfPopup/IncomingPopup.tsx | 4 +- .../VideoConfPopup/OutgoingPopup.tsx | 4 +- .../VideoConfPopup/StartCallPopup.tsx | 4 +- .../modals/FileUploadModal/MediaPreview.tsx | 4 +- .../ReactionListModal/ReactionListModal.tsx | 4 +- .../FilePickerBreadcrumbs.tsx | 4 +- .../WebdavFilePickerTable.tsx | 4 +- .../ChannelDesertionTable.tsx | 4 +- .../ModalSteps/FirstStep.tsx | 4 +- .../ModalSteps/SecondStep.tsx | 4 +- .../channels/TeamsChannelItemMenu.tsx | 4 +- .../contextualBar/channels/TeamsChannels.tsx | 4 +- .../ChannelDeletionTable.tsx | 4 +- .../info/DeleteTeam/DeleteTeamChannels.tsx | 4 +- .../DeleteTeam/DeleteTeamConfirmation.tsx | 4 +- .../LeaveTeamModal/LeaveTeamModalChannels.tsx | 4 +- .../LeaveTeamModalConfirmation.tsx | 4 +- .../teams/contextualBar/info/TeamsInfo.tsx | 4 +- .../RemoveUsersModal/RemoveUsersFirstStep.js | 4 +- .../RemoveUsersModal/RemoveUsersSecondStep.js | 4 +- .../client/voip/modal/DialPad/DialInput.tsx | 4 +- .../voip/modal/DialPad/hooks/useDialPad.tsx | 4 +- apps/meteor/package.json | 4 +- .../EmailInbox/EmailInbox_Incoming.ts | 2 +- .../EmailInbox/EmailInbox_Outgoing.ts | 2 +- apps/meteor/server/lib/i18n.ts | 11 - apps/meteor/server/lib/resetUserE2EKey.ts | 2 +- .../modules/core-apps/mention.module.ts | 44 +- .../services/omnichannel-analytics/service.ts | 2 +- package.json | 3 +- packages/fuselage-ui-kit/package.json | 4 +- packages/gazzodown/package.json | 47 +-- packages/gazzodown/src/elements/LinkSpan.tsx | 4 +- packages/gazzodown/src/elements/PlainSpan.tsx | 4 +- .../src/mentions/ChannelMentionElement.tsx | 4 +- .../src/mentions/UserMentionElement.tsx | 4 +- packages/i18n/jest.config.ts | 2 +- packages/i18n/package.json | 31 +- packages/i18n/src/index.mjs | 14 +- packages/jest-presets/package.json | 2 +- packages/livechat/package.json | 4 +- packages/mock-providers/package.json | 4 +- packages/ui-client/package.json | 34 +- .../src/components/CustomFieldsForm.tsx | 4 +- .../GenericMenu/GenericMenu.spec.tsx | 7 +- .../components/GenericMenu/GenericMenu.tsx | 10 +- .../MultiSelectCustomAnchor.tsx | 4 +- .../MultiSelectCustomList.tsx | 4 +- .../MultiSelectCustom/useFilteredOptions.tsx | 4 +- .../src/components/UserStatus/UserStatus.tsx | 4 +- packages/web-ui-registration/package.json | 8 +- .../src/SecretRegisterInvalidForm.tsx | 4 +- yarn.lock | 380 ++++++------------ 425 files changed, 1208 insertions(+), 1238 deletions(-) create mode 100644 .yarn/patches/react-i18next-npm-15.0.1-0812bb73aa.patch diff --git a/.yarn/patches/react-i18next-npm-15.0.1-0812bb73aa.patch b/.yarn/patches/react-i18next-npm-15.0.1-0812bb73aa.patch new file mode 100644 index 000000000000..cf5a292c0253 --- /dev/null +++ b/.yarn/patches/react-i18next-npm-15.0.1-0812bb73aa.patch @@ -0,0 +1,99 @@ +diff --git a/dist/amd/react-i18next.js b/dist/amd/react-i18next.js +index 115ef3cc362e5ce38e875f9b35dfd1fe687cfd6c..2ba1b4d54295eeff49c8c650f214d7875d9219a5 100644 +--- a/dist/amd/react-i18next.js ++++ b/dist/amd/react-i18next.js +@@ -495,7 +495,7 @@ define(['exports', 'react'], (function (exports, react) { 'use strict'; + } + addUsedNamespaces(namespaces) { + namespaces.forEach(ns => { +- this.usedNamespaces[ns] ??= true; ++ this.usedNamespaces[ns] = this.usedNamespaces[ns] ?? true; + }); + } + getUsedNamespaces() { +diff --git a/dist/amd/react-i18next.min.js b/dist/amd/react-i18next.min.js +index c54c9114869feb14df7855be24237f85d64fe7e4..0cc2b09d6db9bfc6f94dffff4b9e0f3fd9108510 100644 +--- a/dist/amd/react-i18next.min.js ++++ b/dist/amd/react-i18next.min.js +@@ -1 +1 @@ +-define(["exports","react"],(function(e,n){"use strict";function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var s=t({area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),a=/\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g;function i(e){var n={type:"tag",name:"",voidElement:!1,attrs:{},children:[]},t=e.match(/<\/?([^\s]+?)[/\s>]/);if(t&&(n.name=t[1],(s[t[1]]||"/"===e.charAt(e.length-2))&&(n.voidElement=!0),n.name.startsWith("!--"))){var i=e.indexOf("--\x3e");return{type:"comment",comment:-1!==i?e.slice(4,i):""}}for(var r=new RegExp(a),o=null;null!==(o=r.exec(e));)if(o[0].trim())if(o[1]){var l=o[1].trim(),c=[l,""];l.indexOf("=")>-1&&(c=l.split("=")),n.attrs[c[0]]=c[1],r.lastIndex--}else o[2]&&(n.attrs[o[2]]=o[3].trim().substring(1,o[3].length-1));return n}var r=/<[a-zA-Z0-9\-\!\/](?:"[^"]*"|'[^']*'|[^'">])*>/g,o=/^\s*$/,l=Object.create(null);var c=function(e,n){n||(n={}),n.components||(n.components=l);var t,s=[],a=[],c=-1,u=!1;if(0!==e.indexOf("<")){var p=e.indexOf("<");s.push({type:"text",content:-1===p?e:e.substring(0,p)})}return e.replace(r,(function(r,l){if(u){if(r!=="")return;u=!1}var p,d="/"!==r.charAt(1),f=r.startsWith("\x3c!--"),h=l+r.length,m=e.charAt(h);if(f){var g=i(r);return c<0?(s.push(g),s):((p=a[c]).children.push(g),s)}if(d&&(c++,"tag"===(t=i(r)).type&&n.components[t.name]&&(t.type="component",u=!0),t.voidElement||u||!m||"<"===m||t.children.push({type:"text",content:e.slice(h,e.indexOf("<",h))}),0===c&&s.push(t),(p=a[c-1])&&p.children.push(t),a[c]=t),(!d||t.voidElement)&&(c>-1&&(t.voidElement||t.name===r.slice(2,-1))&&(c--,t=-1===c?s:a[c]),!u&&"<"!==m&&m)){p=-1===c?s:a[c].children;var y=e.indexOf("<",h),v=e.slice(h,-1===y?void 0:y);o.test(v)&&(v=" "),(y>-1&&c+p.length>=0||" "!==v)&&p.push({type:"text",content:v})}})),s};const u=function(){if(console?.warn){for(var e=arguments.length,n=new Array(e),t=0;t()=>{if(e.isInitialized)n();else{const t=()=>{setTimeout((()=>{e.off("initialized",t)}),0),n()};e.on("initialized",t)}},h=(e,n,t)=>{e.loadNamespaces(n,f(e,t))},m=(e,n,t,s)=>{y(t)&&(t=[t]),t.forEach((n=>{e.options.ns.indexOf(n)<0&&e.options.ns.push(n)})),e.loadLanguages(n,f(e,s))},g=e=>e.displayName||e.name||(y(e)&&e.length>0?e:"Unknown"),y=e=>"string"==typeof e,v=e=>"object"==typeof e&&null!==e,x=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,b={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},E=e=>b[e];let O={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:e=>e.replace(x,E)};const N=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};O={...O,...e}},$=()=>O;let w;const I=e=>{w=e},k=()=>w,S=(e,n)=>{if(!e)return!1;const t=e.props?.children??e.children;return n?t.length>0:!!t},j=e=>{if(!e)return[];const n=e.props?.children??e.children;return e.props?.i18nIsDynamicList?R(n):n},R=e=>Array.isArray(e)?e:[e],C=(e,t)=>{if(!e)return"";let s="";const a=R(e),i=t?.transSupportBasicHtmlNodes?t.transKeepBasicHtmlNodesFor??[]:[];return a.forEach(((e,a)=>{if(y(e))s+=`${e}`;else if(n.isValidElement(e)){const{props:n,type:r}=e,o=Object.keys(n).length,l=i.indexOf(r)>-1,c=n.children;if(c||!l||o)if(!c&&(!l||o)||n.i18nIsDynamicList)s+=`<${a}>`;else if(l&&1===o&&y(c))s+=`<${r}>${c}`;else{const e=C(c,t);s+=`<${a}>${e}`}else s+=`<${r}/>`}else if(null===e)u("Trans: the passed in value is invalid - seems you passed in a null child.");else if(v(e)){const{format:n,...t}=e,a=Object.keys(t);if(1===a.length){const e=n?`${a[0]}, ${n}`:a[0];s+=`{{${e}}}`}else u("react-i18next: the passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.",e)}else u("Trans: the passed in value is invalid - seems you passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}.",e)})),s},T=(e,t,s,a,i,r)=>{if(""===t)return[];const o=a.transKeepBasicHtmlNodesFor||[],l=t&&new RegExp(o.map((e=>`<${e}`)).join("|")).test(t);if(!e&&!l&&!r)return[t];const u={},p=e=>{R(e).forEach((e=>{y(e)||(S(e)?p(j(e)):v(e)&&!n.isValidElement(e)&&Object.assign(u,e))}))};p(e);const d=c(`<0>${t}`),f={...u,...i},h=(e,t,s)=>{const a=j(e),i=g(a,t.children,s);return(e=>Array.isArray(e)&&e.every(n.isValidElement))(a)&&0===i.length||e.props?.i18nIsDynamicList?a:i},m=(e,t,s,a,i)=>{e.dummy?(e.children=t,s.push(n.cloneElement(e,{key:a},i?void 0:t))):s.push(...n.Children.map([e],(e=>{const s={...e.props};return delete s.i18nIsDynamicList,n.createElement(e.type,{...s,key:a,ref:e.ref},i?null:t)})))},g=(t,i,c)=>{const u=R(t);return R(i).reduce(((t,i,p)=>{const d=i.children?.[0]?.content&&s.services.interpolator.interpolate(i.children[0].content,f,s.language);if("tag"===i.type){let r=u[parseInt(i.name,10)];1!==c.length||r||(r=c[0][i.name]),r||(r={});const x=0!==Object.keys(i.attrs).length?((e,n)=>{const t={...n};return t.props=Object.assign(e.props,n.props),t})({props:i.attrs},r):r,b=n.isValidElement(x),E=b&&S(i,!0)&&!i.voidElement,O=l&&v(x)&&x.dummy&&!b,N=v(e)&&Object.hasOwnProperty.call(e,i.name);if(y(x)){const e=s.services.interpolator.interpolate(x,f,s.language);t.push(e)}else if(S(x)||E){const e=h(x,i,c);m(x,e,t,p)}else if(O){const e=g(u,i.children,c);m(x,e,t,p)}else if(Number.isNaN(parseFloat(i.name)))if(N){const e=h(x,i,c);m(x,e,t,p,i.voidElement)}else if(a.transSupportBasicHtmlNodes&&o.indexOf(i.name)>-1)if(i.voidElement)t.push(n.createElement(i.name,{key:`${i.name}-${p}`}));else{const e=g(u,i.children,c);t.push(n.createElement(i.name,{key:`${i.name}-${p}`},e))}else if(i.voidElement)t.push(`<${i.name} />`);else{const e=g(u,i.children,c);t.push(`<${i.name}>${e}`)}else if(v(x)&&!b){const e=i.children[0]?d:null;e&&t.push(e)}else m(x,d,t,p,1!==i.children.length||!d)}else if("text"===i.type){const e=a.transWrapTextNodes,o=r?a.unescape(s.services.interpolator.interpolate(i.content,f,s.language)):s.services.interpolator.interpolate(i.content,f,s.language);e?t.push(n.createElement(e,{key:`${i.name}-${p}`},o)):t.push(o)}return t}),[])},x=g([{dummy:!0,children:e||[]}],d,R(e||[]));return j(x[0])};function P(e){let{children:t,count:s,parent:a,i18nKey:i,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:f,t:h,shouldUnescape:m,...g}=e;const v=f||k();if(!v)return d("You will need to pass in an i18next instance by using i18nextReactModule"),t;const x=h||v.t.bind(v)||(e=>e),b={...$(),...v.options?.react};let E=p||x.ns||v.options?.defaultNS;E=y(E)?[E]:E||["translation"];const O=C(t,b),N=c||O||b.transEmptyNodeValue||i,{hashTransKey:w}=b,I=i||(w?w(O||N):O||N);v.options?.interpolation?.defaultVariables&&(l=l&&Object.keys(l).length>0?{...l,...v.options.interpolation.defaultVariables}:{...v.options.interpolation.defaultVariables});const S=l||void 0!==s||!t?o.interpolation:{interpolation:{...o.interpolation,prefix:"#$?",suffix:"?$#"}},j={...o,context:r||o.context,count:s,...l,...S,defaultValue:N,ns:E},R=I?x(I,j):N;u&&Object.keys(u).forEach((e=>{const t=u[e];"function"==typeof t.type||!t.props||!t.props.children||R.indexOf(`${e}/>`)<0&&R.indexOf(`${e} />`)<0||(u[e]=n.createElement((function(){return n.createElement(n.Fragment,null,t)})))}));const P=T(u||t,R,v,b,j,m),L=a??b.defaultTransParent;return L?n.createElement(L,g,P):P}const L={type:"3rdParty",init(e){N(e.options.react),I(e)}},A=n.createContext();class V{constructor(){this.usedNamespaces={}}addUsedNamespaces(e){e.forEach((e=>{this.usedNamespaces[e]??=!0}))}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}const z=e=>async n=>({...await(e.getInitialProps?.(n))??{},...F()}),F=()=>{const e=k(),n=e.reportNamespaces?.getUsedNamespaces()??[],t={},s={};return e.languages.forEach((t=>{s[t]={},n.forEach((n=>{s[t][n]=e.getResourceBundle(t,n)||{}}))})),t.initialI18nStore=s,t.initialLanguage=e.language,t};const U=(e,n,t,s)=>e.getFixedT(n,t,s),B=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{i18n:s}=t,{i18n:a,defaultNS:i}=n.useContext(A)||{},r=s||a||k();if(r&&!r.reportNamespaces&&(r.reportNamespaces=new V),!r){d("You will need to pass in an i18next instance by using initReactI18next");const e=(e,n)=>y(n)?n:v(n)&&y(n.defaultValue)?n.defaultValue:Array.isArray(e)?e[e.length-1]:e,n=[e,{},!1];return n.t=e,n.i18n={},n.ready=!1,n}r.options.react?.wait&&d("It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.");const o={...$(),...r.options.react,...t},{useSuspense:l,keyPrefix:c}=o;let u=e||i||r.options?.defaultNS;u=y(u)?[u]:u||["translation"],r.reportNamespaces.addUsedNamespaces?.(u);const p=(r.isInitialized||r.initializedStoreOnce)&&u.every((e=>function(e,n){let t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return n.languages&&n.languages.length?n.hasLoadedNamespace(e,{lng:t.lng,precheck:(n,s)=>{if(t.bindI18n?.indexOf("languageChanging")>-1&&n.services.backendConnector.backend&&n.isLanguageChangingTo&&!s(n.isLanguageChangingTo,e))return!1}}):(d("i18n.languages were undefined or empty",n.languages),!0)}(e,r,o))),f=((e,t,s,a)=>n.useCallback(U(e,t,s,a),[e,t,s,a]))(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),g=()=>f,x=()=>U(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),[b,E]=n.useState(g);let O=u.join();t.lng&&(O=`${t.lng}${O}`);const N=((e,t)=>{const s=n.useRef();return n.useEffect((()=>{s.current=e}),[e,t]),s.current})(O),w=n.useRef(!0);n.useEffect((()=>{const{bindI18n:e,bindI18nStore:n}=o;w.current=!0,p||l||(t.lng?m(r,t.lng,u,(()=>{w.current&&E(x)})):h(r,u,(()=>{w.current&&E(x)}))),p&&N&&N!==O&&w.current&&E(x);const s=()=>{w.current&&E(x)};return e&&r?.on(e,s),n&&r?.store.on(n,s),()=>{w.current=!1,r&&e?.split(" ").forEach((e=>r.off(e,s))),n&&r&&n.split(" ").forEach((e=>r.store.off(e,s)))}}),[r,O]),n.useEffect((()=>{w.current&&p&&E(g)}),[r,c,p]);const I=[b,r,p];if(I.t=b,I.i18n=r,I.ready=p,p)return I;if(!p&&!l)return I;throw new Promise((e=>{t.lng?m(r,t.lng,u,(()=>e())):h(r,u,(()=>e()))}))};const D=function(e,t){let s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{i18n:a}=s,{i18n:i}=n.useContext(A)||{},r=a||i||k();r.options?.isClone||(e&&!r.initializedStoreOnce&&(r.services.resourceStore.data=e,r.options.ns=Object.values(e).reduce(((e,n)=>(Object.keys(n).forEach((n=>{e.indexOf(n)<0&&e.push(n)})),e)),r.options.ns),r.initializedStoreOnce=!0,r.isInitialized=!0),t&&!r.initializedLanguageOnce&&(r.changeLanguage(t),r.initializedLanguageOnce=!0))};e.I18nContext=A,e.I18nextProvider=function(e){let{i18n:t,defaultNS:s,children:a}=e;const i=n.useMemo((()=>({i18n:t,defaultNS:s})),[t,s]);return n.createElement(A.Provider,{value:i},a)},e.Trans=function(e){let{children:t,count:s,parent:a,i18nKey:i,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:d,t:f,shouldUnescape:h,...m}=e;const{i18n:g,defaultNS:y}=n.useContext(A)||{},v=d||g||k(),x=f||v?.t.bind(v);return P({children:t,count:s,parent:a,i18nKey:i,context:r,tOptions:o,values:l,defaults:c,components:u,ns:p||x?.ns||y||v?.options?.defaultNS,i18n:v,t:f,shouldUnescape:h,...m})},e.TransWithoutContext=P,e.Translation=e=>{let{ns:n,children:t,...s}=e;const[a,i,r]=B(n,s);return t(a,{i18n:i,lng:i.language},r)},e.composeInitialProps=z,e.date=()=>"",e.getDefaults=$,e.getI18n=k,e.getInitialProps=F,e.initReactI18next=L,e.number=()=>"",e.plural=()=>"",e.select=()=>"",e.selectOrdinal=()=>"",e.setDefaults=N,e.setI18n=I,e.time=()=>"",e.useSSR=D,e.useTranslation=B,e.withSSR=()=>function(e){function t(t){let{initialI18nStore:s,initialLanguage:a,...i}=t;return D(s,a),n.createElement(e,{...i})}return t.getInitialProps=z(e),t.displayName=`withI18nextSSR(${g(e)})`,t.WrappedComponent=e,t},e.withTranslation=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(s){function a(a){let{forwardedRef:i,...r}=a;const[o,l,c]=B(e,{...r,keyPrefix:t.keyPrefix}),u={...r,t:o,i18n:l,tReady:c};return t.withRef&&i?u.ref=i:!t.withRef&&i&&(u.forwardedRef=i),n.createElement(s,u)}a.displayName=`withI18nextTranslation(${g(s)})`,a.WrappedComponent=s;return t.withRef?n.forwardRef(((e,t)=>n.createElement(a,Object.assign({},e,{forwardedRef:t})))):a}}})); ++define(["exports","react"],(function(e,n){"use strict";function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var s=t({area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),a=/\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g;function i(e){var n={type:"tag",name:"",voidElement:!1,attrs:{},children:[]},t=e.match(/<\/?([^\s]+?)[/\s>]/);if(t&&(n.name=t[1],(s[t[1]]||"/"===e.charAt(e.length-2))&&(n.voidElement=!0),n.name.startsWith("!--"))){var i=e.indexOf("--\x3e");return{type:"comment",comment:-1!==i?e.slice(4,i):""}}for(var r=new RegExp(a),o=null;null!==(o=r.exec(e));)if(o[0].trim())if(o[1]){var l=o[1].trim(),c=[l,""];l.indexOf("=")>-1&&(c=l.split("=")),n.attrs[c[0]]=c[1],r.lastIndex--}else o[2]&&(n.attrs[o[2]]=o[3].trim().substring(1,o[3].length-1));return n}var r=/<[a-zA-Z0-9\-\!\/](?:"[^"]*"|'[^']*'|[^'">])*>/g,o=/^\s*$/,l=Object.create(null);var c=function(e,n){n||(n={}),n.components||(n.components=l);var t,s=[],a=[],c=-1,u=!1;if(0!==e.indexOf("<")){var p=e.indexOf("<");s.push({type:"text",content:-1===p?e:e.substring(0,p)})}return e.replace(r,(function(r,l){if(u){if(r!=="")return;u=!1}var p,d="/"!==r.charAt(1),f=r.startsWith("\x3c!--"),h=l+r.length,m=e.charAt(h);if(f){var g=i(r);return c<0?(s.push(g),s):((p=a[c]).children.push(g),s)}if(d&&(c++,"tag"===(t=i(r)).type&&n.components[t.name]&&(t.type="component",u=!0),t.voidElement||u||!m||"<"===m||t.children.push({type:"text",content:e.slice(h,e.indexOf("<",h))}),0===c&&s.push(t),(p=a[c-1])&&p.children.push(t),a[c]=t),(!d||t.voidElement)&&(c>-1&&(t.voidElement||t.name===r.slice(2,-1))&&(c--,t=-1===c?s:a[c]),!u&&"<"!==m&&m)){p=-1===c?s:a[c].children;var y=e.indexOf("<",h),v=e.slice(h,-1===y?void 0:y);o.test(v)&&(v=" "),(y>-1&&c+p.length>=0||" "!==v)&&p.push({type:"text",content:v})}})),s};const u=function(){if(console?.warn){for(var e=arguments.length,n=new Array(e),t=0;t()=>{if(e.isInitialized)n();else{const t=()=>{setTimeout((()=>{e.off("initialized",t)}),0),n()};e.on("initialized",t)}},h=(e,n,t)=>{e.loadNamespaces(n,f(e,t))},m=(e,n,t,s)=>{y(t)&&(t=[t]),t.forEach((n=>{e.options.ns.indexOf(n)<0&&e.options.ns.push(n)})),e.loadLanguages(n,f(e,s))},g=e=>e.displayName||e.name||(y(e)&&e.length>0?e:"Unknown"),y=e=>"string"==typeof e,v=e=>"object"==typeof e&&null!==e,x=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,b={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},E=e=>b[e];let O={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:e=>e.replace(x,E)};const N=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};O={...O,...e}},$=()=>O;let w;const I=e=>{w=e},k=()=>w,S=(e,n)=>{if(!e)return!1;const t=e.props?.children??e.children;return n?t.length>0:!!t},j=e=>{if(!e)return[];const n=e.props?.children??e.children;return e.props?.i18nIsDynamicList?R(n):n},R=e=>Array.isArray(e)?e:[e],C=(e,t)=>{if(!e)return"";let s="";const a=R(e),i=t?.transSupportBasicHtmlNodes?t.transKeepBasicHtmlNodesFor??[]:[];return a.forEach(((e,a)=>{if(y(e))s+=`${e}`;else if(n.isValidElement(e)){const{props:n,type:r}=e,o=Object.keys(n).length,l=i.indexOf(r)>-1,c=n.children;if(c||!l||o)if(!c&&(!l||o)||n.i18nIsDynamicList)s+=`<${a}>`;else if(l&&1===o&&y(c))s+=`<${r}>${c}`;else{const e=C(c,t);s+=`<${a}>${e}`}else s+=`<${r}/>`}else if(null===e)u("Trans: the passed in value is invalid - seems you passed in a null child.");else if(v(e)){const{format:n,...t}=e,a=Object.keys(t);if(1===a.length){const e=n?`${a[0]}, ${n}`:a[0];s+=`{{${e}}}`}else u("react-i18next: the passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.",e)}else u("Trans: the passed in value is invalid - seems you passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}.",e)})),s},T=(e,t,s,a,i,r)=>{if(""===t)return[];const o=a.transKeepBasicHtmlNodesFor||[],l=t&&new RegExp(o.map((e=>`<${e}`)).join("|")).test(t);if(!e&&!l&&!r)return[t];const u={},p=e=>{R(e).forEach((e=>{y(e)||(S(e)?p(j(e)):v(e)&&!n.isValidElement(e)&&Object.assign(u,e))}))};p(e);const d=c(`<0>${t}`),f={...u,...i},h=(e,t,s)=>{const a=j(e),i=g(a,t.children,s);return(e=>Array.isArray(e)&&e.every(n.isValidElement))(a)&&0===i.length||e.props?.i18nIsDynamicList?a:i},m=(e,t,s,a,i)=>{e.dummy?(e.children=t,s.push(n.cloneElement(e,{key:a},i?void 0:t))):s.push(...n.Children.map([e],(e=>{const s={...e.props};return delete s.i18nIsDynamicList,n.createElement(e.type,{...s,key:a,ref:e.ref},i?null:t)})))},g=(t,i,c)=>{const u=R(t);return R(i).reduce(((t,i,p)=>{const d=i.children?.[0]?.content&&s.services.interpolator.interpolate(i.children[0].content,f,s.language);if("tag"===i.type){let r=u[parseInt(i.name,10)];1!==c.length||r||(r=c[0][i.name]),r||(r={});const x=0!==Object.keys(i.attrs).length?((e,n)=>{const t={...n};return t.props=Object.assign(e.props,n.props),t})({props:i.attrs},r):r,b=n.isValidElement(x),E=b&&S(i,!0)&&!i.voidElement,O=l&&v(x)&&x.dummy&&!b,N=v(e)&&Object.hasOwnProperty.call(e,i.name);if(y(x)){const e=s.services.interpolator.interpolate(x,f,s.language);t.push(e)}else if(S(x)||E){const e=h(x,i,c);m(x,e,t,p)}else if(O){const e=g(u,i.children,c);m(x,e,t,p)}else if(Number.isNaN(parseFloat(i.name)))if(N){const e=h(x,i,c);m(x,e,t,p,i.voidElement)}else if(a.transSupportBasicHtmlNodes&&o.indexOf(i.name)>-1)if(i.voidElement)t.push(n.createElement(i.name,{key:`${i.name}-${p}`}));else{const e=g(u,i.children,c);t.push(n.createElement(i.name,{key:`${i.name}-${p}`},e))}else if(i.voidElement)t.push(`<${i.name} />`);else{const e=g(u,i.children,c);t.push(`<${i.name}>${e}`)}else if(v(x)&&!b){const e=i.children[0]?d:null;e&&t.push(e)}else m(x,d,t,p,1!==i.children.length||!d)}else if("text"===i.type){const e=a.transWrapTextNodes,o=r?a.unescape(s.services.interpolator.interpolate(i.content,f,s.language)):s.services.interpolator.interpolate(i.content,f,s.language);e?t.push(n.createElement(e,{key:`${i.name}-${p}`},o)):t.push(o)}return t}),[])},x=g([{dummy:!0,children:e||[]}],d,R(e||[]));return j(x[0])};function P(e){let{children:t,count:s,parent:a,i18nKey:i,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:f,t:h,shouldUnescape:m,...g}=e;const v=f||k();if(!v)return d("You will need to pass in an i18next instance by using i18nextReactModule"),t;const x=h||v.t.bind(v)||(e=>e),b={...$(),...v.options?.react};let E=p||x.ns||v.options?.defaultNS;E=y(E)?[E]:E||["translation"];const O=C(t,b),N=c||O||b.transEmptyNodeValue||i,{hashTransKey:w}=b,I=i||(w?w(O||N):O||N);v.options?.interpolation?.defaultVariables&&(l=l&&Object.keys(l).length>0?{...l,...v.options.interpolation.defaultVariables}:{...v.options.interpolation.defaultVariables});const S=l||void 0!==s||!t?o.interpolation:{interpolation:{...o.interpolation,prefix:"#$?",suffix:"?$#"}},j={...o,context:r||o.context,count:s,...l,...S,defaultValue:N,ns:E},R=I?x(I,j):N;u&&Object.keys(u).forEach((e=>{const t=u[e];"function"==typeof t.type||!t.props||!t.props.children||R.indexOf(`${e}/>`)<0&&R.indexOf(`${e} />`)<0||(u[e]=n.createElement((function(){return n.createElement(n.Fragment,null,t)})))}));const P=T(u||t,R,v,b,j,m),L=a??b.defaultTransParent;return L?n.createElement(L,g,P):P}const L={type:"3rdParty",init(e){N(e.options.react),I(e)}},A=n.createContext();class V{constructor(){this.usedNamespaces={}}addUsedNamespaces(e){e.forEach((e=>{this.usedNamespaces[e]=this.usedNamespaces[e]??!0}))}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}const z=e=>async n=>({...await(e.getInitialProps?.(n))??{},...F()}),F=()=>{const e=k(),n=e.reportNamespaces?.getUsedNamespaces()??[],t={},s={};return e.languages.forEach((t=>{s[t]={},n.forEach((n=>{s[t][n]=e.getResourceBundle(t,n)||{}}))})),t.initialI18nStore=s,t.initialLanguage=e.language,t};const U=(e,n,t,s)=>e.getFixedT(n,t,s),B=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{i18n:s}=t,{i18n:a,defaultNS:i}=n.useContext(A)||{},r=s||a||k();if(r&&!r.reportNamespaces&&(r.reportNamespaces=new V),!r){d("You will need to pass in an i18next instance by using initReactI18next");const e=(e,n)=>y(n)?n:v(n)&&y(n.defaultValue)?n.defaultValue:Array.isArray(e)?e[e.length-1]:e,n=[e,{},!1];return n.t=e,n.i18n={},n.ready=!1,n}r.options.react?.wait&&d("It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.");const o={...$(),...r.options.react,...t},{useSuspense:l,keyPrefix:c}=o;let u=e||i||r.options?.defaultNS;u=y(u)?[u]:u||["translation"],r.reportNamespaces.addUsedNamespaces?.(u);const p=(r.isInitialized||r.initializedStoreOnce)&&u.every((e=>function(e,n){let t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return n.languages&&n.languages.length?n.hasLoadedNamespace(e,{lng:t.lng,precheck:(n,s)=>{if(t.bindI18n?.indexOf("languageChanging")>-1&&n.services.backendConnector.backend&&n.isLanguageChangingTo&&!s(n.isLanguageChangingTo,e))return!1}}):(d("i18n.languages were undefined or empty",n.languages),!0)}(e,r,o))),f=((e,t,s,a)=>n.useCallback(U(e,t,s,a),[e,t,s,a]))(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),g=()=>f,x=()=>U(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),[b,E]=n.useState(g);let O=u.join();t.lng&&(O=`${t.lng}${O}`);const N=((e,t)=>{const s=n.useRef();return n.useEffect((()=>{s.current=e}),[e,t]),s.current})(O),w=n.useRef(!0);n.useEffect((()=>{const{bindI18n:e,bindI18nStore:n}=o;w.current=!0,p||l||(t.lng?m(r,t.lng,u,(()=>{w.current&&E(x)})):h(r,u,(()=>{w.current&&E(x)}))),p&&N&&N!==O&&w.current&&E(x);const s=()=>{w.current&&E(x)};return e&&r?.on(e,s),n&&r?.store.on(n,s),()=>{w.current=!1,r&&e?.split(" ").forEach((e=>r.off(e,s))),n&&r&&n.split(" ").forEach((e=>r.store.off(e,s)))}}),[r,O]),n.useEffect((()=>{w.current&&p&&E(g)}),[r,c,p]);const I=[b,r,p];if(I.t=b,I.i18n=r,I.ready=p,p)return I;if(!p&&!l)return I;throw new Promise((e=>{t.lng?m(r,t.lng,u,(()=>e())):h(r,u,(()=>e()))}))};const D=function(e,t){let s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{i18n:a}=s,{i18n:i}=n.useContext(A)||{},r=a||i||k();r.options?.isClone||(e&&!r.initializedStoreOnce&&(r.services.resourceStore.data=e,r.options.ns=Object.values(e).reduce(((e,n)=>(Object.keys(n).forEach((n=>{e.indexOf(n)<0&&e.push(n)})),e)),r.options.ns),r.initializedStoreOnce=!0,r.isInitialized=!0),t&&!r.initializedLanguageOnce&&(r.changeLanguage(t),r.initializedLanguageOnce=!0))};e.I18nContext=A,e.I18nextProvider=function(e){let{i18n:t,defaultNS:s,children:a}=e;const i=n.useMemo((()=>({i18n:t,defaultNS:s})),[t,s]);return n.createElement(A.Provider,{value:i},a)},e.Trans=function(e){let{children:t,count:s,parent:a,i18nKey:i,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:d,t:f,shouldUnescape:h,...m}=e;const{i18n:g,defaultNS:y}=n.useContext(A)||{},v=d||g||k(),x=f||v?.t.bind(v);return P({children:t,count:s,parent:a,i18nKey:i,context:r,tOptions:o,values:l,defaults:c,components:u,ns:p||x?.ns||y||v?.options?.defaultNS,i18n:v,t:f,shouldUnescape:h,...m})},e.TransWithoutContext=P,e.Translation=e=>{let{ns:n,children:t,...s}=e;const[a,i,r]=B(n,s);return t(a,{i18n:i,lng:i.language},r)},e.composeInitialProps=z,e.date=()=>"",e.getDefaults=$,e.getI18n=k,e.getInitialProps=F,e.initReactI18next=L,e.number=()=>"",e.plural=()=>"",e.select=()=>"",e.selectOrdinal=()=>"",e.setDefaults=N,e.setI18n=I,e.time=()=>"",e.useSSR=D,e.useTranslation=B,e.withSSR=()=>function(e){function t(t){let{initialI18nStore:s,initialLanguage:a,...i}=t;return D(s,a),n.createElement(e,{...i})}return t.getInitialProps=z(e),t.displayName=`withI18nextSSR(${g(e)})`,t.WrappedComponent=e,t},e.withTranslation=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(s){function a(a){let{forwardedRef:i,...r}=a;const[o,l,c]=B(e,{...r,keyPrefix:t.keyPrefix}),u={...r,t:o,i18n:l,tReady:c};return t.withRef&&i?u.ref=i:!t.withRef&&i&&(u.forwardedRef=i),n.createElement(s,u)}a.displayName=`withI18nextTranslation(${g(s)})`,a.WrappedComponent=s;return t.withRef?n.forwardRef(((e,t)=>n.createElement(a,Object.assign({},e,{forwardedRef:t})))):a}}})); +diff --git a/dist/commonjs/context.js b/dist/commonjs/context.js +index 5c4506e4d3424e4ffd167fd5bb696dabd67b662b..dcc11b798da72771953acce3c1368f006c3c1478 100644 +--- a/dist/commonjs/context.js ++++ b/dist/commonjs/context.js +@@ -46,7 +46,7 @@ class ReportNamespaces { + } + addUsedNamespaces(namespaces) { + namespaces.forEach(ns => { +- this.usedNamespaces[ns] ??= true; ++ this.usedNamespaces[ns] = this.usedNamespaces[ns] ?? true; + }); + } + getUsedNamespaces() { +diff --git a/dist/es/context.js b/dist/es/context.js +index 89afe45d6cf480079598dd183521b32f28f77f06..a953078f44008ee751f51257536a31ceba2fd672 100644 +--- a/dist/es/context.js ++++ b/dist/es/context.js +@@ -10,7 +10,7 @@ export class ReportNamespaces { + } + addUsedNamespaces(namespaces) { + namespaces.forEach(ns => { +- this.usedNamespaces[ns] ??= true; ++ this.usedNamespaces[ns] = this.usedNamespaces[ns] ?? true; + }); + } + getUsedNamespaces() { +diff --git a/dist/umd/react-i18next.js b/dist/umd/react-i18next.js +index 3723bd7c0f5762bdb09e3226ac86ff255cbf9859..9178ae9f7cdb776f51a64ff6c79eed1d18fbd836 100644 +--- a/dist/umd/react-i18next.js ++++ b/dist/umd/react-i18next.js +@@ -499,7 +499,7 @@ + } + addUsedNamespaces(namespaces) { + namespaces.forEach(ns => { +- this.usedNamespaces[ns] ??= true; ++ this.usedNamespaces[ns] = this.usedNamespaces[ns] ?? true; + }); + } + getUsedNamespaces() { +diff --git a/dist/umd/react-i18next.min.js b/dist/umd/react-i18next.min.js +index 2eef624040aab6b4b9ba4699bf7e4777842bf0a2..69e17753d545df9dc26aa3411b477a4dff5e8361 100644 +--- a/dist/umd/react-i18next.min.js ++++ b/dist/umd/react-i18next.min.js +@@ -1 +1 @@ +-!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).ReactI18next={},e.React)}(this,(function(e,n){"use strict";function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var s=t({area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),i=/\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g;function a(e){var n={type:"tag",name:"",voidElement:!1,attrs:{},children:[]},t=e.match(/<\/?([^\s]+?)[/\s>]/);if(t&&(n.name=t[1],(s[t[1]]||"/"===e.charAt(e.length-2))&&(n.voidElement=!0),n.name.startsWith("!--"))){var a=e.indexOf("--\x3e");return{type:"comment",comment:-1!==a?e.slice(4,a):""}}for(var r=new RegExp(i),o=null;null!==(o=r.exec(e));)if(o[0].trim())if(o[1]){var l=o[1].trim(),c=[l,""];l.indexOf("=")>-1&&(c=l.split("=")),n.attrs[c[0]]=c[1],r.lastIndex--}else o[2]&&(n.attrs[o[2]]=o[3].trim().substring(1,o[3].length-1));return n}var r=/<[a-zA-Z0-9\-\!\/](?:"[^"]*"|'[^']*'|[^'">])*>/g,o=/^\s*$/,l=Object.create(null);var c=function(e,n){n||(n={}),n.components||(n.components=l);var t,s=[],i=[],c=-1,u=!1;if(0!==e.indexOf("<")){var p=e.indexOf("<");s.push({type:"text",content:-1===p?e:e.substring(0,p)})}return e.replace(r,(function(r,l){if(u){if(r!=="")return;u=!1}var p,d="/"!==r.charAt(1),f=r.startsWith("\x3c!--"),h=l+r.length,m=e.charAt(h);if(f){var g=a(r);return c<0?(s.push(g),s):((p=i[c]).children.push(g),s)}if(d&&(c++,"tag"===(t=a(r)).type&&n.components[t.name]&&(t.type="component",u=!0),t.voidElement||u||!m||"<"===m||t.children.push({type:"text",content:e.slice(h,e.indexOf("<",h))}),0===c&&s.push(t),(p=i[c-1])&&p.children.push(t),i[c]=t),(!d||t.voidElement)&&(c>-1&&(t.voidElement||t.name===r.slice(2,-1))&&(c--,t=-1===c?s:i[c]),!u&&"<"!==m&&m)){p=-1===c?s:i[c].children;var y=e.indexOf("<",h),x=e.slice(h,-1===y?void 0:y);o.test(x)&&(x=" "),(y>-1&&c+p.length>=0||" "!==x)&&p.push({type:"text",content:x})}})),s};const u=function(){if(console?.warn){for(var e=arguments.length,n=new Array(e),t=0;t()=>{if(e.isInitialized)n();else{const t=()=>{setTimeout((()=>{e.off("initialized",t)}),0),n()};e.on("initialized",t)}},h=(e,n,t)=>{e.loadNamespaces(n,f(e,t))},m=(e,n,t,s)=>{y(t)&&(t=[t]),t.forEach((n=>{e.options.ns.indexOf(n)<0&&e.options.ns.push(n)})),e.loadLanguages(n,f(e,s))},g=e=>e.displayName||e.name||(y(e)&&e.length>0?e:"Unknown"),y=e=>"string"==typeof e,x=e=>"object"==typeof e&&null!==e,b=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,v={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},E=e=>v[e];let O={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:e=>e.replace(b,E)};const N=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};O={...O,...e}},$=()=>O;let w;const I=e=>{w=e},k=()=>w,S=(e,n)=>{if(!e)return!1;const t=e.props?.children??e.children;return n?t.length>0:!!t},j=e=>{if(!e)return[];const n=e.props?.children??e.children;return e.props?.i18nIsDynamicList?R(n):n},R=e=>Array.isArray(e)?e:[e],T=(e,t)=>{if(!e)return"";let s="";const i=R(e),a=t?.transSupportBasicHtmlNodes?t.transKeepBasicHtmlNodesFor??[]:[];return i.forEach(((e,i)=>{if(y(e))s+=`${e}`;else if(n.isValidElement(e)){const{props:n,type:r}=e,o=Object.keys(n).length,l=a.indexOf(r)>-1,c=n.children;if(c||!l||o)if(!c&&(!l||o)||n.i18nIsDynamicList)s+=`<${i}>`;else if(l&&1===o&&y(c))s+=`<${r}>${c}`;else{const e=T(c,t);s+=`<${i}>${e}`}else s+=`<${r}/>`}else if(null===e)u("Trans: the passed in value is invalid - seems you passed in a null child.");else if(x(e)){const{format:n,...t}=e,i=Object.keys(t);if(1===i.length){const e=n?`${i[0]}, ${n}`:i[0];s+=`{{${e}}}`}else u("react-i18next: the passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.",e)}else u("Trans: the passed in value is invalid - seems you passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}.",e)})),s},C=(e,t,s,i,a,r)=>{if(""===t)return[];const o=i.transKeepBasicHtmlNodesFor||[],l=t&&new RegExp(o.map((e=>`<${e}`)).join("|")).test(t);if(!e&&!l&&!r)return[t];const u={},p=e=>{R(e).forEach((e=>{y(e)||(S(e)?p(j(e)):x(e)&&!n.isValidElement(e)&&Object.assign(u,e))}))};p(e);const d=c(`<0>${t}`),f={...u,...a},h=(e,t,s)=>{const i=j(e),a=g(i,t.children,s);return(e=>Array.isArray(e)&&e.every(n.isValidElement))(i)&&0===a.length||e.props?.i18nIsDynamicList?i:a},m=(e,t,s,i,a)=>{e.dummy?(e.children=t,s.push(n.cloneElement(e,{key:i},a?void 0:t))):s.push(...n.Children.map([e],(e=>{const s={...e.props};return delete s.i18nIsDynamicList,n.createElement(e.type,{...s,key:i,ref:e.ref},a?null:t)})))},g=(t,a,c)=>{const u=R(t);return R(a).reduce(((t,a,p)=>{const d=a.children?.[0]?.content&&s.services.interpolator.interpolate(a.children[0].content,f,s.language);if("tag"===a.type){let r=u[parseInt(a.name,10)];1!==c.length||r||(r=c[0][a.name]),r||(r={});const b=0!==Object.keys(a.attrs).length?((e,n)=>{const t={...n};return t.props=Object.assign(e.props,n.props),t})({props:a.attrs},r):r,v=n.isValidElement(b),E=v&&S(a,!0)&&!a.voidElement,O=l&&x(b)&&b.dummy&&!v,N=x(e)&&Object.hasOwnProperty.call(e,a.name);if(y(b)){const e=s.services.interpolator.interpolate(b,f,s.language);t.push(e)}else if(S(b)||E){const e=h(b,a,c);m(b,e,t,p)}else if(O){const e=g(u,a.children,c);m(b,e,t,p)}else if(Number.isNaN(parseFloat(a.name)))if(N){const e=h(b,a,c);m(b,e,t,p,a.voidElement)}else if(i.transSupportBasicHtmlNodes&&o.indexOf(a.name)>-1)if(a.voidElement)t.push(n.createElement(a.name,{key:`${a.name}-${p}`}));else{const e=g(u,a.children,c);t.push(n.createElement(a.name,{key:`${a.name}-${p}`},e))}else if(a.voidElement)t.push(`<${a.name} />`);else{const e=g(u,a.children,c);t.push(`<${a.name}>${e}`)}else if(x(b)&&!v){const e=a.children[0]?d:null;e&&t.push(e)}else m(b,d,t,p,1!==a.children.length||!d)}else if("text"===a.type){const e=i.transWrapTextNodes,o=r?i.unescape(s.services.interpolator.interpolate(a.content,f,s.language)):s.services.interpolator.interpolate(a.content,f,s.language);e?t.push(n.createElement(e,{key:`${a.name}-${p}`},o)):t.push(o)}return t}),[])},b=g([{dummy:!0,children:e||[]}],d,R(e||[]));return j(b[0])};function P(e){let{children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:f,t:h,shouldUnescape:m,...g}=e;const x=f||k();if(!x)return d("You will need to pass in an i18next instance by using i18nextReactModule"),t;const b=h||x.t.bind(x)||(e=>e),v={...$(),...x.options?.react};let E=p||b.ns||x.options?.defaultNS;E=y(E)?[E]:E||["translation"];const O=T(t,v),N=c||O||v.transEmptyNodeValue||a,{hashTransKey:w}=v,I=a||(w?w(O||N):O||N);x.options?.interpolation?.defaultVariables&&(l=l&&Object.keys(l).length>0?{...l,...x.options.interpolation.defaultVariables}:{...x.options.interpolation.defaultVariables});const S=l||void 0!==s||!t?o.interpolation:{interpolation:{...o.interpolation,prefix:"#$?",suffix:"?$#"}},j={...o,context:r||o.context,count:s,...l,...S,defaultValue:N,ns:E},R=I?b(I,j):N;u&&Object.keys(u).forEach((e=>{const t=u[e];"function"==typeof t.type||!t.props||!t.props.children||R.indexOf(`${e}/>`)<0&&R.indexOf(`${e} />`)<0||(u[e]=n.createElement((function(){return n.createElement(n.Fragment,null,t)})))}));const P=C(u||t,R,x,v,j,m),L=i??v.defaultTransParent;return L?n.createElement(L,g,P):P}const L={type:"3rdParty",init(e){N(e.options.react),I(e)}},A=n.createContext();class V{constructor(){this.usedNamespaces={}}addUsedNamespaces(e){e.forEach((e=>{this.usedNamespaces[e]??=!0}))}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}const z=e=>async n=>({...await(e.getInitialProps?.(n))??{},...F()}),F=()=>{const e=k(),n=e.reportNamespaces?.getUsedNamespaces()??[],t={},s={};return e.languages.forEach((t=>{s[t]={},n.forEach((n=>{s[t][n]=e.getResourceBundle(t,n)||{}}))})),t.initialI18nStore=s,t.initialLanguage=e.language,t};const U=(e,n,t,s)=>e.getFixedT(n,t,s),B=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{i18n:s}=t,{i18n:i,defaultNS:a}=n.useContext(A)||{},r=s||i||k();if(r&&!r.reportNamespaces&&(r.reportNamespaces=new V),!r){d("You will need to pass in an i18next instance by using initReactI18next");const e=(e,n)=>y(n)?n:x(n)&&y(n.defaultValue)?n.defaultValue:Array.isArray(e)?e[e.length-1]:e,n=[e,{},!1];return n.t=e,n.i18n={},n.ready=!1,n}r.options.react?.wait&&d("It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.");const o={...$(),...r.options.react,...t},{useSuspense:l,keyPrefix:c}=o;let u=e||a||r.options?.defaultNS;u=y(u)?[u]:u||["translation"],r.reportNamespaces.addUsedNamespaces?.(u);const p=(r.isInitialized||r.initializedStoreOnce)&&u.every((e=>function(e,n){let t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return n.languages&&n.languages.length?n.hasLoadedNamespace(e,{lng:t.lng,precheck:(n,s)=>{if(t.bindI18n?.indexOf("languageChanging")>-1&&n.services.backendConnector.backend&&n.isLanguageChangingTo&&!s(n.isLanguageChangingTo,e))return!1}}):(d("i18n.languages were undefined or empty",n.languages),!0)}(e,r,o))),f=((e,t,s,i)=>n.useCallback(U(e,t,s,i),[e,t,s,i]))(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),g=()=>f,b=()=>U(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),[v,E]=n.useState(g);let O=u.join();t.lng&&(O=`${t.lng}${O}`);const N=((e,t)=>{const s=n.useRef();return n.useEffect((()=>{s.current=e}),[e,t]),s.current})(O),w=n.useRef(!0);n.useEffect((()=>{const{bindI18n:e,bindI18nStore:n}=o;w.current=!0,p||l||(t.lng?m(r,t.lng,u,(()=>{w.current&&E(b)})):h(r,u,(()=>{w.current&&E(b)}))),p&&N&&N!==O&&w.current&&E(b);const s=()=>{w.current&&E(b)};return e&&r?.on(e,s),n&&r?.store.on(n,s),()=>{w.current=!1,r&&e?.split(" ").forEach((e=>r.off(e,s))),n&&r&&n.split(" ").forEach((e=>r.store.off(e,s)))}}),[r,O]),n.useEffect((()=>{w.current&&p&&E(g)}),[r,c,p]);const I=[v,r,p];if(I.t=v,I.i18n=r,I.ready=p,p)return I;if(!p&&!l)return I;throw new Promise((e=>{t.lng?m(r,t.lng,u,(()=>e())):h(r,u,(()=>e()))}))};const D=function(e,t){let s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{i18n:i}=s,{i18n:a}=n.useContext(A)||{},r=i||a||k();r.options?.isClone||(e&&!r.initializedStoreOnce&&(r.services.resourceStore.data=e,r.options.ns=Object.values(e).reduce(((e,n)=>(Object.keys(n).forEach((n=>{e.indexOf(n)<0&&e.push(n)})),e)),r.options.ns),r.initializedStoreOnce=!0,r.isInitialized=!0),t&&!r.initializedLanguageOnce&&(r.changeLanguage(t),r.initializedLanguageOnce=!0))};e.I18nContext=A,e.I18nextProvider=function(e){let{i18n:t,defaultNS:s,children:i}=e;const a=n.useMemo((()=>({i18n:t,defaultNS:s})),[t,s]);return n.createElement(A.Provider,{value:a},i)},e.Trans=function(e){let{children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:d,t:f,shouldUnescape:h,...m}=e;const{i18n:g,defaultNS:y}=n.useContext(A)||{},x=d||g||k(),b=f||x?.t.bind(x);return P({children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o,values:l,defaults:c,components:u,ns:p||b?.ns||y||x?.options?.defaultNS,i18n:x,t:f,shouldUnescape:h,...m})},e.TransWithoutContext=P,e.Translation=e=>{let{ns:n,children:t,...s}=e;const[i,a,r]=B(n,s);return t(i,{i18n:a,lng:a.language},r)},e.composeInitialProps=z,e.date=()=>"",e.getDefaults=$,e.getI18n=k,e.getInitialProps=F,e.initReactI18next=L,e.number=()=>"",e.plural=()=>"",e.select=()=>"",e.selectOrdinal=()=>"",e.setDefaults=N,e.setI18n=I,e.time=()=>"",e.useSSR=D,e.useTranslation=B,e.withSSR=()=>function(e){function t(t){let{initialI18nStore:s,initialLanguage:i,...a}=t;return D(s,i),n.createElement(e,{...a})}return t.getInitialProps=z(e),t.displayName=`withI18nextSSR(${g(e)})`,t.WrappedComponent=e,t},e.withTranslation=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(s){function i(i){let{forwardedRef:a,...r}=i;const[o,l,c]=B(e,{...r,keyPrefix:t.keyPrefix}),u={...r,t:o,i18n:l,tReady:c};return t.withRef&&a?u.ref=a:!t.withRef&&a&&(u.forwardedRef=a),n.createElement(s,u)}i.displayName=`withI18nextTranslation(${g(s)})`,i.WrappedComponent=s;return t.withRef?n.forwardRef(((e,t)=>n.createElement(i,Object.assign({},e,{forwardedRef:t})))):i}}})); ++!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).ReactI18next={},e.React)}(this,(function(e,n){"use strict";function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var s=t({area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),i=/\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g;function a(e){var n={type:"tag",name:"",voidElement:!1,attrs:{},children:[]},t=e.match(/<\/?([^\s]+?)[/\s>]/);if(t&&(n.name=t[1],(s[t[1]]||"/"===e.charAt(e.length-2))&&(n.voidElement=!0),n.name.startsWith("!--"))){var a=e.indexOf("--\x3e");return{type:"comment",comment:-1!==a?e.slice(4,a):""}}for(var r=new RegExp(i),o=null;null!==(o=r.exec(e));)if(o[0].trim())if(o[1]){var l=o[1].trim(),c=[l,""];l.indexOf("=")>-1&&(c=l.split("=")),n.attrs[c[0]]=c[1],r.lastIndex--}else o[2]&&(n.attrs[o[2]]=o[3].trim().substring(1,o[3].length-1));return n}var r=/<[a-zA-Z0-9\-\!\/](?:"[^"]*"|'[^']*'|[^'">])*>/g,o=/^\s*$/,l=Object.create(null);var c=function(e,n){n||(n={}),n.components||(n.components=l);var t,s=[],i=[],c=-1,u=!1;if(0!==e.indexOf("<")){var p=e.indexOf("<");s.push({type:"text",content:-1===p?e:e.substring(0,p)})}return e.replace(r,(function(r,l){if(u){if(r!=="")return;u=!1}var p,d="/"!==r.charAt(1),f=r.startsWith("\x3c!--"),h=l+r.length,m=e.charAt(h);if(f){var g=a(r);return c<0?(s.push(g),s):((p=i[c]).children.push(g),s)}if(d&&(c++,"tag"===(t=a(r)).type&&n.components[t.name]&&(t.type="component",u=!0),t.voidElement||u||!m||"<"===m||t.children.push({type:"text",content:e.slice(h,e.indexOf("<",h))}),0===c&&s.push(t),(p=i[c-1])&&p.children.push(t),i[c]=t),(!d||t.voidElement)&&(c>-1&&(t.voidElement||t.name===r.slice(2,-1))&&(c--,t=-1===c?s:i[c]),!u&&"<"!==m&&m)){p=-1===c?s:i[c].children;var y=e.indexOf("<",h),x=e.slice(h,-1===y?void 0:y);o.test(x)&&(x=" "),(y>-1&&c+p.length>=0||" "!==x)&&p.push({type:"text",content:x})}})),s};const u=function(){if(console?.warn){for(var e=arguments.length,n=new Array(e),t=0;t()=>{if(e.isInitialized)n();else{const t=()=>{setTimeout((()=>{e.off("initialized",t)}),0),n()};e.on("initialized",t)}},h=(e,n,t)=>{e.loadNamespaces(n,f(e,t))},m=(e,n,t,s)=>{y(t)&&(t=[t]),t.forEach((n=>{e.options.ns.indexOf(n)<0&&e.options.ns.push(n)})),e.loadLanguages(n,f(e,s))},g=e=>e.displayName||e.name||(y(e)&&e.length>0?e:"Unknown"),y=e=>"string"==typeof e,x=e=>"object"==typeof e&&null!==e,b=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,v={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},E=e=>v[e];let O={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:e=>e.replace(b,E)};const N=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};O={...O,...e}},$=()=>O;let w;const I=e=>{w=e},k=()=>w,S=(e,n)=>{if(!e)return!1;const t=e.props?.children??e.children;return n?t.length>0:!!t},j=e=>{if(!e)return[];const n=e.props?.children??e.children;return e.props?.i18nIsDynamicList?R(n):n},R=e=>Array.isArray(e)?e:[e],T=(e,t)=>{if(!e)return"";let s="";const i=R(e),a=t?.transSupportBasicHtmlNodes?t.transKeepBasicHtmlNodesFor??[]:[];return i.forEach(((e,i)=>{if(y(e))s+=`${e}`;else if(n.isValidElement(e)){const{props:n,type:r}=e,o=Object.keys(n).length,l=a.indexOf(r)>-1,c=n.children;if(c||!l||o)if(!c&&(!l||o)||n.i18nIsDynamicList)s+=`<${i}>`;else if(l&&1===o&&y(c))s+=`<${r}>${c}`;else{const e=T(c,t);s+=`<${i}>${e}`}else s+=`<${r}/>`}else if(null===e)u("Trans: the passed in value is invalid - seems you passed in a null child.");else if(x(e)){const{format:n,...t}=e,i=Object.keys(t);if(1===i.length){const e=n?`${i[0]}, ${n}`:i[0];s+=`{{${e}}}`}else u("react-i18next: the passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.",e)}else u("Trans: the passed in value is invalid - seems you passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}.",e)})),s},C=(e,t,s,i,a,r)=>{if(""===t)return[];const o=i.transKeepBasicHtmlNodesFor||[],l=t&&new RegExp(o.map((e=>`<${e}`)).join("|")).test(t);if(!e&&!l&&!r)return[t];const u={},p=e=>{R(e).forEach((e=>{y(e)||(S(e)?p(j(e)):x(e)&&!n.isValidElement(e)&&Object.assign(u,e))}))};p(e);const d=c(`<0>${t}`),f={...u,...a},h=(e,t,s)=>{const i=j(e),a=g(i,t.children,s);return(e=>Array.isArray(e)&&e.every(n.isValidElement))(i)&&0===a.length||e.props?.i18nIsDynamicList?i:a},m=(e,t,s,i,a)=>{e.dummy?(e.children=t,s.push(n.cloneElement(e,{key:i},a?void 0:t))):s.push(...n.Children.map([e],(e=>{const s={...e.props};return delete s.i18nIsDynamicList,n.createElement(e.type,{...s,key:i,ref:e.ref},a?null:t)})))},g=(t,a,c)=>{const u=R(t);return R(a).reduce(((t,a,p)=>{const d=a.children?.[0]?.content&&s.services.interpolator.interpolate(a.children[0].content,f,s.language);if("tag"===a.type){let r=u[parseInt(a.name,10)];1!==c.length||r||(r=c[0][a.name]),r||(r={});const b=0!==Object.keys(a.attrs).length?((e,n)=>{const t={...n};return t.props=Object.assign(e.props,n.props),t})({props:a.attrs},r):r,v=n.isValidElement(b),E=v&&S(a,!0)&&!a.voidElement,O=l&&x(b)&&b.dummy&&!v,N=x(e)&&Object.hasOwnProperty.call(e,a.name);if(y(b)){const e=s.services.interpolator.interpolate(b,f,s.language);t.push(e)}else if(S(b)||E){const e=h(b,a,c);m(b,e,t,p)}else if(O){const e=g(u,a.children,c);m(b,e,t,p)}else if(Number.isNaN(parseFloat(a.name)))if(N){const e=h(b,a,c);m(b,e,t,p,a.voidElement)}else if(i.transSupportBasicHtmlNodes&&o.indexOf(a.name)>-1)if(a.voidElement)t.push(n.createElement(a.name,{key:`${a.name}-${p}`}));else{const e=g(u,a.children,c);t.push(n.createElement(a.name,{key:`${a.name}-${p}`},e))}else if(a.voidElement)t.push(`<${a.name} />`);else{const e=g(u,a.children,c);t.push(`<${a.name}>${e}`)}else if(x(b)&&!v){const e=a.children[0]?d:null;e&&t.push(e)}else m(b,d,t,p,1!==a.children.length||!d)}else if("text"===a.type){const e=i.transWrapTextNodes,o=r?i.unescape(s.services.interpolator.interpolate(a.content,f,s.language)):s.services.interpolator.interpolate(a.content,f,s.language);e?t.push(n.createElement(e,{key:`${a.name}-${p}`},o)):t.push(o)}return t}),[])},b=g([{dummy:!0,children:e||[]}],d,R(e||[]));return j(b[0])};function P(e){let{children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:f,t:h,shouldUnescape:m,...g}=e;const x=f||k();if(!x)return d("You will need to pass in an i18next instance by using i18nextReactModule"),t;const b=h||x.t.bind(x)||(e=>e),v={...$(),...x.options?.react};let E=p||b.ns||x.options?.defaultNS;E=y(E)?[E]:E||["translation"];const O=T(t,v),N=c||O||v.transEmptyNodeValue||a,{hashTransKey:w}=v,I=a||(w?w(O||N):O||N);x.options?.interpolation?.defaultVariables&&(l=l&&Object.keys(l).length>0?{...l,...x.options.interpolation.defaultVariables}:{...x.options.interpolation.defaultVariables});const S=l||void 0!==s||!t?o.interpolation:{interpolation:{...o.interpolation,prefix:"#$?",suffix:"?$#"}},j={...o,context:r||o.context,count:s,...l,...S,defaultValue:N,ns:E},R=I?b(I,j):N;u&&Object.keys(u).forEach((e=>{const t=u[e];"function"==typeof t.type||!t.props||!t.props.children||R.indexOf(`${e}/>`)<0&&R.indexOf(`${e} />`)<0||(u[e]=n.createElement((function(){return n.createElement(n.Fragment,null,t)})))}));const P=C(u||t,R,x,v,j,m),L=i??v.defaultTransParent;return L?n.createElement(L,g,P):P}const L={type:"3rdParty",init(e){N(e.options.react),I(e)}},A=n.createContext();class V{constructor(){this.usedNamespaces={}}addUsedNamespaces(e){e.forEach((e=>{this.usedNamespaces[e]=this.usedNamespaces[e]??!0}))}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}const z=e=>async n=>({...await(e.getInitialProps?.(n))??{},...F()}),F=()=>{const e=k(),n=e.reportNamespaces?.getUsedNamespaces()??[],t={},s={};return e.languages.forEach((t=>{s[t]={},n.forEach((n=>{s[t][n]=e.getResourceBundle(t,n)||{}}))})),t.initialI18nStore=s,t.initialLanguage=e.language,t};const U=(e,n,t,s)=>e.getFixedT(n,t,s),B=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{i18n:s}=t,{i18n:i,defaultNS:a}=n.useContext(A)||{},r=s||i||k();if(r&&!r.reportNamespaces&&(r.reportNamespaces=new V),!r){d("You will need to pass in an i18next instance by using initReactI18next");const e=(e,n)=>y(n)?n:x(n)&&y(n.defaultValue)?n.defaultValue:Array.isArray(e)?e[e.length-1]:e,n=[e,{},!1];return n.t=e,n.i18n={},n.ready=!1,n}r.options.react?.wait&&d("It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.");const o={...$(),...r.options.react,...t},{useSuspense:l,keyPrefix:c}=o;let u=e||a||r.options?.defaultNS;u=y(u)?[u]:u||["translation"],r.reportNamespaces.addUsedNamespaces?.(u);const p=(r.isInitialized||r.initializedStoreOnce)&&u.every((e=>function(e,n){let t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return n.languages&&n.languages.length?n.hasLoadedNamespace(e,{lng:t.lng,precheck:(n,s)=>{if(t.bindI18n?.indexOf("languageChanging")>-1&&n.services.backendConnector.backend&&n.isLanguageChangingTo&&!s(n.isLanguageChangingTo,e))return!1}}):(d("i18n.languages were undefined or empty",n.languages),!0)}(e,r,o))),f=((e,t,s,i)=>n.useCallback(U(e,t,s,i),[e,t,s,i]))(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),g=()=>f,b=()=>U(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),[v,E]=n.useState(g);let O=u.join();t.lng&&(O=`${t.lng}${O}`);const N=((e,t)=>{const s=n.useRef();return n.useEffect((()=>{s.current=e}),[e,t]),s.current})(O),w=n.useRef(!0);n.useEffect((()=>{const{bindI18n:e,bindI18nStore:n}=o;w.current=!0,p||l||(t.lng?m(r,t.lng,u,(()=>{w.current&&E(b)})):h(r,u,(()=>{w.current&&E(b)}))),p&&N&&N!==O&&w.current&&E(b);const s=()=>{w.current&&E(b)};return e&&r?.on(e,s),n&&r?.store.on(n,s),()=>{w.current=!1,r&&e?.split(" ").forEach((e=>r.off(e,s))),n&&r&&n.split(" ").forEach((e=>r.store.off(e,s)))}}),[r,O]),n.useEffect((()=>{w.current&&p&&E(g)}),[r,c,p]);const I=[v,r,p];if(I.t=v,I.i18n=r,I.ready=p,p)return I;if(!p&&!l)return I;throw new Promise((e=>{t.lng?m(r,t.lng,u,(()=>e())):h(r,u,(()=>e()))}))};const D=function(e,t){let s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{i18n:i}=s,{i18n:a}=n.useContext(A)||{},r=i||a||k();r.options?.isClone||(e&&!r.initializedStoreOnce&&(r.services.resourceStore.data=e,r.options.ns=Object.values(e).reduce(((e,n)=>(Object.keys(n).forEach((n=>{e.indexOf(n)<0&&e.push(n)})),e)),r.options.ns),r.initializedStoreOnce=!0,r.isInitialized=!0),t&&!r.initializedLanguageOnce&&(r.changeLanguage(t),r.initializedLanguageOnce=!0))};e.I18nContext=A,e.I18nextProvider=function(e){let{i18n:t,defaultNS:s,children:i}=e;const a=n.useMemo((()=>({i18n:t,defaultNS:s})),[t,s]);return n.createElement(A.Provider,{value:a},i)},e.Trans=function(e){let{children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:d,t:f,shouldUnescape:h,...m}=e;const{i18n:g,defaultNS:y}=n.useContext(A)||{},x=d||g||k(),b=f||x?.t.bind(x);return P({children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o,values:l,defaults:c,components:u,ns:p||b?.ns||y||x?.options?.defaultNS,i18n:x,t:f,shouldUnescape:h,...m})},e.TransWithoutContext=P,e.Translation=e=>{let{ns:n,children:t,...s}=e;const[i,a,r]=B(n,s);return t(i,{i18n:a,lng:a.language},r)},e.composeInitialProps=z,e.date=()=>"",e.getDefaults=$,e.getI18n=k,e.getInitialProps=F,e.initReactI18next=L,e.number=()=>"",e.plural=()=>"",e.select=()=>"",e.selectOrdinal=()=>"",e.setDefaults=N,e.setI18n=I,e.time=()=>"",e.useSSR=D,e.useTranslation=B,e.withSSR=()=>function(e){function t(t){let{initialI18nStore:s,initialLanguage:i,...a}=t;return D(s,i),n.createElement(e,{...a})}return t.getInitialProps=z(e),t.displayName=`withI18nextSSR(${g(e)})`,t.WrappedComponent=e,t},e.withTranslation=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(s){function i(i){let{forwardedRef:a,...r}=i;const[o,l,c]=B(e,{...r,keyPrefix:t.keyPrefix}),u={...r,t:o,i18n:l,tReady:c};return t.withRef&&a?u.ref=a:!t.withRef&&a&&(u.forwardedRef=a),n.createElement(s,u)}i.displayName=`withI18nextTranslation(${g(s)})`,i.WrappedComponent=s;return t.withRef?n.forwardRef(((e,t)=>n.createElement(i,Object.assign({},e,{forwardedRef:t})))):i}}})); +diff --git a/react-i18next.js b/react-i18next.js +index 3723bd7c0f5762bdb09e3226ac86ff255cbf9859..9178ae9f7cdb776f51a64ff6c79eed1d18fbd836 100644 +--- a/react-i18next.js ++++ b/react-i18next.js +@@ -499,7 +499,7 @@ + } + addUsedNamespaces(namespaces) { + namespaces.forEach(ns => { +- this.usedNamespaces[ns] ??= true; ++ this.usedNamespaces[ns] = this.usedNamespaces[ns] ?? true; + }); + } + getUsedNamespaces() { +diff --git a/react-i18next.min.js b/react-i18next.min.js +index 2eef624040aab6b4b9ba4699bf7e4777842bf0a2..69e17753d545df9dc26aa3411b477a4dff5e8361 100644 +--- a/react-i18next.min.js ++++ b/react-i18next.min.js +@@ -1 +1 @@ +-!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).ReactI18next={},e.React)}(this,(function(e,n){"use strict";function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var s=t({area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),i=/\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g;function a(e){var n={type:"tag",name:"",voidElement:!1,attrs:{},children:[]},t=e.match(/<\/?([^\s]+?)[/\s>]/);if(t&&(n.name=t[1],(s[t[1]]||"/"===e.charAt(e.length-2))&&(n.voidElement=!0),n.name.startsWith("!--"))){var a=e.indexOf("--\x3e");return{type:"comment",comment:-1!==a?e.slice(4,a):""}}for(var r=new RegExp(i),o=null;null!==(o=r.exec(e));)if(o[0].trim())if(o[1]){var l=o[1].trim(),c=[l,""];l.indexOf("=")>-1&&(c=l.split("=")),n.attrs[c[0]]=c[1],r.lastIndex--}else o[2]&&(n.attrs[o[2]]=o[3].trim().substring(1,o[3].length-1));return n}var r=/<[a-zA-Z0-9\-\!\/](?:"[^"]*"|'[^']*'|[^'">])*>/g,o=/^\s*$/,l=Object.create(null);var c=function(e,n){n||(n={}),n.components||(n.components=l);var t,s=[],i=[],c=-1,u=!1;if(0!==e.indexOf("<")){var p=e.indexOf("<");s.push({type:"text",content:-1===p?e:e.substring(0,p)})}return e.replace(r,(function(r,l){if(u){if(r!=="")return;u=!1}var p,d="/"!==r.charAt(1),f=r.startsWith("\x3c!--"),h=l+r.length,m=e.charAt(h);if(f){var g=a(r);return c<0?(s.push(g),s):((p=i[c]).children.push(g),s)}if(d&&(c++,"tag"===(t=a(r)).type&&n.components[t.name]&&(t.type="component",u=!0),t.voidElement||u||!m||"<"===m||t.children.push({type:"text",content:e.slice(h,e.indexOf("<",h))}),0===c&&s.push(t),(p=i[c-1])&&p.children.push(t),i[c]=t),(!d||t.voidElement)&&(c>-1&&(t.voidElement||t.name===r.slice(2,-1))&&(c--,t=-1===c?s:i[c]),!u&&"<"!==m&&m)){p=-1===c?s:i[c].children;var y=e.indexOf("<",h),x=e.slice(h,-1===y?void 0:y);o.test(x)&&(x=" "),(y>-1&&c+p.length>=0||" "!==x)&&p.push({type:"text",content:x})}})),s};const u=function(){if(console?.warn){for(var e=arguments.length,n=new Array(e),t=0;t()=>{if(e.isInitialized)n();else{const t=()=>{setTimeout((()=>{e.off("initialized",t)}),0),n()};e.on("initialized",t)}},h=(e,n,t)=>{e.loadNamespaces(n,f(e,t))},m=(e,n,t,s)=>{y(t)&&(t=[t]),t.forEach((n=>{e.options.ns.indexOf(n)<0&&e.options.ns.push(n)})),e.loadLanguages(n,f(e,s))},g=e=>e.displayName||e.name||(y(e)&&e.length>0?e:"Unknown"),y=e=>"string"==typeof e,x=e=>"object"==typeof e&&null!==e,b=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,v={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},E=e=>v[e];let O={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:e=>e.replace(b,E)};const N=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};O={...O,...e}},$=()=>O;let w;const I=e=>{w=e},k=()=>w,S=(e,n)=>{if(!e)return!1;const t=e.props?.children??e.children;return n?t.length>0:!!t},j=e=>{if(!e)return[];const n=e.props?.children??e.children;return e.props?.i18nIsDynamicList?R(n):n},R=e=>Array.isArray(e)?e:[e],T=(e,t)=>{if(!e)return"";let s="";const i=R(e),a=t?.transSupportBasicHtmlNodes?t.transKeepBasicHtmlNodesFor??[]:[];return i.forEach(((e,i)=>{if(y(e))s+=`${e}`;else if(n.isValidElement(e)){const{props:n,type:r}=e,o=Object.keys(n).length,l=a.indexOf(r)>-1,c=n.children;if(c||!l||o)if(!c&&(!l||o)||n.i18nIsDynamicList)s+=`<${i}>`;else if(l&&1===o&&y(c))s+=`<${r}>${c}`;else{const e=T(c,t);s+=`<${i}>${e}`}else s+=`<${r}/>`}else if(null===e)u("Trans: the passed in value is invalid - seems you passed in a null child.");else if(x(e)){const{format:n,...t}=e,i=Object.keys(t);if(1===i.length){const e=n?`${i[0]}, ${n}`:i[0];s+=`{{${e}}}`}else u("react-i18next: the passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.",e)}else u("Trans: the passed in value is invalid - seems you passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}.",e)})),s},C=(e,t,s,i,a,r)=>{if(""===t)return[];const o=i.transKeepBasicHtmlNodesFor||[],l=t&&new RegExp(o.map((e=>`<${e}`)).join("|")).test(t);if(!e&&!l&&!r)return[t];const u={},p=e=>{R(e).forEach((e=>{y(e)||(S(e)?p(j(e)):x(e)&&!n.isValidElement(e)&&Object.assign(u,e))}))};p(e);const d=c(`<0>${t}`),f={...u,...a},h=(e,t,s)=>{const i=j(e),a=g(i,t.children,s);return(e=>Array.isArray(e)&&e.every(n.isValidElement))(i)&&0===a.length||e.props?.i18nIsDynamicList?i:a},m=(e,t,s,i,a)=>{e.dummy?(e.children=t,s.push(n.cloneElement(e,{key:i},a?void 0:t))):s.push(...n.Children.map([e],(e=>{const s={...e.props};return delete s.i18nIsDynamicList,n.createElement(e.type,{...s,key:i,ref:e.ref},a?null:t)})))},g=(t,a,c)=>{const u=R(t);return R(a).reduce(((t,a,p)=>{const d=a.children?.[0]?.content&&s.services.interpolator.interpolate(a.children[0].content,f,s.language);if("tag"===a.type){let r=u[parseInt(a.name,10)];1!==c.length||r||(r=c[0][a.name]),r||(r={});const b=0!==Object.keys(a.attrs).length?((e,n)=>{const t={...n};return t.props=Object.assign(e.props,n.props),t})({props:a.attrs},r):r,v=n.isValidElement(b),E=v&&S(a,!0)&&!a.voidElement,O=l&&x(b)&&b.dummy&&!v,N=x(e)&&Object.hasOwnProperty.call(e,a.name);if(y(b)){const e=s.services.interpolator.interpolate(b,f,s.language);t.push(e)}else if(S(b)||E){const e=h(b,a,c);m(b,e,t,p)}else if(O){const e=g(u,a.children,c);m(b,e,t,p)}else if(Number.isNaN(parseFloat(a.name)))if(N){const e=h(b,a,c);m(b,e,t,p,a.voidElement)}else if(i.transSupportBasicHtmlNodes&&o.indexOf(a.name)>-1)if(a.voidElement)t.push(n.createElement(a.name,{key:`${a.name}-${p}`}));else{const e=g(u,a.children,c);t.push(n.createElement(a.name,{key:`${a.name}-${p}`},e))}else if(a.voidElement)t.push(`<${a.name} />`);else{const e=g(u,a.children,c);t.push(`<${a.name}>${e}`)}else if(x(b)&&!v){const e=a.children[0]?d:null;e&&t.push(e)}else m(b,d,t,p,1!==a.children.length||!d)}else if("text"===a.type){const e=i.transWrapTextNodes,o=r?i.unescape(s.services.interpolator.interpolate(a.content,f,s.language)):s.services.interpolator.interpolate(a.content,f,s.language);e?t.push(n.createElement(e,{key:`${a.name}-${p}`},o)):t.push(o)}return t}),[])},b=g([{dummy:!0,children:e||[]}],d,R(e||[]));return j(b[0])};function P(e){let{children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:f,t:h,shouldUnescape:m,...g}=e;const x=f||k();if(!x)return d("You will need to pass in an i18next instance by using i18nextReactModule"),t;const b=h||x.t.bind(x)||(e=>e),v={...$(),...x.options?.react};let E=p||b.ns||x.options?.defaultNS;E=y(E)?[E]:E||["translation"];const O=T(t,v),N=c||O||v.transEmptyNodeValue||a,{hashTransKey:w}=v,I=a||(w?w(O||N):O||N);x.options?.interpolation?.defaultVariables&&(l=l&&Object.keys(l).length>0?{...l,...x.options.interpolation.defaultVariables}:{...x.options.interpolation.defaultVariables});const S=l||void 0!==s||!t?o.interpolation:{interpolation:{...o.interpolation,prefix:"#$?",suffix:"?$#"}},j={...o,context:r||o.context,count:s,...l,...S,defaultValue:N,ns:E},R=I?b(I,j):N;u&&Object.keys(u).forEach((e=>{const t=u[e];"function"==typeof t.type||!t.props||!t.props.children||R.indexOf(`${e}/>`)<0&&R.indexOf(`${e} />`)<0||(u[e]=n.createElement((function(){return n.createElement(n.Fragment,null,t)})))}));const P=C(u||t,R,x,v,j,m),L=i??v.defaultTransParent;return L?n.createElement(L,g,P):P}const L={type:"3rdParty",init(e){N(e.options.react),I(e)}},A=n.createContext();class V{constructor(){this.usedNamespaces={}}addUsedNamespaces(e){e.forEach((e=>{this.usedNamespaces[e]??=!0}))}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}const z=e=>async n=>({...await(e.getInitialProps?.(n))??{},...F()}),F=()=>{const e=k(),n=e.reportNamespaces?.getUsedNamespaces()??[],t={},s={};return e.languages.forEach((t=>{s[t]={},n.forEach((n=>{s[t][n]=e.getResourceBundle(t,n)||{}}))})),t.initialI18nStore=s,t.initialLanguage=e.language,t};const U=(e,n,t,s)=>e.getFixedT(n,t,s),B=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{i18n:s}=t,{i18n:i,defaultNS:a}=n.useContext(A)||{},r=s||i||k();if(r&&!r.reportNamespaces&&(r.reportNamespaces=new V),!r){d("You will need to pass in an i18next instance by using initReactI18next");const e=(e,n)=>y(n)?n:x(n)&&y(n.defaultValue)?n.defaultValue:Array.isArray(e)?e[e.length-1]:e,n=[e,{},!1];return n.t=e,n.i18n={},n.ready=!1,n}r.options.react?.wait&&d("It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.");const o={...$(),...r.options.react,...t},{useSuspense:l,keyPrefix:c}=o;let u=e||a||r.options?.defaultNS;u=y(u)?[u]:u||["translation"],r.reportNamespaces.addUsedNamespaces?.(u);const p=(r.isInitialized||r.initializedStoreOnce)&&u.every((e=>function(e,n){let t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return n.languages&&n.languages.length?n.hasLoadedNamespace(e,{lng:t.lng,precheck:(n,s)=>{if(t.bindI18n?.indexOf("languageChanging")>-1&&n.services.backendConnector.backend&&n.isLanguageChangingTo&&!s(n.isLanguageChangingTo,e))return!1}}):(d("i18n.languages were undefined or empty",n.languages),!0)}(e,r,o))),f=((e,t,s,i)=>n.useCallback(U(e,t,s,i),[e,t,s,i]))(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),g=()=>f,b=()=>U(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),[v,E]=n.useState(g);let O=u.join();t.lng&&(O=`${t.lng}${O}`);const N=((e,t)=>{const s=n.useRef();return n.useEffect((()=>{s.current=e}),[e,t]),s.current})(O),w=n.useRef(!0);n.useEffect((()=>{const{bindI18n:e,bindI18nStore:n}=o;w.current=!0,p||l||(t.lng?m(r,t.lng,u,(()=>{w.current&&E(b)})):h(r,u,(()=>{w.current&&E(b)}))),p&&N&&N!==O&&w.current&&E(b);const s=()=>{w.current&&E(b)};return e&&r?.on(e,s),n&&r?.store.on(n,s),()=>{w.current=!1,r&&e?.split(" ").forEach((e=>r.off(e,s))),n&&r&&n.split(" ").forEach((e=>r.store.off(e,s)))}}),[r,O]),n.useEffect((()=>{w.current&&p&&E(g)}),[r,c,p]);const I=[v,r,p];if(I.t=v,I.i18n=r,I.ready=p,p)return I;if(!p&&!l)return I;throw new Promise((e=>{t.lng?m(r,t.lng,u,(()=>e())):h(r,u,(()=>e()))}))};const D=function(e,t){let s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{i18n:i}=s,{i18n:a}=n.useContext(A)||{},r=i||a||k();r.options?.isClone||(e&&!r.initializedStoreOnce&&(r.services.resourceStore.data=e,r.options.ns=Object.values(e).reduce(((e,n)=>(Object.keys(n).forEach((n=>{e.indexOf(n)<0&&e.push(n)})),e)),r.options.ns),r.initializedStoreOnce=!0,r.isInitialized=!0),t&&!r.initializedLanguageOnce&&(r.changeLanguage(t),r.initializedLanguageOnce=!0))};e.I18nContext=A,e.I18nextProvider=function(e){let{i18n:t,defaultNS:s,children:i}=e;const a=n.useMemo((()=>({i18n:t,defaultNS:s})),[t,s]);return n.createElement(A.Provider,{value:a},i)},e.Trans=function(e){let{children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:d,t:f,shouldUnescape:h,...m}=e;const{i18n:g,defaultNS:y}=n.useContext(A)||{},x=d||g||k(),b=f||x?.t.bind(x);return P({children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o,values:l,defaults:c,components:u,ns:p||b?.ns||y||x?.options?.defaultNS,i18n:x,t:f,shouldUnescape:h,...m})},e.TransWithoutContext=P,e.Translation=e=>{let{ns:n,children:t,...s}=e;const[i,a,r]=B(n,s);return t(i,{i18n:a,lng:a.language},r)},e.composeInitialProps=z,e.date=()=>"",e.getDefaults=$,e.getI18n=k,e.getInitialProps=F,e.initReactI18next=L,e.number=()=>"",e.plural=()=>"",e.select=()=>"",e.selectOrdinal=()=>"",e.setDefaults=N,e.setI18n=I,e.time=()=>"",e.useSSR=D,e.useTranslation=B,e.withSSR=()=>function(e){function t(t){let{initialI18nStore:s,initialLanguage:i,...a}=t;return D(s,i),n.createElement(e,{...a})}return t.getInitialProps=z(e),t.displayName=`withI18nextSSR(${g(e)})`,t.WrappedComponent=e,t},e.withTranslation=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(s){function i(i){let{forwardedRef:a,...r}=i;const[o,l,c]=B(e,{...r,keyPrefix:t.keyPrefix}),u={...r,t:o,i18n:l,tReady:c};return t.withRef&&a?u.ref=a:!t.withRef&&a&&(u.forwardedRef=a),n.createElement(s,u)}i.displayName=`withI18nextTranslation(${g(s)})`,i.WrappedComponent=s;return t.withRef?n.forwardRef(((e,t)=>n.createElement(i,Object.assign({},e,{forwardedRef:t})))):i}}})); ++!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).ReactI18next={},e.React)}(this,(function(e,n){"use strict";function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var s=t({area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),i=/\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g;function a(e){var n={type:"tag",name:"",voidElement:!1,attrs:{},children:[]},t=e.match(/<\/?([^\s]+?)[/\s>]/);if(t&&(n.name=t[1],(s[t[1]]||"/"===e.charAt(e.length-2))&&(n.voidElement=!0),n.name.startsWith("!--"))){var a=e.indexOf("--\x3e");return{type:"comment",comment:-1!==a?e.slice(4,a):""}}for(var r=new RegExp(i),o=null;null!==(o=r.exec(e));)if(o[0].trim())if(o[1]){var l=o[1].trim(),c=[l,""];l.indexOf("=")>-1&&(c=l.split("=")),n.attrs[c[0]]=c[1],r.lastIndex--}else o[2]&&(n.attrs[o[2]]=o[3].trim().substring(1,o[3].length-1));return n}var r=/<[a-zA-Z0-9\-\!\/](?:"[^"]*"|'[^']*'|[^'">])*>/g,o=/^\s*$/,l=Object.create(null);var c=function(e,n){n||(n={}),n.components||(n.components=l);var t,s=[],i=[],c=-1,u=!1;if(0!==e.indexOf("<")){var p=e.indexOf("<");s.push({type:"text",content:-1===p?e:e.substring(0,p)})}return e.replace(r,(function(r,l){if(u){if(r!=="")return;u=!1}var p,d="/"!==r.charAt(1),f=r.startsWith("\x3c!--"),h=l+r.length,m=e.charAt(h);if(f){var g=a(r);return c<0?(s.push(g),s):((p=i[c]).children.push(g),s)}if(d&&(c++,"tag"===(t=a(r)).type&&n.components[t.name]&&(t.type="component",u=!0),t.voidElement||u||!m||"<"===m||t.children.push({type:"text",content:e.slice(h,e.indexOf("<",h))}),0===c&&s.push(t),(p=i[c-1])&&p.children.push(t),i[c]=t),(!d||t.voidElement)&&(c>-1&&(t.voidElement||t.name===r.slice(2,-1))&&(c--,t=-1===c?s:i[c]),!u&&"<"!==m&&m)){p=-1===c?s:i[c].children;var y=e.indexOf("<",h),x=e.slice(h,-1===y?void 0:y);o.test(x)&&(x=" "),(y>-1&&c+p.length>=0||" "!==x)&&p.push({type:"text",content:x})}})),s};const u=function(){if(console?.warn){for(var e=arguments.length,n=new Array(e),t=0;t()=>{if(e.isInitialized)n();else{const t=()=>{setTimeout((()=>{e.off("initialized",t)}),0),n()};e.on("initialized",t)}},h=(e,n,t)=>{e.loadNamespaces(n,f(e,t))},m=(e,n,t,s)=>{y(t)&&(t=[t]),t.forEach((n=>{e.options.ns.indexOf(n)<0&&e.options.ns.push(n)})),e.loadLanguages(n,f(e,s))},g=e=>e.displayName||e.name||(y(e)&&e.length>0?e:"Unknown"),y=e=>"string"==typeof e,x=e=>"object"==typeof e&&null!==e,b=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,v={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},E=e=>v[e];let O={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:e=>e.replace(b,E)};const N=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};O={...O,...e}},$=()=>O;let w;const I=e=>{w=e},k=()=>w,S=(e,n)=>{if(!e)return!1;const t=e.props?.children??e.children;return n?t.length>0:!!t},j=e=>{if(!e)return[];const n=e.props?.children??e.children;return e.props?.i18nIsDynamicList?R(n):n},R=e=>Array.isArray(e)?e:[e],T=(e,t)=>{if(!e)return"";let s="";const i=R(e),a=t?.transSupportBasicHtmlNodes?t.transKeepBasicHtmlNodesFor??[]:[];return i.forEach(((e,i)=>{if(y(e))s+=`${e}`;else if(n.isValidElement(e)){const{props:n,type:r}=e,o=Object.keys(n).length,l=a.indexOf(r)>-1,c=n.children;if(c||!l||o)if(!c&&(!l||o)||n.i18nIsDynamicList)s+=`<${i}>`;else if(l&&1===o&&y(c))s+=`<${r}>${c}`;else{const e=T(c,t);s+=`<${i}>${e}`}else s+=`<${r}/>`}else if(null===e)u("Trans: the passed in value is invalid - seems you passed in a null child.");else if(x(e)){const{format:n,...t}=e,i=Object.keys(t);if(1===i.length){const e=n?`${i[0]}, ${n}`:i[0];s+=`{{${e}}}`}else u("react-i18next: the passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.",e)}else u("Trans: the passed in value is invalid - seems you passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}.",e)})),s},C=(e,t,s,i,a,r)=>{if(""===t)return[];const o=i.transKeepBasicHtmlNodesFor||[],l=t&&new RegExp(o.map((e=>`<${e}`)).join("|")).test(t);if(!e&&!l&&!r)return[t];const u={},p=e=>{R(e).forEach((e=>{y(e)||(S(e)?p(j(e)):x(e)&&!n.isValidElement(e)&&Object.assign(u,e))}))};p(e);const d=c(`<0>${t}`),f={...u,...a},h=(e,t,s)=>{const i=j(e),a=g(i,t.children,s);return(e=>Array.isArray(e)&&e.every(n.isValidElement))(i)&&0===a.length||e.props?.i18nIsDynamicList?i:a},m=(e,t,s,i,a)=>{e.dummy?(e.children=t,s.push(n.cloneElement(e,{key:i},a?void 0:t))):s.push(...n.Children.map([e],(e=>{const s={...e.props};return delete s.i18nIsDynamicList,n.createElement(e.type,{...s,key:i,ref:e.ref},a?null:t)})))},g=(t,a,c)=>{const u=R(t);return R(a).reduce(((t,a,p)=>{const d=a.children?.[0]?.content&&s.services.interpolator.interpolate(a.children[0].content,f,s.language);if("tag"===a.type){let r=u[parseInt(a.name,10)];1!==c.length||r||(r=c[0][a.name]),r||(r={});const b=0!==Object.keys(a.attrs).length?((e,n)=>{const t={...n};return t.props=Object.assign(e.props,n.props),t})({props:a.attrs},r):r,v=n.isValidElement(b),E=v&&S(a,!0)&&!a.voidElement,O=l&&x(b)&&b.dummy&&!v,N=x(e)&&Object.hasOwnProperty.call(e,a.name);if(y(b)){const e=s.services.interpolator.interpolate(b,f,s.language);t.push(e)}else if(S(b)||E){const e=h(b,a,c);m(b,e,t,p)}else if(O){const e=g(u,a.children,c);m(b,e,t,p)}else if(Number.isNaN(parseFloat(a.name)))if(N){const e=h(b,a,c);m(b,e,t,p,a.voidElement)}else if(i.transSupportBasicHtmlNodes&&o.indexOf(a.name)>-1)if(a.voidElement)t.push(n.createElement(a.name,{key:`${a.name}-${p}`}));else{const e=g(u,a.children,c);t.push(n.createElement(a.name,{key:`${a.name}-${p}`},e))}else if(a.voidElement)t.push(`<${a.name} />`);else{const e=g(u,a.children,c);t.push(`<${a.name}>${e}`)}else if(x(b)&&!v){const e=a.children[0]?d:null;e&&t.push(e)}else m(b,d,t,p,1!==a.children.length||!d)}else if("text"===a.type){const e=i.transWrapTextNodes,o=r?i.unescape(s.services.interpolator.interpolate(a.content,f,s.language)):s.services.interpolator.interpolate(a.content,f,s.language);e?t.push(n.createElement(e,{key:`${a.name}-${p}`},o)):t.push(o)}return t}),[])},b=g([{dummy:!0,children:e||[]}],d,R(e||[]));return j(b[0])};function P(e){let{children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:f,t:h,shouldUnescape:m,...g}=e;const x=f||k();if(!x)return d("You will need to pass in an i18next instance by using i18nextReactModule"),t;const b=h||x.t.bind(x)||(e=>e),v={...$(),...x.options?.react};let E=p||b.ns||x.options?.defaultNS;E=y(E)?[E]:E||["translation"];const O=T(t,v),N=c||O||v.transEmptyNodeValue||a,{hashTransKey:w}=v,I=a||(w?w(O||N):O||N);x.options?.interpolation?.defaultVariables&&(l=l&&Object.keys(l).length>0?{...l,...x.options.interpolation.defaultVariables}:{...x.options.interpolation.defaultVariables});const S=l||void 0!==s||!t?o.interpolation:{interpolation:{...o.interpolation,prefix:"#$?",suffix:"?$#"}},j={...o,context:r||o.context,count:s,...l,...S,defaultValue:N,ns:E},R=I?b(I,j):N;u&&Object.keys(u).forEach((e=>{const t=u[e];"function"==typeof t.type||!t.props||!t.props.children||R.indexOf(`${e}/>`)<0&&R.indexOf(`${e} />`)<0||(u[e]=n.createElement((function(){return n.createElement(n.Fragment,null,t)})))}));const P=C(u||t,R,x,v,j,m),L=i??v.defaultTransParent;return L?n.createElement(L,g,P):P}const L={type:"3rdParty",init(e){N(e.options.react),I(e)}},A=n.createContext();class V{constructor(){this.usedNamespaces={}}addUsedNamespaces(e){e.forEach((e=>{this.usedNamespaces[e]=this.usedNamespaces[e]??!0}))}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}const z=e=>async n=>({...await(e.getInitialProps?.(n))??{},...F()}),F=()=>{const e=k(),n=e.reportNamespaces?.getUsedNamespaces()??[],t={},s={};return e.languages.forEach((t=>{s[t]={},n.forEach((n=>{s[t][n]=e.getResourceBundle(t,n)||{}}))})),t.initialI18nStore=s,t.initialLanguage=e.language,t};const U=(e,n,t,s)=>e.getFixedT(n,t,s),B=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{i18n:s}=t,{i18n:i,defaultNS:a}=n.useContext(A)||{},r=s||i||k();if(r&&!r.reportNamespaces&&(r.reportNamespaces=new V),!r){d("You will need to pass in an i18next instance by using initReactI18next");const e=(e,n)=>y(n)?n:x(n)&&y(n.defaultValue)?n.defaultValue:Array.isArray(e)?e[e.length-1]:e,n=[e,{},!1];return n.t=e,n.i18n={},n.ready=!1,n}r.options.react?.wait&&d("It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.");const o={...$(),...r.options.react,...t},{useSuspense:l,keyPrefix:c}=o;let u=e||a||r.options?.defaultNS;u=y(u)?[u]:u||["translation"],r.reportNamespaces.addUsedNamespaces?.(u);const p=(r.isInitialized||r.initializedStoreOnce)&&u.every((e=>function(e,n){let t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return n.languages&&n.languages.length?n.hasLoadedNamespace(e,{lng:t.lng,precheck:(n,s)=>{if(t.bindI18n?.indexOf("languageChanging")>-1&&n.services.backendConnector.backend&&n.isLanguageChangingTo&&!s(n.isLanguageChangingTo,e))return!1}}):(d("i18n.languages were undefined or empty",n.languages),!0)}(e,r,o))),f=((e,t,s,i)=>n.useCallback(U(e,t,s,i),[e,t,s,i]))(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),g=()=>f,b=()=>U(r,t.lng||null,"fallback"===o.nsMode?u:u[0],c),[v,E]=n.useState(g);let O=u.join();t.lng&&(O=`${t.lng}${O}`);const N=((e,t)=>{const s=n.useRef();return n.useEffect((()=>{s.current=e}),[e,t]),s.current})(O),w=n.useRef(!0);n.useEffect((()=>{const{bindI18n:e,bindI18nStore:n}=o;w.current=!0,p||l||(t.lng?m(r,t.lng,u,(()=>{w.current&&E(b)})):h(r,u,(()=>{w.current&&E(b)}))),p&&N&&N!==O&&w.current&&E(b);const s=()=>{w.current&&E(b)};return e&&r?.on(e,s),n&&r?.store.on(n,s),()=>{w.current=!1,r&&e?.split(" ").forEach((e=>r.off(e,s))),n&&r&&n.split(" ").forEach((e=>r.store.off(e,s)))}}),[r,O]),n.useEffect((()=>{w.current&&p&&E(g)}),[r,c,p]);const I=[v,r,p];if(I.t=v,I.i18n=r,I.ready=p,p)return I;if(!p&&!l)return I;throw new Promise((e=>{t.lng?m(r,t.lng,u,(()=>e())):h(r,u,(()=>e()))}))};const D=function(e,t){let s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{i18n:i}=s,{i18n:a}=n.useContext(A)||{},r=i||a||k();r.options?.isClone||(e&&!r.initializedStoreOnce&&(r.services.resourceStore.data=e,r.options.ns=Object.values(e).reduce(((e,n)=>(Object.keys(n).forEach((n=>{e.indexOf(n)<0&&e.push(n)})),e)),r.options.ns),r.initializedStoreOnce=!0,r.isInitialized=!0),t&&!r.initializedLanguageOnce&&(r.changeLanguage(t),r.initializedLanguageOnce=!0))};e.I18nContext=A,e.I18nextProvider=function(e){let{i18n:t,defaultNS:s,children:i}=e;const a=n.useMemo((()=>({i18n:t,defaultNS:s})),[t,s]);return n.createElement(A.Provider,{value:a},i)},e.Trans=function(e){let{children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o={},values:l,defaults:c,components:u,ns:p,i18n:d,t:f,shouldUnescape:h,...m}=e;const{i18n:g,defaultNS:y}=n.useContext(A)||{},x=d||g||k(),b=f||x?.t.bind(x);return P({children:t,count:s,parent:i,i18nKey:a,context:r,tOptions:o,values:l,defaults:c,components:u,ns:p||b?.ns||y||x?.options?.defaultNS,i18n:x,t:f,shouldUnescape:h,...m})},e.TransWithoutContext=P,e.Translation=e=>{let{ns:n,children:t,...s}=e;const[i,a,r]=B(n,s);return t(i,{i18n:a,lng:a.language},r)},e.composeInitialProps=z,e.date=()=>"",e.getDefaults=$,e.getI18n=k,e.getInitialProps=F,e.initReactI18next=L,e.number=()=>"",e.plural=()=>"",e.select=()=>"",e.selectOrdinal=()=>"",e.setDefaults=N,e.setI18n=I,e.time=()=>"",e.useSSR=D,e.useTranslation=B,e.withSSR=()=>function(e){function t(t){let{initialI18nStore:s,initialLanguage:i,...a}=t;return D(s,i),n.createElement(e,{...a})}return t.getInitialProps=z(e),t.displayName=`withI18nextSSR(${g(e)})`,t.WrappedComponent=e,t},e.withTranslation=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(s){function i(i){let{forwardedRef:a,...r}=i;const[o,l,c]=B(e,{...r,keyPrefix:t.keyPrefix}),u={...r,t:o,i18n:l,tReady:c};return t.withRef&&a?u.ref=a:!t.withRef&&a&&(u.forwardedRef=a),n.createElement(s,u)}i.displayName=`withI18nextTranslation(${g(s)})`,i.WrappedComponent=s;return t.withRef?n.forwardRef(((e,t)=>n.createElement(i,Object.assign({},e,{forwardedRef:t})))):i}}})); +diff --git a/src/context.js b/src/context.js +index 167af9c50f47e34f7473df03bb2bb1e369725934..9b9a5570b0b765c9d7809f912dba2db759ebb68d 100644 +--- a/src/context.js ++++ b/src/context.js +@@ -14,7 +14,7 @@ export class ReportNamespaces { + + addUsedNamespaces(namespaces) { + namespaces.forEach((ns) => { +- this.usedNamespaces[ns] ??= true; ++ this.usedNamespaces[ns] = this.usedNamespaces[ns] ?? true; + }); + } + diff --git a/apps/meteor/app/2fa/server/code/EmailCheck.ts b/apps/meteor/app/2fa/server/code/EmailCheck.ts index d947c1b30c2e..5baf218a62bb 100644 --- a/apps/meteor/app/2fa/server/code/EmailCheck.ts +++ b/apps/meteor/app/2fa/server/code/EmailCheck.ts @@ -38,7 +38,7 @@ export class EmailCheck implements ICodeCheck { private async send2FAEmail(address: string, random: string, user: IUser): Promise { const language = user.language || settings.get('Language') || 'en'; - const t = (s: string): string => i18n.t(s, { lng: language }); + const t = i18n.getFixedT(language); await Mailer.send({ to: address, diff --git a/apps/meteor/app/2fa/server/functions/resetTOTP.ts b/apps/meteor/app/2fa/server/functions/resetTOTP.ts index 3be8ec7c8060..84426cd4f88d 100644 --- a/apps/meteor/app/2fa/server/functions/resetTOTP.ts +++ b/apps/meteor/app/2fa/server/functions/resetTOTP.ts @@ -22,7 +22,7 @@ const sendResetNotification = async function (uid: string): Promise { return; } - const t = (s: string): string => i18n.t(s, { lng: language }); + const t = i18n.getFixedT(language); const text = ` ${t('Your_TOTP_has_been_reset')} diff --git a/apps/meteor/app/lib/server/methods/addUsersToRoom.ts b/apps/meteor/app/lib/server/methods/addUsersToRoom.ts index 73fbf6e51a04..119071e8ece0 100644 --- a/apps/meteor/app/lib/server/methods/addUsersToRoom.ts +++ b/apps/meteor/app/lib/server/methods/addUsersToRoom.ts @@ -98,14 +98,11 @@ export const addUsersToRoomMethod = async (userId: string, data: { rid: string; return; } void api.broadcast('notify.ephemeralMessage', userId, data.rid, { - msg: i18n.t( - 'Username_is_already_in_here', - { - postProcess: 'sprintf', - sprintf: [newUser.username], - }, - user?.language, - ), + msg: i18n.t('Username_is_already_in_here', { + postProcess: 'sprintf', + sprintf: [newUser.username], + lng: user?.language, + }), }); } }), diff --git a/apps/meteor/app/lib/server/methods/sendMessage.ts b/apps/meteor/app/lib/server/methods/sendMessage.ts index 56009f15fede..e004f2199fa0 100644 --- a/apps/meteor/app/lib/server/methods/sendMessage.ts +++ b/apps/meteor/app/lib/server/methods/sendMessage.ts @@ -2,6 +2,7 @@ import { api } from '@rocket.chat/core-services'; import type { AtLeast, IMessage, IUser } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Messages, Users } from '@rocket.chat/models'; +import type { TOptions } from 'i18next'; import { check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; import moment from 'moment'; @@ -98,9 +99,9 @@ export async function executeSendMessage(uid: IUser['_id'], message: AtLeast void; @@ -9,7 +9,7 @@ type PlaceChatOnHoldModalProps = { }; const PlaceChatOnHoldModal = ({ onCancel, onOnHoldChat, confirm = onOnHoldChat, ...props }: PlaceChatOnHoldModalProps) => { - const t = useTranslation(); + const { t } = useTranslation(); return ( diff --git a/apps/meteor/app/livechat/server/api/v1/room.ts b/apps/meteor/app/livechat/server/api/v1/room.ts index 7aacfacb4476..404f576ea513 100644 --- a/apps/meteor/app/livechat/server/api/v1/room.ts +++ b/apps/meteor/app/livechat/server/api/v1/room.ts @@ -159,7 +159,7 @@ API.v1.addRoute( const visitorEmail = visitor.visitorEmails?.[0]?.address; const language = servingAgent.language || rcSettings.get('Language') || 'en'; - const t = (s: string): string => i18n.t(s, { lng: language }); + const t = i18n.getFixedT(language); const subject = t('Transcript_of_your_livechat_conversation'); options.emailTranscript = { diff --git a/apps/meteor/app/livechat/server/lib/Helper.ts b/apps/meteor/app/livechat/server/lib/Helper.ts index 17f21d8d7b04..017eb516a487 100644 --- a/apps/meteor/app/livechat/server/lib/Helper.ts +++ b/apps/meteor/app/livechat/server/lib/Helper.ts @@ -439,8 +439,8 @@ export const dispatchInquiryQueued = async (inquiry: ILivechatInquiryRecord, age hasMentionToHere: false, message: { _id: '', u: v, msg: '' }, // we should use server's language for this type of messages instead of user's - notificationMessage: i18n.t('User_started_a_new_conversation', { username: notificationUserName }, language), - room: Object.assign(room, { name: i18n.t('New_chat_in_queue', {}, language) }), + notificationMessage: i18n.t('User_started_a_new_conversation', { username: notificationUserName, lng: language }), + room: Object.assign(room, { name: i18n.t('New_chat_in_queue', { lng: language }) }), mentionIds: [], }); } diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.ts b/apps/meteor/app/livechat/server/lib/QueueManager.ts index e1ea79d84163..c6728d470870 100644 --- a/apps/meteor/app/livechat/server/lib/QueueManager.ts +++ b/apps/meteor/app/livechat/server/lib/QueueManager.ts @@ -371,8 +371,8 @@ export class QueueManager { hasMentionToHere: false, message: { _id: '', u: v, msg: '' }, // we should use server's language for this type of messages instead of user's - notificationMessage: i18n.t('User_started_a_new_conversation', { username: notificationUserName }, language), - room: { ...room, name: i18n.t('New_chat_in_queue', {}, language) }, + notificationMessage: i18n.t('User_started_a_new_conversation', { username: notificationUserName, lng: language }), + room: { ...room, name: i18n.t('New_chat_in_queue', { lng: language }) }, mentionIds: [], }); } diff --git a/apps/meteor/app/ui-message/client/messageBox/AddLinkComposerActionModal.tsx b/apps/meteor/app/ui-message/client/messageBox/AddLinkComposerActionModal.tsx index 420bf93df66d..21e502c90001 100644 --- a/apps/meteor/app/ui-message/client/messageBox/AddLinkComposerActionModal.tsx +++ b/apps/meteor/app/ui-message/client/messageBox/AddLinkComposerActionModal.tsx @@ -1,8 +1,8 @@ import { Field, FieldGroup, TextInput, FieldLabel, FieldRow, Box } from '@rocket.chat/fuselage'; import { useUniqueId } from '@rocket.chat/fuselage-hooks'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { useEffect } from 'react'; import { useForm, Controller } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; import GenericModal from '../../../../client/components/GenericModal'; @@ -13,7 +13,7 @@ type AddLinkComposerActionModalProps = { }; const AddLinkComposerActionModal = ({ selectedText, onClose, onConfirm }: AddLinkComposerActionModalProps) => { - const t = useTranslation(); + const { t } = useTranslation(); const textField = useUniqueId(); const urlField = useUniqueId(); diff --git a/apps/meteor/app/utils/lib/i18n.ts b/apps/meteor/app/utils/lib/i18n.ts index b69fe6b30513..737b98666d0a 100644 --- a/apps/meteor/app/utils/lib/i18n.ts +++ b/apps/meteor/app/utils/lib/i18n.ts @@ -1,4 +1,5 @@ import type { RocketchatI18nKeys } from '@rocket.chat/i18n'; +import type { TOptions } from 'i18next'; import i18next from 'i18next'; import sprintf from 'i18next-sprintf-postprocessor'; @@ -13,7 +14,7 @@ export const addSprinfToI18n = function (t: (typeof i18n)['t']) { } if (isObject(replaces[0]) && !Array.isArray(replaces[0])) { - return t(key, replaces[0]); + return t(key, replaces[0] as TOptions); } return t(key, { diff --git a/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmniChannelCallDialPad.tsx b/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmniChannelCallDialPad.tsx index af9b907df12e..2693060578ed 100644 --- a/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmniChannelCallDialPad.tsx +++ b/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmniChannelCallDialPad.tsx @@ -1,7 +1,7 @@ import { NavBarItem } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentPropsWithoutRef } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { useVoipOutboundStates } from '../../contexts/CallContext'; import { useDialModal } from '../../hooks/useDialModal'; @@ -9,7 +9,7 @@ import { useDialModal } from '../../hooks/useDialModal'; type NavBarItemOmniChannelCallDialPadProps = ComponentPropsWithoutRef; const NavBarItemOmniChannelCallDialPad = (props: NavBarItemOmniChannelCallDialPadProps) => { - const t = useTranslation(); + const { t } = useTranslation(); const { openDialModal } = useDialModal(); diff --git a/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleError.tsx b/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleError.tsx index cf4e7ec240b4..7f2b6adc8691 100644 --- a/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleError.tsx +++ b/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleError.tsx @@ -1,12 +1,12 @@ import { NavBarItem } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentPropsWithoutRef } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; type NavBarItemOmnichannelCallToggleErrorProps = ComponentPropsWithoutRef; const NavBarItemOmnichannelCallToggleError = (props: NavBarItemOmnichannelCallToggleErrorProps) => { - const t = useTranslation(); + const { t } = useTranslation(); return ; }; diff --git a/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleLoading.tsx b/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleLoading.tsx index c4b53acefabb..149500050402 100644 --- a/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleLoading.tsx +++ b/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleLoading.tsx @@ -1,12 +1,12 @@ import { NavBarItem } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentPropsWithoutRef } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; type NavBarItemOmnichannelCallToggleLoadingProps = ComponentPropsWithoutRef; const NavBarItemOmnichannelCallToggleLoading = (props: NavBarItemOmnichannelCallToggleLoadingProps) => { - const t = useTranslation(); + const { t } = useTranslation(); return ; }; diff --git a/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleReady.tsx b/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleReady.tsx index 8b51fc6c5b57..82f1c28350cd 100644 --- a/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleReady.tsx +++ b/apps/meteor/client/NavBarV2/NavBarOmnichannelToolbar/NavBarItemOmnichannelCallToggleReady.tsx @@ -1,14 +1,14 @@ import { NavBarItem } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentPropsWithoutRef } from 'react'; import React, { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import { useCallerInfo, useCallRegisterClient, useCallUnregisterClient, useVoipNetworkStatus } from '../../contexts/CallContext'; type NavBarItemOmnichannelCallToggleReadyProps = ComponentPropsWithoutRef; const NavBarItemOmnichannelCallToggleReady = (props: NavBarItemOmnichannelCallToggleReadyProps) => { - const t = useTranslation(); + const { t } = useTranslation(); const caller = useCallerInfo(); const unregister = useCallUnregisterClient(); diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenu.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenu.tsx index 22895d55388f..149ad0ea585e 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenu.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/UserMenu.tsx @@ -1,9 +1,9 @@ import type { IUser } from '@rocket.chat/core-typings'; import { GenericMenu, useHandleMenuAction } from '@rocket.chat/ui-client'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import React, { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import UserMenuButton from './UserMenuButton'; import { useUserMenu } from './hooks/useUserMenu'; @@ -11,7 +11,7 @@ import { useUserMenu } from './hooks/useUserMenu'; type UserMenuProps = { user: IUser } & Omit, 'sections' | 'items' | 'title'>; const UserMenu = function UserMenu({ user, ...props }: UserMenuProps) { - const t = useTranslation(); + const { t } = useTranslation(); const [isOpen, setIsOpen] = useState(false); const sections = useUserMenu(user); diff --git a/apps/meteor/client/apps/gameCenter/GameCenterContainer.tsx b/apps/meteor/client/apps/gameCenter/GameCenterContainer.tsx index f589dd21ed50..dbaea02ace4a 100644 --- a/apps/meteor/client/apps/gameCenter/GameCenterContainer.tsx +++ b/apps/meteor/client/apps/gameCenter/GameCenterContainer.tsx @@ -1,7 +1,7 @@ import { Avatar } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { ContextualbarTitle, @@ -19,7 +19,7 @@ interface IGameCenterContainerProps { } const GameCenterContainer = ({ handleClose, handleBack, game }: IGameCenterContainerProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); return ( <> diff --git a/apps/meteor/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx b/apps/meteor/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx index d0dcc6fad4fe..871e82f3ff56 100644 --- a/apps/meteor/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx +++ b/apps/meteor/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx @@ -1,8 +1,8 @@ import type { IUser } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import GenericModal from '../../components/GenericModal'; import UserAutoCompleteMultipleFederated from '../../components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated'; @@ -19,7 +19,7 @@ interface IGameCenterInvitePlayersModalProps { } const GameCenterInvitePlayersModal = ({ game, onClose }: IGameCenterInvitePlayersModalProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); const [users, setUsers] = useState>([]); const { name } = game; diff --git a/apps/meteor/client/components/ActionManagerBusyState.tsx b/apps/meteor/client/components/ActionManagerBusyState.tsx index 1399c045271f..932eb08ea502 100644 --- a/apps/meteor/client/components/ActionManagerBusyState.tsx +++ b/apps/meteor/client/components/ActionManagerBusyState.tsx @@ -1,12 +1,12 @@ import { css } from '@rocket.chat/css-in-js'; import { Box } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useUiKitActionManager } from '../uikit/hooks/useUiKitActionManager'; const ActionManagerBusyState = () => { - const t = useTranslation(); + const { t } = useTranslation(); const actionManager = useUiKitActionManager(); const [busy, setBusy] = useState(false); diff --git a/apps/meteor/client/components/AutoCompleteDepartment.tsx b/apps/meteor/client/components/AutoCompleteDepartment.tsx index 6217f1d99610..0c50f2254aac 100644 --- a/apps/meteor/client/components/AutoCompleteDepartment.tsx +++ b/apps/meteor/client/components/AutoCompleteDepartment.tsx @@ -1,8 +1,8 @@ import { PaginatedSelectFiltered } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactElement } from 'react'; import React, { memo, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useRecordList } from '../hooks/lists/useRecordList'; import { AsyncStatePhase } from '../hooks/useAsyncState'; @@ -28,7 +28,7 @@ const AutoCompleteDepartment = ({ showArchived = false, ...props }: AutoCompleteDepartmentProps): ReactElement | null => { - const t = useTranslation(); + const { t } = useTranslation(); const [departmentsFilter, setDepartmentsFilter] = useState(''); const debouncedDepartmentsFilter = useDebouncedValue(departmentsFilter, 500); diff --git a/apps/meteor/client/components/AutoCompleteDepartmentMultiple.tsx b/apps/meteor/client/components/AutoCompleteDepartmentMultiple.tsx index 99af9a1f6a2c..c15d480f3900 100644 --- a/apps/meteor/client/components/AutoCompleteDepartmentMultiple.tsx +++ b/apps/meteor/client/components/AutoCompleteDepartmentMultiple.tsx @@ -1,9 +1,9 @@ import { CheckOption, PaginatedMultiSelectFiltered } from '@rocket.chat/fuselage'; import type { PaginatedMultiSelectOption } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import React, { memo, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useRecordList } from '../hooks/lists/useRecordList'; import { AsyncStatePhase } from '../hooks/useAsyncState'; @@ -24,7 +24,7 @@ const AutoCompleteDepartmentMultiple = ({ enabled = false, onChange = () => undefined, }: AutoCompleteDepartmentMultipleProps) => { - const t = useTranslation(); + const { t } = useTranslation(); const [departmentsFilter, setDepartmentsFilter] = useState(''); const debouncedDepartmentsFilter = useDebouncedValue(departmentsFilter, 500); diff --git a/apps/meteor/client/components/ConfirmOwnerChangeModal.tsx b/apps/meteor/client/components/ConfirmOwnerChangeModal.tsx index 349341baf003..77135fad6230 100644 --- a/apps/meteor/client/components/ConfirmOwnerChangeModal.tsx +++ b/apps/meteor/client/components/ConfirmOwnerChangeModal.tsx @@ -1,7 +1,7 @@ import { Box } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentPropsWithoutRef } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import GenericModal from './GenericModal'; import RawText from './RawText'; @@ -20,7 +20,7 @@ const ConfirmOwnerChangeModal = ({ onConfirm, onCancel, }: ConfirmOwnerChangeModalProps) => { - const t = useTranslation(); + const { t } = useTranslation(); let changeOwnerRooms = ''; if (shouldChangeOwner.length > 0) { diff --git a/apps/meteor/client/components/Contextualbar/ContextualbarBack.tsx b/apps/meteor/client/components/Contextualbar/ContextualbarBack.tsx index c8e17ab88d80..dcac448b1e92 100644 --- a/apps/meteor/client/components/Contextualbar/ContextualbarBack.tsx +++ b/apps/meteor/client/components/Contextualbar/ContextualbarBack.tsx @@ -1,13 +1,13 @@ -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement, ComponentProps } from 'react'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import ContextualbarAction from './ContextualbarAction'; type ContextualbarBackProps = Partial>; const ContextualbarBack = (props: ContextualbarBackProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); return ; }; diff --git a/apps/meteor/client/components/Contextualbar/ContextualbarClose.tsx b/apps/meteor/client/components/Contextualbar/ContextualbarClose.tsx index 1670c9be5895..38db516476e3 100644 --- a/apps/meteor/client/components/Contextualbar/ContextualbarClose.tsx +++ b/apps/meteor/client/components/Contextualbar/ContextualbarClose.tsx @@ -1,13 +1,13 @@ -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactElement } from 'react'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import ContextualbarAction from './ContextualbarAction'; type ContextualbarCloseProps = Partial>; const ContextualbarClose = (props: ContextualbarCloseProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); return ; }; diff --git a/apps/meteor/client/components/FilterByText.tsx b/apps/meteor/client/components/FilterByText.tsx index 5c5a3d599e2f..25d8e225e3d8 100644 --- a/apps/meteor/client/components/FilterByText.tsx +++ b/apps/meteor/client/components/FilterByText.tsx @@ -1,8 +1,8 @@ import { Box, Icon, TextInput, Margins } from '@rocket.chat/fuselage'; import { useAutoFocus, useMergedRefs } from '@rocket.chat/fuselage-hooks'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ChangeEvent, FormEvent, HTMLAttributes } from 'react'; import React, { forwardRef, memo, useCallback, useState } from 'react'; +import { useTranslation } from 'react-i18next'; type FilterByTextProps = { onChange: (filter: string) => void; @@ -13,7 +13,7 @@ const FilterByText = forwardRef(function Fi { placeholder, onChange: setFilter, shouldAutoFocus = false, children, ...props }, ref, ) { - const t = useTranslation(); + const { t } = useTranslation(); const [text, setText] = useState(''); const autoFocusRef = useAutoFocus(shouldAutoFocus); const mergedRefs = useMergedRefs(ref, autoFocusRef); diff --git a/apps/meteor/client/components/FingerprintChangeModal.tsx b/apps/meteor/client/components/FingerprintChangeModal.tsx index db4c33654a92..a45a17db8ccc 100644 --- a/apps/meteor/client/components/FingerprintChangeModal.tsx +++ b/apps/meteor/client/components/FingerprintChangeModal.tsx @@ -1,7 +1,7 @@ import { Box } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import GenericModal from './GenericModal'; @@ -12,7 +12,7 @@ type FingerprintChangeModalProps = { }; const FingerprintChangeModal = ({ onConfirm, onCancel, onClose }: FingerprintChangeModalProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); return ( { - const t = useTranslation(); + const { t } = useTranslation(); return ( { - const t = useTranslation(); + const { t } = useTranslation(); return ( diff --git a/apps/meteor/client/components/GenericModal/GenericModal.tsx b/apps/meteor/client/components/GenericModal/GenericModal.tsx index 5d025e05827d..d91e3c066007 100644 --- a/apps/meteor/client/components/GenericModal/GenericModal.tsx +++ b/apps/meteor/client/components/GenericModal/GenericModal.tsx @@ -1,9 +1,9 @@ import { Button, Modal } from '@rocket.chat/fuselage'; import { useEffectEvent, useUniqueId } from '@rocket.chat/fuselage-hooks'; import type { Keys as IconName } from '@rocket.chat/icons'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactElement, ReactNode, ComponentPropsWithoutRef } from 'react'; import React, { useEffect, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; import type { RequiredModalProps } from './withDoNotAskAgain'; import { withDoNotAskAgain } from './withDoNotAskAgain'; @@ -75,7 +75,7 @@ const GenericModal = ({ annotation, ...props }: GenericModalProps) => { - const t = useTranslation(); + const { t } = useTranslation(); const genericModalId = useUniqueId(); const dismissedRef = useRef(true); diff --git a/apps/meteor/client/components/GenericNoResults/GenericNoResults.tsx b/apps/meteor/client/components/GenericNoResults/GenericNoResults.tsx index 3fcfe2b0e0ac..d21023024fb3 100644 --- a/apps/meteor/client/components/GenericNoResults/GenericNoResults.tsx +++ b/apps/meteor/client/components/GenericNoResults/GenericNoResults.tsx @@ -1,7 +1,7 @@ import { Box, States, StatesIcon, StatesLink, StatesTitle, StatesSubtitle, StatesActions, StatesAction } from '@rocket.chat/fuselage'; import type { Keys as IconName } from '@rocket.chat/icons'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; +import { useTranslation } from 'react-i18next'; type LinkProps = { linkText: string; linkHref: string } | { linkText?: never; linkHref?: never }; type ButtonProps = { buttonTitle: string; buttonAction: () => void } | { buttonTitle?: never; buttonAction?: never }; @@ -23,7 +23,7 @@ const GenericNoResults = ({ linkHref, linkText, }: GenericNoResultsProps) => { - const t = useTranslation(); + const { t } = useTranslation(); return ( diff --git a/apps/meteor/client/components/GenericTable/hooks/useItemsPerPageLabel.ts b/apps/meteor/client/components/GenericTable/hooks/useItemsPerPageLabel.ts index 0a8a8deb8262..4c390041497e 100644 --- a/apps/meteor/client/components/GenericTable/hooks/useItemsPerPageLabel.ts +++ b/apps/meteor/client/components/GenericTable/hooks/useItemsPerPageLabel.ts @@ -1,7 +1,7 @@ -import { useTranslation } from '@rocket.chat/ui-contexts'; import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; export const useItemsPerPageLabel = (): (() => string) => { - const t = useTranslation(); + const { t } = useTranslation(); return useCallback(() => t('Items_per_page:'), [t]); }; diff --git a/apps/meteor/client/components/GenericTable/hooks/useShowingResultsLabel.ts b/apps/meteor/client/components/GenericTable/hooks/useShowingResultsLabel.ts index c610340f28bd..8ff7d2ac18cf 100644 --- a/apps/meteor/client/components/GenericTable/hooks/useShowingResultsLabel.ts +++ b/apps/meteor/client/components/GenericTable/hooks/useShowingResultsLabel.ts @@ -1,15 +1,19 @@ import type { Pagination } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; type Props['showingResultsLabel'] = ComponentProps['showingResultsLabel']> = T extends (...args: any[]) => any ? Parameters : never; export const useShowingResultsLabel = (): ((...params: Props) => string) => { - const t = useTranslation(); + const { t } = useTranslation(); return useCallback( - ({ count, current, itemsPerPage }) => t('Showing_results_of', current + 1, Math.min(current + itemsPerPage, count), count), + ({ count, current, itemsPerPage }) => + t('Showing_results_of', { + postProcess: 'sprintf', + sprintf: [current + 1, Math.min(current + itemsPerPage, count), count], + }), [t], ); }; diff --git a/apps/meteor/client/components/GenericUpsellModal/GenericUpsellModal.tsx b/apps/meteor/client/components/GenericUpsellModal/GenericUpsellModal.tsx index 3d68e3f4b6d3..e7ce515ac496 100644 --- a/apps/meteor/client/components/GenericUpsellModal/GenericUpsellModal.tsx +++ b/apps/meteor/client/components/GenericUpsellModal/GenericUpsellModal.tsx @@ -1,8 +1,8 @@ import { Box, Button, Modal } from '@rocket.chat/fuselage'; import type { Keys as IconName } from '@rocket.chat/icons'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactNode, ReactElement, ComponentProps } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; type GenericUpsellModalProps = { children?: ReactNode; @@ -35,7 +35,7 @@ const GenericUpsellModal = ({ annotation, ...props }: GenericUpsellModalProps) => { - const t = useTranslation(); + const { t } = useTranslation(); return ( diff --git a/apps/meteor/client/components/ImageGallery/ImageGallery.tsx b/apps/meteor/client/components/ImageGallery/ImageGallery.tsx index 2cabfed460bd..6db61b2ec910 100644 --- a/apps/meteor/client/components/ImageGallery/ImageGallery.tsx +++ b/apps/meteor/client/components/ImageGallery/ImageGallery.tsx @@ -1,10 +1,10 @@ import type { IUpload } from '@rocket.chat/core-typings'; import { css } from '@rocket.chat/css-in-js'; import { Box, ButtonGroup, IconButton, Palette, Throbber } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { useRef, useState } from 'react'; import { FocusScope } from 'react-aria'; import { createPortal } from 'react-dom'; +import { useTranslation } from 'react-i18next'; import { Keyboard, Navigation, Zoom, A11y } from 'swiper'; import type { SwiperRef } from 'swiper/react'; import { type SwiperClass, Swiper, SwiperSlide } from 'swiper/react'; @@ -108,7 +108,7 @@ const swiperStyle = css` `; export const ImageGallery = ({ images, onClose, loadMore }: { images: IUpload[]; onClose: () => void; loadMore?: () => void }) => { - const t = useTranslation(); + const { t } = useTranslation(); const swiperRef = useRef(null); const [, setSwiperInst] = useState(); const [zoomScale, setZoomScale] = useState(1); diff --git a/apps/meteor/client/components/ImageGallery/ImageGalleryError.tsx b/apps/meteor/client/components/ImageGallery/ImageGalleryError.tsx index 97d91de95f62..8dcc55a93a48 100644 --- a/apps/meteor/client/components/ImageGallery/ImageGalleryError.tsx +++ b/apps/meteor/client/components/ImageGallery/ImageGalleryError.tsx @@ -1,8 +1,8 @@ import { css } from '@rocket.chat/css-in-js'; import { IconButton, ModalBackdrop } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; import { createPortal } from 'react-dom'; +import { useTranslation } from 'react-i18next'; import GenericError from '../GenericError/GenericError'; @@ -14,7 +14,7 @@ const closeButtonStyle = css` `; export const ImageGalleryError = ({ onClose }: { onClose: () => void }) => { - const t = useTranslation(); + const { t } = useTranslation(); return createPortal( diff --git a/apps/meteor/client/components/ImageGallery/ImageGalleryLoading.tsx b/apps/meteor/client/components/ImageGallery/ImageGalleryLoading.tsx index 1c057584bd1f..588605786664 100644 --- a/apps/meteor/client/components/ImageGallery/ImageGalleryLoading.tsx +++ b/apps/meteor/client/components/ImageGallery/ImageGalleryLoading.tsx @@ -1,8 +1,8 @@ import { css } from '@rocket.chat/css-in-js'; import { IconButton, ModalBackdrop, Throbber } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; import { createPortal } from 'react-dom'; +import { useTranslation } from 'react-i18next'; const closeButtonStyle = css` position: absolute; @@ -12,7 +12,7 @@ const closeButtonStyle = css` `; export const ImageGalleryLoading = ({ onClose }: { onClose: () => void }) => { - const t = useTranslation(); + const { t } = useTranslation(); return createPortal( diff --git a/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx b/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx index cbefeb2c72c1..6f94be4ebc90 100644 --- a/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx +++ b/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx @@ -1,14 +1,14 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { Callout } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { usePruneWarningMessage } from '../../hooks/usePruneWarningMessage'; import { withErrorBoundary } from '../withErrorBoundary'; const RetentionPolicyCallout = ({ room }: { room: IRoom }) => { const message = usePruneWarningMessage(room); - const t = useTranslation(); + const { t } = useTranslation(); return ( diff --git a/apps/meteor/client/components/LocalTime.tsx b/apps/meteor/client/components/LocalTime.tsx index 100ba2ec6a62..498b2da9711e 100644 --- a/apps/meteor/client/components/LocalTime.tsx +++ b/apps/meteor/client/components/LocalTime.tsx @@ -1,6 +1,6 @@ -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { useUTCClock } from '../hooks/useUTCClock'; @@ -10,7 +10,7 @@ type LocalTimeProps = { const LocalTime = ({ utcOffset }: LocalTimeProps): ReactElement => { const time = useUTCClock(utcOffset); - const t = useTranslation(); + const { t } = useTranslation(); return <>{t('Local_Time_time', { time })}; }; diff --git a/apps/meteor/client/components/MarkdownText.tsx b/apps/meteor/client/components/MarkdownText.tsx index c9af942f6e1c..6426b24810ee 100644 --- a/apps/meteor/client/components/MarkdownText.tsx +++ b/apps/meteor/client/components/MarkdownText.tsx @@ -1,10 +1,10 @@ import { Box } from '@rocket.chat/fuselage'; import { isExternal, getBaseURI } from '@rocket.chat/ui-client'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import dompurify from 'dompurify'; import { marked } from 'marked'; import type { ComponentProps } from 'react'; import React, { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; import { renderMessageEmoji } from '../lib/utils/renderMessageEmoji'; @@ -89,7 +89,7 @@ const MarkdownText = ({ ...props }: MarkdownTextProps) => { const sanitizer = dompurify.sanitize; - const t = useTranslation(); + const { t } = useTranslation(); let markedOptions: marked.MarkedOptions; const schemes = 'http,https,notes,ftp,ftps,tel,mailto,sms,cid'; diff --git a/apps/meteor/client/components/Omnichannel/modals/ReturnChatQueueModal.tsx b/apps/meteor/client/components/Omnichannel/modals/ReturnChatQueueModal.tsx index 04fcb29eed01..b19ccfee1769 100644 --- a/apps/meteor/client/components/Omnichannel/modals/ReturnChatQueueModal.tsx +++ b/apps/meteor/client/components/Omnichannel/modals/ReturnChatQueueModal.tsx @@ -1,6 +1,6 @@ import { Button, Modal } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; +import { useTranslation } from 'react-i18next'; type ReturnChatQueueModalProps = { onMoveChat: () => void; @@ -8,7 +8,7 @@ type ReturnChatQueueModalProps = { }; const ReturnChatQueueModal = ({ onCancel, onMoveChat, ...props }: ReturnChatQueueModalProps) => { - const t = useTranslation(); + const { t } = useTranslation(); return ( diff --git a/apps/meteor/client/components/Omnichannel/modals/TranscriptModal.tsx b/apps/meteor/client/components/Omnichannel/modals/TranscriptModal.tsx index c06b6a190465..502d0f9d1af7 100644 --- a/apps/meteor/client/components/Omnichannel/modals/TranscriptModal.tsx +++ b/apps/meteor/client/components/Omnichannel/modals/TranscriptModal.tsx @@ -1,8 +1,8 @@ import type { IOmnichannelRoom } from '@rocket.chat/core-typings'; import { Field, Button, TextInput, Modal, Box, FieldGroup, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { useCallback, useEffect } from 'react'; import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; type TranscriptModalProps = { email: string; @@ -14,7 +14,7 @@ type TranscriptModalProps = { }; const TranscriptModal = ({ email: emailDefault = '', room, onRequest, onSend, onCancel, onDiscard, ...props }: TranscriptModalProps) => { - const t = useTranslation(); + const { t } = useTranslation(); const { register, diff --git a/apps/meteor/client/components/Sidebar/Header.tsx b/apps/meteor/client/components/Sidebar/Header.tsx index e4bf5a5e7041..dcbf7f1cb505 100644 --- a/apps/meteor/client/components/Sidebar/Header.tsx +++ b/apps/meteor/client/components/Sidebar/Header.tsx @@ -1,7 +1,7 @@ import { Box, IconButton } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactNode } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; type HeaderProps = { children?: ReactNode; @@ -10,7 +10,7 @@ type HeaderProps = { }; const Header = ({ title, onClose, children, ...props }: HeaderProps) => { - const t = useTranslation(); + const { t } = useTranslation(); return ( diff --git a/apps/meteor/client/components/Sidebar/SidebarItemsAssembler.tsx b/apps/meteor/client/components/Sidebar/SidebarItemsAssembler.tsx index 45eb6094572a..b588e223d922 100644 --- a/apps/meteor/client/components/Sidebar/SidebarItemsAssembler.tsx +++ b/apps/meteor/client/components/Sidebar/SidebarItemsAssembler.tsx @@ -1,6 +1,6 @@ import { Divider } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { Fragment, memo } from 'react'; +import { useTranslation } from 'react-i18next'; import type { SidebarItem } from '../../lib/createSidebarItems'; import { isSidebarItem } from '../../lib/createSidebarItems'; @@ -12,7 +12,7 @@ type SidebarItemsAssemblerProps = { }; const SidebarItemsAssembler = ({ items, currentPath }: SidebarItemsAssemblerProps) => { - const t = useTranslation(); + const { t, i18n } = useTranslation(); return ( <> @@ -25,7 +25,7 @@ const SidebarItemsAssembler = ({ items, currentPath }: SidebarItemsAssemblerProp icon={props.icon} label={t((props.i18nLabel || props.name) as Parameters[0])} currentPath={currentPath} - tag={props.tag && t.has(props.tag) ? t(props.tag) : props.tag} + tag={props.tag && i18n.exists(props.tag) ? t(props.tag) : props.tag} externalUrl={props.externalUrl} badge={props.badge} /> diff --git a/apps/meteor/client/components/SidebarToggler/SidebarTogglerButton.tsx b/apps/meteor/client/components/SidebarToggler/SidebarTogglerButton.tsx index cd0c25f03d86..1eefc50baabd 100644 --- a/apps/meteor/client/components/SidebarToggler/SidebarTogglerButton.tsx +++ b/apps/meteor/client/components/SidebarToggler/SidebarTogglerButton.tsx @@ -1,6 +1,6 @@ import { Box, IconButton } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import SidebarTogglerBadge from './SidebarTogglerBadge'; @@ -10,7 +10,7 @@ type SideBarTogglerButtonProps = { }; const SideBarTogglerButton = ({ badge, onClick }: SideBarTogglerButtonProps) => { - const t = useTranslation(); + const { t } = useTranslation(); return ( diff --git a/apps/meteor/client/components/TextCopy.tsx b/apps/meteor/client/components/TextCopy.tsx index 467e954ddd65..f9e2ffc62284 100644 --- a/apps/meteor/client/components/TextCopy.tsx +++ b/apps/meteor/client/components/TextCopy.tsx @@ -1,7 +1,7 @@ import { Box, Button, Scrollable } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactElement } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import useClipboardWithToast from '../hooks/useClipboardWithToast'; @@ -17,7 +17,7 @@ type TextCopyProps = { } & ComponentProps; const TextCopy = ({ text, wrapper = defaultWrapperRenderer, ...props }: TextCopyProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); const { copy } = useClipboardWithToast(text); diff --git a/apps/meteor/client/components/TwoFactorModal/TwoFactorPasswordModal.tsx b/apps/meteor/client/components/TwoFactorModal/TwoFactorPasswordModal.tsx index 4c91e274de68..4867d171aee8 100644 --- a/apps/meteor/client/components/TwoFactorModal/TwoFactorPasswordModal.tsx +++ b/apps/meteor/client/components/TwoFactorModal/TwoFactorPasswordModal.tsx @@ -1,8 +1,8 @@ import { Box, PasswordInput, FieldGroup, Field, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; import { useAutoFocus, useUniqueId } from '@rocket.chat/fuselage-hooks'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement, ChangeEvent, Ref, SyntheticEvent } from 'react'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import GenericModal from '../GenericModal'; import type { OnConfirm } from './TwoFactorModal'; @@ -15,7 +15,7 @@ type TwoFactorPasswordModalProps = { }; const TwoFactorPasswordModal = ({ onConfirm, onClose, invalidAttempt }: TwoFactorPasswordModalProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); const [code, setCode] = useState(''); const ref = useAutoFocus(); diff --git a/apps/meteor/client/components/TwoFactorModal/TwoFactorTotpModal.tsx b/apps/meteor/client/components/TwoFactorModal/TwoFactorTotpModal.tsx index 6f36c9c8ce26..d6f167be8588 100644 --- a/apps/meteor/client/components/TwoFactorModal/TwoFactorTotpModal.tsx +++ b/apps/meteor/client/components/TwoFactorModal/TwoFactorTotpModal.tsx @@ -1,8 +1,8 @@ import { Box, TextInput, Field, FieldGroup, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; import { useAutoFocus, useUniqueId } from '@rocket.chat/fuselage-hooks'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement, ChangeEvent, SyntheticEvent } from 'react'; import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import GenericModal from '../GenericModal'; import type { OnConfirm } from './TwoFactorModal'; @@ -15,7 +15,7 @@ type TwoFactorTotpModalProps = { }; const TwoFactorTotpModal = ({ onConfirm, onClose, invalidAttempt }: TwoFactorTotpModalProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); const [code, setCode] = useState(''); const ref = useAutoFocus(); diff --git a/apps/meteor/client/components/UrlChangeModal.tsx b/apps/meteor/client/components/UrlChangeModal.tsx index 13d0523c92aa..dbc152c7fbff 100644 --- a/apps/meteor/client/components/UrlChangeModal.tsx +++ b/apps/meteor/client/components/UrlChangeModal.tsx @@ -1,7 +1,7 @@ import { Box } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import GenericModal from './GenericModal'; @@ -13,14 +13,17 @@ type UrlChangeModalProps = { }; const UrlChangeModal = ({ onConfirm, siteUrl, currentUrl, onClose }: UrlChangeModalProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); return (

diff --git a/apps/meteor/client/components/UserCard/UserCard.tsx b/apps/meteor/client/components/UserCard/UserCard.tsx index bf143229cf65..98e1cce2ab78 100644 --- a/apps/meteor/client/components/UserCard/UserCard.tsx +++ b/apps/meteor/client/components/UserCard/UserCard.tsx @@ -1,9 +1,9 @@ import { css } from '@rocket.chat/css-in-js'; import { Box, Button, IconButton } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactNode, ComponentProps } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { useEmbeddedLayout } from '../../hooks/useEmbeddedLayout'; import MarkdownText from '../MarkdownText'; @@ -52,7 +52,7 @@ const UserCard = ({ nickname, ...props }: UserCardProps) => { - const t = useTranslation(); + const { t } = useTranslation(); const isLayoutEmbedded = useEmbeddedLayout(); return ( diff --git a/apps/meteor/client/components/UserInfo/UserInfo.tsx b/apps/meteor/client/components/UserInfo/UserInfo.tsx index a7f32f82f454..ac879d21738b 100644 --- a/apps/meteor/client/components/UserInfo/UserInfo.tsx +++ b/apps/meteor/client/components/UserInfo/UserInfo.tsx @@ -1,9 +1,9 @@ import type { IUser, Serialized } from '@rocket.chat/core-typings'; import { Box, Margins, Tag } from '@rocket.chat/fuselage'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; import React, { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import { useTimeAgo } from '../../hooks/useTimeAgo'; import { useUserCustomFields } from '../../hooks/useUserCustomFields'; @@ -72,7 +72,7 @@ const UserInfo = ({ reason, ...props }: UserInfoProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); const timeAgo = useTimeAgo(); const userDisplayName = useUserDisplayName({ name, username }); const userCustomFields = useUserCustomFields(customFields); diff --git a/apps/meteor/client/components/WarningModal.tsx b/apps/meteor/client/components/WarningModal.tsx index 00ae92e1d3bd..db0697f78c0d 100644 --- a/apps/meteor/client/components/WarningModal.tsx +++ b/apps/meteor/client/components/WarningModal.tsx @@ -1,7 +1,7 @@ import { Button, Modal } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; import React from 'react'; +import { useTranslation } from 'react-i18next'; type WarningModalProps = { text: ReactNode; @@ -13,7 +13,7 @@ type WarningModalProps = { }; const WarningModal = ({ text, confirmText, close, cancel, cancelText, confirm, ...props }: WarningModalProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); return ( diff --git a/apps/meteor/client/components/dashboards/PeriodSelector.tsx b/apps/meteor/client/components/dashboards/PeriodSelector.tsx index 6977e3334f4f..d441fbf2f19a 100644 --- a/apps/meteor/client/components/dashboards/PeriodSelector.tsx +++ b/apps/meteor/client/components/dashboards/PeriodSelector.tsx @@ -1,7 +1,7 @@ import { Select } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; import type { Period } from './periods'; import { getPeriod } from './periods'; @@ -14,9 +14,9 @@ type PeriodSelectorProps = { }; const PeriodSelector = ({ periods, value, name, onChange }: PeriodSelectorProps): ReactElement => { - const t = useTranslation(); + const { t } = useTranslation(); - const options = useMemo<[string, string][]>(() => periods.map((period) => [period, t(...getPeriod(period).label)]), [periods, t]); + const options = useMemo<[string, string][]>(() => periods.map((period) => [period, t(getPeriod(period).label)]), [periods, t]); return ( ( ( validateChannelName(value), })} error={errors.name?.message} diff --git a/apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx b/apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx index ad1abdcbf399..3543234bca96 100644 --- a/apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx +++ b/apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx @@ -181,7 +181,7 @@ const CreateTeamModal = ({ onClose }: { onClose: () => void }): ReactElement => id={nameId} aria-invalid={errors.name ? 'true' : 'false'} {...register('name', { - required: t('error-the-field-is-required', { field: t('Name') }), + required: t('Required_field', { field: t('Name') }), validate: (value) => validateTeamName(value), })} addon={} diff --git a/apps/meteor/client/sidebarv2/header/CreateChannelModal.tsx b/apps/meteor/client/sidebarv2/header/CreateChannelModal.tsx index 38a1df5a5ec8..2ff468f4f72b 100644 --- a/apps/meteor/client/sidebarv2/header/CreateChannelModal.tsx +++ b/apps/meteor/client/sidebarv2/header/CreateChannelModal.tsx @@ -222,7 +222,7 @@ const CreateChannelModal = ({ teamId = '', onClose, reload }: CreateChannelModal id={nameId} data-qa-type='channel-name-input' {...register('name', { - required: t('error-the-field-is-required', { field: t('Name') }), + required: t('Required_field', { field: t('Name') }), validate: (value) => validateChannelName(value), })} error={errors.name?.message} diff --git a/apps/meteor/client/sidebarv2/header/CreateTeamModal.tsx b/apps/meteor/client/sidebarv2/header/CreateTeamModal.tsx index e907558ce278..a7e7b506de0f 100644 --- a/apps/meteor/client/sidebarv2/header/CreateTeamModal.tsx +++ b/apps/meteor/client/sidebarv2/header/CreateTeamModal.tsx @@ -183,7 +183,7 @@ const CreateTeamModal = ({ onClose }: CreateTeamModalProps) => { id={nameId} aria-invalid={errors.name ? 'true' : 'false'} {...register('name', { - required: t('error-the-field-is-required', { field: t('Name') }), + required: t('Required_field', { field: t('Name') }), validate: (value) => validateTeamName(value), })} addon={} diff --git a/apps/meteor/client/views/account/integrations/AccountIntegrationsPage.tsx b/apps/meteor/client/views/account/integrations/AccountIntegrationsPage.tsx index 2c11b7a384cd..ce9fad8591fa 100644 --- a/apps/meteor/client/views/account/integrations/AccountIntegrationsPage.tsx +++ b/apps/meteor/client/views/account/integrations/AccountIntegrationsPage.tsx @@ -1,6 +1,6 @@ import type { SelectOption } from '@rocket.chat/fuselage'; -import { SelectLegacy, Box, Button, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; -import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; +import { SelectLegacy, Box, Button, Field, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; +import { useEffectEvent, useUniqueId } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useMemo } from 'react'; import { useForm, Controller } from 'react-hook-form'; @@ -13,7 +13,11 @@ import { useRemoveWebDAVAccountIntegrationMutation } from './hooks/useRemoveWebD const AccountIntegrationsPage = () => { const { data: webdavAccountIntegrations } = useWebDAVAccountIntegrationsQuery(); - const { handleSubmit, control } = useForm<{ accountSelected: string }>(); + const { + handleSubmit, + control, + formState: { errors }, + } = useForm<{ accountSelected: string }>(); const options: SelectOption[] = useMemo( () => webdavAccountIntegrations?.map(({ _id, ...current }) => [_id, getWebdavServerName(current)]) ?? [], @@ -36,6 +40,8 @@ const AccountIntegrationsPage = () => { removeMutation.mutate({ accountSelected }); }); + const accountSelectedId = useUniqueId(); + return ( @@ -47,22 +53,18 @@ const AccountIntegrationsPage = () => { ( - - )} + rules={{ required: t('Required_field', { field: t('WebDAV_Accounts') }) }} + render={({ field }) => } /> + {errors?.accountSelected && ( + + {errors.accountSelected.message} + + )} diff --git a/apps/meteor/client/views/account/profile/AccountProfileForm.tsx b/apps/meteor/client/views/account/profile/AccountProfileForm.tsx index 0de462cd5bd3..95398b352049 100644 --- a/apps/meteor/client/views/account/profile/AccountProfileForm.tsx +++ b/apps/meteor/client/views/account/profile/AccountProfileForm.tsx @@ -166,7 +166,9 @@ const AccountProfileForm = (props: AllHTMLAttributes): ReactEle (requireName && name === '' ? t('error-the-field-is-required', { field: t('Name') }) : true) }} + rules={{ + required: requireName && t('Required_field', { field: t('Name') }), + }} render={({ field }) => ( ): ReactEle control={control} name='username' rules={{ - required: t('error-the-field-is-required', { field: t('Username') }), + required: t('Required_field', { field: t('Username') }), validate: (username) => validateUsername(username), }} render={({ field }) => ( @@ -305,7 +307,10 @@ const AccountProfileForm = (props: AllHTMLAttributes): ReactEle (validateEmail(email) ? undefined : t('error-invalid-email-address')) } }} + rules={{ + required: t('Required_field', { field: t('Email') }), + validate: { validateEmail: (email) => (validateEmail(email) ? undefined : t('error-invalid-email-address')) }, + }} render={({ field }) => ( { const methods = useForm({ defaultValues: passwordDefaultValues, - mode: 'onBlur', + mode: 'all', }); const { reset, diff --git a/apps/meteor/client/views/account/security/ChangePassword.tsx b/apps/meteor/client/views/account/security/ChangePassword.tsx index c70d9e166175..e5cb61e34547 100644 --- a/apps/meteor/client/views/account/security/ChangePassword.tsx +++ b/apps/meteor/client/views/account/security/ChangePassword.tsx @@ -53,13 +53,13 @@ const ChangePassword = (props: AllHTMLAttributes) => { control={control} name='password' rules={{ + required: t('Required_field', { field: t('New_password') }), validate: () => (password?.length && !passwordIsValid ? t('Password_must_meet_the_complexity_requirements') : true), }} - render={({ field: { onChange, value } }) => ( + render={({ field }) => ( } @@ -84,12 +84,14 @@ const ChangePassword = (props: AllHTMLAttributes) => { (password !== confirmationPassword ? t('Passwords_do_not_match') : true) }} - render={({ field: { onChange, value } }) => ( + rules={{ + required: t('Required_field', { field: t('Confirm_password') }), + validate: (confirmationPassword) => (password !== confirmationPassword ? t('Passwords_do_not_match') : true), + }} + render={({ field }) => ( } diff --git a/apps/meteor/client/views/account/security/EndToEnd.tsx b/apps/meteor/client/views/account/security/EndToEnd.tsx index 72213f3202ba..b2fb982ebb9b 100644 --- a/apps/meteor/client/views/account/security/EndToEnd.tsx +++ b/apps/meteor/client/views/account/security/EndToEnd.tsx @@ -1,8 +1,9 @@ import { Box, Margins, PasswordInput, Field, FieldGroup, FieldLabel, FieldRow, FieldError, FieldHint, Button } from '@rocket.chat/fuselage'; +import { useUniqueId } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch, useMethod, useTranslation, useLogout } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactElement } from 'react'; import React, { useCallback, useEffect } from 'react'; -import { useForm } from 'react-hook-form'; +import { Controller, useForm } from 'react-hook-form'; import { e2e } from '../../../../app/e2e/client/rocketchat.e2e'; @@ -17,17 +18,17 @@ const EndToEnd = (props: ComponentProps): ReactElement => { const resetE2eKey = useMethod('e2e.resetOwnE2EKey'); const { - register, handleSubmit, watch, resetField, formState: { errors, isValid }, + control, } = useForm({ defaultValues: { password: '', passwordConfirm: '', }, - mode: 'onChange', + mode: 'all', }); const { password } = watch(); @@ -64,37 +65,71 @@ const EndToEnd = (props: ComponentProps): ReactElement => { } }, [password, resetField]); + const passwordId = useUniqueId(); + const e2ePasswordExplanationId = useUniqueId(); + const passwordConfirmId = useUniqueId(); + return ( {t('E2E_Encryption_Password_Change')} - + - {t('New_encryption_password')} + {t('New_encryption_password')} - ( + + )} /> - {!keysExist && {t('EncryptionKey_Change_Disabled')}} + {!keysExist && {t('EncryptionKey_Change_Disabled')}} + {errors?.password && ( + + {errors.password.message} + + )} {hasTypedPassword && ( - {t('Confirm_new_encryption_password')} - (password !== value ? 'Your passwords do no match' : true), - })} - placeholder={t('Confirm_New_Password_Placeholder')} - aria-labelledby='Confirm_new_encryption_password' - /> - {errors.passwordConfirm && {errors.passwordConfirm.message}} + {t('Confirm_new_encryption_password')} + + (password !== value ? 'Your passwords do no match' : true), + }} + render={({ field }) => ( + + )} + /> + + {errors.passwordConfirm && ( + + {errors.passwordConfirm.message} + + )} )} diff --git a/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx index 59da79508192..f6f52507d33a 100644 --- a/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx @@ -1,4 +1,4 @@ -import { Box, Button, ButtonGroup, Margins, TextInput, Field, FieldLabel, FieldRow, FieldError, Icon } from '@rocket.chat/fuselage'; +import { Box, Button, ButtonGroup, Margins, TextInput, Field, FieldLabel, FieldRow, FieldError, IconButton } from '@rocket.chat/fuselage'; import type { ReactElement, ChangeEvent } from 'react'; import React, { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -82,7 +82,7 @@ const AddCustomEmoji = ({ close, onChange, ...props }: AddCustomEmojiProps): Rea - {errors.name && {t('error-the-field-is-required', { field: t('Name') })}} + {errors.name && {t('Required_field', { field: t('Name') })}} {t('Aliases')} @@ -94,12 +94,9 @@ const AddCustomEmoji = ({ close, onChange, ...props }: AddCustomEmojiProps): Rea {t('Custom_Emoji')} - {/* FIXME: replace to IconButton */} - + - {errors.emoji && {t('error-the-field-is-required', { field: t('Custom_Emoji') })}} + {errors.emoji && {t('Required_field', { field: t('Custom_Emoji') })}} {newEmojiPreview && ( diff --git a/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx index 8f63b2ac7b48..49ee12b69dd0 100644 --- a/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx @@ -150,7 +150,7 @@ const EditCustomEmoji = ({ close, onChange, data, ...props }: EditCustomEmojiPro - {errors.name && {t('error-the-field-is-required', { field: t('Name') })}} + {errors.name && {t('Required_field', { field: t('Name') })}} {t('Aliases')} diff --git a/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx b/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx index 82f668a2d7d5..430d05ceaa53 100644 --- a/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx +++ b/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx @@ -1,4 +1,4 @@ -import { Field, FieldLabel, FieldRow, TextInput, Box, Icon, Margins, Button, ButtonGroup } from '@rocket.chat/fuselage'; +import { Field, FieldLabel, FieldRow, TextInput, Box, Margins, Button, ButtonGroup, IconButton } from '@rocket.chat/fuselage'; import { useToastMessageDispatch, useMethod, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement, FormEvent } from 'react'; import React, { useState, useCallback } from 'react'; @@ -34,8 +34,8 @@ const AddCustomSound = ({ goToNew, close, onChange, ...props }: AddCustomSoundPr const soundData = createSoundData(soundFile, name); const validation = validate(soundData, soundFile) as Array[0]>; - validation.forEach((error) => { - throw new Error(t('error-the-field-is-required', { field: t(error) })); + validation.forEach((invalidFieldName) => { + throw new Error(t('Required_field', { field: t(invalidFieldName) })); }); try { @@ -97,12 +97,9 @@ const AddCustomSound = ({ goToNew, close, onChange, ...props }: AddCustomSoundPr {t('Sound_File_mp3')} - + - {/* FIXME: replace to IconButton */} - + {sound?.name || t('None')} @@ -111,7 +108,7 @@ const AddCustomSound = ({ goToNew, close, onChange, ...props }: AddCustomSoundPr - diff --git a/apps/meteor/client/views/admin/customSounds/EditSound.tsx b/apps/meteor/client/views/admin/customSounds/EditSound.tsx index b358d0bb7c84..1274e9deda35 100644 --- a/apps/meteor/client/views/admin/customSounds/EditSound.tsx +++ b/apps/meteor/client/views/admin/customSounds/EditSound.tsx @@ -76,10 +76,10 @@ function EditSound({ close, onChange, data, ...props }: EditSoundProps): ReactEl } } - validation.forEach((error) => + validation.forEach((invalidFieldName) => dispatchToastMessage({ type: 'error', - message: t('error-the-field-is-required', { field: t(error) }), + message: t('Required_field', { field: t(invalidFieldName) }), }), ); }, @@ -131,9 +131,9 @@ function EditSound({ close, onChange, data, ...props }: EditSoundProps): ReactEl {t('Sound_File_mp3')} - + - + {sound?.name || 'none'} diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx index 78c2618b4c53..07376208aaef 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx @@ -28,9 +28,10 @@ const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFor register, control, handleSubmit, - formState: { isDirty, errors }, + formState: { errors }, } = useForm({ defaultValues: { name: status?.name ?? '', statusType: status?.statusType ?? '' }, + mode: 'all', }); const saveStatus = useEndpoint('POST', _id ? '/v1/custom-user-status.update' : '/v1/custom-user-status.create'); @@ -94,9 +95,9 @@ const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFor {t('Name')} - + - {errors?.name && {t('error-the-field-is-required', { field: t('Name') })}} + {errors.name && {errors.name.message}} {t('Presence')} @@ -104,18 +105,18 @@ const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFor )} /> - {errors.accountId && {t('Field_required')}} + {errors.accountId && {errors.accountId.message}} )} diff --git a/apps/meteor/client/views/root/MainLayout/RegisterUsername.tsx b/apps/meteor/client/views/root/MainLayout/RegisterUsername.tsx index bfbbce5d37e1..fd1691bcb16d 100644 --- a/apps/meteor/client/views/root/MainLayout/RegisterUsername.tsx +++ b/apps/meteor/client/views/root/MainLayout/RegisterUsername.tsx @@ -105,7 +105,10 @@ const RegisterUsername = () => { {t('Username')} - + {errors.username && ( diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center.spec.ts index d0e7b7133423..d3c667e20f82 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center.spec.ts @@ -42,7 +42,7 @@ const URL = { }; const ERROR = { - nameRequired: 'The field Name is required.', + nameRequired: 'Name required', invalidEmail: 'Invalid email address', existingEmail: 'Email already exists', existingPhone: 'Phone already exists', diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-departaments.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-departaments.spec.ts index 872eafdfb2a2..023d11de4757 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-departaments.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-departaments.spec.ts @@ -8,8 +8,8 @@ import { createDepartment, deleteDepartment } from '../utils/omnichannel/departm import { test, expect } from '../utils/test'; const ERROR = { - requiredName: 'The field name is required.', - requiredEmail: 'The field email is required.', + requiredName: 'Name required', + requiredEmail: 'Email required', invalidEmail: 'Invalid email address', }; diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-priorities.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-priorities.spec.ts index 1da1837572e5..9ee1d8d99fd9 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-priorities.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-priorities.spec.ts @@ -8,7 +8,7 @@ import { test, expect } from '../utils/test'; const PRIORITY_NAME = faker.person.firstName(); const ERROR = { - fieldNameRequired: 'The field Name is required.', + fieldNameRequired: 'Name required', }; test.skip(!IS_EE, 'Omnichannel Priorities > Enterprise Only'); diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-sla-policies.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-sla-policies.spec.ts index 35a371c61ba6..d5b5544e9ace 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-sla-policies.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-sla-policies.spec.ts @@ -6,8 +6,8 @@ import { OmnichannelSlaPolicies } from '../page-objects/omnichannel-sla-policies import { test, expect } from '../utils/test'; const ERROR = { - nameRequired: 'The field Name is required.', - estimatedWaitTimeRequired: 'The field Estimated wait time (time in minutes) is required.', + nameRequired: 'Name required', + estimatedWaitTimeRequired: 'Estimated wait time (time in minutes) required', }; const INITIAL_SLA = { diff --git a/packages/i18n/src/locales/af.i18n.json b/packages/i18n/src/locales/af.i18n.json index 40ab367489b6..661360c109b2 100644 --- a/packages/i18n/src/locales/af.i18n.json +++ b/packages/i18n/src/locales/af.i18n.json @@ -2367,7 +2367,6 @@ "The_application_name_is_required": "Die aansoek naam is nodig", "The_channel_name_is_required": "Die kanaal naam is nodig", "The_emails_are_being_sent": "Die e-posse word gestuur.", - "The_field_is_required": "Die veld%s is nodig.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Die grootte van die prentjie sal nie werk nie omdat ons ImageMagick of GraphicsMagick nie op u bediener geïnstalleer het nie.", "The_redirectUri_is_required": "Die redirectUri is nodig", "The_server_will_restart_in_s_seconds": "Die bediener sal herbegin in%s sekondes", diff --git a/packages/i18n/src/locales/ar.i18n.json b/packages/i18n/src/locales/ar.i18n.json index d3a86879f716..6d3d406e6c81 100644 --- a/packages/i18n/src/locales/ar.i18n.json +++ b/packages/i18n/src/locales/ar.i18n.json @@ -4126,8 +4126,7 @@ "The_application_name_is_required": "اسم التطبيق مطلوب", "The_channel_name_is_required": "اسم القناة مطلوب", "The_emails_are_being_sent": "يتم إرسال رسائل البريد الإلكتروني.", - "The_empty_room__roomName__will_be_removed_automatically": "ستتم إزالة الغرفة الفارغة {{roomName}} will be تلقائيًا.", - "The_field_is_required": "الحقل %s مطلوب.", + "The_empty_room__roomName__will_be_removed_automatically": "ستتم إزالة الغرفة الفارغة {{roomName}} will be تلقائيًا.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "لن يعمل تغيير حجم الصورة لأننا لا نستطيع اكتشاف تثبيت ImageMagick أو GraphicsMagick على الخادم الخاص بك.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "الرسالة عبارة عن مناقشة أنك لن تتمكن من استعادة الرسائل!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "تم تعطيل إشعارات الهاتف المحمول لجميع المستخدمين، انتقل إلى \"المسؤول > منبثق\" لتمكين البوابة المنبثقة مرة أخرى", diff --git a/packages/i18n/src/locales/az.i18n.json b/packages/i18n/src/locales/az.i18n.json index 118be4b37920..7b1c3f48fa1c 100644 --- a/packages/i18n/src/locales/az.i18n.json +++ b/packages/i18n/src/locales/az.i18n.json @@ -2366,8 +2366,7 @@ "Thank_you_for_your_feedback": "Əlaqə üçün təşəkkür edirik", "The_application_name_is_required": "Ərizə adı tələb olunur", "The_channel_name_is_required": "Kanal adı tələb olunur", - "The_emails_are_being_sent": "E-poçt göndərilir.", - "The_field_is_required": "%s sahə tələb olunur.", + "The_emails_are_being_sent": "E-poçt göndərilir.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "ImageMagick və ya GraphicsMagick-i serverinizdə yükləməyəcəyimiz üçün şəkil ölçüsünün işləməyəcəyi.", "The_redirectUri_is_required": "RedirectUri tələb olunur", "The_server_will_restart_in_s_seconds": "Server%s saniyə ərzində yenidən başlayacaq", diff --git a/packages/i18n/src/locales/be-BY.i18n.json b/packages/i18n/src/locales/be-BY.i18n.json index 858688468755..daea286edfed 100644 --- a/packages/i18n/src/locales/be-BY.i18n.json +++ b/packages/i18n/src/locales/be-BY.i18n.json @@ -2384,8 +2384,7 @@ "Thank_you_for_your_feedback": "Дзякуй за ваш водгук", "The_application_name_is_required": "Імя прыкладання патрабуецца", "The_channel_name_is_required": "Назва канала патрабуецца", - "The_emails_are_being_sent": "Лісты былі адпраўленыя.", - "The_field_is_required": "Поле %s патрабуецца.", + "The_emails_are_being_sent": "Лісты былі адпраўленыя.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Змяніць памер малюнка не будзе працаваць, таму што мы не можам выявіць ImageMagick або GraphicsMagick усталяваны на вашым серверы.", "The_redirectUri_is_required": "RedirectUri патрабуецца", "The_server_will_restart_in_s_seconds": "Сервер будзе перазагружаны у %s секунд", diff --git a/packages/i18n/src/locales/bg.i18n.json b/packages/i18n/src/locales/bg.i18n.json index ac7c8ddcd000..f7bc5ad2cf8f 100644 --- a/packages/i18n/src/locales/bg.i18n.json +++ b/packages/i18n/src/locales/bg.i18n.json @@ -2363,8 +2363,7 @@ "Thank_you_for_your_feedback": "Благодарим Ви за обратната връзка", "The_application_name_is_required": "Името на приложението е задължително", "The_channel_name_is_required": "Името на канала е задължително", - "The_emails_are_being_sent": "Изпращат се имейлите.", - "The_field_is_required": "Полето %s е задължително.", + "The_emails_are_being_sent": "Изпращат се имейлите.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Размерът на изображението няма да работи, защото не можем да открием ImageMagick или GraphicsMagick, инсталирани на вашия сървър.", "The_redirectUri_is_required": "Необходимо е пренасочването", "The_server_will_restart_in_s_seconds": "Сървъра ще бъде рестартиран след %s секунди", diff --git a/packages/i18n/src/locales/bs.i18n.json b/packages/i18n/src/locales/bs.i18n.json index ebe0b045c418..85e70bbb0abc 100644 --- a/packages/i18n/src/locales/bs.i18n.json +++ b/packages/i18n/src/locales/bs.i18n.json @@ -2360,8 +2360,7 @@ "Thank_you_for_your_feedback": "Hvala vam na povratnim informacijama", "The_application_name_is_required": "Naziv aplikacije je potreban", "The_channel_name_is_required": "Ime sobe je potrebno", - "The_emails_are_being_sent": "E-mailovi su poslani.", - "The_field_is_required": "Polje %s je traženo.", + "The_emails_are_being_sent": "E-mailovi su poslani.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Promjena veličine slike neće raditi, jer ne možemo provjeriti da je ImageMagick ili GraphicsMagick instaliran na vašem poslužitelju.", "The_redirectUri_is_required": "RedirectUri je potrebno", "The_server_will_restart_in_s_seconds": "Poslužitelj će se ponovno pokrenuti u %s sekundi", diff --git a/packages/i18n/src/locales/ca.i18n.json b/packages/i18n/src/locales/ca.i18n.json index 3f74fc967416..f4d304e08633 100644 --- a/packages/i18n/src/locales/ca.i18n.json +++ b/packages/i18n/src/locales/ca.i18n.json @@ -4044,8 +4044,7 @@ "The_application_name_is_required": "El nom de laplicació és obligatori.", "The_channel_name_is_required": "Es requereix el nom del canal", "The_emails_are_being_sent": "Els missatges de correu-e s'estan enviant.", - "The_empty_room__roomName__will_be_removed_automatically": "La sala buida {{roomName}} s'eliminarà automàticament.", - "The_field_is_required": "El camp %s és obligatori.", + "The_empty_room__roomName__will_be_removed_automatically": "La sala buida {{roomName}} s'eliminarà automàticament.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "L'ajust de mida de les imatges no funcionarà perquè no podem detectar ni ImageMagick ni GraphicsMagick al servidor.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "El missatge és una discussió, no podrà recuperar els missatges!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Les notificacions mòbils es deshabilitaron per a tots els usuaris, aneu a \"Admin> Push\" per habilitar Push inici novament", diff --git a/packages/i18n/src/locales/cs.i18n.json b/packages/i18n/src/locales/cs.i18n.json index 914d6c35d485..a74224912766 100644 --- a/packages/i18n/src/locales/cs.i18n.json +++ b/packages/i18n/src/locales/cs.i18n.json @@ -3413,8 +3413,7 @@ "The_application_name_is_required": "Název aplikace je vyžadován", "The_channel_name_is_required": "Název místnosti je vyžadován", "The_emails_are_being_sent": "Tyto e-maily jsou odesílány.", - "The_empty_room__roomName__will_be_removed_automatically": "Prázdná místnost {{roomName}} bude automaticky odstraněna.", - "The_field_is_required": "Pole %s je povinné.", + "The_empty_room__roomName__will_be_removed_automatically": "Prázdná místnost {{roomName}} bude automaticky odstraněna.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Nelze změnit velikost obrázku, protože na serveru nebyl nalezen ImageMagick ani GraphicsMagick.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Zpráva je diskuse, ze které nebudete moci obnovit zprávy!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Mobilní oznámení byla deaktivována všem uživatelům, v admin sekci \"Notifikace\" znovu aktivujte Push Gateway", diff --git a/packages/i18n/src/locales/cy.i18n.json b/packages/i18n/src/locales/cy.i18n.json index f9c7b4d7ec87..7f63d511201f 100644 --- a/packages/i18n/src/locales/cy.i18n.json +++ b/packages/i18n/src/locales/cy.i18n.json @@ -2361,8 +2361,7 @@ "Thank_you_for_your_feedback": "Diolch i chi am eich adborth", "The_application_name_is_required": "Mae angen enw'r cais", "The_channel_name_is_required": "Mae angen enw'r sianel", - "The_emails_are_being_sent": "Mae'r negeseuon e-bost yn cael eu hanfon.", - "The_field_is_required": "Mae'r maes %s yn ofynnol.", + "The_emails_are_being_sent": "Mae'r negeseuon e-bost yn cael eu hanfon.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Ni fydd maint y delwedd yn gweithio oherwydd na allwn ganfod ImageMagick neu GraphicsMagick ar eich gweinydd.", "The_redirectUri_is_required": "Mae angen y redirectUri", "The_server_will_restart_in_s_seconds": "Bydd y gweinydd yn ailgychwyn yn %s eiliad", diff --git a/packages/i18n/src/locales/da.i18n.json b/packages/i18n/src/locales/da.i18n.json index a675ab4843c0..2aabbfcd8642 100644 --- a/packages/i18n/src/locales/da.i18n.json +++ b/packages/i18n/src/locales/da.i18n.json @@ -3521,8 +3521,7 @@ "The_application_name_is_required": "Ansøgningsnavnet er påkrævet", "The_channel_name_is_required": "Kanalnavnet er påkrævet", "The_emails_are_being_sent": "E-mailsne bliver sendt.", - "The_empty_room__roomName__will_be_removed_automatically": "Det tomme rum {{roomName}} fjernes automatisk.", - "The_field_is_required": "Feltet%s er påkrævet.", + "The_empty_room__roomName__will_be_removed_automatically": "Det tomme rum {{roomName}} fjernes automatisk.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Billedforstørrelsen fungerer ikke, fordi vi ikke kan opdage ImageMagick eller GraphicsMagick installeret på din server.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Meddelelsen er en diskussion og du vil derfor ikke kunne gendanne meddelelserne!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Mobilmeddelelser blev deaktiveret for alle brugere. Tilgå \"Admin > Push\" for at aktivere Push Gateway igen", diff --git a/packages/i18n/src/locales/de-AT.i18n.json b/packages/i18n/src/locales/de-AT.i18n.json index 0be8030f5738..bbe960596a28 100644 --- a/packages/i18n/src/locales/de-AT.i18n.json +++ b/packages/i18n/src/locales/de-AT.i18n.json @@ -2368,8 +2368,7 @@ "Thank_you_for_your_feedback": "Vielen Dank für Ihre Rückmeldung.", "The_application_name_is_required": "Es muss ein Name für diese Anwendung angegeben werden.", "The_channel_name_is_required": "Ein Name für den Raum muss angegeben werden.", - "The_emails_are_being_sent": "Die E-Mails werden gesendet.", - "The_field_is_required": "Das Feld %s ist erforderlich.", + "The_emails_are_being_sent": "Die E-Mails werden gesendet.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Die automatische Skalierung der Bilder funktioniert nicht, da ImageMagick oder GraphicsMagick nicht auf dem Server installiert sind.", "The_redirectUri_is_required": "Es muss eine Weiterleitung-URL angegeben werden.", "The_server_will_restart_in_s_seconds": "Der Server wird in %s Sekunden neu gestartet", diff --git a/packages/i18n/src/locales/de-IN.i18n.json b/packages/i18n/src/locales/de-IN.i18n.json index 41da8fb3c809..edccd128e314 100644 --- a/packages/i18n/src/locales/de-IN.i18n.json +++ b/packages/i18n/src/locales/de-IN.i18n.json @@ -2661,8 +2661,7 @@ "Thank_you_for_your_feedback": "Vielen Dank für Deine Rückmeldung", "The_application_name_is_required": "Es muss ein Name für diese Anwendung angegeben werden", "The_channel_name_is_required": "Ein Name für den Kanal muss angegeben werden", - "The_emails_are_being_sent": "E-Mails werden gesendet", - "The_field_is_required": "Das Feld %s ist erforderlich", + "The_emails_are_being_sent": "E-Mails werden gesendet", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Die automatische Skalierung der Bilder funktioniert nicht, da ImageMagick oder GraphicsMagick nicht auf dem Server installiert sind.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Diese Nachricht ist eine Diskussion. Wenn Du diese löschst, wirst Du die Nachrichten der Diskussion nicht mehr auffinden können.", "The_peer__peer__does_not_exist": "Der Peer {{peer}} ist nicht vorhanden.", diff --git a/packages/i18n/src/locales/de.i18n.json b/packages/i18n/src/locales/de.i18n.json index 72963c308e67..59e329014186 100644 --- a/packages/i18n/src/locales/de.i18n.json +++ b/packages/i18n/src/locales/de.i18n.json @@ -4635,8 +4635,7 @@ "The_application_name_is_required": "Es muss ein Name für diese Anwendung angegeben werden", "The_channel_name_is_required": "Ein Name für den Channel muss angegeben werden", "The_emails_are_being_sent": "E-Mails werden gesendet", - "The_empty_room__roomName__will_be_removed_automatically": "Der leere Raum {{roomName}} wird automatisch entfernt.", - "The_field_is_required": "Das Feld %s ist erforderlich", + "The_empty_room__roomName__will_be_removed_automatically": "Der leere Raum {{roomName}} wird automatisch entfernt.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Die automatische Skalierung der Bilder funktioniert nicht, da ImageMagick oder GraphicsMagick nicht auf dem Server installiert sind.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Diese Nachricht ist eine Diskussion. Wenn Sie diese löschen, werden Sie die Nachrichten der Diskussion nicht mehr auffinden können.", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Die mobilen Benachrichtigungen wurden für alle Benutzer deaktiviert, wechseln Sie zu \"Admin > Push\", um das Push-Gateway erneut zu aktivieren", diff --git a/packages/i18n/src/locales/el.i18n.json b/packages/i18n/src/locales/el.i18n.json index 731a56695f7a..3e335c6638d3 100644 --- a/packages/i18n/src/locales/el.i18n.json +++ b/packages/i18n/src/locales/el.i18n.json @@ -2373,8 +2373,7 @@ "Thank_you_for_your_feedback": "Ευχαριστούμε για τα σχόλιά σας", "The_application_name_is_required": "Το όνομα της εφαρμογής απαιτείται", "The_channel_name_is_required": "Το όνομα του καναλιού απαιτείται", - "The_emails_are_being_sent": "Τα μηνύματα ηλεκτρονικού ταχυδρομείου που αποστέλλονται.", - "The_field_is_required": "Το πεδίο %s απαιτείται.", + "The_emails_are_being_sent": "Τα μηνύματα ηλεκτρονικού ταχυδρομείου που αποστέλλονται.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Το μέγεθος της εικόνας δεν θα λειτουργήσει, επειδή δεν μπορεί να ανιχνεύσει ImageMagick ή GraphicsMagick εγκατεστημένο στον server σας.", "The_redirectUri_is_required": "Η redirectUri απαιτείται", "The_server_will_restart_in_s_seconds": "Ο διακομιστής θα κάνει επανεκκίνηση στο %s δευτερόλεπτα", diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 849582f934b7..796e9d0519ff 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -1682,7 +1682,7 @@ "Direct_Message": "Direct message", "Livechat_Facebook_Enabled": "Facebook integration enabled", "Direct_message_creation_description": "Select one or more people to message", - "Direct_message_creation_error": "Please select at least one person", + "Direct_message_creation_error": "Select at least one person", "Direct_message_creation_description_hint": "More people cannot be added once created", "Direct_message_someone": "Direct message someone", "Direct_message_you_have_joined": "You have joined a new direct message with", @@ -4239,7 +4239,6 @@ "Please_fill_all_the_information": "Please fill all the information", "Please_fill_an_email": "Please fill an email", "Please_fill_name_and_email": "Please fill name and email", - "Please_fill_out_reason_for_report": "Please fill out the reason for the report", "Please_select_an_user": "Please select an user", "Please_select_enabled_yes_or_no": "Please select an option for Enabled", "Please_select_visibility": "Please select a visibility", @@ -4390,6 +4389,7 @@ "Real_Time_Monitoring": "Real-time Monitoring", "RealName_Change_Disabled": "Your Rocket.Chat administrator has disabled the changing of names", "Reason_for_joining": "Reason for joining", + "Reason_for_report": "Reason for report", "Reason_To_Join": "Reason to Join", "Receive_alerts": "Receive alerts", "Receive_Group_Mentions": "Receive @all and @here mentions", @@ -4583,6 +4583,7 @@ "Robot_Instructions_File_Content": "Robots.txt File Contents", "Root": "Root", "Required_action": "Required action", + "Required_field": "{{field}} required", "Default_Referrer_Policy": "Default Referrer Policy", "Default_Referrer_Policy_Description": "This controls the 'referrer' header that's sent when requesting embedded media from other servers. For more information, refer to [this link from MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy). Remember, a full page refresh is required for this to take effect", "No_feature_to_preview": "No feature to preview", @@ -5279,7 +5280,6 @@ "The_channel_name_is_required": "The channel name is required", "The_emails_are_being_sent": "The emails are being sent.", "The_empty_room__roomName__will_be_removed_automatically": "The empty room {{roomName}} will be removed automatically.", - "The_field_is_required": "The field %s is required.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "The image resize will not work because we can not detect ImageMagick or GraphicsMagick installed on your server.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "The message is a discussion you will not be able to recover the messages!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "The mobile notifications were disabled to all users, go to \"Admin > Push\" to enable the Push Gateway again", diff --git a/packages/i18n/src/locales/eo.i18n.json b/packages/i18n/src/locales/eo.i18n.json index 1558424c9445..907767a7f7da 100644 --- a/packages/i18n/src/locales/eo.i18n.json +++ b/packages/i18n/src/locales/eo.i18n.json @@ -2366,8 +2366,7 @@ "Thank_you_for_your_feedback": "Dankon pro viaj sugestoj", "The_application_name_is_required": "La aplika nomo estas postulita", "The_channel_name_is_required": "La kanala nomo estas postulita", - "The_emails_are_being_sent": "La retpoŝtoj estas senditaj.", - "The_field_is_required": "La kampo%s estas postulita.", + "The_emails_are_being_sent": "La retpoŝtoj estas senditaj.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "La regrandigo de bildoj ne funkcios ĉar ni ne povas detekti ImageMagick aŭ GraphicsMagick instalitan sur via servilo.", "The_redirectUri_is_required": "La redirectUri estas postulita", "The_server_will_restart_in_s_seconds": "La servilo rekomencos en%s sekundoj", diff --git a/packages/i18n/src/locales/es.i18n.json b/packages/i18n/src/locales/es.i18n.json index a276a3c51690..4a690dd7a4b2 100644 --- a/packages/i18n/src/locales/es.i18n.json +++ b/packages/i18n/src/locales/es.i18n.json @@ -4109,8 +4109,7 @@ "The_application_name_is_required": "El nombre de la aplicación es obligatorio", "The_channel_name_is_required": "El nombre del canal es obligatorio", "The_emails_are_being_sent": "Los correos electrónicos se están enviando.", - "The_empty_room__roomName__will_be_removed_automatically": "La sala vacía {{roomName}} se eliminará automáticamente.", - "The_field_is_required": "El campo %s es obligatorio.", + "The_empty_room__roomName__will_be_removed_automatically": "La sala vacía {{roomName}} se eliminará automáticamente.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "El ajuste de tamaño de las imágenes no funcionará porque no detectamos ImageMagick o GraphicsMagick instalados en tu servidor.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "El mensaje es una discusión, así que no podrás recuperar los mensajes", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Las notificaciones móviles se han deshabilitado para todos los usuarios. Ve a \"Administración\" > \"Push\" para habilitar puerta de enlace push nuevamente", diff --git a/packages/i18n/src/locales/fa.i18n.json b/packages/i18n/src/locales/fa.i18n.json index c4850a7d30eb..b14bc31d7733 100644 --- a/packages/i18n/src/locales/fa.i18n.json +++ b/packages/i18n/src/locales/fa.i18n.json @@ -2702,7 +2702,6 @@ "The_application_name_is_required": "نام نرم افزار مورد نیاز است", "The_channel_name_is_required": "نام کانال نیاز است", "The_emails_are_being_sent": "ایمیل در حال ارسال.", - "The_field_is_required": "زمینه به %s مورد نیاز است.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "تغییر اندازه تصویر به کار نخواهد کرد زیرا ما نمی توانیم تشخیص ImageMagick را یا GraphicsMagick بر روی سرور خود نصب شده است.", "The_redirectUri_is_required": "redirectUri مورد نیاز است", "The_server_will_restart_in_s_seconds": "سرور در %s ثانیه راه اندازی مجدد خواهد", diff --git a/packages/i18n/src/locales/fi.i18n.json b/packages/i18n/src/locales/fi.i18n.json index 17b5f65eab31..26ba8019aeb1 100644 --- a/packages/i18n/src/locales/fi.i18n.json +++ b/packages/i18n/src/locales/fi.i18n.json @@ -4727,8 +4727,7 @@ "The_application_will_be_able_to": "<1>{{appName}} voi:", "The_channel_name_is_required": "Kanavan nimi on pakollinen", "The_emails_are_being_sent": "Sähköpostiviestejä lähetetään.", - "The_empty_room__roomName__will_be_removed_automatically": "Tyhjä huone {{roomName}} poistetaan automaattisesti.", - "The_field_is_required": "Kenttä %s on pakollinen.", + "The_empty_room__roomName__will_be_removed_automatically": "Tyhjä huone {{roomName}} poistetaan automaattisesti.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Kuvien koon muuttaminen ei toimi, koska ImageMagickia tai GraphicsMagickia ei havaittu asennettuna palvelimessa.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Viesti on keskustelu, et voi palauttaa näitä viestejä!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Mobiili-ilmoitukset oli poistettu käytöstä kaikilta käyttäjiltä. Ota Push Gateway uudelleen käyttöön kohdassa \"Admin > Push\"", diff --git a/packages/i18n/src/locales/fr.i18n.json b/packages/i18n/src/locales/fr.i18n.json index 84d33eaf5330..80e4504d2085 100644 --- a/packages/i18n/src/locales/fr.i18n.json +++ b/packages/i18n/src/locales/fr.i18n.json @@ -4121,8 +4121,7 @@ "The_application_name_is_required": "Le nom de l'application est requis", "The_channel_name_is_required": "Le nom du canal est obligatoire", "The_emails_are_being_sent": "Les e-mails sont en cours d'envoi.", - "The_empty_room__roomName__will_be_removed_automatically": "Le salon vide {{roomName}} sera supprimé automatiquement.", - "The_field_is_required": "Le champ %s est requis.", + "The_empty_room__roomName__will_be_removed_automatically": "Le salon vide {{roomName}} sera supprimé automatiquement.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Le redimensionnement de l'image ne fonctionnera pas car nous n'avons pas trouvé ImageMagick ou GraphicsMagick installé sur votre serveur.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Le message est une discussion, vous ne pourrez pas récupérer les messages.", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Les notifications mobiles ont été désactivées pour tous les utilisateurs, accédez à \"Admin > Push\" pour réactiver la passerelle Push", diff --git a/packages/i18n/src/locales/he.i18n.json b/packages/i18n/src/locales/he.i18n.json index 33a4b920b4b2..499e2ca41d2d 100644 --- a/packages/i18n/src/locales/he.i18n.json +++ b/packages/i18n/src/locales/he.i18n.json @@ -1304,8 +1304,7 @@ "Thank_you_for_your_feedback": "תודה לך על המשוב", "The_application_name_is_required": "שם האפליקציה נדרש", "The_channel_name_is_required": "שם הערוץ נדרש", - "The_emails_are_being_sent": "האימיילים נשלחים.", - "The_field_is_required": "השדה %s הוא חובה.", + "The_emails_are_being_sent": "האימיילים נשלחים.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "שינוי גודל התמונה לא יעבוד כי אנחנו לא יכולים לזהות ImageMagick או GraphicsMagick מותקן על השרת שלך.", "The_redirectUri_is_required": "RedirectUri נדרש", "The_server_will_restart_in_s_seconds": "השרת יפעיל את עצמו מחדש בעוד ", diff --git a/packages/i18n/src/locales/hi-IN.i18n.json b/packages/i18n/src/locales/hi-IN.i18n.json index 1049d8495d86..090e081e83fa 100644 --- a/packages/i18n/src/locales/hi-IN.i18n.json +++ b/packages/i18n/src/locales/hi-IN.i18n.json @@ -4010,7 +4010,6 @@ "Please_fill_all_the_information": "कृपया सारी जानकारी भरें", "Please_fill_an_email": "कृपया एक ईमेल भरें", "Please_fill_name_and_email": "कृपया नाम और ईमेल भरें", - "Please_fill_out_reason_for_report": "कृपया रिपोर्ट का कारण भरें", "Please_select_an_user": "कृपया एक उपयोगकर्ता चुनें", "Please_select_enabled_yes_or_no": "कृपया सक्षम के लिए एक विकल्प चुनें", "Please_select_visibility": "कृपया एक दृश्यता चुनें", @@ -4988,8 +4987,7 @@ "The_application_will_be_able_to": "<1>{{appName}} यह करने में सक्षम होगा:", "The_channel_name_is_required": "चैनल का नाम आवश्यक है", "The_emails_are_being_sent": "ईमेल भेजे जा रहे हैं.", - "The_empty_room__roomName__will_be_removed_automatically": "खाली कमरा {{roomName}} स्वचालित रूप से हटा दिया जाएगा।", - "The_field_is_required": "फ़ील्ड %s आवश्यक है.", + "The_empty_room__roomName__will_be_removed_automatically": "खाली कमरा {{roomName}} स्वचालित रूप से हटा दिया जाएगा।", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "छवि का आकार बदलना काम नहीं करेगा क्योंकि हम आपके सर्वर पर स्थापित ImageMagick या ग्राफ़िक्सMagick का पता नहीं लगा सकते हैं।", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "संदेश एक चर्चा है आप संदेशों को पुनर्प्राप्त नहीं कर पाएंगे!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "मोबाइल सूचनाएं सभी उपयोगकर्ताओं के लिए अक्षम कर दी गई थीं, पुश गेटवे को फिर से सक्षम करने के लिए \"एडमिन > पुश\" पर जाएं", diff --git a/packages/i18n/src/locales/hr.i18n.json b/packages/i18n/src/locales/hr.i18n.json index 84c4295d5201..c9547b1042e9 100644 --- a/packages/i18n/src/locales/hr.i18n.json +++ b/packages/i18n/src/locales/hr.i18n.json @@ -2501,7 +2501,6 @@ "The_application_name_is_required": "Naziv aplikacije je potreban", "The_channel_name_is_required": "Ime sobe je potrebno", "The_emails_are_being_sent": "E-mailovi su poslani.", - "The_field_is_required": "Polje %s je traženo.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Promjena veličine slike neće raditi, jer ne možemo provjeriti da je ImageMagick ili GraphicsMagick instaliran na vašem poslužitelju.", "The_redirectUri_is_required": "RedirectUri je potrebno", "The_server_will_restart_in_s_seconds": "Poslužitelj će se ponovno pokrenuti u %s sekundi", diff --git a/packages/i18n/src/locales/hu.i18n.json b/packages/i18n/src/locales/hu.i18n.json index f7f85536c183..a281e3b2c64b 100644 --- a/packages/i18n/src/locales/hu.i18n.json +++ b/packages/i18n/src/locales/hu.i18n.json @@ -4540,8 +4540,7 @@ "The_application_name_is_required": "Az alkalmazás neve kötelező", "The_channel_name_is_required": "A csatorna neve kötelező", "The_emails_are_being_sent": "Az e-mailek elküldésre kerültek.", - "The_empty_room__roomName__will_be_removed_automatically": "Az üres {{roomName}} szoba automatikusan el lesz távolítva.", - "The_field_is_required": "A(z) %s mező kötelező.", + "The_empty_room__roomName__will_be_removed_automatically": "Az üres {{roomName}} szoba automatikusan el lesz távolítva.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "A kép átméretezése nem fog működni, mert nem észlelhető a kiszolgálóra telepített ImageMagick vagy GraphicsMagick program.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Az üzenet egy megbeszélés, nem lesz képes helyreállítani az üzeneteket!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "A mobil értesítések le lettek tiltva az összes felhasználó számára. Menjen az „Adminisztráció → Leküldés” menüponthoz a leküldéses átjáró újbóli engedélyezéséhez.", diff --git a/packages/i18n/src/locales/id.i18n.json b/packages/i18n/src/locales/id.i18n.json index 1abc2fadd68c..6eb8dd75ec6e 100644 --- a/packages/i18n/src/locales/id.i18n.json +++ b/packages/i18n/src/locales/id.i18n.json @@ -2374,7 +2374,6 @@ "The_application_name_is_required": "Nama aplikasi diperlukan", "The_channel_name_is_required": "Nama channel diperlukan", "The_emails_are_being_sent": "Email telah dikirim.", - "The_field_is_required": "Kolom %s wajib diisi", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Gambar resize tidak akan bekerja karena kita tidak dapat mendeteksi ImageMagick atau GraphicsMagick diinstal pada server Anda.", "The_redirectUri_is_required": "The redirectUri diperlukan", "The_server_will_restart_in_s_seconds": "server akan restart%s detik", diff --git a/packages/i18n/src/locales/it.i18n.json b/packages/i18n/src/locales/it.i18n.json index 160dbe3cf40e..f4bbf05e2faf 100644 --- a/packages/i18n/src/locales/it.i18n.json +++ b/packages/i18n/src/locales/it.i18n.json @@ -2920,8 +2920,7 @@ "Thank_you_for_your_feedback": "Grazie per il tuo feedback", "The_application_name_is_required": "Il nome dell'applicazione è richiesta", "The_channel_name_is_required": "Il nome del canale è richiesto", - "The_emails_are_being_sent": "Le email verranno inviate.", - "The_field_is_required": "Il campo %s è richiesto.", + "The_emails_are_being_sent": "Le email verranno inviate.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Il ridimensionamento dell'immagine non funzionerà se non rileva ImageMagick or GraphicsMagick installato sul tuo server.", "The_redirectUri_is_required": "Il redirectUri é richiesto", "The_server_will_restart_in_s_seconds": "Il server si riavvierà in %s secondi", diff --git a/packages/i18n/src/locales/ja.i18n.json b/packages/i18n/src/locales/ja.i18n.json index 982f9495d914..dcdf00bf7ed6 100644 --- a/packages/i18n/src/locales/ja.i18n.json +++ b/packages/i18n/src/locales/ja.i18n.json @@ -4070,8 +4070,7 @@ "The_application_name_is_required": "アプリケーション名は必須です", "The_channel_name_is_required": "チャネル名は必須です", "The_emails_are_being_sent": "メールを送信中です。", - "The_empty_room__roomName__will_be_removed_automatically": "空のルーム{{roomName}}は自動的に削除されます。", - "The_field_is_required": "%s 項目は、必須です。", + "The_empty_room__roomName__will_be_removed_automatically": "空のルーム{{roomName}}は自動的に削除されます。", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "サーバーにインストールされたImageMagickまたはGraphicsMagickを検出できないため、画像のサイズ変更が機能しません。", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "このメッセージはメッセージを復元できないディスカッションです!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "すべてのユーザーに対してモバイル通知が無効になりました。[管理]>[プッシュ]に移動して、プッシュゲートウェイを再度有効にしてください", diff --git a/packages/i18n/src/locales/ka-GE.i18n.json b/packages/i18n/src/locales/ka-GE.i18n.json index 3c550632cc4c..8f2098ff495f 100644 --- a/packages/i18n/src/locales/ka-GE.i18n.json +++ b/packages/i18n/src/locales/ka-GE.i18n.json @@ -3165,7 +3165,6 @@ "The_channel_name_is_required": "საჭიროა არხის სახელი", "The_emails_are_being_sent": "ელ.ფოსტა იგზავნება.", "The_empty_room__roomName__will_be_removed_automatically": "ცარიელი ოთახი {{roomName}} ავტომატურად მოიხსნება.", - "The_field_is_required": "ველი %s აუცილებელია.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "სურათის ზომის შეცვლა არ იმუშავებს, რადგან ჩვენ ვერ ვპოულობთ თქვენს სერვერზე დაყენებულ ImageMagick ან GraphicsMagick-ს.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "შეტყობინება არის განხილვა და თქვენ ვერ შეძლებთ შეტყობინებების აღდგენას", "The_redirectUri_is_required": "გადამისამართების ლინკია საჭირო", diff --git a/packages/i18n/src/locales/km.i18n.json b/packages/i18n/src/locales/km.i18n.json index 997ee66a00e7..8927c7f3335b 100644 --- a/packages/i18n/src/locales/km.i18n.json +++ b/packages/i18n/src/locales/km.i18n.json @@ -2691,8 +2691,7 @@ "Thank_you_for_your_feedback": "សូមអរគុណសម្រាប់មតិរបស់អ្នក", "The_application_name_is_required": "ឈ្មោះកម្មវិធីនេះគឺត្រូវបានទាមទារ", "The_channel_name_is_required": "ឈ្មោះឆានែលនេះគឺត្រូវបានទាមទារ", - "The_emails_are_being_sent": "នេះ​អ៊ីមែល​ត្រូវ​បាន​បញ្ជូន​។", - "The_field_is_required": "ចន្លោះ %s ត្រូវ​បំពេញ", + "The_emails_are_being_sent": "នេះ​អ៊ីមែល​ត្រូវ​បាន​បញ្ជូន​។", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "ប្ដូរទំហំរូបភាពនឹងមិនធ្វើការដោយសារតែយើងមិនអាចរកឃើញ ImageMagick ឬ GraphicsMagick ដែលបានដំឡើងនៅលើម៉ាស៊ីនបម្រើរបស់អ្នក។", "The_redirectUri_is_required": "redirectUri នេះគឺត្រូវបានទាមទារ", "The_server_will_restart_in_s_seconds": "ម៉ាស៊ីនបម្រើនេះនឹងចាប់ផ្ដើមឡើងវិញនៅក្នុង %s វិនាទី", diff --git a/packages/i18n/src/locales/ko.i18n.json b/packages/i18n/src/locales/ko.i18n.json index ad5818ab9f85..5df1f0db78ba 100644 --- a/packages/i18n/src/locales/ko.i18n.json +++ b/packages/i18n/src/locales/ko.i18n.json @@ -3470,8 +3470,7 @@ "The_application_name_is_required": "응용프로그램명이 필요합니다.", "The_channel_name_is_required": "채널명이 필요합니다.", "The_emails_are_being_sent": "이메일을 전송 중입니다.", - "The_empty_room__roomName__will_be_removed_automatically": "사용하지 않는 대화방 {{roomName}}은 자동으로 제거됩니다.", - "The_field_is_required": "%s 필드는 필수 항목입니다.", + "The_empty_room__roomName__will_be_removed_automatically": "사용하지 않는 대화방 {{roomName}}은 자동으로 제거됩니다.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "서버에 ImageMagick 또는 GraphicMagick이 설치되어 있지 않아 이미지 크기를 재조정할 수 없습니다.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "그 메시지는 메시지 복구가 불가능한 토론입니다.", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "모바일 알림이 모든 사용자에게 사용 중지되었습니다. \"관리자> 푸시\"로 이동하여 푸시 게이트웨이를 다시 사용으로 변경하십시오.", diff --git a/packages/i18n/src/locales/ku.i18n.json b/packages/i18n/src/locales/ku.i18n.json index 9b4a4d1aaeb2..a4c5e7108a2f 100644 --- a/packages/i18n/src/locales/ku.i18n.json +++ b/packages/i18n/src/locales/ku.i18n.json @@ -2360,8 +2360,7 @@ "Thank_you_for_your_feedback": "Spas ji bo we Deng xwe", "The_application_name_is_required": "Navê sepanê pêwîst e", "The_channel_name_is_required": "The name kanala pêwîst e", - "The_emails_are_being_sent": "Mailan têne şandin.", - "The_field_is_required": "Li qadê %s tê xwestin.", + "The_emails_are_being_sent": "Mailan têne şandin.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Mezinahiyê image xebata wê ne ji ber ku em nikarin bi durustî .Pêşîn an GraphicsMagick li ser server te sazkirin.", "The_redirectUri_is_required": "The redirectUri pêwîst e", "The_server_will_restart_in_s_seconds": "ڕاژەکارەکە هەڵ ئەبێتەوە لە %s چرکەدا", diff --git a/packages/i18n/src/locales/lo.i18n.json b/packages/i18n/src/locales/lo.i18n.json index d427b251e863..547e9274a6ff 100644 --- a/packages/i18n/src/locales/lo.i18n.json +++ b/packages/i18n/src/locales/lo.i18n.json @@ -2403,8 +2403,7 @@ "Thank_you_for_your_feedback": "ຂໍ​ຂອບ​ໃຈ​ທ່ານ​ສໍາ​ລັບ​ການ​ຕໍາ​ນິ​ຕິ​ຊົມ​ຂອງ​ທ່ານ​", "The_application_name_is_required": "ຊື່ຄໍາຮ້ອງສະຫມັກແມ່ນຈໍາເປັນຕ້ອງ", "The_channel_name_is_required": "ຊື່ຊ່ອງທາງການຈໍາເປັນຕ້ອງ", - "The_emails_are_being_sent": "ອີເມວໄດ້ຖືກສົ່ງໄປແລ້ວ.", - "The_field_is_required": "ພາກສະຫນາມ %s ແມ່ນຕ້ອງການ.", + "The_emails_are_being_sent": "ອີເມວໄດ້ຖືກສົ່ງໄປແລ້ວ.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "ການ resize ຮູບພາບຈະບໍ່ເຮັດວຽກເພາະວ່າພວກເຮົາບໍ່ສາມາດກວດພົບ ImageMagick ຫຼື GraphicsMagick ການຕິດຕັ້ງໃນເຄື່ອງແມ່ຂ່າຍຂອງທ່ານ.", "The_redirectUri_is_required": "The redirectUri ຈໍາເປັນຕ້ອງມີ", "The_server_will_restart_in_s_seconds": "ເຄື່ອງແມ່ຂ່າຍຂອງຈະເລີ່ມການເຮັດວຽກໃນ %s ວິນາທີ", diff --git a/packages/i18n/src/locales/lt.i18n.json b/packages/i18n/src/locales/lt.i18n.json index 88fb66dc554f..7408a8eeb762 100644 --- a/packages/i18n/src/locales/lt.i18n.json +++ b/packages/i18n/src/locales/lt.i18n.json @@ -2421,8 +2421,7 @@ "Thank_you_for_your_feedback": "Dėkojame už jūsų atsiliepimus", "The_application_name_is_required": "Būtina nurodyti programos pavadinimą", "The_channel_name_is_required": "Reikalingas kanalo pavadinimas", - "The_emails_are_being_sent": "El. Laiškai siunčiami.", - "The_field_is_required": "Laukas%s reikalingas.", + "The_emails_are_being_sent": "El. Laiškai siunčiami.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Vaizdo dydžio keitimas neveiks, nes negalime nustatyti serverio \"ImageMagick\" ar \"GraphicsMagick\".", "The_redirectUri_is_required": "Reikia redirectUri", "The_server_will_restart_in_s_seconds": "Serveris bus paleistas iš naujo po%s sekundžių", diff --git a/packages/i18n/src/locales/lv.i18n.json b/packages/i18n/src/locales/lv.i18n.json index 544eac3dbeb3..a9e38267b01c 100644 --- a/packages/i18n/src/locales/lv.i18n.json +++ b/packages/i18n/src/locales/lv.i18n.json @@ -2375,8 +2375,7 @@ "Thank_you_for_your_feedback": "Paldies par jūsu atsauksmēm", "The_application_name_is_required": "Pieteikuma nosaukums ir nepieciešams", "The_channel_name_is_required": "Ir nepieciešams kanāla nosaukums", - "The_emails_are_being_sent": "E-pasta ziņojumi tiek nosūtīti.", - "The_field_is_required": "Nepieciešams %s lauks.", + "The_emails_are_being_sent": "E-pasta ziņojumi tiek nosūtīti.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Attēla izmēru maiņa nestrādās, jo mēs nevaram atrast jūsu serverī uzinstalētu ImageMagick vai GraphicsMagick.", "The_redirectUri_is_required": "Nepieciešams RedirectUri ", "The_server_will_restart_in_s_seconds": "Serveris restartēsies pēc %s sekundēm", diff --git a/packages/i18n/src/locales/mn.i18n.json b/packages/i18n/src/locales/mn.i18n.json index 60e18063b49f..407c86309db8 100644 --- a/packages/i18n/src/locales/mn.i18n.json +++ b/packages/i18n/src/locales/mn.i18n.json @@ -2361,8 +2361,7 @@ "Thank_you_for_your_feedback": "Таны санал хүсэлтэнд баярлалаа", "The_application_name_is_required": "Програмын нэр шаардлагатай", "The_channel_name_is_required": "Сувгийн нэр шаардлагатай", - "The_emails_are_being_sent": "Э-мэйл илгээж байна.", - "The_field_is_required": "%s талбар шаардлагатай.", + "The_emails_are_being_sent": "Э-мэйл илгээж байна.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "ImageMagick эсвэл GraphicsMagick-г сервер дээрээ суулгаж чаддаггүй болохоор зургийн хэмжээг өөрчлөх боломжгүй.", "The_redirectUri_is_required": "RedirectUri шаардлагатай", "The_server_will_restart_in_s_seconds": "Сервер%s секундын дараа дахин эхлүүлэх болно", diff --git a/packages/i18n/src/locales/ms-MY.i18n.json b/packages/i18n/src/locales/ms-MY.i18n.json index 524260560a3f..9e203c69baf3 100644 --- a/packages/i18n/src/locales/ms-MY.i18n.json +++ b/packages/i18n/src/locales/ms-MY.i18n.json @@ -2372,8 +2372,7 @@ "Thank_you_for_your_feedback": "Terima kasih atas maklum balas anda", "The_application_name_is_required": "Nama permohonan diperlukan", "The_channel_name_is_required": "Nama saluran diperlukan", - "The_emails_are_being_sent": "E-mel yang sedang dihantar.", - "The_field_is_required": "Medan ini %s diperlukan", + "The_emails_are_being_sent": "E-mel yang sedang dihantar.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "The saiz semula imej tidak akan berfungsi kerana kita tidak dapat mengesan ImageMagick atau GraphicsMagick dipasang pada pelayan anda.", "The_redirectUri_is_required": "The redirectUri diperlukan", "The_server_will_restart_in_s_seconds": "Server akan memulakan semula dalam %s saat", diff --git a/packages/i18n/src/locales/nl.i18n.json b/packages/i18n/src/locales/nl.i18n.json index bf7f7ffb780c..9796181ae1bb 100644 --- a/packages/i18n/src/locales/nl.i18n.json +++ b/packages/i18n/src/locales/nl.i18n.json @@ -4109,8 +4109,7 @@ "The_application_name_is_required": "De naam van de applicatie is vereist", "The_channel_name_is_required": "De naam van het kanaal is vereist", "The_emails_are_being_sent": "De e-mails worden verzonden.", - "The_empty_room__roomName__will_be_removed_automatically": "De lege kamer {{roomName}} wordt automatisch verwijderd.", - "The_field_is_required": "Het veld %s is vereist.", + "The_empty_room__roomName__will_be_removed_automatically": "De lege kamer {{roomName}} wordt automatisch verwijderd.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Het wijzigen van de grootte van de afbeelding zal niet werken omdat we ImageMagick of GraphicsMagick niet kunnen detecteren die op uw server zijn geïnstalleerd.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Het bericht is een discussie, u kunt de berichten niet herstellen!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "De mobiele meldingen werden voor alle gebruikers uitgeschakeld, ga naar \"Admin > Push\" om de Push Gateway weer in te schakelen", diff --git a/packages/i18n/src/locales/no.i18n.json b/packages/i18n/src/locales/no.i18n.json index 5bdbf2fb89cc..a89485a5f6c3 100644 --- a/packages/i18n/src/locales/no.i18n.json +++ b/packages/i18n/src/locales/no.i18n.json @@ -3962,8 +3962,7 @@ "The_application_name_is_required": "Programnavnet kreves", "The_application_will_be_able_to": "<1>{{appName}} vil kunne:", "The_channel_name_is_required": "Kanalnavnet er påkrevd", - "The_emails_are_being_sent": "E-postene blir sendt.", - "The_field_is_required": "Feltet%s er påkrevd.", + "The_emails_are_being_sent": "E-postene blir sendt.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Bildestørrelsen fungerer ikke fordi vi ikke kan oppdage ImageMagick eller GraphicsMagick installert på serveren din.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Meldingen er en diskusjon, du vil ikke kunne gjenopprette meldingene!", "The_necessary_browser_permissions_for_location_sharing_are_not_granted": "De nødvendige nettlesertillatelsene for posisjonsdeling ble ikke gitt", diff --git a/packages/i18n/src/locales/pl.i18n.json b/packages/i18n/src/locales/pl.i18n.json index b7d60c54ee2c..e909624ad4a9 100644 --- a/packages/i18n/src/locales/pl.i18n.json +++ b/packages/i18n/src/locales/pl.i18n.json @@ -4543,8 +4543,7 @@ "The_application_name_is_required": "Wymagana jest nazwa aplikacji", "The_channel_name_is_required": "Wymagana jest nazwa pokoju", "The_emails_are_being_sent": "Wiadomości e-mail są wysyłane.", - "The_empty_room__roomName__will_be_removed_automatically": "Pusty pokój {{roomName}} zostanie automatycznie usunięty.", - "The_field_is_required": "Pole %s jest wymagane.", + "The_empty_room__roomName__will_be_removed_automatically": "Pusty pokój {{roomName}} zostanie automatycznie usunięty.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Zmiana rozmiaru obrazu nie będzie działać, ponieważ nie możemy wykryć zainstalowanego ImageMagick lub GraphicsMagick na serwerze.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Wiadomość jest dyskusją, której nie będziesz w stanie odzyskać!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Powiadomienia mobilne zostały wyłączone dla wszystkich użytkowników, idź do \"Admin>Push\" aby uruchomić ponownie bramę push", diff --git a/packages/i18n/src/locales/pt-BR.i18n.json b/packages/i18n/src/locales/pt-BR.i18n.json index dc62318cb230..b2575a190671 100644 --- a/packages/i18n/src/locales/pt-BR.i18n.json +++ b/packages/i18n/src/locales/pt-BR.i18n.json @@ -4223,8 +4223,7 @@ "The_application_name_is_required": "O nome do aplicativo é obrigatório", "The_channel_name_is_required": "O nome do canal é obrigatório", "The_emails_are_being_sent": "Os e-mails estão sendo enviados.", - "The_empty_room__roomName__will_be_removed_automatically": "A sala vazia {{roomName}} será removida automaticamente.", - "The_field_is_required": "O campo %s é obrigatório.", + "The_empty_room__roomName__will_be_removed_automatically": "A sala vazia {{roomName}} será removida automaticamente.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "O redimensionamento da imagem não vai funcionar porque não conseguimos detectar se o ImageMagick ou GraphicsMagick está instalado no seu servidor.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "A mensagem é uma discussão, você não poderá recuperar as mensagens!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "As notificações móveis foram desativadas para todos os usuários, vá para \"Admin > Push\" para ativar o Push Gateway novamente", diff --git a/packages/i18n/src/locales/pt.i18n.json b/packages/i18n/src/locales/pt.i18n.json index 8f4acc81dbdd..84d840b92a53 100644 --- a/packages/i18n/src/locales/pt.i18n.json +++ b/packages/i18n/src/locales/pt.i18n.json @@ -2729,8 +2729,7 @@ "Thank_you_for_your_feedback": "Obrigado pelo sua opinião", "The_application_name_is_required": "O nome da aplicação é obrigatório", "The_channel_name_is_required": "O nome do canal é obrigatório", - "The_emails_are_being_sent": "Os emails estão a ser enviados.", - "The_field_is_required": "O campo %s é obrigatório.", + "The_emails_are_being_sent": "Os emails estão a ser enviados.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "O redimensionamento da imagem não vai funcionar porque não conseguimos detectar ImageMagick ou GraphicsMagick instalado no seu servidor.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "A mensagem é uma discussão, não poderá recuperar as mensagens!", "The_peer__peer__does_not_exist": "O par {{peer}} não existe.", diff --git a/packages/i18n/src/locales/ro.i18n.json b/packages/i18n/src/locales/ro.i18n.json index aefc4d07065f..7266b1883386 100644 --- a/packages/i18n/src/locales/ro.i18n.json +++ b/packages/i18n/src/locales/ro.i18n.json @@ -2364,8 +2364,7 @@ "Thank_you_for_your_feedback": "Vă mulțumim pentru feedback", "The_application_name_is_required": "Este nevoie de numele aplicației", "The_channel_name_is_required": "Este nevoie de numele canalului", - "The_emails_are_being_sent": "E-mail-urile sunt trimise.", - "The_field_is_required": "Este nevoie de câmpul %s.", + "The_emails_are_being_sent": "E-mail-urile sunt trimise.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Redimensionarea imaginii nu va funcționa, deoarece nu putem detecta ImageMagick sau GraphicsMagick instalat pe server.", "The_redirectUri_is_required": "URI de redirectare este necesar", "The_server_will_restart_in_s_seconds": "Serverul va reporni în %s secunde", diff --git a/packages/i18n/src/locales/ru.i18n.json b/packages/i18n/src/locales/ru.i18n.json index 1829f7f2eb08..6edc8030513f 100644 --- a/packages/i18n/src/locales/ru.i18n.json +++ b/packages/i18n/src/locales/ru.i18n.json @@ -4294,8 +4294,7 @@ "The_application_name_is_required": "Требуется название приложения", "The_channel_name_is_required": "Требуется название канала", "The_emails_are_being_sent": "Письма отправляются.", - "The_empty_room__roomName__will_be_removed_automatically": "Пустой чат {{roomName}} будет удален автоматически.", - "The_field_is_required": "Поле %s обязательно.", + "The_empty_room__roomName__will_be_removed_automatically": "Пустой чат {{roomName}} будет удален автоматически.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Изменить размер изображения не получится, потому что мы не можем обнаружить установленные на вашем сервере ImageMagick или GraphicsMagick.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Сообщение обсуждения, вы не сможете восстановить сообщения!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Мобильные уведомления были отключены для всех пользователей, перейдите в \"Admin > Push\", чтобы снова включить Push Gateway", diff --git a/packages/i18n/src/locales/sk-SK.i18n.json b/packages/i18n/src/locales/sk-SK.i18n.json index f5bc7bfcbc58..d6cf085ad972 100644 --- a/packages/i18n/src/locales/sk-SK.i18n.json +++ b/packages/i18n/src/locales/sk-SK.i18n.json @@ -2375,8 +2375,7 @@ "Thank_you_for_your_feedback": "Ďakujeme vám za vašu spätnú väzbu", "The_application_name_is_required": "Názov aplikácie je povinný", "The_channel_name_is_required": "Názov kanála je povinný", - "The_emails_are_being_sent": "Posielajú sa e-maily.", - "The_field_is_required": "Je potrebné pole%s.", + "The_emails_are_being_sent": "Posielajú sa e-maily.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Zmena veľkosti obrázka nebude fungovať, pretože na vašom serveri nemôžeme nájsť aplikácie ImageMagick alebo GraphicsMagick.", "The_redirectUri_is_required": "Vyžaduje sa presmerovanie", "The_server_will_restart_in_s_seconds": "Server sa reštartuje v%s", diff --git a/packages/i18n/src/locales/sl-SI.i18n.json b/packages/i18n/src/locales/sl-SI.i18n.json index 668bb94dc2c5..64900b03860d 100644 --- a/packages/i18n/src/locales/sl-SI.i18n.json +++ b/packages/i18n/src/locales/sl-SI.i18n.json @@ -2355,8 +2355,7 @@ "Thank_you_for_your_feedback": "Hvala za vaše mnenje", "The_application_name_is_required": "Ime aplikacije je obvezno", "The_channel_name_is_required": "Ime kanala je obvezno", - "The_emails_are_being_sent": "Pošiljanje e-poštnih sporočil.", - "The_field_is_required": "Polje %s je obvezno.", + "The_emails_are_being_sent": "Pošiljanje e-poštnih sporočil.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Velikost slike ne bo delovala, ker ne moremo zaznati ImageMagick ali GraphicsMagick, nameščenega na vašem strežniku.", "The_redirectUri_is_required": "Preusmeritveni uri (redirectUri) je zahtevan", "The_server_will_restart_in_s_seconds": "Strežnik se bo znova zagnal v %s sekundah", diff --git a/packages/i18n/src/locales/sq.i18n.json b/packages/i18n/src/locales/sq.i18n.json index 312494da2e8d..c5fb06df9529 100644 --- a/packages/i18n/src/locales/sq.i18n.json +++ b/packages/i18n/src/locales/sq.i18n.json @@ -2365,8 +2365,7 @@ "Thank_you_for_your_feedback": "Faleminderit për komentin tuaj", "The_application_name_is_required": "Emri i aplikimit është e nevojshme", "The_channel_name_is_required": "Emri kanal është e nevojshme", - "The_emails_are_being_sent": "Email janë duke u dërguar.", - "The_field_is_required": "Fusha %s është e nevojshme.", + "The_emails_are_being_sent": "Email janë duke u dërguar.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Imazhi resize nuk do të funksionojë, sepse ne nuk mund të zbulojë ImageMagick ose GraphicsMagick instaluar në serverin tuaj.", "The_redirectUri_is_required": "RedirectUri është e nevojshme", "The_server_will_restart_in_s_seconds": "Serveri do të rifillojë në %s sekonda", diff --git a/packages/i18n/src/locales/sr.i18n.json b/packages/i18n/src/locales/sr.i18n.json index e26e8bd3862f..d60ff9ce80fe 100644 --- a/packages/i18n/src/locales/sr.i18n.json +++ b/packages/i18n/src/locales/sr.i18n.json @@ -2170,8 +2170,7 @@ "Thank_you_for_your_feedback": "Хвала на повратним информацијама", "The_application_name_is_required": "Име апликације је потребно", "The_channel_name_is_required": "Име канала је потребно", - "The_emails_are_being_sent": "Е-поруке се шаљу.", - "The_field_is_required": "је обавезно поље %s.", + "The_emails_are_being_sent": "Е-поруке се шаљу.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Ресизе слика неће радити, јер не можемо открити ИмагеМагицк или грапхицсмагицк инсталиран на вашем серверу.", "The_redirectUri_is_required": "РедирецтУри је потребна", "The_server_will_restart_in_s_seconds": "Сервер ће се поново покренути у %s секунди", diff --git a/packages/i18n/src/locales/sv.i18n.json b/packages/i18n/src/locales/sv.i18n.json index 4e436fe6c538..4f091bb77fa5 100644 --- a/packages/i18n/src/locales/sv.i18n.json +++ b/packages/i18n/src/locales/sv.i18n.json @@ -4735,8 +4735,7 @@ "The_application_will_be_able_to": "<1>{{appName}} kommer att kunna:", "The_channel_name_is_required": "Kanalnamnet krävs ", "The_emails_are_being_sent": "E-postmeddelandena skickas.", - "The_empty_room__roomName__will_be_removed_automatically": "Det tomma rummet {{roomName}} tas bort automatiskt.", - "The_field_is_required": "Fältet %s krävs.", + "The_empty_room__roomName__will_be_removed_automatically": "Det tomma rummet {{roomName}} tas bort automatiskt.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Det kommer inte att gå att ändra storlek på bilden, eftersom vi inte kan hitta ImageMagick eller GraphicsMagick på din server.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Meddelandet är en diskussion. Du kan inte återskapa meddelandena.", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "Mobilaviseringar inaktiverades för alla användare. Gå till \"Administration > Push\" om du vill aktivera en gateway för pushmeddelanden igen", diff --git a/packages/i18n/src/locales/ta-IN.i18n.json b/packages/i18n/src/locales/ta-IN.i18n.json index 7a2c562d4fff..c4c941c40d7b 100644 --- a/packages/i18n/src/locales/ta-IN.i18n.json +++ b/packages/i18n/src/locales/ta-IN.i18n.json @@ -2366,7 +2366,6 @@ "The_application_name_is_required": "விண்ணப்ப பெயர் தேவை", "The_channel_name_is_required": "சேனல் பெயர் தேவைப்படுகிறது", "The_emails_are_being_sent": "மின்னஞ்சல்களை அனுப்பி வைக்கப்படுகின்றனர்.", - "The_field_is_required": "துறையில்% கள் தேவை.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "நாங்கள் ImageMagick அல்லது GraphicsMagick உங்கள் சர்வரில் நிறுவப்பட்ட கண்டறிய முடியாது, ஏனெனில் படஅளவை இயங்காது.", "The_redirectUri_is_required": "redirecturi தேவை", "The_server_will_restart_in_s_seconds": "சர்வர் %s வினாடிகள் மீண்டும் தொடங்கும்", diff --git a/packages/i18n/src/locales/th-TH.i18n.json b/packages/i18n/src/locales/th-TH.i18n.json index 7d393a3034fb..520f6ce3a20f 100644 --- a/packages/i18n/src/locales/th-TH.i18n.json +++ b/packages/i18n/src/locales/th-TH.i18n.json @@ -2359,8 +2359,7 @@ "Thank_you_for_your_feedback": "ขอบคุณสำหรับความคิดเห็นของคุณ", "The_application_name_is_required": "ต้องระบุชื่อแอ็พพลิเคชัน", "The_channel_name_is_required": "ต้องระบุชื่อช่อง", - "The_emails_are_being_sent": "กำลังส่งอีเมล", - "The_field_is_required": "ต้องระบุฟิลด์%s", + "The_emails_are_being_sent": "กำลังส่งอีเมล", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "การปรับขนาดภาพจะไม่ทำงานเนื่องจากเราไม่สามารถตรวจพบ ImageMagick หรือ GraphicsMagick ที่ติดตั้งบนเซิร์ฟเวอร์ของคุณ", "The_redirectUri_is_required": "จำเป็นต้องมี redirectUri", "The_server_will_restart_in_s_seconds": "เซิร์ฟเวอร์จะรีสตาร์ทเป็น %s วินาที", diff --git a/packages/i18n/src/locales/tr.i18n.json b/packages/i18n/src/locales/tr.i18n.json index 59b0c8927e23..c3e879031912 100644 --- a/packages/i18n/src/locales/tr.i18n.json +++ b/packages/i18n/src/locales/tr.i18n.json @@ -2801,8 +2801,7 @@ "Thank_you_for_your_feedback": "Görüşleriniz için teşekkür ederiz", "The_application_name_is_required": "Uygulama adı gerekli", "The_channel_name_is_required": "Kanal adı gerekli", - "The_emails_are_being_sent": "E-postalar gönderiliyor.", - "The_field_is_required": "%s alanı gerekli.", + "The_emails_are_being_sent": "E-postalar gönderiliyor.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Biz ImageMagick veya GraphicsMagick sunucunuzda yüklü algılayamaz çünkü resim boyutlandırmak çalışmaz.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Bu ileti bir tartışma olduğu için iletileri geri getiremeyeceksiniz!", "The_peer__peer__does_not_exist": "{{peer}} adında bir eş yok.", diff --git a/packages/i18n/src/locales/ug.i18n.json b/packages/i18n/src/locales/ug.i18n.json index 78c3650e0038..b576cd5102cd 100644 --- a/packages/i18n/src/locales/ug.i18n.json +++ b/packages/i18n/src/locales/ug.i18n.json @@ -1045,8 +1045,7 @@ "Thank_you_for_your_feedback": "سىزنىڭ ئىنكاسىڭىزگە كۆپتىن كۆپ رەھمەت", "The_application_name_is_required": "ئەپنىڭ ئىسمىنى چوقۇم تولدۇرىسىز", "The_channel_name_is_required": "قانالنىڭ ئىسمىنى چوقۇم تولدۇرۇڭ", - "The_emails_are_being_sent": "ئىلخەت يوللاندى", - "The_field_is_required": "چوقۇم تولدۇرۇڭ%sخەت بۆلىكى", + "The_emails_are_being_sent": "ئىلخەت يوللاندى", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "تاپالمىدۇق.GraphicsMagickنى ياكىImageMagick رەسىمنىڭ چوڭ كىچىكلىكىنى ئۆزگەرتكىلى بولمىدى، چۈنكى بىز مۇلازىمتېردا قاچىلىنىپ بولغان", "The_redirectUri_is_required": "چوقۇم تولدۇرۇڭURIسەكرەپ يۆتكەلگەن", "The_server_will_restart_in_s_seconds": "سېكۇنتتىن كېيىن قايتىدىن قوزغىتىلىدۇ %s مۇلازىمىتېر", diff --git a/packages/i18n/src/locales/uk.i18n.json b/packages/i18n/src/locales/uk.i18n.json index b8e27a4f8c34..eb2b8542d4e3 100644 --- a/packages/i18n/src/locales/uk.i18n.json +++ b/packages/i18n/src/locales/uk.i18n.json @@ -2911,8 +2911,7 @@ "Thank_you_for_your_feedback": "Спасибі за ваш відгук", "The_application_name_is_required": "Ім'я програми потрібен", "The_channel_name_is_required": "Назва каналу потрібно", - "The_emails_are_being_sent": "Електронні листи відправляються.", - "The_field_is_required": "Поле %s потрібно.", + "The_emails_are_being_sent": "Електронні листи відправляються.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Зміни розміру зображення не буде працювати, тому що ми не можемо виявити ImageMagick або GraphicsMagick встановлений на вашому сервері.", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "Повідомлення - це обговорення яке ви не зможете відновити!", "The_redirectUri_is_required": "RedirectUri потрібно", diff --git a/packages/i18n/src/locales/vi-VN.i18n.json b/packages/i18n/src/locales/vi-VN.i18n.json index bf073e9c6aee..e4ff1343a079 100644 --- a/packages/i18n/src/locales/vi-VN.i18n.json +++ b/packages/i18n/src/locales/vi-VN.i18n.json @@ -2465,8 +2465,7 @@ "Thank_you_for_your_feedback": "Cảm ơn phản hồi của bạn", "The_application_name_is_required": "Tên ứng dụng là bắt buộc", "The_channel_name_is_required": "Tên kênh là bắt buộc", - "The_emails_are_being_sent": "Các email đang được gửi.", - "The_field_is_required": "Trường%s là bắt buộc.", + "The_emails_are_being_sent": "Các email đang được gửi.", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "Thay đổi kích thước hình ảnh sẽ không hoạt động vì chúng tôi không thể phát hiện ImageMagick hoặc GraphicsMagick được cài đặt trên máy chủ của bạn.", "The_redirectUri_is_required": "RedirectUri là bắt buộc", "The_server_will_restart_in_s_seconds": "Máy chủ sẽ khởi động lại trong%s giây", diff --git a/packages/i18n/src/locales/zh-HK.i18n.json b/packages/i18n/src/locales/zh-HK.i18n.json index e9821173dc0c..2da4905ae336 100644 --- a/packages/i18n/src/locales/zh-HK.i18n.json +++ b/packages/i18n/src/locales/zh-HK.i18n.json @@ -2392,8 +2392,7 @@ "Thank_you_for_your_feedback": "感谢您的反馈意见", "The_application_name_is_required": "应用程序名称是必需的", "The_channel_name_is_required": "频道名称是必需的", - "The_emails_are_being_sent": "电子邮件正在发送。", - "The_field_is_required": "字段 %s 必须填写。", + "The_emails_are_being_sent": "电子邮件正在发送。", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "图像大小调整不起作用,因为我们无法检测到服务器上安装的ImageMagick或GraphicsMagick。", "The_redirectUri_is_required": "redirectUri是必需的", "The_server_will_restart_in_s_seconds": "服务器将以%s秒为单位重新启动", diff --git a/packages/i18n/src/locales/zh-TW.i18n.json b/packages/i18n/src/locales/zh-TW.i18n.json index 741132996be6..7b8dc7495a84 100644 --- a/packages/i18n/src/locales/zh-TW.i18n.json +++ b/packages/i18n/src/locales/zh-TW.i18n.json @@ -3896,8 +3896,7 @@ "The_application_name_is_required": "應用程式名稱是必需的", "The_channel_name_is_required": "頻道名稱是必需的", "The_emails_are_being_sent": "電子郵件傳送中", - "The_empty_room__roomName__will_be_removed_automatically": "空房間 {{roomName}} 將自動刪除。", - "The_field_is_required": "欄位 %s 必填", + "The_empty_room__roomName__will_be_removed_automatically": "空房間 {{roomName}} 將自動刪除。", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "圖片大小調整不會起作用,因為在我們偵測不到伺服器上安裝的 ImageMagick 或 GraphicsMagick 工具", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "此訊息是在論壇中您不可以復原訊息!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "所有使用者都停用了手機通知,請到“管理>推送”以再次啟用推送閘道", diff --git a/packages/i18n/src/locales/zh.i18n.json b/packages/i18n/src/locales/zh.i18n.json index 323da5954332..f3e8c2e0fc9e 100644 --- a/packages/i18n/src/locales/zh.i18n.json +++ b/packages/i18n/src/locales/zh.i18n.json @@ -3556,8 +3556,7 @@ "The_application_name_is_required": "应用名称必填", "The_channel_name_is_required": "频道名称为必填", "The_emails_are_being_sent": "邮件已发送。", - "The_empty_room__roomName__will_be_removed_automatically": "空房间 {{roomName}} 将被自动移除。", - "The_field_is_required": "字段 %s 必填", + "The_empty_room__roomName__will_be_removed_automatically": "空房间 {{roomName}} 将被自动移除。", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "无法调整图片尺寸,因为我们无法在服务器上找到已安装的 ImageMagick 或 GraphicsMagick 。", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "此消息是一个讨论你将无法恢复此消息!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "所有用户的移动端通知都已禁用。前往 “管理 > 推送” 再次启用推送网关", diff --git a/packages/ui-client/src/components/CustomFieldsForm.tsx b/packages/ui-client/src/components/CustomFieldsForm.tsx index dc464fcd23c2..98b9c3fdad79 100644 --- a/packages/ui-client/src/components/CustomFieldsForm.tsx +++ b/packages/ui-client/src/components/CustomFieldsForm.tsx @@ -52,7 +52,7 @@ const CustomField = ({ (error: RHFFieldError) => { switch (error?.type) { case 'required': - return t('The_field_is_required', label || name); + return t('Required_field', { field: label || name }); case 'minLength': return t('Min_length_is', props?.minLength); case 'maxLength': diff --git a/packages/web-ui-registration/src/LoginForm.tsx b/packages/web-ui-registration/src/LoginForm.tsx index d63886091fa0..6e28a443be63 100644 --- a/packages/web-ui-registration/src/LoginForm.tsx +++ b/packages/web-ui-registration/src/LoginForm.tsx @@ -162,7 +162,7 @@ export const LoginForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRoute (!passwordIsValid ? t('Password_must_meet_the_complexity_requirements') : true), })} error={errors.password?.message} @@ -247,7 +247,7 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo (watch('password') === val ? true : t('registration.component.form.invalidConfirmPass')), })} @@ -275,7 +275,7 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo Date: Sat, 14 Sep 2024 01:01:59 -0300 Subject: [PATCH 081/170] chore(deps): Patch dependencies (#33285) --- .../moleculer-npm-0.14.34-440e26767d.patch | 13 + apps/meteor/ee/server/services/package.json | 18 +- apps/meteor/package.json | 162 +- apps/uikit-playground/package.json | 14 +- ee/apps/account-service/package.json | 12 +- ee/apps/authorization-service/package.json | 10 +- ee/apps/ddp-streamer/package.json | 16 +- ee/apps/omnichannel-transcript/package.json | 12 +- ee/apps/presence-service/package.json | 10 +- ee/apps/queue-worker/package.json | 12 +- ee/apps/stream-hub-service/package.json | 12 +- ee/packages/license/package.json | 6 +- ee/packages/omnichannel-services/package.json | 4 +- ee/packages/pdf-worker/package.json | 12 +- ee/packages/ui-theming/package.json | 6 +- package.json | 9 +- packages/agenda/package.json | 4 +- packages/api-client/package.json | 4 +- packages/core-services/package.json | 6 +- packages/ddp-client/package.json | 4 +- packages/eslint-config/package.json | 4 +- packages/fuselage-ui-kit/package.json | 12 +- packages/gazzodown/package.json | 16 +- packages/jest-presets/package.json | 8 +- packages/jwt/package.json | 2 +- packages/livechat/package.json | 12 +- packages/log-format/package.json | 2 +- packages/message-parser/package.json | 20 +- packages/mock-providers/package.json | 2 +- packages/model-typings/package.json | 2 +- packages/models/package.json | 2 +- packages/password-policies/package.json | 2 +- packages/patch-injection/package.json | 2 +- packages/peggy-loader/package.json | 4 +- packages/release-action/package.json | 2 +- packages/release-changelog/package.json | 2 +- packages/rest-typings/package.json | 2 +- packages/server-fetch/package.json | 2 +- packages/tools/package.json | 4 +- packages/ui-avatar/package.json | 7 +- packages/ui-client/package.json | 13 +- packages/ui-composer/package.json | 9 +- packages/ui-contexts/package.json | 10 +- packages/ui-kit/package.json | 16 +- packages/ui-video-conf/package.json | 7 +- packages/web-ui-registration/package.json | 8 +- yarn.lock | 2133 +++++++++++------ 47 files changed, 1631 insertions(+), 1020 deletions(-) create mode 100644 .yarn/patches/moleculer-npm-0.14.34-440e26767d.patch diff --git a/.yarn/patches/moleculer-npm-0.14.34-440e26767d.patch b/.yarn/patches/moleculer-npm-0.14.34-440e26767d.patch new file mode 100644 index 000000000000..005ab83cfb48 --- /dev/null +++ b/.yarn/patches/moleculer-npm-0.14.34-440e26767d.patch @@ -0,0 +1,13 @@ +diff --git a/index.d.ts b/index.d.ts +index f64eda7889619f2a1e7cbd5bb5e3533fc8aaa182..3d815a3b7aaf426235aa92422129079aa5826908 100644 +--- a/index.d.ts ++++ b/index.d.ts +@@ -725,7 +725,7 @@ declare namespace Moleculer { + this: T + ) => void | Promise; + +- interface ServiceSchema { ++ interface ServiceSchema> { + name: string; + version?: string | number; + settings?: S; diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 7c51605d4190..43659382eb67 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -30,7 +30,7 @@ "@rocket.chat/ui-kit": "workspace:~", "ajv": "^8.11.0", "bcrypt": "^5.0.1", - "body-parser": "^1.20.2", + "body-parser": "^1.20.3", "colorette": "^2.0.20", "cookie": "^0.5.0", "cookie-parser": "^1.4.6", @@ -40,7 +40,7 @@ "fibers": "^5.0.3", "jaeger-client": "^3.19.0", "mem": "^8.1.1", - "moleculer": "^0.14.31", + "moleculer": "^0.14.34", "mongodb": "^4.17.2", "nats": "^2.6.1", "pino": "^8.15.0", @@ -51,17 +51,17 @@ }, "devDependencies": { "@rocket.chat/icons": "~0.38.0", - "@types/cookie": "^0.5.3", - "@types/cookie-parser": "^1.4.5", - "@types/ejson": "^2.2.1", - "@types/express": "^4.17.20", - "@types/fibers": "^3.1.3", + "@types/cookie": "^0.5.4", + "@types/cookie-parser": "^1.4.7", + "@types/ejson": "^2.2.2", + "@types/express": "^4.17.21", + "@types/fibers": "^3.1.4", "@types/node": "^14.18.63", - "@types/ws": "^8.5.8", + "@types/ws": "^8.5.12", "npm-run-all": "^4.1.5", "pino-pretty": "^7.6.1", "pm2": "^5.2.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "~5.5.4" }, "volta": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index df12721c5261..9ee7e48d1794 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -66,7 +66,7 @@ "devDependencies": { "@axe-core/playwright": "^4.7.3", "@babel/core": "~7.22.20", - "@babel/eslint-parser": "~7.23.3", + "@babel/eslint-parser": "~7.23.10", "@babel/plugin-proposal-nullish-coalescing-operator": "~7.18.6", "@babel/plugin-proposal-optional-chaining": "~7.21.0", "@babel/preset-env": "~7.22.20", @@ -87,76 +87,76 @@ "@storybook/react": "~6.5.16", "@storybook/testing-library": "0.0.13", "@tanstack/react-query-devtools": "^4.19.1", - "@testing-library/react": "~16.0.0", + "@testing-library/react": "~16.0.1", "@testing-library/user-event": "~14.5.2", - "@types/adm-zip": "^0.5.3", + "@types/adm-zip": "^0.5.5", "@types/archiver": "^5.3.4", - "@types/bad-words": "^3.0.2", - "@types/bcrypt": "^5.0.1", - "@types/body-parser": "^1.19.4", - "@types/busboy": "^1.5.2", - "@types/chai": "~4.3.16", - "@types/chai-as-promised": "^7.1.7", - "@types/chai-datetime": "0.0.38", - "@types/chai-dom": "1.11.2", - "@types/chai-spies": "~1.0.5", - "@types/codemirror": "^5.60.12", - "@types/cookie-parser": "^1.4.5", - "@types/cors": "^2.8.15", - "@types/cssom": "^0.4.2", + "@types/bad-words": "^3.0.3", + "@types/bcrypt": "^5.0.2", + "@types/body-parser": "^1.19.5", + "@types/busboy": "^1.5.4", + "@types/chai": "~4.3.19", + "@types/chai-as-promised": "^7.1.8", + "@types/chai-datetime": "0.0.39", + "@types/chai-dom": "1.11.3", + "@types/chai-spies": "~1.0.6", + "@types/codemirror": "^5.60.15", + "@types/cookie-parser": "^1.4.7", + "@types/cors": "^2.8.17", + "@types/cssom": "^0.4.3", "@types/dompurify": "^2.3.3", - "@types/ejson": "^2.2.1", - "@types/express": "^4.17.20", + "@types/ejson": "^2.2.2", + "@types/express": "^4.17.21", "@types/express-rate-limit": "^5.1.3", - "@types/fibers": "^3.1.3", - "@types/google-libphonenumber": "^7.4.29", - "@types/gravatar": "^1.8.5", + "@types/fibers": "^3.1.4", + "@types/google-libphonenumber": "^7.4.30", + "@types/gravatar": "^1.8.6", "@types/he": "^1.1.2", - "@types/i18next-sprintf-postprocessor": "^0.2.2", - "@types/imap": "^0.8.39", - "@types/jest": "~29.5.12", + "@types/i18next-sprintf-postprocessor": "^0.2.3", + "@types/imap": "^0.8.40", + "@types/jest": "~29.5.13", "@types/jsdom": "^16.2.15", - "@types/jsdom-global": "^3.0.6", - "@types/jsrsasign": "^10.5.11", - "@types/later": "^1.2.8", + "@types/jsdom-global": "^3.0.7", + "@types/jsrsasign": "^10.5.14", + "@types/later": "^1.2.9", "@types/ldapjs": "^2.2.5", - "@types/less": "~3.0.5", + "@types/less": "~3.0.6", "@types/lodash.clonedeep": "^4.5.9", - "@types/lodash.get": "^4.4.8", - "@types/mailparser": "^3.4.3", + "@types/lodash.get": "^4.4.9", + "@types/mailparser": "^3.4.4", "@types/marked": "^4.0.8", "@types/meteor": "^2.9.8", - "@types/meteor-collection-hooks": "^0.8.8", + "@types/meteor-collection-hooks": "^0.8.9", "@types/mkdirp": "^1.0.2", "@types/mocha": "github:whitecolor/mocha-types", "@types/moment-timezone": "^0.5.30", "@types/node": "^14.18.63", - "@types/node-gcm": "^1.0.3", - "@types/node-rsa": "^1.1.3", - "@types/nodemailer": "^6.4.13", - "@types/oauth2-server": "^3.0.15", - "@types/parseurl": "^1.3.2", - "@types/prometheus-gc-stats": "^0.6.3", - "@types/proxyquire": "^1.3.30", - "@types/psl": "^1.1.2", - "@types/react": "~17.0.69", - "@types/react-dom": "~17.0.22", - "@types/rewire": "^2.5.29", + "@types/node-gcm": "^1.0.5", + "@types/node-rsa": "^1.1.4", + "@types/nodemailer": "^6.4.15", + "@types/oauth2-server": "^3.0.17", + "@types/parseurl": "^1.3.3", + "@types/prometheus-gc-stats": "^0.6.4", + "@types/proxyquire": "^1.3.31", + "@types/psl": "^1.1.3", + "@types/react": "~17.0.80", + "@types/react-dom": "~17.0.25", + "@types/rewire": "^2.5.30", "@types/sanitize-html": "^2.9.3", "@types/semver": "^7.3.10", "@types/sharp": "^0.30.5", "@types/sinon": "^10.0.20", - "@types/strict-uri-encode": "^2.0.1", + "@types/strict-uri-encode": "^2.0.2", "@types/string-strip-html": "^5.0.1", - "@types/supertest": "^2.0.15", - "@types/supports-color": "~7.2.0", - "@types/textarea-caret": "^3.0.2", - "@types/ua-parser-js": "^0.7.38", - "@types/use-subscription": "^1.0.1", - "@types/use-sync-external-store": "^0.0.5", + "@types/supertest": "^2.0.16", + "@types/supports-color": "~7.2.1", + "@types/textarea-caret": "^3.0.3", + "@types/ua-parser-js": "^0.7.39", + "@types/use-subscription": "^1.0.2", + "@types/use-sync-external-store": "^0.0.6", "@types/uuid": "^8.3.4", - "@types/xml-crypto": "~1.4.4", - "@types/xml-encryption": "~1.2.3", + "@types/xml-crypto": "~1.4.6", + "@types/xml-encryption": "~1.2.4", "@typescript-eslint/eslint-plugin": "~5.60.1", "@typescript-eslint/parser": "~5.60.1", "autoprefixer": "^9.8.8", @@ -164,12 +164,12 @@ "babel-plugin-array-includes": "^2.0.3", "babel-plugin-istanbul": "^6.1.1", "chai": "^4.3.10", - "chai-as-promised": "^7.1.1", - "chai-datetime": "^1.8.0", + "chai-as-promised": "^7.1.2", + "chai-datetime": "^1.8.1", "chai-dom": "^1.11.0", "chai-spies": "~1.0.0", "cross-env": "^7.0.3", - "docker-compose": "^0.24.3", + "docker-compose": "^0.24.8", "emojione-assets": "^4.5.0", "eslint": "~8.45.0", "eslint-config-prettier": "~8.8.0", @@ -179,7 +179,7 @@ "eslint-plugin-playwright": "~0.15.3", "eslint-plugin-prettier": "~4.2.1", "eslint-plugin-react": "~7.32.2", - "eslint-plugin-react-hooks": "~4.6.0", + "eslint-plugin-react-hooks": "~4.6.2", "eslint-plugin-testing-library": "~6.2.2", "eslint-plugin-you-dont-need-lodash-underscore": "~6.12.0", "fast-glob": "^3.2.12", @@ -190,8 +190,8 @@ "nyc": "^15.1.0", "outdent": "~0.8.0", "pino-pretty": "^7.6.1", - "playwright-qase-reporter": "^1.2.1", - "postcss": "~8.4.31", + "playwright-qase-reporter": "^1.2.2", + "postcss": "~8.4.45", "postcss-custom-properties": "^11.0.0", "postcss-easy-import": "^3.0.0", "postcss-load-config": "^3.1.4", @@ -200,7 +200,7 @@ "postcss-url": "^10.1.3", "prettier": "~2.8.8", "proxyquire": "^2.1.3", - "react-docgen-typescript-plugin": "^1.0.5", + "react-docgen-typescript-plugin": "^1.0.8", "rewire": "^6.0.0", "sinon": "^14.0.2", "source-map": "^0.7.4", @@ -209,7 +209,7 @@ "supertest": "^6.2.3", "supports-color": "~7.2.0", "template-file": "^6.0.1", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "~5.5.4" }, "dependencies": { @@ -217,7 +217,7 @@ "@bugsnag/js": "~7.20.2", "@bugsnag/plugin-react": "~7.19.0", "@google-cloud/storage": "^6.11.0", - "@kaciras/deasync": "^1.0.3", + "@kaciras/deasync": "^1.0.4", "@nivo/bar": "0.84.0", "@nivo/core": "0.84.0", "@nivo/heatmap": "0.84.0", @@ -252,7 +252,7 @@ "@rocket.chat/icons": "~0.38.0", "@rocket.chat/instance-status": "workspace:^", "@rocket.chat/jwt": "workspace:^", - "@rocket.chat/layout": "~0.31.26", + "@rocket.chat/layout": "~0.31.27", "@rocket.chat/license": "workspace:^", "@rocket.chat/log-format": "workspace:^", "@rocket.chat/logger": "workspace:^", @@ -287,15 +287,15 @@ "@slack/bolt": "^3.14.0", "@slack/rtm-api": "^6.0.0", "@tanstack/react-query": "^4.16.1", - "@types/cookie": "^0.5.3", + "@types/cookie": "^0.5.4", "@types/katex": "^0.14.0", "@types/lodash": "^4.14.200", - "@types/lodash.debounce": "^4.0.8", - "@types/object-path": "^0.11.3", - "@types/proxy-from-env": "^1.0.3", - "@types/speakeasy": "^2.0.9", + "@types/lodash.debounce": "^4.0.9", + "@types/object-path": "^0.11.4", + "@types/proxy-from-env": "^1.0.4", + "@types/speakeasy": "^2.0.10", "@xmldom/xmldom": "^0.8.10", - "adm-zip": "0.5.10", + "adm-zip": "0.5.16", "ajv": "^8.11.0", "ajv-formats": "~2.1.1", "apn": "2.2.0", @@ -306,14 +306,14 @@ "aws-sdk": "^2.1363.0", "bad-words": "^3.0.4", "bcrypt": "^5.0.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "bson": "^4.6.4", "busboy": "^1.6.0", "bytebuffer": "5.0.1", "chalk": "^4.0.0", "change-case": "^4.1.2", "chart.js": "^3.8.0", - "codemirror": "^5.65.15", + "codemirror": "^5.65.17", "colorette": "^2.0.20", "colors": "^1.4.0", "connect": "^3.7.0", @@ -321,7 +321,7 @@ "cookie-parser": "^1.4.6", "cors": "^2.8.5", "cron": "~1.8.2", - "css-vars-ponyfill": "^2.4.8", + "css-vars-ponyfill": "^2.4.9", "csv-parse": "^5.2.0", "date-fns": "^2.28.0", "date.js": "~0.3.3", @@ -342,7 +342,7 @@ "filenamify": "^4.3.0", "filesize": "9.0.11", "generate-password": "^1.7.1", - "google-libphonenumber": "^3.2.33", + "google-libphonenumber": "^3.2.38", "gravatar": "^1.8.2", "he": "^1.2.0", "highlight.js": "^11.6.0", @@ -361,7 +361,7 @@ "jsdom": "^16.7.0", "jsrsasign": "^10.5.24", "juice": "^8.0.0", - "katex": "~0.16.9", + "katex": "~0.16.11", "ldap-escape": "^2.0.6", "ldapjs": "^2.3.3", "limax": "^3.0.0", @@ -372,13 +372,13 @@ "mailparser": "^3.4.0", "marked": "^4.2.5", "mem": "^8.1.1", - "meteor-node-stubs": "^1.2.5", + "meteor-node-stubs": "^1.2.10", "mime-db": "^1.52.0", "mime-type": "^4.0.0", "mkdirp": "^1.0.4", - "moleculer": "^0.14.31", + "moleculer": "^0.14.34", "moment": "^2.29.4", - "moment-timezone": "^0.5.43", + "moment-timezone": "^0.5.45", "mongo-message-queue": "^1.0.0", "mongodb": "^4.17.2", "nats": "^2.6.1", @@ -402,7 +402,7 @@ "query-string": "^7.1.3", "queue-fifo": "^0.2.6", "rc-scrollbars": "^1.1.6", - "re-resizable": "^6.9.9", + "re-resizable": "^6.9.18", "react": "~17.0.2", "react-aria": "~3.23.1", "react-dom": "~17.0.2", @@ -419,7 +419,7 @@ "sodium-native": "^3.3.0", "sodium-plus": "^0.9.0", "speakeasy": "^2.0.0", - "stream-buffers": "^3.0.2", + "stream-buffers": "^3.0.3", "strict-uri-encode": "^2.0.0", "string-strip-html": "^7.0.3", "suretype": "~2.4.1", @@ -431,15 +431,15 @@ "twilio": "^3.76.1", "twit": "^2.2.11", "typia": "~6.9.0", - "ua-parser-js": "^1.0.37", - "underscore": "^1.13.6", + "ua-parser-js": "^1.0.38", + "underscore": "^1.13.7", "universal-perf-hooks": "^1.0.1", "url-polyfill": "^1.1.12", "use-subscription": "~1.6.0", - "use-sync-external-store": "^1.2.0", + "use-sync-external-store": "^1.2.2", "uuid": "^8.3.2", "vm2": "^3.9.19", - "webdav": "^4.11.3", + "webdav": "^4.11.4", "xml-crypto": "~3.1.0", "xml-encryption": "~3.0.2", "xml2js": "~0.5.0", diff --git a/apps/uikit-playground/package.json b/apps/uikit-playground/package.json index 233e71b719e5..791526c46f9d 100644 --- a/apps/uikit-playground/package.json +++ b/apps/uikit-playground/package.json @@ -38,19 +38,19 @@ "react-split-pane": "^0.1.92", "react-virtuoso": "^4.7.1", "reactflow": "^11.7.2", - "use-subscription": "^1.8.0" + "use-subscription": "^1.8.2" }, "devDependencies": { - "@types/react": "~17.0.69", - "@types/react-beautiful-dnd": "^13.1.6", - "@types/react-dom": "~17.0.22", - "@types/use-subscription": "^1.0.1", + "@types/react": "~17.0.80", + "@types/react-beautiful-dnd": "^13.1.8", + "@types/react-dom": "~17.0.25", + "@types/use-subscription": "^1.0.2", "@typescript-eslint/eslint-plugin": "~5.60.1", "@typescript-eslint/parser": "~5.60.1", "@vitejs/plugin-react": "^4.0.0", "eslint": "~8.45.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.4", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.11", "typescript": "~5.5.4", "vite": "^4.3.9" }, diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 8143df3577a7..b9e45ed14eda 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -29,9 +29,9 @@ "event-loop-stats": "^1.4.1", "eventemitter3": "^4.0.7", "fibers": "^5.0.3", - "gc-stats": "^1.4.0", + "gc-stats": "^1.4.1", "mem": "^8.1.1", - "moleculer": "^0.14.31", + "moleculer": "^0.14.34", "mongodb": "^4.17.2", "nats": "^2.4.0", "pino": "^8.15.0", @@ -40,11 +40,11 @@ }, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", - "@types/bcrypt": "^5.0.1", - "@types/gc-stats": "^1.4.2", - "@types/polka": "^0.5.6", + "@types/bcrypt": "^5.0.2", + "@types/gc-stats": "^1.4.3", + "@types/polka": "^0.5.7", "eslint": "~8.45.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "~5.5.4" }, "main": "./dist/ee/apps/account-service/src/service.js", diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index c4c0ec82f507..b7912b8bc94d 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -27,9 +27,9 @@ "event-loop-stats": "^1.4.1", "eventemitter3": "^4.0.7", "fibers": "^5.0.3", - "gc-stats": "^1.4.0", + "gc-stats": "^1.4.1", "mem": "^8.1.1", - "moleculer": "^0.14.31", + "moleculer": "^0.14.34", "mongodb": "^4.17.2", "nats": "^2.4.0", "pino": "^8.15.0", @@ -37,10 +37,10 @@ }, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", - "@types/gc-stats": "^1.4.2", - "@types/polka": "^0.5.6", + "@types/gc-stats": "^1.4.3", + "@types/polka": "^0.5.7", "eslint": "~8.45.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "~5.5.4" }, "main": "./dist/ee/apps/authorization-service/src/service.js", diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index be56cb76469c..87029e4b8993 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -30,33 +30,33 @@ "event-loop-stats": "^1.4.1", "eventemitter3": "^4.0.7", "fibers": "^5.0.3", - "gc-stats": "^1.4.0", + "gc-stats": "^1.4.1", "jaeger-client": "^3.19.0", "mem": "^8.1.1", - "moleculer": "^0.14.31", + "moleculer": "^0.14.34", "mongodb": "^4.17.2", "nats": "^2.4.0", "pino": "^8.15.0", "polka": "^0.5.2", "sharp": "^0.32.6", - "underscore": "^1.13.6", + "underscore": "^1.13.7", "uuid": "^7.0.3", "ws": "^8.8.1" }, "devDependencies": { "@rocket.chat/ddp-client": "workspace:~", "@rocket.chat/eslint-config": "workspace:^", - "@types/ejson": "^2.2.1", - "@types/gc-stats": "^1.4.2", + "@types/ejson": "^2.2.2", + "@types/gc-stats": "^1.4.3", "@types/meteor": "^2.9.8", "@types/node": "^14.18.63", - "@types/polka": "^0.5.6", + "@types/polka": "^0.5.7", "@types/sharp": "^0.30.5", "@types/uuid": "^8.3.4", - "@types/ws": "^8.5.8", + "@types/ws": "^8.5.12", "eslint": "~8.45.0", "pino-pretty": "^7.6.1", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "~5.5.4" }, "main": "./dist/service.js", diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 0a8ba5e9f8cc..27290070b653 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -31,10 +31,10 @@ "event-loop-stats": "^1.4.1", "eventemitter3": "^4.0.7", "fibers": "^5.0.3", - "gc-stats": "^1.4.0", + "gc-stats": "^1.4.1", "mem": "^8.1.1", - "moleculer": "^0.14.31", - "moment-timezone": "^0.5.43", + "moleculer": "^0.14.34", + "moment-timezone": "^0.5.45", "mongo-message-queue": "^1.0.0", "mongodb": "^4.17.2", "nats": "^2.4.0", @@ -43,10 +43,10 @@ }, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", - "@types/gc-stats": "^1.4.2", - "@types/polka": "^0.5.6", + "@types/gc-stats": "^1.4.3", + "@types/polka": "^0.5.7", "eslint": "~8.45.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "~5.5.4" }, "main": "./dist/ee/apps/omnichannel-transcript/src/service.js", diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 5ab5a6238266..5968631341b0 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -27,9 +27,9 @@ "event-loop-stats": "^1.4.1", "eventemitter3": "^4.0.7", "fibers": "^5.0.3", - "gc-stats": "^1.4.0", + "gc-stats": "^1.4.1", "mem": "^8.1.1", - "moleculer": "^0.14.31", + "moleculer": "^0.14.34", "mongodb": "^4.17.2", "nats": "^2.4.0", "pino": "^8.15.0", @@ -37,10 +37,10 @@ }, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", - "@types/gc-stats": "^1.4.2", - "@types/polka": "^0.5.6", + "@types/gc-stats": "^1.4.3", + "@types/polka": "^0.5.7", "eslint": "~8.45.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "~5.5.4" }, "main": "./dist/ee/apps/presence-service/src/service.js", diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 7844b0c27693..b3d8b0aff94e 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -29,10 +29,10 @@ "event-loop-stats": "^1.4.1", "eventemitter3": "^4.0.7", "fibers": "^5.0.3", - "gc-stats": "^1.4.0", + "gc-stats": "^1.4.1", "mem": "^8.1.1", - "moleculer": "^0.14.31", - "moment-timezone": "^0.5.43", + "moleculer": "^0.14.34", + "moment-timezone": "^0.5.45", "mongo-message-queue": "^1.0.0", "mongodb": "^4.17.2", "nats": "^2.4.0", @@ -41,10 +41,10 @@ }, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", - "@types/gc-stats": "^1.4.2", - "@types/polka": "^0.5.6", + "@types/gc-stats": "^1.4.3", + "@types/polka": "^0.5.7", "eslint": "~8.45.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "~5.5.4" }, "main": "./dist/ee/apps/queue-worker/src/service.js", diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 030371478cb2..9fd5cf0586f6 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -27,9 +27,9 @@ "event-loop-stats": "^1.4.1", "eventemitter3": "^4.0.7", "fibers": "^5.0.3", - "gc-stats": "^1.4.0", + "gc-stats": "^1.4.1", "mem": "^8.1.1", - "moleculer": "^0.14.31", + "moleculer": "^0.14.34", "mongodb": "^4.17.2", "nats": "^2.4.0", "pino": "^8.15.0", @@ -38,11 +38,11 @@ "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", - "@types/bcrypt": "^5.0.1", - "@types/gc-stats": "^1.4.2", - "@types/polka": "^0.5.6", + "@types/bcrypt": "^5.0.2", + "@types/gc-stats": "^1.4.3", + "@types/polka": "^0.5.7", "eslint": "~8.45.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "~5.5.4" }, "main": "./dist/ee/apps/stream-hub-service/src/service.js", diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 0b66c13574c2..3eceb35e27ff 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -4,9 +4,9 @@ "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", - "@types/bcrypt": "^5.0.1", - "@types/jest": "~29.5.12", - "@types/ws": "^8.5.8", + "@types/bcrypt": "^5.0.2", + "@types/jest": "~29.5.13", + "@types/ws": "^8.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", "jest-websocket-mock": "~2.5.0", diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 6df90c641375..696ac6fee640 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -5,7 +5,7 @@ "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", + "@types/jest": "~29.5.13", "eslint": "~8.45.0", "jest": "~29.7.0", "typescript": "~5.5.4" @@ -28,7 +28,7 @@ "eventemitter3": "^4.0.7", "fibers": "^5.0.3", "mem": "^8.1.1", - "moment-timezone": "^0.5.43", + "moment-timezone": "^0.5.45", "mongo-message-queue": "^1.0.0", "mongodb": "^4.17.2", "pino": "^8.15.0" diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index afd5a4d8e314..234463087a4e 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -6,11 +6,11 @@ "@rocket.chat/jest-presets": "workspace:~", "@storybook/addon-essentials": "~6.5.16", "@storybook/react": "~6.5.16", - "@testing-library/react": "~16.0.0", - "@types/emojione": "^2.2.8", - "@types/jest": "~29.5.12", - "@types/react": "~17.0.69", - "@types/react-dom": "~17.0.22", + "@testing-library/react": "~16.0.1", + "@types/emojione": "^2.2.9", + "@types/jest": "~29.5.13", + "@types/react": "~17.0.80", + "@types/react-dom": "~17.0.25", "eslint": "~8.45.0", "jest": "~29.7.0", "react-dom": "~18.3.1", @@ -38,7 +38,7 @@ "emoji-assets": "^7.0.1", "emoji-toolkit": "^7.0.1", "moment": "^2.29.4", - "moment-timezone": "^0.5.43", + "moment-timezone": "^0.5.45", "react": "~18.3.1" }, "volta": { diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json index 5f3bb4977d7d..d6e3e93c01a4 100644 --- a/ee/packages/ui-theming/package.json +++ b/ee/packages/ui-theming/package.json @@ -8,14 +8,14 @@ "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/ui-contexts": "workspace:~", - "@types/react": "~17.0.69", + "@types/react": "~17.0.80", "eslint": "~8.45.0", "eslint-plugin-anti-trojan-source": "~1.1.1", "eslint-plugin-react": "~7.32.2", - "eslint-plugin-react-hooks": "~4.6.0", + "eslint-plugin-react-hooks": "~4.6.2", "eslint-plugin-testing-library": "^5.11.1", "react": "~17.0.2", - "react-docgen-typescript-plugin": "~1.0.5", + "react-docgen-typescript-plugin": "~1.0.8", "typescript": "~5.5.4" }, "scripts": { diff --git a/package.json b/package.json index 405686417d28..f3e3ce3d3e91 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,10 @@ }, "devDependencies": { "@changesets/cli": "^2.26.2", - "@types/chart.js": "^2.9.39", - "@types/js-yaml": "^4.0.8", + "@types/chart.js": "^2.9.41", + "@types/js-yaml": "^4.0.9", "ts-node": "^10.9.2", - "turbo": "latest" + "turbo": "^2.1.2" }, "workspaces": [ "apps/*", @@ -65,7 +65,8 @@ "mongodb@^4.17.1": "patch:mongodb@npm:4.17.1#.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch", "@rocket.chat/forked-matrix-sdk-crypto-nodejs": "0.1.0-beta.13", "typia@~6.9.0": "patch:typia@npm%3A6.9.0#./.yarn/patches/typia-npm-6.9.0-2fd4d85f25.patch", - "react-i18next@~15.0.1": "patch:react-i18next@npm%3A15.0.1#./.yarn/patches/react-i18next-npm-15.0.1-0812bb73aa.patch" + "react-i18next@~15.0.1": "patch:react-i18next@npm%3A15.0.1#./.yarn/patches/react-i18next-npm-15.0.1-0812bb73aa.patch", + "moleculer@^0.14.34": "patch:moleculer@npm%3A0.14.34#./.yarn/patches/moleculer-npm-0.14.34-440e26767d.patch" }, "dependencies": { "node-gyp": "^9.4.1" diff --git a/packages/agenda/package.json b/packages/agenda/package.json index f09921de6c31..2d1fc084c383 100644 --- a/packages/agenda/package.json +++ b/packages/agenda/package.json @@ -8,11 +8,11 @@ "date.js": "~0.3.3", "debug": "~4.1.1", "human-interval": "^2.0.1", - "moment-timezone": "~0.5.43", + "moment-timezone": "~0.5.45", "mongodb": "^4.17.2" }, "devDependencies": { - "@types/debug": "^4.1.10", + "@types/debug": "^4.1.12", "eslint": "~8.45.0", "typescript": "~5.5.4" }, diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 23e0d7233a0f..b8d9ac155144 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -3,8 +3,8 @@ "version": "0.2.6", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", - "@types/strict-uri-encode": "^2.0.1", + "@types/jest": "~29.5.13", + "@types/strict-uri-encode": "^2.0.2", "eslint": "~8.45.0", "jest": "~29.7.0", "jest-fetch-mock": "^3.0.3", diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 35759dbe5ee6..74250ffa8c16 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -8,9 +8,7 @@ "@babel/preset-typescript": "~7.22.15", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/jest-presets": "workspace:~", - "@types/babel__core": "^7.20.3", - "@types/babel__preset-env": "^7.9.4", - "@types/jest": "~29.5.12", + "@types/jest": "~29.5.13", "babel-jest": "^29.5.0", "eslint": "~8.45.0", "jest": "~29.7.0", @@ -41,7 +39,7 @@ "@rocket.chat/models": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@rocket.chat/ui-kit": "workspace:~", - "@types/fibers": "^3.1.3", + "@types/fibers": "^3.1.4", "fibers": "^5.0.3" } } diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index 6f3f29871ccf..0fc47dc9a122 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -3,8 +3,8 @@ "version": "0.3.6", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", - "@types/ws": "^8.5.8", + "@types/jest": "~29.5.13", + "@types/ws": "^8.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", "jest-websocket-mock": "~2.5.0", diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index c0fa20f58227..4915221b71ca 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -4,8 +4,8 @@ "description": "Rocket.Chat's JS/TS ESLint config", "dependencies": { "@babel/core": "^7.20.7", - "@babel/eslint-parser": "~7.23.3", - "@types/eslint": "~8.44.6", + "@babel/eslint-parser": "~7.23.10", + "@types/eslint": "~8.44.9", "@types/prettier": "^2.6.3", "@typescript-eslint/eslint-plugin": "~5.60.1", "@typescript-eslint/parser": "~5.60.1", diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 43a79f90b9ed..80874491a951 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -86,12 +86,10 @@ "@storybook/source-loader": "~6.5.16", "@storybook/theming": "~6.5.16", "@tanstack/react-query": "^4.16.1", - "@testing-library/react": "~16.0.0", + "@testing-library/react": "~16.0.1", "@testing-library/user-event": "~14.5.2", - "@types/babel__core": "^7.20.3", - "@types/babel__preset-env": "^7.9.4", - "@types/react": "~17.0.69", - "@types/react-dom": "~17.0.22", + "@types/react": "~17.0.80", + "@types/react-dom": "~17.0.25", "babel-loader": "~8.2.5", "cross-env": "^7.0.3", "eslint": "~8.45.0", @@ -100,11 +98,11 @@ "normalize.css": "^8.0.1", "npm-run-all": "^4.1.5", "prettier": "~2.8.8", - "react-docgen-typescript-plugin": "~1.0.5", + "react-docgen-typescript-plugin": "~1.0.8", "react-dom": "^17.0.2", "react-i18next": "~15.0.1", "rimraf": "^3.0.2", - "storybook-dark-mode": "~3.0.1", + "storybook-dark-mode": "~3.0.3", "tslib": "^2.5.3", "typescript": "~5.5.4" }, diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index babdc60161da..c2fbf136b2d6 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -44,25 +44,25 @@ "@storybook/manager-webpack4": "~6.5.16", "@storybook/react": "~6.5.16", "@storybook/testing-library": "~0.0.13", - "@testing-library/react": "~16.0.0", + "@testing-library/react": "~16.0.1", "@types/dompurify": "^3.0.5", - "@types/jest": "~29.5.12", - "@types/katex": "~0.16.5", - "@types/react": "~17.0.69", - "@types/react-dom": "~17.0.22", + "@types/jest": "~29.5.13", + "@types/katex": "~0.16.7", + "@types/react": "~17.0.80", + "@types/react-dom": "~17.0.25", "@typescript-eslint/eslint-plugin": "~5.60.1", "@typescript-eslint/parser": "~5.60.1", "babel-loader": "^8.3.0", "eslint": "~8.45.0", "eslint-plugin-anti-trojan-source": "~1.1.1", "eslint-plugin-react": "~7.32.2", - "eslint-plugin-react-hooks": "~4.6.0", + "eslint-plugin-react-hooks": "~4.6.2", "eslint-plugin-storybook": "~0.6.15", "identity-obj-proxy": "^3.0.0", "jest": "~29.7.0", - "katex": "~0.16.9", + "katex": "~0.16.11", "outdent": "^0.8.0", - "react-docgen-typescript-plugin": "~1.0.5", + "react-docgen-typescript-plugin": "~1.0.8", "react-dom": "~17.0.2", "react-i18next": "~15.0.1", "typescript": "~5.5.4" diff --git a/packages/jest-presets/package.json b/packages/jest-presets/package.json index 078d19289d34..64a511b3de5c 100644 --- a/packages/jest-presets/package.json +++ b/packages/jest-presets/package.json @@ -13,7 +13,7 @@ "/server" ], "dependencies": { - "@swc/core": "~1.7.23", + "@swc/core": "~1.7.26", "@swc/jest": "~0.2.36", "@testing-library/jest-dom": "~6.4.8", "@types/jest-axe": "~3.5.9", @@ -25,9 +25,9 @@ }, "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", - "@types/identity-obj-proxy": "^3", - "@types/jest": "~29.5.12", - "@types/uuid": "^9", + "@types/identity-obj-proxy": "^3.0.2", + "@types/jest": "~29.5.13", + "@types/uuid": "^9.0.8", "eslint": "~8.45.0", "jest": "~29.7.0", "typescript": "~5.5.4" diff --git a/packages/jwt/package.json b/packages/jwt/package.json index d945bd3a6f9c..7235a916385d 100644 --- a/packages/jwt/package.json +++ b/packages/jwt/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", + "@types/jest": "~29.5.13", "eslint": "~8.45.0", "jest": "~29.7.0", "typescript": "~5.5.4" diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 5887c40028c4..ce7bb92d6b78 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -25,7 +25,7 @@ "typecheck": "tsc -p tsconfig.typecheck.json" }, "devDependencies": { - "@babel/eslint-parser": "~7.23.3", + "@babel/eslint-parser": "~7.23.10", "@babel/preset-env": "~7.22.20", "@babel/preset-typescript": "~7.22.15", "@rocket.chat/core-typings": "workspace:^", @@ -42,7 +42,7 @@ "@types/crypto-js": "~4.1.3", "@types/markdown-it": "^14.0.1", "@types/mini-css-extract-plugin": "~1.4.3", - "@types/webpack": "^5.28.4", + "@types/webpack": "^5.28.5", "@types/webpack-bundle-analyzer": "^4.6.2", "@types/webpack-dev-server": "~4.7.2", "@types/whatwg-fetch": "~0.0.33", @@ -57,7 +57,7 @@ "eslint": "~8.45.0", "eslint-plugin-import": "~2.26.0", "eslint-plugin-react": "~7.32.2", - "eslint-plugin-react-hooks": "~4.6.0", + "eslint-plugin-react-hooks": "~4.6.2", "file-loader": "^6.2.0", "gh-release": "^3.5.0", "html-webpack-plugin": "^5.5.3", @@ -102,7 +102,7 @@ "@rocket.chat/random": "workspace:~", "@rocket.chat/sdk": "^1.0.0-alpha.42", "@rocket.chat/ui-kit": "workspace:~", - "css-vars-ponyfill": "^2.4.8", + "css-vars-ponyfill": "^2.4.9", "date-fns": "^2.15.0", "emoji-mart": "^3.0.1", "history": "~5.3.0", @@ -116,8 +116,8 @@ "query-string": "^7.1.3", "react-hook-form": "~7.45.4", "react-i18next": "~15.0.1", - "storybook-dark-mode": "~3.0.1", - "whatwg-fetch": "^3.6.19" + "storybook-dark-mode": "~3.0.3", + "whatwg-fetch": "^3.6.20" }, "browserslist": [ "last 2 versions", diff --git a/packages/log-format/package.json b/packages/log-format/package.json index f6f7c03b6f63..a999c7d884f0 100644 --- a/packages/log-format/package.json +++ b/packages/log-format/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@types/chalk": "^2.2.0", - "@types/ejson": "^2.2.1", + "@types/ejson": "^2.2.2", "eslint": "~8.45.0", "typescript": "~5.5.4" }, diff --git a/packages/message-parser/package.json b/packages/message-parser/package.json index 78ffd3401ff4..e58727ba38c2 100644 --- a/packages/message-parser/package.json +++ b/packages/message-parser/package.json @@ -48,29 +48,29 @@ "docs": "typedoc" }, "devDependencies": { - "@babel/core": "~7.21.4", - "@babel/eslint-parser": "~7.21.3", - "@babel/preset-env": "~7.21.4", + "@babel/core": "~7.21.8", + "@babel/eslint-parser": "~7.21.8", + "@babel/preset-env": "~7.21.5", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/peggy-loader": "workspace:~", "@rocket.chat/prettier-config": "~0.31.25", - "@types/jest": "~29.5.12", - "@types/node": "~14.18.42", + "@types/jest": "~29.5.13", + "@types/node": "~14.18.63", "@typescript-eslint/parser": "~5.58.0", - "babel-loader": "~9.1.2", + "babel-loader": "~9.1.3", "eslint": "~8.45.0", "jest": "~29.7.0", "npm-run-all": "^4.1.5", "peggy": "3.0.2", - "prettier": "~2.8.7", + "prettier": "~2.8.8", "prettier-plugin-pegjs": "~0.5.4", "rimraf": "^3.0.2", - "ts-loader": "~9.4.2", - "typedoc": "~0.24.1", + "ts-loader": "~9.4.4", + "typedoc": "~0.24.8", "typescript": "~5.5.4", "webpack": "~5.78.0", - "webpack-cli": "~5.0.1" + "webpack-cli": "~5.0.2" }, "dependencies": { "tldts": "~5.7.112" diff --git a/packages/mock-providers/package.json b/packages/mock-providers/package.json index fa8c98cfbc5c..f9e9b4d06ab8 100644 --- a/packages/mock-providers/package.json +++ b/packages/mock-providers/package.json @@ -14,7 +14,7 @@ "@rocket.chat/ui-contexts": "workspace:*", "@storybook/react": "~6.5.16", "@tanstack/react-query": "^4.16.1", - "@types/use-sync-external-store": "^0.0.5", + "@types/use-sync-external-store": "^0.0.6", "eslint": "~8.45.0", "react": "~17.0.2", "typescript": "~5.5.4" diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index e1df06d2ba3c..30144dabb49a 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -3,7 +3,7 @@ "version": "0.7.0", "private": true, "devDependencies": { - "@types/node-rsa": "^1.1.3", + "@types/node-rsa": "^1.1.4", "eslint": "~8.45.0", "mongodb": "^4.17.2", "typescript": "~5.5.4" diff --git a/packages/models/package.json b/packages/models/package.json index f64268e12a5b..e55ce8d5a0e1 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", + "@types/jest": "~29.5.13", "eslint": "~8.45.0", "jest": "^29.7.0", "typescript": "~5.5.4" diff --git a/packages/password-policies/package.json b/packages/password-policies/package.json index a2fef4ae0543..6bfb0d6100f1 100644 --- a/packages/password-policies/package.json +++ b/packages/password-policies/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", + "@types/jest": "~29.5.13", "eslint": "~8.45.0", "jest": "~29.7.0", "typescript": "~5.5.4" diff --git a/packages/patch-injection/package.json b/packages/patch-injection/package.json index 8dabf2fb3f2a..2ac35749c481 100644 --- a/packages/patch-injection/package.json +++ b/packages/patch-injection/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", + "@types/jest": "~29.5.13", "eslint": "~8.45.0", "jest": "~29.7.0", "typescript": "~5.5.4" diff --git a/packages/peggy-loader/package.json b/packages/peggy-loader/package.json index f0ac6d915567..6eb584f62d24 100644 --- a/packages/peggy-loader/package.json +++ b/packages/peggy-loader/package.json @@ -44,11 +44,11 @@ "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@rocket.chat/prettier-config": "~0.31.25", - "@types/node": "~14.18.42", + "@types/node": "~14.18.63", "eslint": "~8.45.0", "npm-run-all": "^4.1.5", "peggy": "3.0.2", - "prettier": "~2.8.7", + "prettier": "~2.8.8", "rimraf": "^3.0.2", "typescript": "~5.5.4", "webpack": "~5.78.0" diff --git a/packages/release-action/package.json b/packages/release-action/package.json index e633ef69d06f..0851b8b43fca 100644 --- a/packages/release-action/package.json +++ b/packages/release-action/package.json @@ -10,7 +10,7 @@ "main": "dist/index.js", "packageManager": "yarn@3.5.1", "devDependencies": { - "@types/node": "^16.18.60", + "@types/node": "^16.18.108", "typescript": "~5.5.4" }, "dependencies": { diff --git a/packages/release-changelog/package.json b/packages/release-changelog/package.json index f183d00b550b..222f7f20355a 100644 --- a/packages/release-changelog/package.json +++ b/packages/release-changelog/package.json @@ -16,6 +16,6 @@ }, "dependencies": { "dataloader": "^1.4.0", - "node-fetch": "^2" + "node-fetch": "^2.7.0" } } diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 61e23c4c93ce..972577210f56 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -3,7 +3,7 @@ "version": "6.13.0-develop", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", - "@types/jest": "~29.5.12", + "@types/jest": "~29.5.13", "eslint": "~8.45.0", "jest": "~29.7.0", "mongodb": "^4.17.2", diff --git a/packages/server-fetch/package.json b/packages/server-fetch/package.json index 27f957758520..e09b20d1aa42 100644 --- a/packages/server-fetch/package.json +++ b/packages/server-fetch/package.json @@ -21,7 +21,7 @@ "extends": "../../package.json" }, "dependencies": { - "@types/proxy-from-env": "^1.0.3", + "@types/proxy-from-env": "^1.0.4", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.1", "node-fetch": "2.3.0", diff --git a/packages/tools/package.json b/packages/tools/package.json index 11dade3ac5c8..bb38a8c5ae4f 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", + "@types/jest": "~29.5.13", "eslint": "~8.45.0", "jest": "~29.7.0", "typescript": "~5.5.4" @@ -24,6 +24,6 @@ "/dist" ], "dependencies": { - "moment-timezone": "^0.5.43" + "moment-timezone": "^0.5.45" } } diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 42860fd8692a..0423b68f2b43 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -6,12 +6,11 @@ "@babel/core": "~7.22.20", "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/ui-contexts": "workspace:^", - "@types/babel__core": "~7.20.3", - "@types/react": "~17.0.69", - "@types/react-dom": "~17.0.22", + "@types/react": "~17.0.80", + "@types/react-dom": "~17.0.25", "eslint": "~8.45.0", "eslint-plugin-react": "~7.32.2", - "eslint-plugin-react-hooks": "~4.6.0", + "eslint-plugin-react-hooks": "~4.6.2", "eslint-plugin-storybook": "~0.6.15", "eslint-plugin-testing-library": "~5.11.1", "react": "^17.0.2", diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index a2b916b68241..a84317f37abc 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -26,6 +26,7 @@ "@rocket.chat/icons": "~0.38.0", "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/mock-providers": "workspace:^", + "@rocket.chat/ui-avatar": "workspace:~", "@rocket.chat/ui-contexts": "workspace:~", "@storybook/addon-actions": "~6.5.16", "@storybook/addon-docs": "~6.5.16", @@ -37,15 +38,14 @@ "@storybook/manager-webpack4": "~6.5.16", "@storybook/react": "~6.5.16", "@storybook/testing-library": "~0.0.13", - "@testing-library/react": "~16.0.0", - "@types/babel__core": "~7.20.3", - "@types/jest": "~29.5.12", - "@types/react": "~17.0.69", - "@types/react-dom": "~17.0.22", + "@testing-library/react": "~16.0.1", + "@types/jest": "~29.5.13", + "@types/react": "~17.0.80", + "@types/react-dom": "~17.0.25", "eslint": "~8.45.0", "eslint-plugin-anti-trojan-source": "~1.1.1", "eslint-plugin-react": "~7.32.2", - "eslint-plugin-react-hooks": "~4.6.0", + "eslint-plugin-react-hooks": "~4.6.2", "eslint-plugin-storybook": "~0.6.15", "eslint-plugin-testing-library": "~5.11.1", "jest": "~29.7.0", @@ -61,6 +61,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", + "@rocket.chat/ui-avatar": "*", "@rocket.chat/ui-contexts": "*", "react": "*", "react-i18next": "*" diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index 55e22a79e34c..0f97fef22508 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -28,15 +28,14 @@ "@storybook/manager-webpack4": "~6.5.16", "@storybook/react": "~6.5.16", "@storybook/testing-library": "~0.0.13", - "@types/babel__core": "~7.20.3", - "@types/react": "~17.0.69", - "@types/react-dom": "~17.0.22", + "@types/react": "~17.0.80", + "@types/react-dom": "~17.0.25", "eslint": "~8.45.0", "eslint-plugin-react": "~7.32.2", - "eslint-plugin-react-hooks": "~4.6.0", + "eslint-plugin-react-hooks": "~4.6.2", "eslint-plugin-storybook": "~0.6.15", "react": "~17.0.2", - "react-docgen-typescript-plugin": "~1.0.5", + "react-docgen-typescript-plugin": "~1.0.8", "react-dom": "~17.0.2", "typescript": "~5.5.4" }, diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 24c8b5de5ce2..3ef588432a7c 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -9,15 +9,15 @@ "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/i18n": "workspace:~", "@rocket.chat/rest-typings": "workspace:^", - "@types/react": "~17.0.69", - "@types/react-dom": "~17.0.22", - "@types/use-sync-external-store": "^0.0.5", + "@types/react": "~17.0.80", + "@types/react-dom": "~17.0.25", + "@types/use-sync-external-store": "^0.0.6", "eslint": "~8.45.0", - "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-hooks": "^4.6.2", "mongodb": "^4.17.2", "react": "~17.0.2", "typescript": "~5.5.4", - "use-sync-external-store": "^1.2.0" + "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-kit/package.json b/packages/ui-kit/package.json index 9d39ae97ac55..ae50fbc17168 100644 --- a/packages/ui-kit/package.json +++ b/packages/ui-kit/package.json @@ -35,23 +35,23 @@ "test": "jest" }, "devDependencies": { - "@babel/core": "~7.21.4", - "@babel/eslint-parser": "~7.23.3", + "@babel/core": "~7.21.8", + "@babel/eslint-parser": "~7.23.10", "@babel/plugin-transform-runtime": "~7.21.4", - "@babel/preset-env": "~7.21.4", + "@babel/preset-env": "~7.21.5", "@rocket.chat/eslint-config": "workspace:~", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", - "babel-loader": "~9.1.2", + "@types/jest": "~29.5.13", + "babel-loader": "~9.1.3", "eslint": "~8.45.0", "jest": "~29.7.0", "npm-run-all": "~4.1.5", "prettier": "~2.8.8", "rimraf": "~3.0.2", - "ts-jest": "~29.1.1", - "ts-loader": "~9.4.2", - "ts-node": "~10.9.1", + "ts-jest": "~29.1.5", + "ts-loader": "~9.4.4", + "ts-node": "~10.9.2", "ts-patch": "~3.2.1", "typescript": "~5.5.4" }, diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index d10c05edad2c..eb363da1ceae 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -22,16 +22,15 @@ "@storybook/react": "~6.5.16", "@storybook/testing-library": "~0.0.13", "@storybook/testing-react": "~1.3.0", - "@types/babel__core": "~7.20.3", - "@types/jest": "~29.5.12", + "@types/jest": "~29.5.13", "@types/jest-axe": "~3.5.9", "eslint": "~8.45.0", "eslint-plugin-react": "~7.32.2", - "eslint-plugin-react-hooks": "~4.6.0", + "eslint-plugin-react-hooks": "~4.6.2", "eslint-plugin-storybook": "~0.6.15", "jest": "~29.7.0", "jest-axe": "~9.0.0", - "react-docgen-typescript-plugin": "~1.0.5", + "react-docgen-typescript-plugin": "~1.0.8", "typescript": "~5.5.4" }, "peerDependencies": { diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 71e015bb82c0..ae08e05ee218 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -21,7 +21,7 @@ "@babel/preset-react": "~7.22.15", "@babel/preset-typescript": "~7.22.15", "@rocket.chat/i18n": "workspace:~", - "@rocket.chat/layout": "~0.31.26", + "@rocket.chat/layout": "~0.31.27", "@rocket.chat/mock-providers": "workspace:~", "@rocket.chat/tools": "workspace:~", "@rocket.chat/ui-client": "workspace:^", @@ -34,14 +34,14 @@ "@storybook/react": "~6.5.16", "@storybook/testing-library": "^0.2.2", "@tanstack/react-query": "^4.16.1", - "@testing-library/react": "~16.0.0", - "@types/react": "~17.0.69", + "@testing-library/react": "~16.0.1", + "@types/react": "~17.0.80", "babel-loader": "~8.3.0", "eslint": "~8.45.0", "react": "~17.0.2", "react-hook-form": "~7.45.4", "react-i18next": "~15.0.1", - "storybook-dark-mode": "~3.0.1", + "storybook-dark-mode": "~3.0.3", "typescript": "~5.5.4" }, "peerDependencies": { diff --git a/yarn.lock b/yarn.lock index cd440c92c40f..6b1123701996 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1039,7 +1039,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:~7.21.4": +"@babel/core@npm:~7.21.8": version: 7.21.8 resolution: "@babel/core@npm:7.21.8" dependencies: @@ -1062,7 +1062,7 @@ __metadata: languageName: node linkType: hard -"@babel/eslint-parser@npm:~7.21.3": +"@babel/eslint-parser@npm:~7.21.8": version: 7.21.8 resolution: "@babel/eslint-parser@npm:7.21.8" dependencies: @@ -1076,9 +1076,9 @@ __metadata: languageName: node linkType: hard -"@babel/eslint-parser@npm:~7.23.3": - version: 7.23.3 - resolution: "@babel/eslint-parser@npm:7.23.3" +"@babel/eslint-parser@npm:~7.23.10": + version: 7.23.10 + resolution: "@babel/eslint-parser@npm:7.23.10" dependencies: "@nicolo-ribaudo/eslint-scope-5-internals": 5.1.1-v1 eslint-visitor-keys: ^2.1.0 @@ -1086,7 +1086,7 @@ __metadata: peerDependencies: "@babel/core": ^7.11.0 eslint: ^7.5.0 || ^8.0.0 - checksum: 9573daebe21af5123c302c307be80cacf1c2bf236a9497068a14726d3944ef55e1282519d0ccf51882dfc369359a3442299c98cb22a419e209924db39d4030fd + checksum: 81249edee14f95720044f393b5b0a681a230ac2bde3d656b0c55b1cec4c5cb99ce0584ef6acd2e5413acc7905daee1b2e1db8e3fab18a3a74c508098a584ec9a languageName: node linkType: hard @@ -2733,7 +2733,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:~7.21.4": +"@babel/preset-env@npm:~7.21.5": version: 7.21.5 resolution: "@babel/preset-env@npm:7.21.5" dependencies: @@ -4701,13 +4701,13 @@ __metadata: languageName: node linkType: hard -"@kaciras/deasync@npm:^1.0.3": - version: 1.0.3 - resolution: "@kaciras/deasync@npm:1.0.3" +"@kaciras/deasync@npm:^1.0.4": + version: 1.0.4 + resolution: "@kaciras/deasync@npm:1.0.4" dependencies: - follow-redirects: ^1.15.2 - tar-fs: ^2.1.1 - checksum: 6986db099e8676ae2c21d1122db9f60dd5b74dd4ec06eb164c7ded0f512d037146f82cd3dee189d2863b1c6064f17d33b273edf67b25d3bb71050c5a6fe1aa6b + follow-redirects: ^1.15.6 + tar-fs: ^3.0.5 + checksum: 4bb358de84731000f3576dff029f89bf6ddf8628c95fd3661c029716a796fc44eb3769445479c3f4a0990f10617caf7902bf07547df76bf239582f565d3855fc languageName: node linkType: hard @@ -4858,6 +4858,26 @@ __metadata: languageName: node linkType: hard +"@meteorjs/crypto-browserify@npm:^3.12.1": + version: 3.12.1 + resolution: "@meteorjs/crypto-browserify@npm:3.12.1" + dependencies: + browserify-cipher: ^1.0.1 + browserify-sign: ^4.2.3 + create-ecdh: ^4.0.4 + create-hash: ^1.2.0 + create-hmac: ^1.1.7 + diffie-hellman: ^5.0.3 + hash-base: ~3.0.4 + inherits: ^2.0.4 + pbkdf2: ^3.1.2 + public-encrypt: ^4.0.3 + randombytes: ^2.1.0 + randomfill: ^1.0.4 + checksum: 0e7b3528273d057587a28d5aba644638da966e0d641c9211b16327efa2ce1e69f769d1bfb385cf974eb36e2fd96e81e2a4d75ec4f43bf230df0c4326ed9cdd9e + languageName: node + linkType: hard + "@mongodb-js/saslprep@npm:^1.1.0": version: 1.1.0 resolution: "@mongodb-js/saslprep@npm:1.1.0" @@ -8424,24 +8444,24 @@ __metadata: "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 "@rocket.chat/tools": "workspace:^" - "@types/bcrypt": ^5.0.1 - "@types/gc-stats": ^1.4.2 + "@types/bcrypt": ^5.0.2 + "@types/gc-stats": ^1.4.3 "@types/node": ^14.18.63 - "@types/polka": ^0.5.6 + "@types/polka": ^0.5.7 bcrypt: ^5.0.1 ejson: ^2.2.3 eslint: ~8.45.0 event-loop-stats: ^1.4.1 eventemitter3: ^4.0.7 fibers: ^5.0.3 - gc-stats: ^1.4.0 + gc-stats: ^1.4.1 mem: ^8.1.1 - moleculer: ^0.14.31 + moleculer: ^0.14.34 mongodb: ^4.17.2 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 - ts-node: ^10.9.1 + ts-node: ^10.9.2 typescript: ~5.5.4 uuid: ^9.0.1 languageName: unknown @@ -8460,13 +8480,13 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/agenda@workspace:packages/agenda" dependencies: - "@types/debug": ^4.1.10 + "@types/debug": ^4.1.12 cron: ~1.8.2 date.js: ~0.3.3 debug: ~4.1.1 eslint: ~8.45.0 human-interval: ^2.0.1 - moment-timezone: ~0.5.43 + moment-timezone: ~0.5.45 mongodb: ^4.17.2 typescript: ~5.5.4 languageName: unknown @@ -8479,8 +8499,8 @@ __metadata: "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/rest-typings": "workspace:^" - "@types/jest": ~29.5.12 - "@types/strict-uri-encode": ^2.0.1 + "@types/jest": ~29.5.13 + "@types/strict-uri-encode": ^2.0.2 eslint: ~8.45.0 filter-obj: ^3.0.0 jest: ~29.7.0 @@ -8538,22 +8558,22 @@ __metadata: "@rocket.chat/models": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 - "@types/gc-stats": ^1.4.2 + "@types/gc-stats": ^1.4.3 "@types/node": ^14.18.63 - "@types/polka": ^0.5.6 + "@types/polka": ^0.5.7 ejson: ^2.2.3 eslint: ~8.45.0 event-loop-stats: ^1.4.1 eventemitter3: ^4.0.7 fibers: ^5.0.3 - gc-stats: ^1.4.0 + gc-stats: ^1.4.1 mem: ^8.1.1 - moleculer: ^0.14.31 + moleculer: ^0.14.34 mongodb: ^4.17.2 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 - ts-node: ^10.9.1 + ts-node: ^10.9.2 typescript: ~5.5.4 languageName: unknown linkType: soft @@ -8600,10 +8620,8 @@ __metadata: "@rocket.chat/models": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/ui-kit": "workspace:~" - "@types/babel__core": ^7.20.3 - "@types/babel__preset-env": ^7.9.4 - "@types/fibers": ^3.1.3 - "@types/jest": ~29.5.12 + "@types/fibers": ^3.1.4 + "@types/jest": ~29.5.13 babel-jest: ^29.5.0 eslint: ~8.45.0 fibers: ^5.0.3 @@ -8675,8 +8693,8 @@ __metadata: "@rocket.chat/core-typings": "workspace:~" "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/rest-typings": "workspace:^" - "@types/jest": ~29.5.12 - "@types/ws": ^8.5.8 + "@types/jest": ~29.5.13 + "@types/ws": ^8.5.12 eslint: ~8.45.0 jest: ~29.7.0 jest-websocket-mock: ~2.5.0 @@ -8703,33 +8721,33 @@ __metadata: "@rocket.chat/models": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 - "@types/ejson": ^2.2.1 - "@types/gc-stats": ^1.4.2 + "@types/ejson": ^2.2.2 + "@types/gc-stats": ^1.4.3 "@types/meteor": ^2.9.8 "@types/node": ^14.18.63 - "@types/polka": ^0.5.6 + "@types/polka": ^0.5.7 "@types/sharp": ^0.30.5 "@types/uuid": ^8.3.4 - "@types/ws": ^8.5.8 + "@types/ws": ^8.5.12 colorette: ^1.4.0 ejson: ^2.2.3 eslint: ~8.45.0 event-loop-stats: ^1.4.1 eventemitter3: ^4.0.7 fibers: ^5.0.3 - gc-stats: ^1.4.0 + gc-stats: ^1.4.1 jaeger-client: ^3.19.0 mem: ^8.1.1 - moleculer: ^0.14.31 + moleculer: ^0.14.34 mongodb: ^4.17.2 nats: ^2.4.0 pino: ^8.15.0 pino-pretty: ^7.6.1 polka: ^0.5.2 sharp: ^0.32.6 - ts-node: ^10.9.1 + ts-node: ^10.9.2 typescript: ~5.5.4 - underscore: ^1.13.6 + underscore: ^1.13.7 uuid: ^7.0.3 ws: ^8.8.1 languageName: unknown @@ -8747,8 +8765,8 @@ __metadata: resolution: "@rocket.chat/eslint-config@workspace:packages/eslint-config" dependencies: "@babel/core": ^7.20.7 - "@babel/eslint-parser": ~7.23.3 - "@types/eslint": ~8.44.6 + "@babel/eslint-parser": ~7.23.10 + "@types/eslint": ~8.44.9 "@types/prettier": ^2.6.3 "@typescript-eslint/eslint-plugin": ~5.60.1 "@typescript-eslint/parser": ~5.60.1 @@ -8913,12 +8931,10 @@ __metadata: "@storybook/source-loader": ~6.5.16 "@storybook/theming": ~6.5.16 "@tanstack/react-query": ^4.16.1 - "@testing-library/react": ~16.0.0 + "@testing-library/react": ~16.0.1 "@testing-library/user-event": ~14.5.2 - "@types/babel__core": ^7.20.3 - "@types/babel__preset-env": ^7.9.4 - "@types/react": ~17.0.69 - "@types/react-dom": ~17.0.22 + "@types/react": ~17.0.80 + "@types/react-dom": ~17.0.25 babel-loader: ~8.2.5 cross-env: ^7.0.3 eslint: ~8.45.0 @@ -8927,11 +8943,11 @@ __metadata: normalize.css: ^8.0.1 npm-run-all: ^4.1.5 prettier: ~2.8.8 - react-docgen-typescript-plugin: ~1.0.5 + react-docgen-typescript-plugin: ~1.0.8 react-dom: ^17.0.2 react-i18next: ~15.0.1 rimraf: ^3.0.2 - storybook-dark-mode: ~3.0.1 + storybook-dark-mode: ~3.0.3 tslib: ^2.5.3 typescript: ~5.5.4 peerDependencies: @@ -9000,12 +9016,12 @@ __metadata: "@storybook/manager-webpack4": ~6.5.16 "@storybook/react": ~6.5.16 "@storybook/testing-library": ~0.0.13 - "@testing-library/react": ~16.0.0 + "@testing-library/react": ~16.0.1 "@types/dompurify": ^3.0.5 - "@types/jest": ~29.5.12 - "@types/katex": ~0.16.5 - "@types/react": ~17.0.69 - "@types/react-dom": ~17.0.22 + "@types/jest": ~29.5.13 + "@types/katex": ~0.16.7 + "@types/react": ~17.0.80 + "@types/react-dom": ~17.0.25 "@typescript-eslint/eslint-plugin": ~5.60.1 "@typescript-eslint/parser": ~5.60.1 babel-loader: ^8.3.0 @@ -9014,14 +9030,14 @@ __metadata: eslint: ~8.45.0 eslint-plugin-anti-trojan-source: ~1.1.1 eslint-plugin-react: ~7.32.2 - eslint-plugin-react-hooks: ~4.6.0 + eslint-plugin-react-hooks: ~4.6.2 eslint-plugin-storybook: ~0.6.15 highlight.js: ^11.5.1 identity-obj-proxy: ^3.0.0 jest: ~29.7.0 - katex: ~0.16.9 + katex: ~0.16.11 outdent: ^0.8.0 - react-docgen-typescript-plugin: ~1.0.5 + react-docgen-typescript-plugin: ~1.0.8 react-dom: ~17.0.2 react-error-boundary: ^3.1.4 react-i18next: ~15.0.1 @@ -9079,13 +9095,13 @@ __metadata: resolution: "@rocket.chat/jest-presets@workspace:packages/jest-presets" dependencies: "@rocket.chat/eslint-config": "workspace:~" - "@swc/core": ~1.7.23 + "@swc/core": ~1.7.26 "@swc/jest": ~0.2.36 "@testing-library/jest-dom": ~6.4.8 - "@types/identity-obj-proxy": ^3 - "@types/jest": ~29.5.12 + "@types/identity-obj-proxy": ^3.0.2 + "@types/jest": ~29.5.13 "@types/jest-axe": ~3.5.9 - "@types/uuid": ^9 + "@types/uuid": ^9.0.8 eslint: ~8.45.0 identity-obj-proxy: ~3.0.0 jest: ~29.7.0 @@ -9102,7 +9118,7 @@ __metadata: resolution: "@rocket.chat/jwt@workspace:packages/jwt" dependencies: "@rocket.chat/jest-presets": "workspace:~" - "@types/jest": ~29.5.12 + "@types/jest": ~29.5.13 eslint: ~8.45.0 jest: ~29.7.0 jose: ^4.14.4 @@ -9110,15 +9126,15 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/layout@npm:~0.31.26": - version: 0.31.26 - resolution: "@rocket.chat/layout@npm:0.31.26" +"@rocket.chat/layout@npm:~0.31.27": + version: 0.31.27 + resolution: "@rocket.chat/layout@npm:0.31.27" peerDependencies: "@rocket.chat/fuselage": "*" react: 17.0.2 react-dom: 17.0.2 react-i18next: ~11.15.4 - checksum: 473b3ce43f7e5c495bbbfb54c628a1da9fda672fee0aeef74a25690a462b243982749bb1ba6933130381aea8aae61fb9aed6b45d6c3ec370c7555e1ac69930ce + checksum: 5bf14cc2c85947c5773b9dbaeb7b79f36b770c80673f7eb5aaded80a3f8a7ebcbfb67c8d8c2f4731c630737784b375bd775cc53941f4ce8dd1b9d1a327449b02 languageName: node linkType: hard @@ -9130,9 +9146,9 @@ __metadata: "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/jwt": "workspace:^" "@rocket.chat/logger": "workspace:^" - "@types/bcrypt": ^5.0.1 - "@types/jest": ~29.5.12 - "@types/ws": ^8.5.8 + "@types/bcrypt": ^5.0.2 + "@types/jest": ~29.5.13 + "@types/ws": ^8.5.12 bcrypt: ^5.0.1 eslint: ~8.45.0 jest: ~29.7.0 @@ -9145,7 +9161,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/livechat@workspace:packages/livechat" dependencies: - "@babel/eslint-parser": ~7.23.3 + "@babel/eslint-parser": ~7.23.10 "@babel/preset-env": ~7.22.20 "@babel/preset-typescript": ~7.22.15 "@rocket.chat/core-typings": "workspace:^" @@ -9167,7 +9183,7 @@ __metadata: "@types/crypto-js": ~4.1.3 "@types/markdown-it": ^14.0.1 "@types/mini-css-extract-plugin": ~1.4.3 - "@types/webpack": ^5.28.4 + "@types/webpack": ^5.28.5 "@types/webpack-bundle-analyzer": ^4.6.2 "@types/webpack-dev-server": ~4.7.2 "@types/whatwg-fetch": ~0.0.33 @@ -9177,7 +9193,7 @@ __metadata: babel-loader: ^8.3.0 cross-env: ^7.0.3 css-loader: ^4.3.0 - css-vars-ponyfill: ^2.4.8 + css-vars-ponyfill: ^2.4.9 cssnano: ^4.1.11 date-fns: ^2.15.0 desvg-loader: ^0.1.0 @@ -9185,7 +9201,7 @@ __metadata: eslint: ~8.45.0 eslint-plugin-import: ~2.26.0 eslint-plugin-react: ~7.32.2 - eslint-plugin-react-hooks: ~4.6.0 + eslint-plugin-react-hooks: ~4.6.2 file-loader: ^6.2.0 gh-release: ^3.5.0 history: ~5.3.0 @@ -9219,7 +9235,7 @@ __metadata: sass: ~1.62.1 sass-loader: ~10.4.1 serve: ^11.3.2 - storybook-dark-mode: ~3.0.1 + storybook-dark-mode: ~3.0.3 style-loader: ^1.2.1 stylelint: ^14.9.1 stylelint-order: ^5.0.0 @@ -9231,7 +9247,7 @@ __metadata: webpack-bundle-analyzer: ^4.9.1 webpack-cli: ^5.1.4 webpack-dev-server: ~4.13.3 - whatwg-fetch: ^3.6.19 + whatwg-fetch: ^3.6.20 peerDependencies: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/logo": "*" @@ -9243,7 +9259,7 @@ __metadata: resolution: "@rocket.chat/log-format@workspace:packages/log-format" dependencies: "@types/chalk": ^2.2.0 - "@types/ejson": ^2.2.1 + "@types/ejson": ^2.2.2 chalk: ^4.0.0 ejson: ^2.2.3 eslint: ~8.45.0 @@ -9286,30 +9302,30 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/message-parser@workspace:packages/message-parser" dependencies: - "@babel/core": ~7.21.4 - "@babel/eslint-parser": ~7.21.3 - "@babel/preset-env": ~7.21.4 + "@babel/core": ~7.21.8 + "@babel/eslint-parser": ~7.21.8 + "@babel/preset-env": ~7.21.5 "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/peggy-loader": "workspace:~" "@rocket.chat/prettier-config": ~0.31.25 - "@types/jest": ~29.5.12 - "@types/node": ~14.18.42 + "@types/jest": ~29.5.13 + "@types/node": ~14.18.63 "@typescript-eslint/parser": ~5.58.0 - babel-loader: ~9.1.2 + babel-loader: ~9.1.3 eslint: ~8.45.0 jest: ~29.7.0 npm-run-all: ^4.1.5 peggy: 3.0.2 - prettier: ~2.8.7 + prettier: ~2.8.8 prettier-plugin-pegjs: ~0.5.4 rimraf: ^3.0.2 tldts: ~5.7.112 - ts-loader: ~9.4.2 - typedoc: ~0.24.1 + ts-loader: ~9.4.4 + typedoc: ~0.24.8 typescript: ~5.5.4 webpack: ~5.78.0 - webpack-cli: ~5.0.1 + webpack-cli: ~5.0.2 languageName: unknown linkType: soft @@ -9319,7 +9335,7 @@ __metadata: dependencies: "@axe-core/playwright": ^4.7.3 "@babel/core": ~7.22.20 - "@babel/eslint-parser": ~7.23.3 + "@babel/eslint-parser": ~7.23.10 "@babel/plugin-proposal-nullish-coalescing-operator": ~7.18.6 "@babel/plugin-proposal-optional-chaining": ~7.21.0 "@babel/preset-env": ~7.22.20 @@ -9330,7 +9346,7 @@ __metadata: "@bugsnag/plugin-react": ~7.19.0 "@faker-js/faker": ~8.0.2 "@google-cloud/storage": ^6.11.0 - "@kaciras/deasync": ^1.0.3 + "@kaciras/deasync": ^1.0.4 "@nivo/bar": 0.84.0 "@nivo/core": 0.84.0 "@nivo/heatmap": 0.84.0 @@ -9368,7 +9384,7 @@ __metadata: "@rocket.chat/instance-status": "workspace:^" "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/jwt": "workspace:^" - "@rocket.chat/layout": ~0.31.26 + "@rocket.chat/layout": ~0.31.27 "@rocket.chat/license": "workspace:^" "@rocket.chat/livechat": "workspace:^" "@rocket.chat/log-format": "workspace:^" @@ -9414,87 +9430,87 @@ __metadata: "@storybook/testing-library": 0.0.13 "@tanstack/react-query": ^4.16.1 "@tanstack/react-query-devtools": ^4.19.1 - "@testing-library/react": ~16.0.0 + "@testing-library/react": ~16.0.1 "@testing-library/user-event": ~14.5.2 - "@types/adm-zip": ^0.5.3 + "@types/adm-zip": ^0.5.5 "@types/archiver": ^5.3.4 - "@types/bad-words": ^3.0.2 - "@types/bcrypt": ^5.0.1 - "@types/body-parser": ^1.19.4 - "@types/busboy": ^1.5.2 - "@types/chai": ~4.3.16 - "@types/chai-as-promised": ^7.1.7 - "@types/chai-datetime": 0.0.38 - "@types/chai-dom": 1.11.2 - "@types/chai-spies": ~1.0.5 - "@types/codemirror": ^5.60.12 - "@types/cookie": ^0.5.3 - "@types/cookie-parser": ^1.4.5 - "@types/cors": ^2.8.15 - "@types/cssom": ^0.4.2 + "@types/bad-words": ^3.0.3 + "@types/bcrypt": ^5.0.2 + "@types/body-parser": ^1.19.5 + "@types/busboy": ^1.5.4 + "@types/chai": ~4.3.19 + "@types/chai-as-promised": ^7.1.8 + "@types/chai-datetime": 0.0.39 + "@types/chai-dom": 1.11.3 + "@types/chai-spies": ~1.0.6 + "@types/codemirror": ^5.60.15 + "@types/cookie": ^0.5.4 + "@types/cookie-parser": ^1.4.7 + "@types/cors": ^2.8.17 + "@types/cssom": ^0.4.3 "@types/dompurify": ^2.3.3 - "@types/ejson": ^2.2.1 - "@types/express": ^4.17.20 + "@types/ejson": ^2.2.2 + "@types/express": ^4.17.21 "@types/express-rate-limit": ^5.1.3 - "@types/fibers": ^3.1.3 - "@types/google-libphonenumber": ^7.4.29 - "@types/gravatar": ^1.8.5 + "@types/fibers": ^3.1.4 + "@types/google-libphonenumber": ^7.4.30 + "@types/gravatar": ^1.8.6 "@types/he": ^1.1.2 - "@types/i18next-sprintf-postprocessor": ^0.2.2 - "@types/imap": ^0.8.39 - "@types/jest": ~29.5.12 + "@types/i18next-sprintf-postprocessor": ^0.2.3 + "@types/imap": ^0.8.40 + "@types/jest": ~29.5.13 "@types/jsdom": ^16.2.15 - "@types/jsdom-global": ^3.0.6 - "@types/jsrsasign": ^10.5.11 + "@types/jsdom-global": ^3.0.7 + "@types/jsrsasign": ^10.5.14 "@types/katex": ^0.14.0 - "@types/later": ^1.2.8 + "@types/later": ^1.2.9 "@types/ldapjs": ^2.2.5 - "@types/less": ~3.0.5 + "@types/less": ~3.0.6 "@types/lodash": ^4.14.200 "@types/lodash.clonedeep": ^4.5.9 - "@types/lodash.debounce": ^4.0.8 - "@types/lodash.get": ^4.4.8 - "@types/mailparser": ^3.4.3 + "@types/lodash.debounce": ^4.0.9 + "@types/lodash.get": ^4.4.9 + "@types/mailparser": ^3.4.4 "@types/marked": ^4.0.8 "@types/meteor": ^2.9.8 - "@types/meteor-collection-hooks": ^0.8.8 + "@types/meteor-collection-hooks": ^0.8.9 "@types/mkdirp": ^1.0.2 "@types/mocha": "github:whitecolor/mocha-types" "@types/moment-timezone": ^0.5.30 "@types/node": ^14.18.63 - "@types/node-gcm": ^1.0.3 - "@types/node-rsa": ^1.1.3 - "@types/nodemailer": ^6.4.13 - "@types/oauth2-server": ^3.0.15 - "@types/object-path": ^0.11.3 - "@types/parseurl": ^1.3.2 - "@types/prometheus-gc-stats": ^0.6.3 - "@types/proxy-from-env": ^1.0.3 - "@types/proxyquire": ^1.3.30 - "@types/psl": ^1.1.2 - "@types/react": ~17.0.69 - "@types/react-dom": ~17.0.22 - "@types/rewire": ^2.5.29 + "@types/node-gcm": ^1.0.5 + "@types/node-rsa": ^1.1.4 + "@types/nodemailer": ^6.4.15 + "@types/oauth2-server": ^3.0.17 + "@types/object-path": ^0.11.4 + "@types/parseurl": ^1.3.3 + "@types/prometheus-gc-stats": ^0.6.4 + "@types/proxy-from-env": ^1.0.4 + "@types/proxyquire": ^1.3.31 + "@types/psl": ^1.1.3 + "@types/react": ~17.0.80 + "@types/react-dom": ~17.0.25 + "@types/rewire": ^2.5.30 "@types/sanitize-html": ^2.9.3 "@types/semver": ^7.3.10 "@types/sharp": ^0.30.5 "@types/sinon": ^10.0.20 - "@types/speakeasy": ^2.0.9 - "@types/strict-uri-encode": ^2.0.1 + "@types/speakeasy": ^2.0.10 + "@types/strict-uri-encode": ^2.0.2 "@types/string-strip-html": ^5.0.1 - "@types/supertest": ^2.0.15 - "@types/supports-color": ~7.2.0 - "@types/textarea-caret": ^3.0.2 - "@types/ua-parser-js": ^0.7.38 - "@types/use-subscription": ^1.0.1 - "@types/use-sync-external-store": ^0.0.5 + "@types/supertest": ^2.0.16 + "@types/supports-color": ~7.2.1 + "@types/textarea-caret": ^3.0.3 + "@types/ua-parser-js": ^0.7.39 + "@types/use-subscription": ^1.0.2 + "@types/use-sync-external-store": ^0.0.6 "@types/uuid": ^8.3.4 - "@types/xml-crypto": ~1.4.4 - "@types/xml-encryption": ~1.2.3 + "@types/xml-crypto": ~1.4.6 + "@types/xml-encryption": ~1.2.4 "@typescript-eslint/eslint-plugin": ~5.60.1 "@typescript-eslint/parser": ~5.60.1 "@xmldom/xmldom": ^0.8.10 - adm-zip: 0.5.10 + adm-zip: 0.5.16 ajv: ^8.11.0 ajv-formats: ~2.1.1 apn: 2.2.0 @@ -9509,19 +9525,19 @@ __metadata: babel-plugin-istanbul: ^6.1.1 bad-words: ^3.0.4 bcrypt: ^5.0.1 - body-parser: 1.20.2 + body-parser: 1.20.3 bson: ^4.6.4 busboy: ^1.6.0 bytebuffer: 5.0.1 chai: ^4.3.10 - chai-as-promised: ^7.1.1 - chai-datetime: ^1.8.0 + chai-as-promised: ^7.1.2 + chai-datetime: ^1.8.1 chai-dom: ^1.11.0 chai-spies: ~1.0.0 chalk: ^4.0.0 change-case: ^4.1.2 chart.js: ^3.8.0 - codemirror: ^5.65.15 + codemirror: ^5.65.17 colorette: ^2.0.20 colors: ^1.4.0 connect: ^3.7.0 @@ -9530,12 +9546,12 @@ __metadata: cors: ^2.8.5 cron: ~1.8.2 cross-env: ^7.0.3 - css-vars-ponyfill: ^2.4.8 + css-vars-ponyfill: ^2.4.9 csv-parse: ^5.2.0 date-fns: ^2.28.0 date.js: ~0.3.3 debug: ~4.1.1 - docker-compose: ^0.24.3 + docker-compose: ^0.24.8 dompurify: ^2.3.8 ejson: ^2.2.3 emailreplyparser: ^0.0.5 @@ -9550,7 +9566,7 @@ __metadata: eslint-plugin-playwright: ~0.15.3 eslint-plugin-prettier: ~4.2.1 eslint-plugin-react: ~7.32.2 - eslint-plugin-react-hooks: ~4.6.0 + eslint-plugin-react-hooks: ~4.6.2 eslint-plugin-testing-library: ~6.2.2 eslint-plugin-you-dont-need-lodash-underscore: ~6.12.0 eventemitter3: ^4.0.7 @@ -9565,7 +9581,7 @@ __metadata: filenamify: ^4.3.0 filesize: 9.0.11 generate-password: ^1.7.1 - google-libphonenumber: ^3.2.33 + google-libphonenumber: ^3.2.38 gravatar: ^1.8.2 he: ^1.2.0 highlight.js: ^11.6.0 @@ -9587,7 +9603,7 @@ __metadata: jsdom-global: ^3.0.2 jsrsasign: ^10.5.24 juice: ^8.0.0 - katex: ~0.16.9 + katex: ~0.16.11 ldap-escape: ^2.0.6 ldapjs: ^2.3.3 limax: ^3.0.0 @@ -9598,14 +9614,14 @@ __metadata: mailparser: ^3.4.0 marked: ^4.2.5 mem: ^8.1.1 - meteor-node-stubs: ^1.2.5 + meteor-node-stubs: ^1.2.10 mime-db: ^1.52.0 mime-type: ^4.0.0 mkdirp: ^1.0.4 mocha: ^9.2.2 - moleculer: ^0.14.31 + moleculer: ^0.14.34 moment: ^2.29.4 - moment-timezone: ^0.5.43 + moment-timezone: ^0.5.45 mongo-message-queue: ^1.0.0 mongodb: ^4.17.2 nats: ^2.6.1 @@ -9624,8 +9640,8 @@ __metadata: pdfjs-dist: ^2.13.216 pino: ^8.15.0 pino-pretty: ^7.6.1 - playwright-qase-reporter: ^1.2.1 - postcss: ~8.4.31 + playwright-qase-reporter: ^1.2.2 + postcss: ~8.4.45 postcss-custom-properties: ^11.0.0 postcss-easy-import: ^3.0.0 postcss-load-config: ^3.1.4 @@ -9642,10 +9658,10 @@ __metadata: query-string: ^7.1.3 queue-fifo: ^0.2.6 rc-scrollbars: ^1.1.6 - re-resizable: ^6.9.9 + re-resizable: ^6.9.18 react: ~17.0.2 react-aria: ~3.23.1 - react-docgen-typescript-plugin: ^1.0.5 + react-docgen-typescript-plugin: ^1.0.8 react-dom: ~17.0.2 react-error-boundary: ^3.1.4 react-hook-form: ~7.45.4 @@ -9663,7 +9679,7 @@ __metadata: sodium-plus: ^0.9.0 source-map: ^0.7.4 speakeasy: ^2.0.0 - stream-buffers: ^3.0.2 + stream-buffers: ^3.0.3 strict-uri-encode: ^2.0.0 string-strip-html: ^7.0.3 stylelint: ^14.9.1 @@ -9676,21 +9692,21 @@ __metadata: template-file: ^6.0.1 textarea-caret: ^3.1.0 tinykeys: ^1.4.0 - ts-node: ^10.9.1 + ts-node: ^10.9.2 turndown: ^7.1.2 twilio: ^3.76.1 twit: ^2.2.11 typescript: ~5.5.4 typia: ~6.9.0 - ua-parser-js: ^1.0.37 - underscore: ^1.13.6 + ua-parser-js: ^1.0.38 + underscore: ^1.13.7 universal-perf-hooks: ^1.0.1 url-polyfill: ^1.1.12 use-subscription: ~1.6.0 - use-sync-external-store: ^1.2.0 + use-sync-external-store: ^1.2.2 uuid: ^8.3.2 vm2: ^3.9.19 - webdav: ^4.11.3 + webdav: ^4.11.4 xml-crypto: ~3.1.0 xml-encryption: ~3.0.2 xml2js: ~0.5.0 @@ -9708,7 +9724,7 @@ __metadata: "@rocket.chat/ui-contexts": "workspace:*" "@storybook/react": ~6.5.16 "@tanstack/react-query": ^4.16.1 - "@types/use-sync-external-store": ^0.0.5 + "@types/use-sync-external-store": ^0.0.6 eslint: ~8.45.0 i18next: ~23.14.0 react: ~17.0.2 @@ -9726,7 +9742,7 @@ __metadata: resolution: "@rocket.chat/model-typings@workspace:packages/model-typings" dependencies: "@rocket.chat/core-typings": "workspace:^" - "@types/node-rsa": ^1.1.3 + "@types/node-rsa": ^1.1.4 eslint: ~8.45.0 mongodb: ^4.17.2 typescript: ~5.5.4 @@ -9739,7 +9755,7 @@ __metadata: dependencies: "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/model-typings": "workspace:~" - "@types/jest": ~29.5.12 + "@types/jest": ~29.5.13 eslint: ~8.45.0 jest: ^29.7.0 typescript: ~5.5.4 @@ -9771,7 +9787,7 @@ __metadata: "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 "@rocket.chat/tools": "workspace:^" - "@types/jest": ~29.5.12 + "@types/jest": ~29.5.13 "@types/node": ^14.18.63 date-fns: ^2.28.0 ejson: ^2.2.3 @@ -9781,7 +9797,7 @@ __metadata: fibers: ^5.0.3 jest: ~29.7.0 mem: ^8.1.1 - moment-timezone: ^0.5.43 + moment-timezone: ^0.5.45 mongo-message-queue: ^1.0.0 mongodb: ^4.17.2 pino: ^8.15.0 @@ -9804,25 +9820,25 @@ __metadata: "@rocket.chat/omnichannel-services": "workspace:^" "@rocket.chat/pdf-worker": "workspace:^" "@rocket.chat/tools": "workspace:^" - "@types/gc-stats": ^1.4.2 + "@types/gc-stats": ^1.4.3 "@types/node": ^14.18.63 - "@types/polka": ^0.5.6 + "@types/polka": ^0.5.7 ejson: ^2.2.3 emoji-toolkit: ^7.0.1 eslint: ~8.45.0 event-loop-stats: ^1.4.1 eventemitter3: ^4.0.7 fibers: ^5.0.3 - gc-stats: ^1.4.0 + gc-stats: ^1.4.1 mem: ^8.1.1 - moleculer: ^0.14.31 - moment-timezone: ^0.5.43 + moleculer: ^0.14.34 + moment-timezone: ^0.5.45 mongo-message-queue: ^1.0.0 mongodb: ^4.17.2 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 - ts-node: ^10.9.1 + ts-node: ^10.9.2 typescript: ~5.5.4 languageName: unknown linkType: soft @@ -9853,7 +9869,7 @@ __metadata: resolution: "@rocket.chat/password-policies@workspace:packages/password-policies" dependencies: "@rocket.chat/jest-presets": "workspace:~" - "@types/jest": ~29.5.12 + "@types/jest": ~29.5.13 eslint: ~8.45.0 jest: ~29.7.0 typescript: ~5.5.4 @@ -9865,7 +9881,7 @@ __metadata: resolution: "@rocket.chat/patch-injection@workspace:packages/patch-injection" dependencies: "@rocket.chat/jest-presets": "workspace:~" - "@types/jest": ~29.5.12 + "@types/jest": ~29.5.13 eslint: ~8.45.0 jest: ~29.7.0 typescript: ~5.5.4 @@ -9882,17 +9898,17 @@ __metadata: "@rocket.chat/jest-presets": "workspace:~" "@storybook/addon-essentials": ~6.5.16 "@storybook/react": ~6.5.16 - "@testing-library/react": ~16.0.0 - "@types/emojione": ^2.2.8 - "@types/jest": ~29.5.12 - "@types/react": ~17.0.69 - "@types/react-dom": ~17.0.22 + "@testing-library/react": ~16.0.1 + "@types/emojione": ^2.2.9 + "@types/jest": ~29.5.13 + "@types/react": ~17.0.80 + "@types/react-dom": ~17.0.25 emoji-assets: ^7.0.1 emoji-toolkit: ^7.0.1 eslint: ~8.45.0 jest: ~29.7.0 moment: ^2.29.4 - moment-timezone: ^0.5.43 + moment-timezone: ^0.5.45 react: ~18.3.1 react-dom: ~18.3.1 typescript: ~5.5.4 @@ -9905,11 +9921,11 @@ __metadata: dependencies: "@rocket.chat/eslint-config": "workspace:~" "@rocket.chat/prettier-config": ~0.31.25 - "@types/node": ~14.18.42 + "@types/node": ~14.18.63 eslint: ~8.45.0 npm-run-all: ^4.1.5 peggy: 3.0.2 - prettier: ~2.8.7 + prettier: ~2.8.8 rimraf: ^3.0.2 typescript: ~5.5.4 webpack: ~5.78.0 @@ -9940,22 +9956,22 @@ __metadata: "@rocket.chat/models": "workspace:^" "@rocket.chat/presence": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 - "@types/gc-stats": ^1.4.2 + "@types/gc-stats": ^1.4.3 "@types/node": ^14.18.63 - "@types/polka": ^0.5.6 + "@types/polka": ^0.5.7 ejson: ^2.2.3 eslint: ~8.45.0 event-loop-stats: ^1.4.1 eventemitter3: ^4.0.7 fibers: ^5.0.3 - gc-stats: ^1.4.0 + gc-stats: ^1.4.1 mem: ^8.1.1 - moleculer: ^0.14.31 + moleculer: ^0.14.34 mongodb: ^4.17.2 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 - ts-node: ^10.9.1 + ts-node: ^10.9.2 typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10004,25 +10020,25 @@ __metadata: "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" "@rocket.chat/omnichannel-services": "workspace:^" - "@types/gc-stats": ^1.4.2 + "@types/gc-stats": ^1.4.3 "@types/node": ^14.18.63 - "@types/polka": ^0.5.6 + "@types/polka": ^0.5.7 ejson: ^2.2.3 emoji-toolkit: ^7.0.1 eslint: ~8.45.0 event-loop-stats: ^1.4.1 eventemitter3: ^4.0.7 fibers: ^5.0.3 - gc-stats: ^1.4.0 + gc-stats: ^1.4.1 mem: ^8.1.1 - moleculer: ^0.14.31 - moment-timezone: ^0.5.43 + moleculer: ^0.14.34 + moment-timezone: ^0.5.45 mongo-message-queue: ^1.0.0 mongodb: ^4.17.2 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 - ts-node: ^10.9.1 + ts-node: ^10.9.2 typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10052,7 +10068,7 @@ __metadata: "@actions/github": ^5.1.1 "@octokit/plugin-throttling": ^6.0.0 "@rocket.chat/eslint-config": "workspace:^" - "@types/node": ^16.18.60 + "@types/node": ^16.18.108 eslint: ~8.45.0 mdast-util-to-string: 2.0.0 remark-parse: 9.0.0 @@ -10072,7 +10088,7 @@ __metadata: "@types/node": ^14.18.63 dataloader: ^1.4.0 eslint: ~8.45.0 - node-fetch: ^2 + node-fetch: ^2.7.0 typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10086,7 +10102,7 @@ __metadata: "@rocket.chat/eslint-config": "workspace:~" "@rocket.chat/message-parser": "workspace:^" "@rocket.chat/ui-kit": "workspace:~" - "@types/jest": ~29.5.12 + "@types/jest": ~29.5.13 ajv: ^8.11.0 ajv-formats: ^2.1.1 eslint: ~8.45.0 @@ -10123,7 +10139,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/server-fetch@workspace:packages/server-fetch" dependencies: - "@types/proxy-from-env": ^1.0.3 + "@types/proxy-from-env": ^1.0.4 eslint: ~8.45.0 http-proxy-agent: ^5.0.0 https-proxy-agent: ^5.0.1 @@ -10162,23 +10178,23 @@ __metadata: "@rocket.chat/models": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 - "@types/bcrypt": ^5.0.1 - "@types/gc-stats": ^1.4.2 + "@types/bcrypt": ^5.0.2 + "@types/gc-stats": ^1.4.3 "@types/node": ^14.18.63 - "@types/polka": ^0.5.6 + "@types/polka": ^0.5.7 ejson: ^2.2.3 eslint: ~8.45.0 event-loop-stats: ^1.4.1 eventemitter3: ^4.0.7 fibers: ^5.0.3 - gc-stats: ^1.4.0 + gc-stats: ^1.4.1 mem: ^8.1.1 - moleculer: ^0.14.31 + moleculer: ^0.14.34 mongodb: ^4.17.2 nats: ^2.4.0 pino: ^8.15.0 polka: ^0.5.2 - ts-node: ^10.9.1 + ts-node: ^10.9.2 typescript: ~5.5.4 languageName: unknown linkType: soft @@ -10215,27 +10231,26 @@ __metadata: resolution: "@rocket.chat/tools@workspace:packages/tools" dependencies: "@rocket.chat/jest-presets": "workspace:~" - "@types/jest": ~29.5.12 + "@types/jest": ~29.5.13 eslint: ~8.45.0 jest: ~29.7.0 - moment-timezone: ^0.5.43 + moment-timezone: ^0.5.45 typescript: ~5.5.4 languageName: unknown linkType: soft -"@rocket.chat/ui-avatar@workspace:^, @rocket.chat/ui-avatar@workspace:packages/ui-avatar": +"@rocket.chat/ui-avatar@workspace:^, @rocket.chat/ui-avatar@workspace:packages/ui-avatar, @rocket.chat/ui-avatar@workspace:~": version: 0.0.0-use.local resolution: "@rocket.chat/ui-avatar@workspace:packages/ui-avatar" dependencies: "@babel/core": ~7.22.20 "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/ui-contexts": "workspace:^" - "@types/babel__core": ~7.20.3 - "@types/react": ~17.0.69 - "@types/react-dom": ~17.0.22 + "@types/react": ~17.0.80 + "@types/react-dom": ~17.0.25 eslint: ~8.45.0 eslint-plugin-react: ~7.32.2 - eslint-plugin-react-hooks: ~4.6.0 + eslint-plugin-react-hooks: ~4.6.2 eslint-plugin-storybook: ~0.6.15 eslint-plugin-testing-library: ~5.11.1 react: ^17.0.2 @@ -10259,6 +10274,7 @@ __metadata: "@rocket.chat/icons": ~0.38.0 "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/mock-providers": "workspace:^" + "@rocket.chat/ui-avatar": "workspace:~" "@rocket.chat/ui-contexts": "workspace:~" "@storybook/addon-actions": ~6.5.16 "@storybook/addon-docs": ~6.5.16 @@ -10270,15 +10286,14 @@ __metadata: "@storybook/manager-webpack4": ~6.5.16 "@storybook/react": ~6.5.16 "@storybook/testing-library": ~0.0.13 - "@testing-library/react": ~16.0.0 - "@types/babel__core": ~7.20.3 - "@types/jest": ~29.5.12 - "@types/react": ~17.0.69 - "@types/react-dom": ~17.0.22 + "@testing-library/react": ~16.0.1 + "@types/jest": ~29.5.13 + "@types/react": ~17.0.80 + "@types/react-dom": ~17.0.25 eslint: ~8.45.0 eslint-plugin-anti-trojan-source: ~1.1.1 eslint-plugin-react: ~7.32.2 - eslint-plugin-react-hooks: ~4.6.0 + eslint-plugin-react-hooks: ~4.6.2 eslint-plugin-storybook: ~0.6.15 eslint-plugin-testing-library: ~5.11.1 jest: ~29.7.0 @@ -10293,6 +10308,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" + "@rocket.chat/ui-avatar": "*" "@rocket.chat/ui-contexts": "*" react: "*" react-i18next: "*" @@ -10315,15 +10331,14 @@ __metadata: "@storybook/manager-webpack4": ~6.5.16 "@storybook/react": ~6.5.16 "@storybook/testing-library": ~0.0.13 - "@types/babel__core": ~7.20.3 - "@types/react": ~17.0.69 - "@types/react-dom": ~17.0.22 + "@types/react": ~17.0.80 + "@types/react-dom": ~17.0.25 eslint: ~8.45.0 eslint-plugin-react: ~7.32.2 - eslint-plugin-react-hooks: ~4.6.0 + eslint-plugin-react-hooks: ~4.6.2 eslint-plugin-storybook: ~0.6.15 react: ~17.0.2 - react-docgen-typescript-plugin: ~1.0.5 + react-docgen-typescript-plugin: ~1.0.8 react-dom: ~17.0.2 typescript: ~5.5.4 peerDependencies: @@ -10346,15 +10361,15 @@ __metadata: "@rocket.chat/i18n": "workspace:~" "@rocket.chat/password-policies": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" - "@types/react": ~17.0.69 - "@types/react-dom": ~17.0.22 - "@types/use-sync-external-store": ^0.0.5 + "@types/react": ~17.0.80 + "@types/react-dom": ~17.0.25 + "@types/use-sync-external-store": ^0.0.6 eslint: ~8.45.0 - eslint-plugin-react-hooks: ^4.6.0 + eslint-plugin-react-hooks: ^4.6.2 mongodb: ^4.17.2 react: ~17.0.2 typescript: ~5.5.4 - use-sync-external-store: ^1.2.0 + use-sync-external-store: ^1.2.2 peerDependencies: "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/ddp-client": "workspace:^" @@ -10371,23 +10386,23 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/ui-kit@workspace:packages/ui-kit" dependencies: - "@babel/core": ~7.21.4 - "@babel/eslint-parser": ~7.23.3 + "@babel/core": ~7.21.8 + "@babel/eslint-parser": ~7.23.10 "@babel/plugin-transform-runtime": ~7.21.4 - "@babel/preset-env": ~7.21.4 + "@babel/preset-env": ~7.21.5 "@rocket.chat/eslint-config": "workspace:~" "@rocket.chat/icons": ~0.38.0 "@rocket.chat/jest-presets": "workspace:~" - "@types/jest": ~29.5.12 - babel-loader: ~9.1.2 + "@types/jest": ~29.5.13 + babel-loader: ~9.1.3 eslint: ~8.45.0 jest: ~29.7.0 npm-run-all: ~4.1.5 prettier: ~2.8.8 rimraf: ~3.0.2 - ts-jest: ~29.1.1 - ts-loader: ~9.4.2 - ts-node: ~10.9.1 + ts-jest: ~29.1.5 + ts-loader: ~9.4.4 + ts-node: ~10.9.2 ts-patch: ~3.2.1 typescript: ~5.5.4 typia: ~6.9.0 @@ -10405,14 +10420,14 @@ __metadata: "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/ui-contexts": "workspace:~" - "@types/react": ~17.0.69 + "@types/react": ~17.0.80 eslint: ~8.45.0 eslint-plugin-anti-trojan-source: ~1.1.1 eslint-plugin-react: ~7.32.2 - eslint-plugin-react-hooks: ~4.6.0 + eslint-plugin-react-hooks: ~4.6.2 eslint-plugin-testing-library: ^5.11.1 react: ~17.0.2 - react-docgen-typescript-plugin: ~1.0.5 + react-docgen-typescript-plugin: ~1.0.8 typescript: ~5.5.4 peerDependencies: "@rocket.chat/css-in-js": "*" @@ -10447,16 +10462,15 @@ __metadata: "@storybook/react": ~6.5.16 "@storybook/testing-library": ~0.0.13 "@storybook/testing-react": ~1.3.0 - "@types/babel__core": ~7.20.3 - "@types/jest": ~29.5.12 + "@types/jest": ~29.5.13 "@types/jest-axe": ~3.5.9 eslint: ~8.45.0 eslint-plugin-react: ~7.32.2 - eslint-plugin-react-hooks: ~4.6.0 + eslint-plugin-react-hooks: ~4.6.2 eslint-plugin-storybook: ~0.6.15 jest: ~29.7.0 jest-axe: ~9.0.0 - react-docgen-typescript-plugin: ~1.0.5 + react-docgen-typescript-plugin: ~1.0.8 typescript: ~5.5.4 peerDependencies: "@rocket.chat/css-in-js": "*" @@ -10491,17 +10505,17 @@ __metadata: "@rocket.chat/styled": ~0.31.25 "@rocket.chat/ui-avatar": "workspace:^" "@rocket.chat/ui-contexts": "workspace:~" - "@types/react": ~17.0.69 - "@types/react-beautiful-dnd": ^13.1.6 - "@types/react-dom": ~17.0.22 - "@types/use-subscription": ^1.0.1 + "@types/react": ~17.0.80 + "@types/react-beautiful-dnd": ^13.1.8 + "@types/react-dom": ~17.0.25 + "@types/use-subscription": ^1.0.2 "@typescript-eslint/eslint-plugin": ~5.60.1 "@typescript-eslint/parser": ~5.60.1 "@vitejs/plugin-react": ^4.0.0 codemirror: ^6.0.1 eslint: ~8.45.0 - eslint-plugin-react-hooks: ^4.6.0 - eslint-plugin-react-refresh: ^0.4.4 + eslint-plugin-react-hooks: ^4.6.2 + eslint-plugin-react-refresh: ^0.4.11 eslint4b-prebuilt: ^6.7.2 moment: ^2.29.4 rc-scrollbars: ^1.1.6 @@ -10513,7 +10527,7 @@ __metadata: react-virtuoso: ^4.7.1 reactflow: ^11.7.2 typescript: ~5.5.4 - use-subscription: ^1.8.0 + use-subscription: ^1.8.2 vite: ^4.3.9 languageName: unknown linkType: soft @@ -10527,7 +10541,7 @@ __metadata: "@babel/preset-react": ~7.22.15 "@babel/preset-typescript": ~7.22.15 "@rocket.chat/i18n": "workspace:~" - "@rocket.chat/layout": ~0.31.26 + "@rocket.chat/layout": ~0.31.27 "@rocket.chat/mock-providers": "workspace:~" "@rocket.chat/tools": "workspace:~" "@rocket.chat/ui-client": "workspace:^" @@ -10540,14 +10554,14 @@ __metadata: "@storybook/react": ~6.5.16 "@storybook/testing-library": ^0.2.2 "@tanstack/react-query": ^4.16.1 - "@testing-library/react": ~16.0.0 - "@types/react": ~17.0.69 + "@testing-library/react": ~16.0.1 + "@types/react": ~17.0.80 babel-loader: ~8.3.0 eslint: ~8.45.0 react: ~17.0.2 react-hook-form: ~7.45.4 react-i18next: ~15.0.1 - storybook-dark-mode: ~3.0.1 + storybook-dark-mode: ~3.0.3 typescript: ~5.5.4 peerDependencies: "@rocket.chat/layout": "*" @@ -11278,24 +11292,6 @@ __metadata: languageName: node linkType: hard -"@storybook/api@npm:^7.0.0": - version: 7.3.2 - resolution: "@storybook/api@npm:7.3.2" - dependencies: - "@storybook/client-logger": 7.3.2 - "@storybook/manager-api": 7.3.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: dfe5f976256fc74c82548ca35f7052b82ca87a21d44e8554c0913ecc8f5d0e0d317a57b0308057473c3b8efa95428590d4350c9c4d1ef7f7c02ee8c7c2d2e8ee - languageName: node - linkType: hard - "@storybook/builder-webpack4@npm:6.5.16, @storybook/builder-webpack4@npm:~6.5.16": version: 6.5.16 resolution: "@storybook/builder-webpack4@npm:6.5.16" @@ -11462,6 +11458,20 @@ __metadata: languageName: node linkType: hard +"@storybook/channels@npm:7.6.20": + version: 7.6.20 + resolution: "@storybook/channels@npm:7.6.20" + dependencies: + "@storybook/client-logger": 7.6.20 + "@storybook/core-events": 7.6.20 + "@storybook/global": ^5.0.0 + qs: ^6.10.0 + telejson: ^7.2.0 + tiny-invariant: ^1.3.1 + checksum: e600949b77b8ae2c865eab8e2f4022893843932c76f9f49f2ef6d8a8f62114f979d38fe93fed2d8899fa892bb1dcd353c81e292515a7bd8fbc944629939574b0 + languageName: node + linkType: hard + "@storybook/client-api@npm:6.5.16": version: 6.5.16 resolution: "@storybook/client-api@npm:6.5.16" @@ -11512,6 +11522,15 @@ __metadata: languageName: node linkType: hard +"@storybook/client-logger@npm:7.6.20": + version: 7.6.20 + resolution: "@storybook/client-logger@npm:7.6.20" + dependencies: + "@storybook/global": ^5.0.0 + checksum: 98bf603df918a74bc5b34f344ba70356d8e2b889d8a5cbfb7a03c23dcf409029800319e5d3e0ff7e95545a2d4a989a53c2097eb7a36de808d287d466d4d92573 + languageName: node + linkType: hard + "@storybook/components@npm:6.5.16": version: 6.5.16 resolution: "@storybook/components@npm:6.5.16" @@ -11668,6 +11687,15 @@ __metadata: languageName: node linkType: hard +"@storybook/core-events@npm:7.6.20": + version: 7.6.20 + resolution: "@storybook/core-events@npm:7.6.20" + dependencies: + ts-dedent: ^2.0.0 + checksum: 284f4df326200dc0bdfc74472dccab3bbed38cf8515baebe467830b562f9ace06fb6e5640b155b4ae462288b9f3257233c6b5212fcb9b2d3024f9e4d08d28457 + languageName: node + linkType: hard + "@storybook/core-server@npm:6.5.16": version: 6.5.16 resolution: "@storybook/core-server@npm:6.5.16" @@ -11815,6 +11843,15 @@ __metadata: languageName: node linkType: hard +"@storybook/csf@npm:^0.1.2": + version: 0.1.11 + resolution: "@storybook/csf@npm:0.1.11" + dependencies: + type-fest: ^2.19.0 + checksum: ba2a265f62ad82a2853b069f77e974efe31bed263a640ca1dd8e6d7e194022018a67ad4a2587ae928f33ae45aaf6ffedd5925ba3fcf3fe5b7996667a918e22eb + languageName: node + linkType: hard + "@storybook/docs-tools@npm:6.5.16": version: 6.5.16 resolution: "@storybook/docs-tools@npm:6.5.16" @@ -11886,6 +11923,28 @@ __metadata: languageName: node linkType: hard +"@storybook/manager-api@npm:^7.0.0": + version: 7.6.20 + resolution: "@storybook/manager-api@npm:7.6.20" + dependencies: + "@storybook/channels": 7.6.20 + "@storybook/client-logger": 7.6.20 + "@storybook/core-events": 7.6.20 + "@storybook/csf": ^0.1.2 + "@storybook/global": ^5.0.0 + "@storybook/router": 7.6.20 + "@storybook/theming": 7.6.20 + "@storybook/types": 7.6.20 + dequal: ^2.0.2 + lodash: ^4.17.21 + memoizerific: ^1.11.3 + store2: ^2.14.2 + telejson: ^7.2.0 + ts-dedent: ^2.0.0 + checksum: 01a35e757b0e673570a6868fa64b9a3a258011b6c16afe6e0164ae8406896eeaf53d9a069db6862cbd4b10b64546f0c78ed96872c036a02869b2f530603e9dec + languageName: node + linkType: hard + "@storybook/manager-webpack4@npm:6.5.16, @storybook/manager-webpack4@npm:~6.5.16": version: 6.5.16 resolution: "@storybook/manager-webpack4@npm:6.5.16" @@ -12233,6 +12292,17 @@ __metadata: languageName: node linkType: hard +"@storybook/router@npm:7.6.20": + version: 7.6.20 + resolution: "@storybook/router@npm:7.6.20" + dependencies: + "@storybook/client-logger": 7.6.20 + memoizerific: ^1.11.3 + qs: ^6.10.0 + checksum: 67af15f4144e674dcd957fc8ae2ed6e7cbd3845c8fb1343760ec67bebf04eeb54b7088db701208c976026641373dc2287f6908dbc7e3d96da9a1c910054ba942 + languageName: node + linkType: hard + "@storybook/semver@npm:^7.3.2": version: 7.3.2 resolution: "@storybook/semver@npm:7.3.2" @@ -12381,6 +12451,21 @@ __metadata: languageName: node linkType: hard +"@storybook/theming@npm:7.6.20": + version: 7.6.20 + resolution: "@storybook/theming@npm:7.6.20" + dependencies: + "@emotion/use-insertion-effect-with-fallbacks": ^1.0.0 + "@storybook/client-logger": 7.6.20 + "@storybook/global": ^5.0.0 + memoizerific: ^1.11.3 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 2c3cbac759d300fb471acf4e01514f7728c48533c6e24c37b0351d9f0fcc9240dbdcf50067a81c3ff73b27a1da4227debb55a48ab2920368099871d1f49252ea + languageName: node + linkType: hard + "@storybook/types@npm:7.3.2": version: 7.3.2 resolution: "@storybook/types@npm:7.3.2" @@ -12393,6 +12478,18 @@ __metadata: languageName: node linkType: hard +"@storybook/types@npm:7.6.20": + version: 7.6.20 + resolution: "@storybook/types@npm:7.6.20" + dependencies: + "@storybook/channels": 7.6.20 + "@types/babel__core": ^7.0.0 + "@types/express": ^4.7.0 + file-system-cache: 2.3.0 + checksum: 1e0ae196c63ace6a9a0f06a42c7294cfc840665d1ff7ae6d9fd2466ed3d78387672951aa7a9064a719384938c57d8eb25c8089657710d95c546344fbc28d8df6 + languageName: node + linkType: hard + "@storybook/ui@npm:6.5.16": version: 6.5.16 resolution: "@storybook/ui@npm:6.5.16" @@ -12418,90 +12515,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-darwin-arm64@npm:1.7.23" +"@swc/core-darwin-arm64@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-darwin-arm64@npm:1.7.26" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-darwin-x64@npm:1.7.23" +"@swc/core-darwin-x64@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-darwin-x64@npm:1.7.26" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.7.23" +"@swc/core-linux-arm-gnueabihf@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.7.26" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-linux-arm64-gnu@npm:1.7.23" +"@swc/core-linux-arm64-gnu@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-linux-arm64-gnu@npm:1.7.26" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-linux-arm64-musl@npm:1.7.23" +"@swc/core-linux-arm64-musl@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-linux-arm64-musl@npm:1.7.26" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-linux-x64-gnu@npm:1.7.23" +"@swc/core-linux-x64-gnu@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-linux-x64-gnu@npm:1.7.26" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-linux-x64-musl@npm:1.7.23" +"@swc/core-linux-x64-musl@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-linux-x64-musl@npm:1.7.26" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-win32-arm64-msvc@npm:1.7.23" +"@swc/core-win32-arm64-msvc@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-win32-arm64-msvc@npm:1.7.26" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-win32-ia32-msvc@npm:1.7.23" +"@swc/core-win32-ia32-msvc@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-win32-ia32-msvc@npm:1.7.26" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.7.23": - version: 1.7.23 - resolution: "@swc/core-win32-x64-msvc@npm:1.7.23" +"@swc/core-win32-x64-msvc@npm:1.7.26": + version: 1.7.26 + resolution: "@swc/core-win32-x64-msvc@npm:1.7.26" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core@npm:~1.7.23": - version: 1.7.23 - resolution: "@swc/core@npm:1.7.23" +"@swc/core@npm:~1.7.26": + version: 1.7.26 + resolution: "@swc/core@npm:1.7.26" dependencies: - "@swc/core-darwin-arm64": 1.7.23 - "@swc/core-darwin-x64": 1.7.23 - "@swc/core-linux-arm-gnueabihf": 1.7.23 - "@swc/core-linux-arm64-gnu": 1.7.23 - "@swc/core-linux-arm64-musl": 1.7.23 - "@swc/core-linux-x64-gnu": 1.7.23 - "@swc/core-linux-x64-musl": 1.7.23 - "@swc/core-win32-arm64-msvc": 1.7.23 - "@swc/core-win32-ia32-msvc": 1.7.23 - "@swc/core-win32-x64-msvc": 1.7.23 + "@swc/core-darwin-arm64": 1.7.26 + "@swc/core-darwin-x64": 1.7.26 + "@swc/core-linux-arm-gnueabihf": 1.7.26 + "@swc/core-linux-arm64-gnu": 1.7.26 + "@swc/core-linux-arm64-musl": 1.7.26 + "@swc/core-linux-x64-gnu": 1.7.26 + "@swc/core-linux-x64-musl": 1.7.26 + "@swc/core-win32-arm64-msvc": 1.7.26 + "@swc/core-win32-ia32-msvc": 1.7.26 + "@swc/core-win32-x64-msvc": 1.7.26 "@swc/counter": ^0.1.3 "@swc/types": ^0.1.12 peerDependencies: @@ -12530,7 +12627,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: a21e9a67d305ad9b49b6def9f9698b374db6c15b2ded5e5cf29390221181fc6b91bfa317b53fd41d9cca989d85b79bbbca5ab27635df1e0232cad4681f618fa5 + checksum: 8249f2af001f2b5b312ccace4e3a8575bf286bb0f67f029eb58ef8b144f73e37f766800859161ef87c0993e586055238c000ab17dddf9d3760edcfa63ffd22e6 languageName: node linkType: hard @@ -12679,9 +12776,9 @@ __metadata: languageName: node linkType: hard -"@testing-library/react@npm:~16.0.0": - version: 16.0.0 - resolution: "@testing-library/react@npm:16.0.0" +"@testing-library/react@npm:~16.0.1": + version: 16.0.1 + resolution: "@testing-library/react@npm:16.0.1" dependencies: "@babel/runtime": ^7.12.5 peerDependencies: @@ -12695,7 +12792,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 45a35f0b5f34b5a7f4dcefdd3f1d202d5421692e5cc7a491c9bc71e6ed9dd5872a182b80b4dfefb4a56d9c1df35e50f6fa2917bcf657cc26b4bc0d2259df0027 + checksum: 1837db473ea018cf2b5d0cbfffb7a30d0d759e5a7f23aad431441c77bcc3d2533250cd003a61878fd908267df47404cedcb5914f12d79e413002c659652b37fd languageName: node linkType: hard @@ -12775,12 +12872,12 @@ __metadata: languageName: node linkType: hard -"@types/adm-zip@npm:^0.5.3": - version: 0.5.3 - resolution: "@types/adm-zip@npm:0.5.3" +"@types/adm-zip@npm:^0.5.5": + version: 0.5.5 + resolution: "@types/adm-zip@npm:0.5.5" dependencies: "@types/node": "*" - checksum: 995e21441cc6fe180f12ebf4e722bc6dbde0f9c765e57353018a0969a27cf15542c3f5451bfa1a82b958d5ed5e371fb3cbe55f934076dae22d8bf6a259a536bf + checksum: 808c25b8a1c2e1c594cf9b1514e7953105cf96e19e38aa7dc109ff2537bda7345b950ef1f4e54a6e824e5503e29d24b0ff6d0aa1ff9bd4afb79ef0ef2df9ebab languageName: node linkType: hard @@ -12800,7 +12897,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.20.3, @types/babel__core@npm:~7.20.3": +"@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14": version: 7.20.3 resolution: "@types/babel__core@npm:7.20.3" dependencies: @@ -12822,13 +12919,6 @@ __metadata: languageName: node linkType: hard -"@types/babel__preset-env@npm:^7.9.4": - version: 7.9.4 - resolution: "@types/babel__preset-env@npm:7.9.4" - checksum: a4580b541d4fe7bdf9ecb9695cb90827f96c75e5c807e6fcf6cbca3beeb9106019dc322b2d08de03025d57c6f3f1431d80eb3ea6d9416e90bc8ee15460efa27d - languageName: node - linkType: hard - "@types/babel__template@npm:*": version: 7.4.1 resolution: "@types/babel__template@npm:7.4.1" @@ -12848,23 +12938,23 @@ __metadata: languageName: node linkType: hard -"@types/bad-words@npm:^3.0.2": - version: 3.0.2 - resolution: "@types/bad-words@npm:3.0.2" - checksum: aa40d10364b73deb5617c0b53d5a782841ddd173e6cc68bc41d48c2c95c63ac81d23e2cabeb3d686cb7d655512353ac1866135203305b820d4c60859635ba9d3 +"@types/bad-words@npm:^3.0.3": + version: 3.0.3 + resolution: "@types/bad-words@npm:3.0.3" + checksum: 220729e6888b523477e3b1ca431b2fd01d816e9dbdd309c8a68b7a1a64ce02ed13ec44fe83bf83872f559d19b9180d4103b5f4179b7d4b1dd497306a46cb3c1d languageName: node linkType: hard -"@types/bcrypt@npm:^5.0.1": - version: 5.0.1 - resolution: "@types/bcrypt@npm:5.0.1" +"@types/bcrypt@npm:^5.0.2": + version: 5.0.2 + resolution: "@types/bcrypt@npm:5.0.2" dependencies: "@types/node": "*" - checksum: 2419ad2e7601b2c306ce2bd8bd8d911770f1abdea780efd4e61e9329b757e47c80fbd73fc52a925a371de47247ce92f04d11bdf24b8b44754ea0ba18d06d2202 + checksum: b1f97532ffe6079cb57a464f28b5b37a30bc9620f43469e1f27ab9c979c8a114be5b667e7b115a5556fd5be463b65968da9bb32573c6faf74fecf6e565d8974b languageName: node linkType: hard -"@types/body-parser@npm:*, @types/body-parser@npm:^1.19.4": +"@types/body-parser@npm:*": version: 1.19.4 resolution: "@types/body-parser@npm:1.19.4" dependencies: @@ -12874,6 +12964,16 @@ __metadata: languageName: node linkType: hard +"@types/body-parser@npm:^1.19.5": + version: 1.19.5 + resolution: "@types/body-parser@npm:1.19.5" + dependencies: + "@types/connect": "*" + "@types/node": "*" + checksum: 1e251118c4b2f61029cc43b0dc028495f2d1957fe8ee49a707fb940f86a9bd2f9754230805598278fe99958b49e9b7e66eec8ef6a50ab5c1f6b93e1ba2aaba82 + languageName: node + linkType: hard + "@types/bonjour@npm:^3.5.9": version: 3.5.10 resolution: "@types/bonjour@npm:3.5.10" @@ -12883,58 +12983,65 @@ __metadata: languageName: node linkType: hard -"@types/busboy@npm:^1.5.2": - version: 1.5.2 - resolution: "@types/busboy@npm:1.5.2" +"@types/busboy@npm:^1.5.4": + version: 1.5.4 + resolution: "@types/busboy@npm:1.5.4" dependencies: "@types/node": "*" - checksum: d2cfa334e06ce0fbeb31bdac7b4ba051b85e508f4f46d016e55488a717c626e19285f0e2fae40d0183d0f676dd162ab9216613799f83d40430e1996fba4bfb2f + checksum: 56444ed1223d5c8f6340128561c25bf7d6567494f507d386241de2ed6e22f9a69de7f536d71502c2f0897f81be7e8253455522ddd791db7e3eb769db7eae9e92 languageName: node linkType: hard -"@types/chai-as-promised@npm:^7.1.7": - version: 7.1.7 - resolution: "@types/chai-as-promised@npm:7.1.7" +"@types/chai-as-promised@npm:^7.1.8": + version: 7.1.8 + resolution: "@types/chai-as-promised@npm:7.1.8" dependencies: "@types/chai": "*" - checksum: 59199afbd91289588648e263d7f32f7d72fa9c0075f3c17b1e760e10fdc1a310c2170a392b0d17d96cfff2c51daca72839eed6d80142f9230c9784b8e08ba676 + checksum: f0e5eab451b91bc1e289ed89519faf6591932e8a28d2ec9bbe95826eb73d28fe43713633e0c18706f3baa560a7d97e7c7c20dc53ce639e5d75bac46b2a50bf21 languageName: node linkType: hard -"@types/chai-datetime@npm:0.0.38": - version: 0.0.38 - resolution: "@types/chai-datetime@npm:0.0.38" +"@types/chai-datetime@npm:0.0.39": + version: 0.0.39 + resolution: "@types/chai-datetime@npm:0.0.39" dependencies: "@types/chai": "*" - checksum: 2c0269e91a282ef71fe5603a94b6df4c3b784e3ded25f380ed91c0d91c26d08ac33da6bde903bc9bddfec4636455378c26810947a989ef87fe37078213e350ca + checksum: fc5266f839f7005b34d04d4e3f67b232ec86eb50291cf4769f4875bc81a21afd8c9a51547da71f7903e2124379019b83bfc400a1b6315c719888dedb678c760b languageName: node linkType: hard -"@types/chai-dom@npm:1.11.2": - version: 1.11.2 - resolution: "@types/chai-dom@npm:1.11.2" +"@types/chai-dom@npm:1.11.3": + version: 1.11.3 + resolution: "@types/chai-dom@npm:1.11.3" dependencies: "@types/chai": "*" - checksum: d59a90bf2b497797178d3a5bd17f242caaf6ee098563142fdc765a6c12786f94bc0a9b8e4023de37ef8c803198ce9562823651610b02c80f1e21a29f2ece80fd + checksum: 274afd91062b54fb56c95fc2c919d0d6d2f6b2c608f5849d27227a72f99d33ccf01b3fd59e3282e2c9626b8eba4e45d4266a742f61bb2ff506ddbfba0892d0c9 languageName: node linkType: hard -"@types/chai-spies@npm:~1.0.5": - version: 1.0.5 - resolution: "@types/chai-spies@npm:1.0.5" +"@types/chai-spies@npm:~1.0.6": + version: 1.0.6 + resolution: "@types/chai-spies@npm:1.0.6" dependencies: "@types/chai": "*" - checksum: d8009e0e4bf78fdce4a6824d43a2e206ddc0c07e3869f5d55ed7a7476c5623f77d0a5f444148ce7a0b9d9f47592fe3f0c6652952e6a0f514d8603cbb2e587cd4 + checksum: 2f4e1fd3ed4f317b6f445a4516612b2a40e25c86cf60ba093ce3569012d612d0fc05c96d69223221c26fad60d0f3af75f7c2bb1858e48b209e8da8f0a1d5fccd languageName: node linkType: hard -"@types/chai@npm:*, @types/chai@npm:~4.3.16": +"@types/chai@npm:*": version: 4.3.16 resolution: "@types/chai@npm:4.3.16" checksum: bb5f52d1b70534ed8b4bf74bd248add003ffe1156303802ea367331607c06b494da885ffbc2b674a66b4f90c9ee88759790a5f243879f6759f124f22328f5e95 languageName: node linkType: hard +"@types/chai@npm:~4.3.19": + version: 4.3.19 + resolution: "@types/chai@npm:4.3.19" + checksum: abd4d3239735054f3b6e8163e45bc6495f66469729fbcf4784c9f2b82361a6845d45ab9c518818c78eafa46d015e3a72306e9949d1333e10d7eaedf426af4261 + languageName: node + linkType: hard + "@types/chalk@npm:^2.2.0": version: 2.2.0 resolution: "@types/chalk@npm:2.2.0" @@ -12944,21 +13051,21 @@ __metadata: languageName: node linkType: hard -"@types/chart.js@npm:^2.9.39": - version: 2.9.39 - resolution: "@types/chart.js@npm:2.9.39" +"@types/chart.js@npm:^2.9.41": + version: 2.9.41 + resolution: "@types/chart.js@npm:2.9.41" dependencies: moment: ^2.10.2 - checksum: c19cab03143db9cabc9c7277b77a974634baa9a9554dc95a7d2996091ac88ca9d98718e701446932a4cf0b8f3c2862ad0d3f232e1deb6a9bdf72d9ef5342582d + checksum: 7c6b29c837d35edaa371e05850e10468d6690dec1128f247b108c3cd15903c80cafb158a3cbd6a90beb0a9e1e33b12759251e1e63d6cbfa5995a0c5dc0df58b1 languageName: node linkType: hard -"@types/codemirror@npm:^5.60.12": - version: 5.60.12 - resolution: "@types/codemirror@npm:5.60.12" +"@types/codemirror@npm:^5.60.15": + version: 5.60.15 + resolution: "@types/codemirror@npm:5.60.15" dependencies: "@types/tern": "*" - checksum: dff22f32ea42ccd3f9bfcf408631f94a11ffb4614ff4fa8cc55adf7da6e7ba96650533b8dd27d037242747bdaa85141e93520f84409db7bc394862a174a10e1e + checksum: cfad3f569de48fba3efa44fdfeba77933e231486a52cc80cff7ce6eeeed5b447a5bc2b11e2226bc00ccee332c661e53e35a15cf14eb835f434a6a402d9462f5f languageName: node linkType: hard @@ -12981,19 +13088,19 @@ __metadata: languageName: node linkType: hard -"@types/cookie-parser@npm:^1.4.5": - version: 1.4.5 - resolution: "@types/cookie-parser@npm:1.4.5" +"@types/cookie-parser@npm:^1.4.7": + version: 1.4.7 + resolution: "@types/cookie-parser@npm:1.4.7" dependencies: "@types/express": "*" - checksum: 45855721706d6a57bb0441db11fb59db407414ea83a0000a0df80d19230447cc3bcc43c436397bfb8998ec78db222265fa8083456b00c5b5054a0c03d06f0086 + checksum: 7b87c59420598e686a57e240be6e0db53967c3c8814be9326bf86609ee2fc39c4b3b9f2263e1deba43526090121d1df88684b64c19f7b494a80a4437caf3d40b languageName: node linkType: hard -"@types/cookie@npm:^0.5.3": - version: 0.5.3 - resolution: "@types/cookie@npm:0.5.3" - checksum: b785618f6b2fdceb6a20a17e1dfe99651b1e5c2c079f486de76dfb21b508f09d91913755e4a6dbdfe628882ea32466bb2e9318b114ce34efa5e624356494fcab +"@types/cookie@npm:^0.5.4": + version: 0.5.4 + resolution: "@types/cookie@npm:0.5.4" + checksum: bd9603ce5e9bcbe1c2c9fabe3d1b1da131f1db10a7fa0077b17eb06d59bf4a6192fbb890597e8e2295067a078aaf8299bc662bfe993e8c2d1ecd62f859317ece languageName: node linkType: hard @@ -13004,12 +13111,12 @@ __metadata: languageName: node linkType: hard -"@types/cors@npm:^2.8.15": - version: 2.8.15 - resolution: "@types/cors@npm:2.8.15" +"@types/cors@npm:^2.8.17": + version: 2.8.17 + resolution: "@types/cors@npm:2.8.17" dependencies: "@types/node": "*" - checksum: ef7b0aba4c6a4c1fe9d459bd471ebaa891a75319682c9248daa17720003d1d0d2c59de4bdb6868630596ade9b7c3c949e652d6141b14c6fe4387ffcc520d0f3f + checksum: 469bd85e29a35977099a3745c78e489916011169a664e97c4c3d6538143b0a16e4cc72b05b407dc008df3892ed7bf595f9b7c0f1f4680e169565ee9d64966bde languageName: node linkType: hard @@ -13020,10 +13127,10 @@ __metadata: languageName: node linkType: hard -"@types/cssom@npm:^0.4.2": - version: 0.4.2 - resolution: "@types/cssom@npm:0.4.2" - checksum: 4bcc54245b8c09c832c21465f60af412a5c2446ae5c17ab1a874dd87a9488e43951f8027594cc0eaf99d4e9a7c061882f017552a13f0a94ac25db9ac92fea837 +"@types/cssom@npm:^0.4.3": + version: 0.4.3 + resolution: "@types/cssom@npm:0.4.3" + checksum: 3a04921a41fd353e3484962ed705385847b5aeb740988d7c773691417673d01b7cf79d0093fd2b57515d86a0e3ad76dc804b63def8be48ae6f1fdcebd2ab4cd9 languageName: node linkType: hard @@ -13380,12 +13487,12 @@ __metadata: languageName: node linkType: hard -"@types/debug@npm:^4.1.10": - version: 4.1.10 - resolution: "@types/debug@npm:4.1.10" +"@types/debug@npm:^4.1.12": + version: 4.1.12 + resolution: "@types/debug@npm:4.1.12" dependencies: "@types/ms": "*" - checksum: 938f79c5b610f851da9c67ecd8641a09b33ce9cb38fe4c9f4d20ee743d6bccb5d8e9a833a4cd23e0684a316622af67a0634fa706baea5a01f5219961d1976314 + checksum: 47876a852de8240bfdaf7481357af2b88cb660d30c72e73789abf00c499d6bc7cd5e52f41c915d1b9cd8ec9fef5b05688d7b7aef17f7f272c2d04679508d1053 languageName: node linkType: hard @@ -13407,17 +13514,17 @@ __metadata: languageName: node linkType: hard -"@types/ejson@npm:^2.2.1": - version: 2.2.1 - resolution: "@types/ejson@npm:2.2.1" - checksum: 8a0e6e9d50a9b33cdb645e7fdaca5fccb5a0687be0918eaeb06c9c7f21bb8b5757881de77c9d19d84bf16e6949c10b23d098954990aef7bd26257d471f4c008f +"@types/ejson@npm:^2.2.2": + version: 2.2.2 + resolution: "@types/ejson@npm:2.2.2" + checksum: 3f2eb25d98f93821156b071e647bca626563900ecb34bb81cdba33721ee7d046bb66db7d6de664312b9480821821a1d177cf5e146dc1f10adcf43cbd2e387bbe languageName: node linkType: hard -"@types/emojione@npm:^2.2.8": - version: 2.2.8 - resolution: "@types/emojione@npm:2.2.8" - checksum: 3342fd3fbcbc7e7429c7a23330f559d0f41f4fcba5a699035fddb53efba8c7c5ed3af54024011643aa338792d8fd963768766877bc115e093bef193a391abb05 +"@types/emojione@npm:^2.2.9": + version: 2.2.9 + resolution: "@types/emojione@npm:2.2.9" + checksum: ec16f96f8d9886dc3f82bd8aa3ee34f320069771d9a82d01c3c20da9c0c13c7b07347eff2912b914caf3416e3cedea4b963ecc3331c23d743270c975a91ff4d4 languageName: node linkType: hard @@ -13431,7 +13538,7 @@ __metadata: languageName: node linkType: hard -"@types/eslint@npm:*, @types/eslint@npm:~8.44.6": +"@types/eslint@npm:*": version: 8.44.6 resolution: "@types/eslint@npm:8.44.6" dependencies: @@ -13441,6 +13548,16 @@ __metadata: languageName: node linkType: hard +"@types/eslint@npm:~8.44.9": + version: 8.44.9 + resolution: "@types/eslint@npm:8.44.9" + dependencies: + "@types/estree": "*" + "@types/json-schema": "*" + checksum: 6f8889e94e67a5e43c15f5a2530798f864ace08c270bfb3f153cb705da4e30a80e0e9a0fc05317c8642c8dda909d528968172089eb4d52aca9f212761df25d90 + languageName: node + linkType: hard + "@types/estree@npm:*, @types/estree@npm:^1.0.0": version: 1.0.1 resolution: "@types/estree@npm:1.0.1" @@ -13476,7 +13593,7 @@ __metadata: languageName: node linkType: hard -"@types/express@npm:*, @types/express@npm:^4.16.1, @types/express@npm:^4.17.13, @types/express@npm:^4.17.20, @types/express@npm:^4.17.8, @types/express@npm:^4.7.0": +"@types/express@npm:*, @types/express@npm:^4.16.1, @types/express@npm:^4.17.13, @types/express@npm:^4.17.8, @types/express@npm:^4.7.0": version: 4.17.20 resolution: "@types/express@npm:4.17.20" dependencies: @@ -13500,19 +13617,19 @@ __metadata: languageName: node linkType: hard -"@types/fibers@npm:^3.1.3": - version: 3.1.3 - resolution: "@types/fibers@npm:3.1.3" - checksum: c4511eecea1c4e73a4b4310ff5152bb43477dfbd7c19ea8614de5ce6d604c6bd629b4552bdbc06fbd593215c684d06aee4e6d8e6681b4ab019f2b8a03838de79 +"@types/fibers@npm:^3.1.4": + version: 3.1.4 + resolution: "@types/fibers@npm:3.1.4" + checksum: 36bb70198fb5b7f99b010c006ad0e77d473061cf03d4f63f1842040b7ecb62e8800041c9509b927ec59a1d5ac374d5e7c86b2fe0de2a9813f1538ab0248e5dea languageName: node linkType: hard -"@types/gc-stats@npm:^1.4.2": - version: 1.4.2 - resolution: "@types/gc-stats@npm:1.4.2" +"@types/gc-stats@npm:^1.4.3": + version: 1.4.3 + resolution: "@types/gc-stats@npm:1.4.3" dependencies: "@types/node": "*" - checksum: 4039f699b497595c3ac30f221f72d798e12a764093ab5df05cec25cd501fe806005daec10c25737d2b08449772bc318ac720f01fe73d13fdb33168429e25483f + checksum: 983ad3841a1f62a1014e4c0becf81d258f07dc44849598079168df6f4ea293eb8abef7896b6847b9dd68e61b4628525279950b3bb4a75c045b8d461cbaaef3e9 languageName: node linkType: hard @@ -13533,10 +13650,10 @@ __metadata: languageName: node linkType: hard -"@types/google-libphonenumber@npm:^7.4.29": - version: 7.4.29 - resolution: "@types/google-libphonenumber@npm:7.4.29" - checksum: 63b1d03ab6dcd877c1249251d73c54777f6b6cbd13f6b3107c8fcef70d19f8e3a768555942735318da86fa6c50ea0dcfc82d521d4defc9e9dfc1e67b4746ab96 +"@types/google-libphonenumber@npm:^7.4.30": + version: 7.4.30 + resolution: "@types/google-libphonenumber@npm:7.4.30" + checksum: 09270ed030076a0e69965ad5bad564e672a110e1e83c9092f6d264c3e0355921631521cb9afd022018a51cddfd19ba52d0421f4682d7b68b836dbb52537320de languageName: node linkType: hard @@ -13549,10 +13666,10 @@ __metadata: languageName: node linkType: hard -"@types/gravatar@npm:^1.8.5": - version: 1.8.5 - resolution: "@types/gravatar@npm:1.8.5" - checksum: a4a5e9010e5f2caff27f360cd4e0acf4e3276be3fdf8cc4a38baed8b9ca14d187b6b5c1d30d4d3abe326b0aecf30d1b47111ea543c8f6caf8bce9a8bb147c090 +"@types/gravatar@npm:^1.8.6": + version: 1.8.6 + resolution: "@types/gravatar@npm:1.8.6" + checksum: b690f2816321358e8528fe0b731e5c50905ed2c4859327156a87b717a59b45363a2f2c1398c3a9015fa45b17d71d86b1e828fd3df542d13ba946745d9a26094e languageName: node linkType: hard @@ -13605,28 +13722,28 @@ __metadata: languageName: node linkType: hard -"@types/i18next-sprintf-postprocessor@npm:^0.2.2": - version: 0.2.2 - resolution: "@types/i18next-sprintf-postprocessor@npm:0.2.2" +"@types/i18next-sprintf-postprocessor@npm:^0.2.3": + version: 0.2.3 + resolution: "@types/i18next-sprintf-postprocessor@npm:0.2.3" dependencies: i18next: ">=17.0.11" - checksum: 1029c5f896e453534a128013f9ee8a0873a2e03b82a18a530842d06618c3dd1b1f3adf0491efa3f7efd86d19c61b23af60df5c0f36306ed298a20d6d895db95e + checksum: d647c6bb75e2e038ee82d2e5bac762c0254d4fe31232f2fba5f35945779e8509cfa687746219280e2a126e33a647fd459641e8353cf922ddcd2a4e528a1234ba languageName: node linkType: hard -"@types/identity-obj-proxy@npm:^3": +"@types/identity-obj-proxy@npm:^3.0.2": version: 3.0.2 resolution: "@types/identity-obj-proxy@npm:3.0.2" checksum: 77387ee587657ab24f12a1dee5c0e1386358d5c38cda5cac78bc5049340cb358e009f6254de3bbdee6a08e46f13b1552cd47a0bbd3e7a53ff469bf58a04ec6e9 languageName: node linkType: hard -"@types/imap@npm:^0.8.39": - version: 0.8.39 - resolution: "@types/imap@npm:0.8.39" +"@types/imap@npm:^0.8.40": + version: 0.8.40 + resolution: "@types/imap@npm:0.8.40" dependencies: "@types/node": "*" - checksum: 403a0810dc24f035d1762d9ebc1cf548448bdbe565ab6062d2a1d1be2afd4f8ef1483723d4077c0e0e2312a39a27f393a513a40515589149c0617aa984946ae5 + checksum: 5bd33aeeca13bd3403f685048c7c8e136502dc3f5703d732748b488193c96b79295b0901ff1dd72a5cc6b826fc33572bf7376cd6533194797903f9d58cfa8e6d languageName: node linkType: hard @@ -13690,7 +13807,7 @@ __metadata: languageName: node linkType: hard -"@types/jest@npm:*, @types/jest@npm:~29.5.12": +"@types/jest@npm:*": version: 29.5.12 resolution: "@types/jest@npm:29.5.12" dependencies: @@ -13700,6 +13817,16 @@ __metadata: languageName: node linkType: hard +"@types/jest@npm:~29.5.13": + version: 29.5.13 + resolution: "@types/jest@npm:29.5.13" + dependencies: + expect: ^29.0.0 + pretty-format: ^29.0.0 + checksum: 875ac23c2398cdcf22aa56c6ba24560f11d2afda226d4fa23936322dde6202f9fdbd2b91602af51c27ecba223d9fc3c1e33c9df7e47b3bf0e2aefc6baf13ce53 + languageName: node + linkType: hard + "@types/jquery@npm:*": version: 3.5.14 resolution: "@types/jquery@npm:3.5.14" @@ -13709,19 +13836,19 @@ __metadata: languageName: node linkType: hard -"@types/js-yaml@npm:^4.0.8": - version: 4.0.8 - resolution: "@types/js-yaml@npm:4.0.8" - checksum: a5a77a5a1eac7e7fb667156c251c2b947ca4ddfdda570726369dd50bd5b2b1d0da2d0fb4273d1b10aa1782406d7b3da8923d957df4fb89dbfa1db06f43297de2 +"@types/js-yaml@npm:^4.0.9": + version: 4.0.9 + resolution: "@types/js-yaml@npm:4.0.9" + checksum: e5e5e49b5789a29fdb1f7d204f82de11cb9e8f6cb24ab064c616da5d6e1b3ccfbf95aa5d1498a9fbd3b9e745564e69b4a20b6c530b5a8bbb2d4eb830cda9bc69 languageName: node linkType: hard -"@types/jsdom-global@npm:^3.0.6": - version: 3.0.6 - resolution: "@types/jsdom-global@npm:3.0.6" +"@types/jsdom-global@npm:^3.0.7": + version: 3.0.7 + resolution: "@types/jsdom-global@npm:3.0.7" dependencies: "@types/jsdom": "*" - checksum: cb216d588d6abc583615706bbc8beab6265d7afec8e51cadea06f84dd5ba4508e583c500556b2c273d7569c80af9cd68dce19ab6042cd881567aa0fe10261cd1 + checksum: 7b6e58419b56c69fc1b1ef4df8180f19bf171eaa06d1dcc073e87f4cdeb172538b1b2fc16bc783e9521a7630787bad3d0607f4ac66730e5b27525eb73656b86f languageName: node linkType: hard @@ -13770,10 +13897,10 @@ __metadata: languageName: node linkType: hard -"@types/jsrsasign@npm:^10.5.11": - version: 10.5.11 - resolution: "@types/jsrsasign@npm:10.5.11" - checksum: c18b52af99ffb831fd84738356a49e94407e732f0a88f0f6db1e1fd55c06a47d2bab23a9e17b3b21af50fbf5f4d115e13fbe2796357204b18072929bd7b4bd5c +"@types/jsrsasign@npm:^10.5.14": + version: 10.5.14 + resolution: "@types/jsrsasign@npm:10.5.14" + checksum: 04e48fa2a225b6108eb6399a2485ed597fabe4dbd6cf02309abfca9da3e6028697d0fb20e4399b1ef340d7f1a70ace70746aa156ca0c2785663cb2e15797e653 languageName: node linkType: hard @@ -13784,10 +13911,10 @@ __metadata: languageName: node linkType: hard -"@types/katex@npm:~0.16.5": - version: 0.16.5 - resolution: "@types/katex@npm:0.16.5" - checksum: a1ce22cd87acd9b32891931f2bc4355c3540cc0a423e161a2e5b040d3e50812cb85ce1fd09f23d42324b19f9da30ded6b1807114f215624f670d79bb46c47cc8 +"@types/katex@npm:~0.16.7": + version: 0.16.7 + resolution: "@types/katex@npm:0.16.7" + checksum: 4fd15d93553be97c02c064e16be18d7ccbabf66ec72a9dc7fd5bfa47f0c7581da2f942f693c7cb59499de4c843c2189796e49c9647d336cbd52b777b6722a95a languageName: node linkType: hard @@ -13800,10 +13927,10 @@ __metadata: languageName: node linkType: hard -"@types/later@npm:^1.2.8": - version: 1.2.8 - resolution: "@types/later@npm:1.2.8" - checksum: b89b391e6dc6721955b04c01b81a3e38b4ac3d4f40ebcf35bc34d694c46a81c387c028760b3fc1441b9852c46298dfd562708f61504aba65983d2484b99d6420 +"@types/later@npm:^1.2.9": + version: 1.2.9 + resolution: "@types/later@npm:1.2.9" + checksum: dc0db51bfbeb0caa4528e10725728349824dbe1ddbce6acd5258370bde586bb6ee67880d543e7e8dbb178c4001ba6db2e71cddfbcbdd7a1c523d49fbb26b61fb languageName: node linkType: hard @@ -13816,10 +13943,10 @@ __metadata: languageName: node linkType: hard -"@types/less@npm:~3.0.5": - version: 3.0.5 - resolution: "@types/less@npm:3.0.5" - checksum: 72d04c7877a63ef8a49e22a2aaf2e595aec41b4fcbbb48603e4d3a3d1e2d903edea6654db00bba52148ea4101a904e866b410599088b41935aa4c0733d25ef3c +"@types/less@npm:~3.0.6": + version: 3.0.6 + resolution: "@types/less@npm:3.0.6" + checksum: f1e5a7b7da6c0e65e0881a563d71287243f8cdeee1abb3e72ed9d449b4fb5421deee9b3bbd3bff856f17870563c2fc8cc4674c1f77632a73a9d713200dd7505a languageName: node linkType: hard @@ -13839,21 +13966,21 @@ __metadata: languageName: node linkType: hard -"@types/lodash.debounce@npm:^4.0.8": - version: 4.0.8 - resolution: "@types/lodash.debounce@npm:4.0.8" +"@types/lodash.debounce@npm:^4.0.9": + version: 4.0.9 + resolution: "@types/lodash.debounce@npm:4.0.9" dependencies: "@types/lodash": "*" - checksum: 63f195cb053ca390135a9aca62bb60fa149ca81838519871506b60760ff4113333709becb8e4147707eaa3d916dab7eff66b0588caf4ce508cabda9bee9c5b60 + checksum: 8183a152e01928e3b97ca773f6ae6038b8695e76493ba8bf6b743ec143948a62294fbc9d49fa4a78b52265b3ba4892ef57534e0c13d04aa0f111671b5a944feb languageName: node linkType: hard -"@types/lodash.get@npm:^4.4.8": - version: 4.4.8 - resolution: "@types/lodash.get@npm:4.4.8" +"@types/lodash.get@npm:^4.4.9": + version: 4.4.9 + resolution: "@types/lodash.get@npm:4.4.9" dependencies: "@types/lodash": "*" - checksum: fea09c12f098e5cbdc16510e8319a7f0dd4d0af49a5e6622ae4f0dcd4893f1b2c44a5d22f452d73443f50b85c8461f3fe2370c19b8d9051686265bbb0aae0ffa + checksum: d7e071d267e3d1bab58db14b6ce63fc51ca3c9c9697d3548cd5c0f16c08a7ce2188cff75dff1858b5623c3bd070836857211ebef4f364c53b82e31f3190fe0b4 languageName: node linkType: hard @@ -13864,13 +13991,13 @@ __metadata: languageName: node linkType: hard -"@types/mailparser@npm:^3.4.3": - version: 3.4.3 - resolution: "@types/mailparser@npm:3.4.3" +"@types/mailparser@npm:^3.4.4": + version: 3.4.4 + resolution: "@types/mailparser@npm:3.4.4" dependencies: "@types/node": "*" iconv-lite: ^0.6.3 - checksum: 9374b713311b523b66429a7b509e90229dd001029e87d901ab6c756e1856eb2a8427012c016ad70ac45b39056eba1334e568f85ce9f329f5dd147986a897b691 + checksum: c8bdb579d66756042b75c3763dd8b7b2fab6657d7e7d33504bb65bbbe6fa220b8da2ae67918dd821716c3229d8803bedffb00f2314a8946da1856396187c646a languageName: node linkType: hard @@ -13907,12 +14034,12 @@ __metadata: languageName: node linkType: hard -"@types/meteor-collection-hooks@npm:^0.8.8": - version: 0.8.8 - resolution: "@types/meteor-collection-hooks@npm:0.8.8" +"@types/meteor-collection-hooks@npm:^0.8.9": + version: 0.8.9 + resolution: "@types/meteor-collection-hooks@npm:0.8.9" dependencies: meteor-typings: ^1.3.1 - checksum: bf0afc8531c836f3f7ead4aa0f8be3f69257af7a62397924a50533a20837b21b16c307777bb4fe52dc2e26753ba7269d0df6133ba6f1dad27d4075fea38a05f9 + checksum: 7b12838587a6d411e3c44c682532cd43a4db99d4b11164867a2831a45593d2c637fb7feeede661b05eb6a63d8fa48228c0b5a0cb61e556c291e4d06f9f457892 languageName: node linkType: hard @@ -14012,19 +14139,19 @@ __metadata: languageName: node linkType: hard -"@types/node-gcm@npm:^1.0.3": - version: 1.0.3 - resolution: "@types/node-gcm@npm:1.0.3" - checksum: 232e3d401f381fe9312343efb920892a7aa2f63457e00608ff2c3f0d1bff4a3707affe9a9e484ffead39272cfba0d1791901b7e937420233455dd047d63a4587 +"@types/node-gcm@npm:^1.0.5": + version: 1.0.5 + resolution: "@types/node-gcm@npm:1.0.5" + checksum: 5448aa9de99b23700a2cc243483ed08bffd988a91d7431ed193dfbb55fc5c087c58310f728992a83f0e653b9edf9220434b62a0fabc5c7f417067ca805c1f92c languageName: node linkType: hard -"@types/node-rsa@npm:^1.1.3": - version: 1.1.3 - resolution: "@types/node-rsa@npm:1.1.3" +"@types/node-rsa@npm:^1.1.4": + version: 1.1.4 + resolution: "@types/node-rsa@npm:1.1.4" dependencies: "@types/node": "*" - checksum: 03606729a96722623e316b1728d45ba452e008e01e886127d1d964221119dd4196be724ec062fc81be5beb28ce8e5fcc9c55109275cdae60545ddc293b89e77d + checksum: cd607463b7954dd0eda390e0710fa5fdc1a26e716baefd77134f54893ed57bfbf1906f3a354f43f89174aa37ac6f05fa450b708e516a4a8fa643e0d2f8e26106 languageName: node linkType: hard @@ -14044,21 +14171,28 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^14.0.10 || ^16.0.0, @types/node@npm:^14.14.20 || ^16.0.0, @types/node@npm:^16.18.60": +"@types/node@npm:^14.0.10 || ^16.0.0, @types/node@npm:^14.14.20 || ^16.0.0": version: 16.18.60 resolution: "@types/node@npm:16.18.60" checksum: aa0c81c3f20e663584bf17a5968e54c419277af7982ef41f9d83edd1b7ab4c8af2583a3c8a9e1cf659c6307e6f787e1be20522855121371f5a46d1d54f8a70e3 languageName: node linkType: hard -"@types/node@npm:^14.0.26, @types/node@npm:^14.14.37, @types/node@npm:^14.18.63, @types/node@npm:~14.18.42": +"@types/node@npm:^14.0.26, @types/node@npm:^14.14.37, @types/node@npm:^14.18.63, @types/node@npm:~14.18.63": version: 14.18.63 resolution: "@types/node@npm:14.18.63" checksum: be909061a54931778c71c49dc562586c32f909c4b6197e3d71e6dac726d8bd9fccb9f599c0df99f52742b68153712b5097c0f00cac4e279fa894b0ea6719a8fd languageName: node linkType: hard -"@types/nodemailer@npm:*, @types/nodemailer@npm:^6.4.13": +"@types/node@npm:^16.18.108": + version: 16.18.108 + resolution: "@types/node@npm:16.18.108" + checksum: 5029ce7b0d247690360f2698da4fe765ef5cd5e2409b63b3a45e90bbf7bbaaf3497e769336fb7725be04a221d6e934e3a4616ec7fc205812943def3ea9d70862 + languageName: node + linkType: hard + +"@types/nodemailer@npm:*": version: 6.4.13 resolution: "@types/nodemailer@npm:6.4.13" dependencies: @@ -14067,6 +14201,15 @@ __metadata: languageName: node linkType: hard +"@types/nodemailer@npm:^6.4.15": + version: 6.4.15 + resolution: "@types/nodemailer@npm:6.4.15" + dependencies: + "@types/node": "*" + checksum: f6f9a2f8a669703ecc3ca6359c12345b16f6b2e5691b93c406b9af7de639c02092ec00133526e6fecd8c60d884890a7cd0f967d8e64bedab46d5c3d8be0882d7 + languageName: node + linkType: hard + "@types/normalize-package-data@npm:^2.4.0": version: 2.4.1 resolution: "@types/normalize-package-data@npm:2.4.1" @@ -14081,19 +14224,19 @@ __metadata: languageName: node linkType: hard -"@types/oauth2-server@npm:^3.0.15": - version: 3.0.15 - resolution: "@types/oauth2-server@npm:3.0.15" +"@types/oauth2-server@npm:^3.0.17": + version: 3.0.17 + resolution: "@types/oauth2-server@npm:3.0.17" dependencies: "@types/express": "*" - checksum: b6c73ec0ba3a83e7a9cc1bf0e75fd640a76bcf57742642775abf950d851478a686e3f54ad8e24a09772e1dd89ed953742418c76ebb7df12b97b68f1cb94dae80 + checksum: f45224356b9a3736b86f3ed1a8873f7f535e10b22af06bc7d34eefd96af4f5db83ed4b618b0103566828fe279e8bed2ee304f6644a31bd127470a5a49398ca49 languageName: node linkType: hard -"@types/object-path@npm:^0.11.3": - version: 0.11.3 - resolution: "@types/object-path@npm:0.11.3" - checksum: 9c2f1ec11d9d15df1682ab1483c0f51cac3ff8c3a951662a50d15fd48824fc43a052041503d0761790a29a4100e33989eb519889948c3592d0bf6bde59d3ec79 +"@types/object-path@npm:^0.11.4": + version: 0.11.4 + resolution: "@types/object-path@npm:0.11.4" + checksum: 7f1f5cb18b651d21e7861da176d8f87526c936ed949a8126a2692195cbe65734ed1a1a22c06a24a54afe1890483a3d6b074b402ebfca7a7567c1c287b588f563 languageName: node linkType: hard @@ -14125,24 +14268,24 @@ __metadata: languageName: node linkType: hard -"@types/parseurl@npm:^1.3.2": - version: 1.3.2 - resolution: "@types/parseurl@npm:1.3.2" +"@types/parseurl@npm:^1.3.3": + version: 1.3.3 + resolution: "@types/parseurl@npm:1.3.3" dependencies: "@types/node": "*" - checksum: bfe0ad3222a957a1d8d21a5378a61a3ce21f0ce45ddfdd98fc727207b4bd3caf590d2a448c39d08774949e485a5f5f08429f6025a6b0123456a8a7fb9270ddb2 + checksum: 2ea8d3b9615850fce3dd208f980aaca2c82c6cb20e033ee5705adbc773ea167fc57ee72045ba521fef0f6ad292fddaf91e398dad9edec10b9829621a8556446f languageName: node linkType: hard -"@types/polka@npm:^0.5.6": - version: 0.5.6 - resolution: "@types/polka@npm:0.5.6" +"@types/polka@npm:^0.5.7": + version: 0.5.7 + resolution: "@types/polka@npm:0.5.7" dependencies: "@types/express": "*" "@types/express-serve-static-core": "*" "@types/node": "*" "@types/trouter": "*" - checksum: e956629526782b722fe134a93e159774d13d58a66796f5b6f763b04cd5c426439a8556962e1da8e8a61574ed1ad6239ffbef28cd8c03b4f8828a9a4b03189dde + checksum: ec9bd7ae06b6cd49c972cd3af750c29dd6de28bf2aaf7e710ef2eec839636ee6efe8cf354008b80f9a865675cb3cedc60aab1bf9737bf4f5835d1c527b4f64c8 languageName: node linkType: hard @@ -14160,10 +14303,10 @@ __metadata: languageName: node linkType: hard -"@types/prometheus-gc-stats@npm:^0.6.3": - version: 0.6.3 - resolution: "@types/prometheus-gc-stats@npm:0.6.3" - checksum: b8ad00f21c2d7f19819b0d82b778f4919847e44f1f74a570fb52386fa7c5250af3a5e2eef5b8aa69cbf7fd8cc68f31f91bd7a002ce5b3722bb971da31af543a0 +"@types/prometheus-gc-stats@npm:^0.6.4": + version: 0.6.4 + resolution: "@types/prometheus-gc-stats@npm:0.6.4" + checksum: 31d9c6a26c55829aa57c05ef602897926b5a068655b9e9850de92a7b7106a9c5e7971d96dc95d082817303899781cd98a319cd05699bc1ef5e9932456c23fd2a languageName: node linkType: hard @@ -14181,26 +14324,26 @@ __metadata: languageName: node linkType: hard -"@types/proxy-from-env@npm:^1.0.3": - version: 1.0.3 - resolution: "@types/proxy-from-env@npm:1.0.3" +"@types/proxy-from-env@npm:^1.0.4": + version: 1.0.4 + resolution: "@types/proxy-from-env@npm:1.0.4" dependencies: "@types/node": "*" - checksum: 3661687ae4bd90b9c41e504d3e3124b1ccd7d39d5877a7930fc3630989e37bde4e6b9055ea719d4b85c400a872bee02336ee5e187380f075cec021a4aebced44 + checksum: cfa34200e6ddb19c78957c2c661212c8eee1f7dbc1931e918909300b47cc0336023c2a526972c494cb5409010fd35edba37bd795893796cc50e1efabd34e3969 languageName: node linkType: hard -"@types/proxyquire@npm:^1.3.30": - version: 1.3.30 - resolution: "@types/proxyquire@npm:1.3.30" - checksum: e247d0afdb59aae942313112ca6429b0cbe410b0a858796c63e16ea945b3a7686f0660a03c685d79f10ed807051f645a763e13aa72d3725aeea74fd40901fdad +"@types/proxyquire@npm:^1.3.31": + version: 1.3.31 + resolution: "@types/proxyquire@npm:1.3.31" + checksum: 945024495fc991f6152686795ac6f2f2d0f571834e67fa41c1e84877eeb1a321a24ab8ff67fc5152d9227f5b39f6254213dced15deaf80ed7443059c2257e072 languageName: node linkType: hard -"@types/psl@npm:^1.1.2": - version: 1.1.2 - resolution: "@types/psl@npm:1.1.2" - checksum: fc0a7ae56ca53157035226d964f5a37749187804c07787d25a3f8e0235130c277b52d027139d1a7058d7826014a8019d68d46e2719b0404ac8545d39d41fc43a +"@types/psl@npm:^1.1.3": + version: 1.1.3 + resolution: "@types/psl@npm:1.1.3" + checksum: adc24b5f0a2569563367437cbdcbb63c780e798360a4c21470043acda2adad56e510c9f357be36f297974d68534821febc38652709e5d712ac2cdd62f9a6777a languageName: node linkType: hard @@ -14225,21 +14368,21 @@ __metadata: languageName: node linkType: hard -"@types/react-beautiful-dnd@npm:^13.1.6": - version: 13.1.6 - resolution: "@types/react-beautiful-dnd@npm:13.1.6" +"@types/react-beautiful-dnd@npm:^13.1.8": + version: 13.1.8 + resolution: "@types/react-beautiful-dnd@npm:13.1.8" dependencies: "@types/react": "*" - checksum: 437c315cac4455fd0085150d5d163330e523e965193f642f45edf34eb56098e68a6f956d90ecb11abfcb03ce34177e5445c1489da46353ee5a6a6306414fb936 + checksum: f71c64ba7e2e1f8480e772b45268856d2bf99adf90d12dd5f31486075dfd3e33a0b0922969851c660f01aa9593aa38b38e17ee9038eb866af9ec4327be903cb9 languageName: node linkType: hard -"@types/react-dom@npm:~17.0.22": - version: 17.0.22 - resolution: "@types/react-dom@npm:17.0.22" +"@types/react-dom@npm:~17.0.25": + version: 17.0.25 + resolution: "@types/react-dom@npm:17.0.25" dependencies: "@types/react": ^17 - checksum: 3c24331c0a2211370968befaad107598ee4f796c08e9b0de0b0126ee598a7c51f7bf4e0e7d9a76522a3b60d91f091d46131d136bcbe49aeb6ec3b8480dff03f9 + checksum: d1e582682478e0848c8d54ea3e89d02047bac6d916266b85ce63731b06987575919653ea7159d98fda47ade3362b8c4d5796831549564b83088e7aa9ce8b60ed languageName: node linkType: hard @@ -14264,7 +14407,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:^17, @types/react@npm:~17.0.69": +"@types/react@npm:*, @types/react@npm:^17": version: 17.0.69 resolution: "@types/react@npm:17.0.69" dependencies: @@ -14275,6 +14418,17 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:~17.0.80": + version: 17.0.80 + resolution: "@types/react@npm:17.0.80" + dependencies: + "@types/prop-types": "*" + "@types/scheduler": ^0.16 + csstype: ^3.0.2 + checksum: 1c27bfc42305d77ef0da55f8f6d4c4a3471aa02b294fcf29ea0f2cfb0bf02892e5a0a3bc7559fa4a5ba50697b2e31076cb5aa5987f69cfc2e880f6426edb8bdf + languageName: node + linkType: hard + "@types/readdir-glob@npm:*": version: 1.1.1 resolution: "@types/readdir-glob@npm:1.1.1" @@ -14300,10 +14454,10 @@ __metadata: languageName: node linkType: hard -"@types/rewire@npm:^2.5.29": - version: 2.5.29 - resolution: "@types/rewire@npm:2.5.29" - checksum: 2ad2f1134fe7c350fc88f0a9cc17eb49377f1a61776cde10b62bae0f5956dedd97adbb8da0e3ca8ddfb7034699a89fe2f9dc31af35f11727c4b38c8a089877c3 +"@types/rewire@npm:^2.5.30": + version: 2.5.30 + resolution: "@types/rewire@npm:2.5.30" + checksum: 75f756ee068ad7f8aac697dc80f0007afa8c837e7aa211fd95ba7eeea8905043b20439e9b1c8326be77643159580aeebc49a464e626b0837ee188bd8a05dfe84 languageName: node linkType: hard @@ -14323,6 +14477,13 @@ __metadata: languageName: node linkType: hard +"@types/scheduler@npm:^0.16": + version: 0.16.8 + resolution: "@types/scheduler@npm:0.16.8" + checksum: 6c091b096daa490093bf30dd7947cd28e5b2cd612ec93448432b33f724b162587fed9309a0acc104d97b69b1d49a0f3fc755a62282054d62975d53d7fd13472d + languageName: node + linkType: hard + "@types/semver@npm:^7.3.10, @types/semver@npm:^7.3.12, @types/semver@npm:^7.5.0": version: 7.5.4 resolution: "@types/semver@npm:7.5.4" @@ -14407,12 +14568,12 @@ __metadata: languageName: node linkType: hard -"@types/speakeasy@npm:^2.0.9": - version: 2.0.9 - resolution: "@types/speakeasy@npm:2.0.9" +"@types/speakeasy@npm:^2.0.10": + version: 2.0.10 + resolution: "@types/speakeasy@npm:2.0.10" dependencies: "@types/node": "*" - checksum: 4f3d2217f96625c481f9220a5d16a776c7003d9025fafe728f91f07ba815ac2233db4df85cf4a721b5e042a478f793eee6e4e54c397288f3a39e3f04aa8375ac + checksum: 672c757a7662895a0d9eea5ecc8309b75c3925f00f0af4e7133fd3e475f3fdb1289d95ae6cf7fbab024f149703d999891b17771cc221db4e9a24c70ab1b04319 languageName: node linkType: hard @@ -14432,10 +14593,10 @@ __metadata: languageName: node linkType: hard -"@types/strict-uri-encode@npm:^2.0.1": - version: 2.0.1 - resolution: "@types/strict-uri-encode@npm:2.0.1" - checksum: 63d62f43d20583428d112f6a9de5a444f31f8e314a8c57b9a59523f99ae3152e41e2e39ff0fb0404171135402d2226aba21a5db64de0d0d385ec8c11d5a0f4ce +"@types/strict-uri-encode@npm:^2.0.2": + version: 2.0.2 + resolution: "@types/strict-uri-encode@npm:2.0.2" + checksum: e395868cc1cd49537be56d2f43b417ddc11559f807d5e1402d180870d0e2872fbe4d35765de1bbec76b939faf77cfdb13aec715d9946f6675e17073169a70dcd languageName: node linkType: hard @@ -14458,16 +14619,16 @@ __metadata: languageName: node linkType: hard -"@types/supertest@npm:^2.0.15": - version: 2.0.15 - resolution: "@types/supertest@npm:2.0.15" +"@types/supertest@npm:^2.0.16": + version: 2.0.16 + resolution: "@types/supertest@npm:2.0.16" dependencies: "@types/superagent": "*" - checksum: 89c1983662f0ab20969b3a6c44344397fd222d0f78b282619aabbe817f7c88a64210fd2b8b8f075ea22a27084e30ebc287bc5105619cbbf9af7f008e77f6eb93 + checksum: 2fc998ea698e0467cdbe3bea0ebce2027ea3a45a13e51a6cecb0435f44b486faecf99c34d8702d2d7fe033e6e09fdd2b374af52ecc8d0c69a1deec66b8c0dd52 languageName: node linkType: hard -"@types/supports-color@npm:~7.2.0": +"@types/supports-color@npm:~7.2.1": version: 7.2.1 resolution: "@types/supports-color@npm:7.2.1" checksum: abf7d9348deadf5386cf5faec062a4132e647a179584f52cace87435248f520be73c58ac28618cf5684e6b0ed6bb635d5a975cc71ff613af7db2d5648557ef45 @@ -14490,10 +14651,10 @@ __metadata: languageName: node linkType: hard -"@types/textarea-caret@npm:^3.0.2": - version: 3.0.2 - resolution: "@types/textarea-caret@npm:3.0.2" - checksum: 6989477fa7be544cb84ffbb3302d5c4c2632e7900e0fcc12adf9bd78f4d0ebbf38db9392cb39c8fa791aba935013e1b14aeb1c222f328a67de6202f945331e73 +"@types/textarea-caret@npm:^3.0.3": + version: 3.0.3 + resolution: "@types/textarea-caret@npm:3.0.3" + checksum: 61d4b08391c28f8b37236e65946457819460de1749b860a852c01cfb1093ab2ceb3fe11b54f788e7c024cb580d26984b9285438139f3cb3bb333150955413a8e languageName: node linkType: hard @@ -14525,10 +14686,10 @@ __metadata: languageName: node linkType: hard -"@types/ua-parser-js@npm:^0.7.38": - version: 0.7.38 - resolution: "@types/ua-parser-js@npm:0.7.38" - checksum: 8a44887f7c782ed4c59c4d9cb254674f2ff41d8f653da0c2bd6d4ace79cc3de1ce5648b77f906e337fb97328e1114583e54c3b8882d194e1b8cb281f407a1ef7 +"@types/ua-parser-js@npm:^0.7.39": + version: 0.7.39 + resolution: "@types/ua-parser-js@npm:0.7.39" + checksum: 81046605eb2815b098228743b7dfde887cc8990369f2ad56e71f1400b4cef5078481c7ca91ca3dddf2e8d4e183fe93224bfdeee13bfe034a1e62d55cfbac9e26 languageName: node linkType: hard @@ -14555,17 +14716,17 @@ __metadata: languageName: node linkType: hard -"@types/use-subscription@npm:^1.0.1": - version: 1.0.1 - resolution: "@types/use-subscription@npm:1.0.1" - checksum: f9e3535d40dbcd606e7ef306120c52a78b9da7a94ebe0b56af8f8326984588b2db12fbc841e2b2d719728810816afa9c7d64b40a849048186a4308e2f3ff0339 +"@types/use-subscription@npm:^1.0.2": + version: 1.0.2 + resolution: "@types/use-subscription@npm:1.0.2" + checksum: e547d8ffdf8410c985c271a30903cd754687a6514a67192378213590f707a0f516e0c11930cba10bd7e98dc4f7917e066b3b8d37a622d02b6fcf3c5df530e467 languageName: node linkType: hard -"@types/use-sync-external-store@npm:^0.0.5": - version: 0.0.5 - resolution: "@types/use-sync-external-store@npm:0.0.5" - checksum: 96a22fa059d8a6d0fe0b03e5157eb22f599ab1cc58b9441617dec4be6d8586260fcf9041912ab90e92d9c6ea6dfec5c758bae6418552aa687fc7e0bb904e68bc +"@types/use-sync-external-store@npm:^0.0.6": + version: 0.0.6 + resolution: "@types/use-sync-external-store@npm:0.0.6" + checksum: a95ce330668501ad9b1c5b7f2b14872ad201e552a0e567787b8f1588b22c7040c7c3d80f142cbb9f92d13c4ea41c46af57a20f2af4edf27f224d352abcfe4049 languageName: node linkType: hard @@ -14576,7 +14737,7 @@ __metadata: languageName: node linkType: hard -"@types/uuid@npm:^9": +"@types/uuid@npm:^9.0.8": version: 9.0.8 resolution: "@types/uuid@npm:9.0.8" checksum: b8c60b7ba8250356b5088302583d1704a4e1a13558d143c549c408bf8920535602ffc12394ede77f8a8083511b023704bc66d1345792714002bfa261b17c5275 @@ -14642,14 +14803,14 @@ __metadata: languageName: node linkType: hard -"@types/webpack@npm:^5.28.4": - version: 5.28.4 - resolution: "@types/webpack@npm:5.28.4" +"@types/webpack@npm:^5.28.5": + version: 5.28.5 + resolution: "@types/webpack@npm:5.28.5" dependencies: "@types/node": "*" tapable: ^2.2.0 webpack: ^5 - checksum: 7a08e31096a05c77bb49b3830f85f2e340090fa2b19dbe4681c7eab92e49db85bdbbe7b374df7d7aa38549922ff3252f43a00d4c5c2f9fe0c2a198cdb5ddde7e + checksum: 14359d9ccecef7ef1ea271c00baec5337213c7fda63a34c61b9e519505b3928d0807cdbb5b1172d1994e1179920b89c57eaf2cbf64599958b67cd70720ac2a9b languageName: node linkType: hard @@ -14688,7 +14849,7 @@ __metadata: languageName: node linkType: hard -"@types/ws@npm:^8.5.1, @types/ws@npm:^8.5.5, @types/ws@npm:^8.5.8": +"@types/ws@npm:^8.5.1, @types/ws@npm:^8.5.5": version: 8.5.8 resolution: "@types/ws@npm:8.5.8" dependencies: @@ -14697,22 +14858,31 @@ __metadata: languageName: node linkType: hard -"@types/xml-crypto@npm:~1.4.4": - version: 1.4.4 - resolution: "@types/xml-crypto@npm:1.4.4" +"@types/ws@npm:^8.5.12": + version: 8.5.12 + resolution: "@types/ws@npm:8.5.12" + dependencies: + "@types/node": "*" + checksum: ddefb6ad1671f70ce73b38a5f47f471d4d493864fca7c51f002a86e5993d031294201c5dced6d5018fb8905ad46888d65c7f20dd54fc165910b69f42fba9a6d0 + languageName: node + linkType: hard + +"@types/xml-crypto@npm:~1.4.6": + version: 1.4.6 + resolution: "@types/xml-crypto@npm:1.4.6" dependencies: "@types/node": "*" xpath: 0.0.27 - checksum: c19616b531b26d7f3fafee6165d7be42969bfa2ef7184f501c489c80515d483425fb97e55ae816d91cf2f92e765e81f0a7cfc97c5dedb46f829edb677b154a55 + checksum: e53516a2f5e4e018e164eb1cb9fc922294b9a339624e567c1c00a2b1496e9f86826210473e62ceb0b45949638c9d149da088b3598f6b3acd86e933f0a2b23f2c languageName: node linkType: hard -"@types/xml-encryption@npm:~1.2.3": - version: 1.2.3 - resolution: "@types/xml-encryption@npm:1.2.3" +"@types/xml-encryption@npm:~1.2.4": + version: 1.2.4 + resolution: "@types/xml-encryption@npm:1.2.4" dependencies: "@types/node": "*" - checksum: 1f678c5cb7378702dd1bfbbe1ec3b4dd62d7b8350c225866df109d60c8c7c4e39b20d32193ead175b1c68944ce22ffcae470685371e6257bf0bfe45f7f366aec + checksum: 1ef957dfb47cf55b12e114755e271a2343f73eb4c59ab6c68b0b7d1b8111d7e1bd8d2bfe0601d2aea09be83c66355bc77fc59f9b71aeff9bb9e15371bcfef5d3 languageName: node linkType: hard @@ -16409,6 +16579,17 @@ __metadata: languageName: node linkType: hard +"asn1.js@npm:^4.10.1": + version: 4.10.1 + resolution: "asn1.js@npm:4.10.1" + dependencies: + bn.js: ^4.0.0 + inherits: ^2.0.1 + minimalistic-assert: ^1.0.0 + checksum: 9289a1a55401238755e3142511d7b8f6fc32f08c86ff68bd7100da8b6c186179dd6b14234fba2f7f6099afcd6758a816708485efe44bc5b2a6ec87d9ceeddbb5 + languageName: node + linkType: hard + "asn1.js@npm:^5.2.0": version: 5.4.1 resolution: "asn1.js@npm:5.4.1" @@ -16447,15 +16628,16 @@ __metadata: languageName: node linkType: hard -"assert@npm:^2.0.0": - version: 2.0.0 - resolution: "assert@npm:2.0.0" +"assert@npm:^2.1.0": + version: 2.1.0 + resolution: "assert@npm:2.1.0" dependencies: - es6-object-assign: ^1.1.0 - is-nan: ^1.2.1 - object-is: ^1.0.1 - util: ^0.12.0 - checksum: bb91f181a86d10588ee16c5e09c280f9811373974c29974cbe401987ea34e966699d7989a812b0e19377b511ea0bc627f5905647ce569311824848ede382cae8 + call-bind: ^1.0.2 + is-nan: ^1.3.2 + object-is: ^1.1.5 + object.assign: ^4.1.4 + util: ^0.12.5 + checksum: 1ed1cabba9abe55f4109b3f7292b4e4f3cf2953aad8dc148c0b3c3bd676675c31b1abb32ef563b7d5a19d1715bf90d1e5f09fad2a4ee655199468902da80f7c2 languageName: node linkType: hard @@ -16784,6 +16966,13 @@ __metadata: languageName: node linkType: hard +"b4a@npm:^1.6.6": + version: 1.6.6 + resolution: "b4a@npm:1.6.6" + checksum: c46a27e3ac9c84426ae728f0fc46a6ae7703a7bc03e771fa0bef4827fd7cf3bb976d1a3d5afff54606248372ab8fdf595bd0114406690edf37f14d120630cf7f + languageName: node + linkType: hard + "babel-jest@npm:^29.0.3, babel-jest@npm:^29.5.0, babel-jest@npm:^29.7.0": version: 29.7.0 resolution: "babel-jest@npm:29.7.0" @@ -16831,7 +17020,7 @@ __metadata: languageName: node linkType: hard -"babel-loader@npm:~9.1.2": +"babel-loader@npm:~9.1.3": version: 9.1.3 resolution: "babel-loader@npm:9.1.3" dependencies: @@ -17118,6 +17307,50 @@ __metadata: languageName: node linkType: hard +"bare-events@npm:^2.0.0, bare-events@npm:^2.2.0": + version: 2.4.2 + resolution: "bare-events@npm:2.4.2" + checksum: 6cd2b10dd32a3410787e120c091b6082fbc2df0c45ed723a7ae51d0e2f55d2a4037e1daff21dae90b671d36582f9f8d50df337875c281d10adb60df81b8cd861 + languageName: node + linkType: hard + +"bare-fs@npm:^2.1.1": + version: 2.3.5 + resolution: "bare-fs@npm:2.3.5" + dependencies: + bare-events: ^2.0.0 + bare-path: ^2.0.0 + bare-stream: ^2.0.0 + checksum: 071b1dff94a213eaf0b41693953959bf10af2deade597a56ff206a5d833579d56bc8530aa4614bb88bf39fd6d52f2404f7c36af4695109ffa756a13837ac3d91 + languageName: node + linkType: hard + +"bare-os@npm:^2.1.0": + version: 2.4.4 + resolution: "bare-os@npm:2.4.4" + checksum: e90088a7dc0307c020350a28df8ec5564cae5a4b7a213d8509d70831d7064308e2ed31de801b68f474cb004ad3a0a66bd28c38374d270484d9025ee71af20396 + languageName: node + linkType: hard + +"bare-path@npm:^2.0.0, bare-path@npm:^2.1.0": + version: 2.1.3 + resolution: "bare-path@npm:2.1.3" + dependencies: + bare-os: ^2.1.0 + checksum: 20301aeb05b735852a396515464908e51e896922c3bb353ef2a09ff54e81ced94e6ad857bb0a36d2ce659c42bd43dd5c3d5643edd8faaf910ee9950c4e137b88 + languageName: node + linkType: hard + +"bare-stream@npm:^2.0.0": + version: 2.3.0 + resolution: "bare-stream@npm:2.3.0" + dependencies: + b4a: ^1.6.6 + streamx: ^2.20.0 + checksum: 17de9dbd5a6d70863b6e55f0acdfe1cb5d2b05f22d87e79986372cc796095eb4882a868ee6ba3dc543243085d27f618b4b81ef2bf384bc1c690dd3a557b6e30d + languageName: node + linkType: hard + "base-64@npm:^1.0.0": version: 1.0.0 resolution: "base-64@npm:1.0.0" @@ -17429,6 +17662,13 @@ __metadata: languageName: node linkType: hard +"bn.js@npm:^5.2.1": + version: 5.2.1 + resolution: "bn.js@npm:5.2.1" + checksum: 3dd8c8d38055fedfa95c1d5fc3c99f8dd547b36287b37768db0abab3c239711f88ff58d18d155dd8ad902b0b0cee973747b7ae20ea12a09473272b0201c9edd3 + languageName: node + linkType: hard + "bodec@npm:^0.1.0": version: 0.1.0 resolution: "bodec@npm:0.1.0" @@ -17456,7 +17696,27 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.2, body-parser@npm:^1.19.0, body-parser@npm:^1.20.2": +"body-parser@npm:1.20.3, body-parser@npm:^1.20.3": + version: 1.20.3 + resolution: "body-parser@npm:1.20.3" + dependencies: + bytes: 3.1.2 + content-type: ~1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.13.0 + raw-body: 2.5.2 + type-is: ~1.6.18 + unpipe: 1.0.0 + checksum: 1a35c59a6be8d852b00946330141c4f142c6af0f970faa87f10ad74f1ee7118078056706a05ae3093c54dabca9cd3770fa62a170a85801da1a4324f04381167d + languageName: node + linkType: hard + +"body-parser@npm:^1.19.0": version: 1.20.2 resolution: "body-parser@npm:1.20.2" dependencies: @@ -17657,7 +17917,7 @@ __metadata: languageName: node linkType: hard -"browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4": +"browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.2.0": version: 1.2.0 resolution: "browserify-aes@npm:1.2.0" dependencies: @@ -17671,7 +17931,7 @@ __metadata: languageName: node linkType: hard -"browserify-cipher@npm:^1.0.0": +"browserify-cipher@npm:^1.0.0, browserify-cipher@npm:^1.0.1": version: 1.0.1 resolution: "browserify-cipher@npm:1.0.1" dependencies: @@ -17694,7 +17954,7 @@ __metadata: languageName: node linkType: hard -"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.0.1": +"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.0.1, browserify-rsa@npm:^4.1.0": version: 4.1.0 resolution: "browserify-rsa@npm:4.1.0" dependencies: @@ -17721,6 +17981,24 @@ __metadata: languageName: node linkType: hard +"browserify-sign@npm:^4.2.3": + version: 4.2.3 + resolution: "browserify-sign@npm:4.2.3" + dependencies: + bn.js: ^5.2.1 + browserify-rsa: ^4.1.0 + create-hash: ^1.2.0 + create-hmac: ^1.1.7 + elliptic: ^6.5.5 + hash-base: ~3.0 + inherits: ^2.0.4 + parse-asn1: ^5.1.7 + readable-stream: ^2.3.8 + safe-buffer: ^5.2.1 + checksum: 403a8061d229ae31266670345b4a7c00051266761d2c9bbeb68b1a9bcb05f68143b16110cf23a171a5d6716396a1f41296282b3e73eeec0a1871c77f0ff4ee6b + languageName: node + linkType: hard + "browserify-zlib@npm:^0.2.0": version: 0.2.0 resolution: "browserify-zlib@npm:0.2.0" @@ -18282,23 +18560,23 @@ __metadata: languageName: node linkType: hard -"chai-as-promised@npm:^7.1.1": - version: 7.1.1 - resolution: "chai-as-promised@npm:7.1.1" +"chai-as-promised@npm:^7.1.2": + version: 7.1.2 + resolution: "chai-as-promised@npm:7.1.2" dependencies: check-error: ^1.0.2 peerDependencies: - chai: ">= 2.1.2 < 5" - checksum: 7262868a5b51a12af4e432838ddf97a893109266a505808e1868ba63a12de7ee1166e9d43b5c501a190c377c1b11ecb9ff8e093c89f097ad96c397e8ec0f8d6a + chai: ">= 2.1.2 < 6" + checksum: 671ee980054eb23a523875c1d22929a2ac05d89b5428e1fd12800f54fc69baf41014667b87e2368e2355ee2a3140d3e3d7d5a1f8638b07cfefd7fe38a149e3f6 languageName: node linkType: hard -"chai-datetime@npm:^1.8.0": - version: 1.8.0 - resolution: "chai-datetime@npm:1.8.0" +"chai-datetime@npm:^1.8.1": + version: 1.8.1 + resolution: "chai-datetime@npm:1.8.1" dependencies: chai: ">1.9.0" - checksum: 37752addc6de4134117342609be85292dcd21cc0ec40b9ed2415c06d75c3a3b4a6d39fe6a675229a973f374abcaf5d2b9ea4c0d88d75508d1ddc641b509aafb0 + checksum: 29d3320a18c5e809e198cc7ed20ebf053eef4081f64a43e91eb388dafe8ad6f3d560fde478d9f599f35be75a95fb33ed40ff22aa9f05f3c047b1b7df2176cb24 languageName: node linkType: hard @@ -18920,10 +19198,10 @@ __metadata: languageName: node linkType: hard -"codemirror@npm:^5.65.15": - version: 5.65.15 - resolution: "codemirror@npm:5.65.15" - checksum: 30e0cff9bfb2265b94fa6766e13975cb71db228e114d6d8cdcc160b495e32b0ff921ac09959715e3fef30a48c5a9d0655ffd0ff6c5fe7024656add438bb2b058 +"codemirror@npm:^5.65.17": + version: 5.65.17 + resolution: "codemirror@npm:5.65.17" + checksum: 8bc853524c6416826364d776b012f488b3f4736899e5c8026062f43927e09de773051dd1b34e8cfd25642d7e358679ca5b113f0034fdd6a295f4193b04f8c528 languageName: node linkType: hard @@ -19590,7 +19868,7 @@ __metadata: languageName: node linkType: hard -"create-ecdh@npm:^4.0.0": +"create-ecdh@npm:^4.0.0, create-ecdh@npm:^4.0.4": version: 4.0.4 resolution: "create-ecdh@npm:4.0.4" dependencies: @@ -19764,7 +20042,7 @@ __metadata: languageName: node linkType: hard -"crypto-browserify@npm:^3.11.0, crypto-browserify@npm:^3.12.0": +"crypto-browserify@npm:^3.11.0": version: 3.12.0 resolution: "crypto-browserify@npm:3.12.0" dependencies: @@ -19947,13 +20225,13 @@ __metadata: languageName: node linkType: hard -"css-vars-ponyfill@npm:^2.4.8": - version: 2.4.8 - resolution: "css-vars-ponyfill@npm:2.4.8" +"css-vars-ponyfill@npm:^2.4.9": + version: 2.4.9 + resolution: "css-vars-ponyfill@npm:2.4.9" dependencies: balanced-match: ^1.0.2 get-css-data: ^2.0.2 - checksum: ea2e270455d039d4b9a34e7a9c0264052c0c9d832538123afce7766cfe833b7c149406d5d984a406ad401d9b7e0115fdbac029321214d49ebe88cd743d055899 + checksum: 0535b54e42ddd9aa7fcda42db98e828c3cab58ffa6d69325d3fe794d3ec3f9bd6f03bdc870a183890a7e6f1fe2b2ef85b1e13431724a0703bb047c98ee083ffc languageName: node linkType: hard @@ -21124,7 +21402,7 @@ __metadata: languageName: node linkType: hard -"diffie-hellman@npm:^5.0.0": +"diffie-hellman@npm:^5.0.0, diffie-hellman@npm:^5.0.3": version: 5.0.3 resolution: "diffie-hellman@npm:5.0.3" dependencies: @@ -21176,12 +21454,12 @@ __metadata: languageName: node linkType: hard -"docker-compose@npm:^0.24.3": - version: 0.24.3 - resolution: "docker-compose@npm:0.24.3" +"docker-compose@npm:^0.24.8": + version: 0.24.8 + resolution: "docker-compose@npm:0.24.8" dependencies: yaml: ^2.2.2 - checksum: b2149eafb6e0a37ff4595044fe63d2fac23483afab06bca71cece78df4bae6f796b0a123854957addda77cc0559f205bc03cf3984ced816161e30e7f247d88e7 + checksum: 48f3564c46490f1f51899a144deb546b61450a76bffddb378379ac7702aa34b055e0237e0dc77507df94d7ad6f1f7daeeac27730230bce9aafe2e35efeda6b45 languageName: node linkType: hard @@ -21283,10 +21561,10 @@ __metadata: languageName: node linkType: hard -"domain-browser@npm:^4.22.0": - version: 4.22.0 - resolution: "domain-browser@npm:4.22.0" - checksum: e7ce1c19073e17dec35cfde050a3ddaac437d3ba8b870adabf9d5682e665eab3084df05de432dedf25b34303f0a2c71ac30f1cdba61b1aea018047b10de3d988 +"domain-browser@npm:^4.23.0": + version: 4.23.0 + resolution: "domain-browser@npm:4.23.0" + checksum: 95b772f5fa88300240694380e06e03868573acdf86ca392a58c78602d6536dca2097ad2469a1500bd23a1329b09992de846e0b66c364cbf5711a7fee3ee5dac9 languageName: node linkType: hard @@ -21600,7 +21878,7 @@ __metadata: languageName: node linkType: hard -"elliptic@npm:^6.5.3, elliptic@npm:^6.5.4": +"elliptic@npm:^6.5.3": version: 6.5.4 resolution: "elliptic@npm:6.5.4" dependencies: @@ -21615,6 +21893,21 @@ __metadata: languageName: node linkType: hard +"elliptic@npm:^6.5.5, elliptic@npm:^6.5.7": + version: 6.5.7 + resolution: "elliptic@npm:6.5.7" + dependencies: + bn.js: ^4.11.9 + brorand: ^1.1.0 + hash.js: ^1.0.0 + hmac-drbg: ^1.0.1 + inherits: ^2.0.4 + minimalistic-assert: ^1.0.1 + minimalistic-crypto-utils: ^1.0.1 + checksum: af0ffddffdbc2fea4eeec74388cd73e62ed5a0eac6711568fb28071566319785df529c968b0bf1250ba4bc628e074b2d64c54a633e034aa6f0c6b152ceb49ab8 + languageName: node + linkType: hard + "email-validator@npm:^2.0.4": version: 2.0.4 resolution: "email-validator@npm:2.0.4" @@ -22083,13 +22376,6 @@ __metadata: languageName: node linkType: hard -"es6-object-assign@npm:^1.1.0": - version: 1.1.0 - resolution: "es6-object-assign@npm:1.1.0" - checksum: 8d4fdf63484d78b5c64cacc2c2e1165bc7b6a64b739d2a9db6a4dc8641d99cc9efb433cdd4dc3d3d6b00bfa6ce959694e4665e3255190339945c5f33b692b5d8 - languageName: node - linkType: hard - "es6-shim@npm:^0.35.5": version: 0.35.6 resolution: "es6-shim@npm:0.35.6" @@ -22481,21 +22767,21 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^4.6.0, eslint-plugin-react-hooks@npm:~4.6.0": - version: 4.6.0 - resolution: "eslint-plugin-react-hooks@npm:4.6.0" +"eslint-plugin-react-hooks@npm:^4.6.2, eslint-plugin-react-hooks@npm:~4.6.2": + version: 4.6.2 + resolution: "eslint-plugin-react-hooks@npm:4.6.2" peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 23001801f14c1d16bf0a837ca7970d9dd94e7b560384b41db378b49b6e32dc43d6e2790de1bd737a652a86f81a08d6a91f402525061b47719328f586a57e86c3 + checksum: 395c433610f59577cfcf3f2e42bcb130436c8a0b3777ac64f441d88c5275f4fcfc89094cedab270f2822daf29af1079151a7a6579a8e9ea8cee66540ba0384c4 languageName: node linkType: hard -"eslint-plugin-react-refresh@npm:^0.4.4": - version: 0.4.4 - resolution: "eslint-plugin-react-refresh@npm:0.4.4" +"eslint-plugin-react-refresh@npm:^0.4.11": + version: 0.4.11 + resolution: "eslint-plugin-react-refresh@npm:0.4.11" peerDependencies: eslint: ">=7" - checksum: 6b93f43cef5f69c18751db3267ce6cc7cb88f07061df28fc12401be56d93f37134f2a794c760f51cd5f84c5e81d81b003ef761ca76e7674646808b82884aa356 + checksum: 55c9efb14c3dadf6422bb96af8a561d3f1385f1dc68e7ca9d388cc4adc69907644e1bb509ecfbb033a8ec19ea326beb99577c82d4a2530000809d897b08bf3d4 languageName: node linkType: hard @@ -23260,7 +23546,7 @@ __metadata: languageName: node linkType: hard -"fast-fifo@npm:^1.1.0, fast-fifo@npm:^1.2.0": +"fast-fifo@npm:^1.1.0, fast-fifo@npm:^1.2.0, fast-fifo@npm:^1.3.2": version: 1.3.2 resolution: "fast-fifo@npm:1.3.2" checksum: 6bfcba3e4df5af7be3332703b69a7898a8ed7020837ec4395bb341bd96cc3a6d86c3f6071dd98da289618cf2234c70d84b2a6f09a33dd6f988b1ff60d8e54275 @@ -23392,10 +23678,10 @@ __metadata: languageName: node linkType: hard -"fastest-validator@npm:^1.17.0": - version: 1.17.0 - resolution: "fastest-validator@npm:1.17.0" - checksum: 0a6240f6dc7b544b3aadf9367410ecd64590dbfe505e6a24c339df954dd216f3a714d64a224abeef531d0a40dc348efe6cdbf59372d28954ac450cc0b212e0ec +"fastest-validator@npm:^1.19.0": + version: 1.19.0 + resolution: "fastest-validator@npm:1.19.0" + checksum: 93a52bcfb9cd3e6117de3ce4c975d182d9870496f2bddc2a71a53d5894ad536c21c62497f120c8d5e396b2312070b8c03acbefdfca32c081d524618ac2ee01a8 languageName: node linkType: hard @@ -23915,7 +24201,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.10.0, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.4, follow-redirects@npm:^1.14.7, follow-redirects@npm:^1.14.8, follow-redirects@npm:^1.14.9, follow-redirects@npm:^1.15.2": +"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.10.0, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.4, follow-redirects@npm:^1.14.7, follow-redirects@npm:^1.14.8, follow-redirects@npm:^1.14.9": version: 1.15.4 resolution: "follow-redirects@npm:1.15.4" peerDependenciesMeta: @@ -23925,6 +24211,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.15.6": + version: 1.15.9 + resolution: "follow-redirects@npm:1.15.9" + peerDependenciesMeta: + debug: + optional: true + checksum: 859e2bacc7a54506f2bf9aacb10d165df78c8c1b0ceb8023f966621b233717dab56e8d08baadc3ad3b9db58af290413d585c999694b7c146aaf2616340c3d2a6 + languageName: node + linkType: hard + "fontkit@npm:^2.0.2": version: 2.0.2 resolution: "fontkit@npm:2.0.2" @@ -24387,6 +24683,17 @@ __metadata: languageName: node linkType: hard +"gc-stats@npm:^1.4.1": + version: 1.4.1 + resolution: "gc-stats@npm:1.4.1" + dependencies: + nan: ^2.18.0 + node-gyp: latest + node-gyp-build: ^4.8.0 + checksum: 81d9bfc884f1cdfcb4683d940eb52a0379cafba11ec2b993946463b6ca30350dcc77e8c62694b7d1ac81f71477f25a72d865181aa1e87368eb79500ebfbdfce0 + languageName: node + linkType: hard + "gcp-metadata@npm:^5.0.0": version: 5.0.0 resolution: "gcp-metadata@npm:5.0.0" @@ -24917,10 +25224,10 @@ __metadata: languageName: node linkType: hard -"google-libphonenumber@npm:^3.2.33": - version: 3.2.33 - resolution: "google-libphonenumber@npm:3.2.33" - checksum: d029c19c7278ac9acb446028c2e304df16341732905a0cf8a105ab595cb19c01456fd57d76e48a3220038044d8ce361edc539eea2bfd924ea36fb28178cf7dbe +"google-libphonenumber@npm:^3.2.38": + version: 3.2.38 + resolution: "google-libphonenumber@npm:3.2.38" + checksum: 5e30ced0399b3803e61d41c0f7a69e289baf0912568381a0f2f0a5f0e5d3403dd8a26dd758ecb52e56337d83f45865fb36c0d7bfec255868286f05cc03a6b920 languageName: node linkType: hard @@ -25288,6 +25595,16 @@ __metadata: languageName: node linkType: hard +"hash-base@npm:~3.0, hash-base@npm:~3.0.4": + version: 3.0.4 + resolution: "hash-base@npm:3.0.4" + dependencies: + inherits: ^2.0.1 + safe-buffer: ^5.0.1 + checksum: 878465a0dfcc33cce195c2804135352c590d6d10980adc91a9005fd377e77f2011256c2b7cfce472e3f2e92d561d1bf3228d2da06348a9017ce9a258b3b49764 + languageName: node + linkType: hard + "hash.js@npm:^1.0.0, hash.js@npm:^1.0.3, hash.js@npm:^1.1.7": version: 1.1.7 resolution: "hash.js@npm:1.1.7" @@ -26613,13 +26930,20 @@ __metadata: languageName: node linkType: hard -"ipaddr.js@npm:^2.0.1, ipaddr.js@npm:^2.1.0": +"ipaddr.js@npm:^2.0.1": version: 2.1.0 resolution: "ipaddr.js@npm:2.1.0" checksum: 807a054f2bd720c4d97ee479d6c9e865c233bea21f139fb8dabd5a35c4226d2621c42e07b4ad94ff3f82add926a607d8d9d37c625ad0319f0e08f9f2bd1968e2 languageName: node linkType: hard +"ipaddr.js@npm:^2.2.0": + version: 2.2.0 + resolution: "ipaddr.js@npm:2.2.0" + checksum: 770ba8451fd9bf78015e8edac0d5abd7a708cbf75f9429ca9147a9d2f3a2d60767cd5de2aab2b1e13ca6e4445bdeff42bf12ef6f151c07a5c6cf8a44328e2859 + languageName: node + linkType: hard + "is-absolute-url@npm:^2.0.0": version: 2.1.0 resolution: "is-absolute-url@npm:2.1.0" @@ -27117,7 +27441,7 @@ __metadata: languageName: node linkType: hard -"is-nan@npm:^1.2.1": +"is-nan@npm:^1.3.2": version: 1.3.2 resolution: "is-nan@npm:1.3.2" dependencies: @@ -28849,14 +29173,14 @@ __metadata: languageName: node linkType: hard -"katex@npm:~0.16.9": - version: 0.16.9 - resolution: "katex@npm:0.16.9" +"katex@npm:~0.16.11": + version: 0.16.11 + resolution: "katex@npm:0.16.11" dependencies: commander: ^8.3.0 bin: katex: cli.js - checksum: 861194dfd4d86505e657f688fb73048d46ac498edafce71199502a35b03c0ecc35ba930c631be79c4a09d90a0d23476673cd52f6bc367c7a161854d64005fa95 + checksum: 49d9340705f4922ee22aacedad45664971449e5ca65e42a70228961336c8d4746c37c3c719bcc2114b6ad21182800c7d3d8bea28fe6f951fc45fe7e8322ea3bd languageName: node linkType: hard @@ -30309,35 +30633,35 @@ __metadata: languageName: node linkType: hard -"meteor-node-stubs@npm:^1.2.5": - version: 1.2.5 - resolution: "meteor-node-stubs@npm:1.2.5" +"meteor-node-stubs@npm:^1.2.10": + version: 1.2.10 + resolution: "meteor-node-stubs@npm:1.2.10" dependencies: - assert: ^2.0.0 + "@meteorjs/crypto-browserify": ^3.12.1 + assert: ^2.1.0 browserify-zlib: ^0.2.0 buffer: ^5.7.1 console-browserify: ^1.2.0 constants-browserify: ^1.0.0 - crypto-browserify: ^3.12.0 - domain-browser: ^4.22.0 - elliptic: ^6.5.4 + domain-browser: ^4.23.0 + elliptic: ^6.5.7 events: ^3.3.0 https-browserify: ^1.0.0 os-browserify: ^0.3.0 - path-browserify: ^1.0.0 + path-browserify: ^1.0.1 process: ^0.11.10 punycode: ^1.4.1 querystring-es3: ^0.2.1 - readable-stream: ^3.6.0 + readable-stream: ^3.6.2 stream-browserify: ^3.0.0 stream-http: ^3.2.0 string_decoder: ^1.3.0 timers-browserify: ^2.0.12 tty-browserify: 0.0.1 - url: ^0.11.0 - util: ^0.12.4 + url: ^0.11.4 + util: ^0.12.5 vm-browserify: ^1.1.2 - checksum: 2529bce377342b2c01f97c397fe89490fce0149ecb37dba1b18d2f865753a25addea2c16dd212afcaa6b9aa01abec52c90721b65653d15ff59708d5bd9adef15 + checksum: ce0e49991b2afba48dea0c5699bebb40502d8e775a486d4dca0f004432063ab56ceae2c4d22d8448d669edcb9cfcd7cb82e7a351b301b59f563ef4067daedf7c languageName: node linkType: hard @@ -30869,15 +31193,104 @@ __metadata: languageName: node linkType: hard -"moleculer@npm:^0.14.31": - version: 0.14.31 - resolution: "moleculer@npm:0.14.31" +"moleculer@npm:0.14.34": + version: 0.14.34 + resolution: "moleculer@npm:0.14.34" + dependencies: + args: ^5.0.3 + eventemitter2: ^6.4.9 + fastest-validator: ^1.19.0 + glob: ^7.2.0 + ipaddr.js: ^2.2.0 + kleur: ^4.1.5 + lodash: ^4.17.21 + lru-cache: ^6.0.0 + node-fetch: ^2.6.7 + recursive-watch: ^1.1.4 + peerDependencies: + amqplib: ^0.7.0 || ^0.8.0 || ^0.9.0 || ^0.10.0 + avsc: ^5.0.0 + bunyan: ^1.0.0 + cbor-x: ^0.8.3 || ^0.9.0 || ^1.2.0 + dd-trace: ^0.33.0 || ^0.34.0 || ^0.35.0 || ^0.36.0 || >=1.0.0 <1.6.0 + debug: ^4.0.0 + etcd3: ^1.0.0 + ioredis: ^4.0.0 || ^5.0.0 + jaeger-client: ^3.0.0 + kafka-node: ^5.0.0 + log4js: ^6.0.0 + mqtt: ^4.0.0 || ^5.0.0 + msgpack5: ^5.0.0 || ^6.0.0 + nats: ^1.0.0 || ^2.0.0 + node-nats-streaming: ^0.0.51 || ^0.2.0 || ^0.3.0 + notepack.io: ^2.0.0 || ^3.0.0 + pino: ^6.0.0 || ^7.0.0 || ^8.0.0 + protobufjs: ^6.0.0 || ^7.0.0 + redlock: ^4.0.0 + rhea-promise: ^1.0.0 || ^2.0.0 + thrift: ^0.12.0 || ^0.16.0 + winston: ^3.0.0 + peerDependenciesMeta: + amqplib: + optional: true + avsc: + optional: true + bunyan: + optional: true + cbor-x: + optional: true + dd-trace: + optional: true + debug: + optional: true + etcd3: + optional: true + ioredis: + optional: true + jaeger-client: + optional: true + kafka-node: + optional: true + log4js: + optional: true + mqtt: + optional: true + msgpack5: + optional: true + nats: + optional: true + node-nats-streaming: + optional: true + notepack.io: + optional: true + pino: + optional: true + protobufjs: + optional: true + redlock: + optional: true + rhea-promise: + optional: true + thrift: + optional: true + winston: + optional: true + bin: + moleculer-runner: bin/moleculer-runner.js + moleculer-runner-esm: bin/moleculer-runner.mjs + checksum: 2f20a28d4796be8b5837ee963e2323ab13dc30064f0c9126dcc04b2969586a1b43c92d875349dc9cc0b36170d8dd640ddf843d022c6b6c803bc84216ec4fa7d9 + languageName: node + linkType: hard + +"moleculer@patch:moleculer@npm%3A0.14.34#./.yarn/patches/moleculer-npm-0.14.34-440e26767d.patch::locator=rocket.chat%40workspace%3A.": + version: 0.14.34 + resolution: "moleculer@patch:moleculer@npm%3A0.14.34#./.yarn/patches/moleculer-npm-0.14.34-440e26767d.patch::version=0.14.34&hash=e1c8f3&locator=rocket.chat%40workspace%3A." dependencies: args: ^5.0.3 eventemitter2: ^6.4.9 - fastest-validator: ^1.17.0 + fastest-validator: ^1.19.0 glob: ^7.2.0 - ipaddr.js: ^2.1.0 + ipaddr.js: ^2.2.0 kleur: ^4.1.5 lodash: ^4.17.21 lru-cache: ^6.0.0 @@ -30895,7 +31308,7 @@ __metadata: jaeger-client: ^3.0.0 kafka-node: ^5.0.0 log4js: ^6.0.0 - mqtt: ^4.0.0 + mqtt: ^4.0.0 || ^5.0.0 msgpack5: ^5.0.0 || ^6.0.0 nats: ^1.0.0 || ^2.0.0 node-nats-streaming: ^0.0.51 || ^0.2.0 || ^0.3.0 @@ -30954,11 +31367,11 @@ __metadata: bin: moleculer-runner: bin/moleculer-runner.js moleculer-runner-esm: bin/moleculer-runner.mjs - checksum: 4d6d05f98e2174b708de8c946901a4a3a1de411505f43909216a9d2ff93820e6eec7edd44b45c99ab04c6c312304a63a346288e181fead48558763fb4ec69c24 + checksum: a5aea2d8fd0cb1b79a64bd67e3e0ebe1d023f66bf268391124968866ca48d305853b9635e92b5e64420ed4bc4625e50a70d505255eede839d4bab1734aa7db91 languageName: node linkType: hard -"moment-timezone@npm:*, moment-timezone@npm:^0.5.43, moment-timezone@npm:^0.5.x, moment-timezone@npm:~0.5.43": +"moment-timezone@npm:*, moment-timezone@npm:^0.5.x": version: 0.5.43 resolution: "moment-timezone@npm:0.5.43" dependencies: @@ -30967,6 +31380,15 @@ __metadata: languageName: node linkType: hard +"moment-timezone@npm:^0.5.45, moment-timezone@npm:~0.5.45": + version: 0.5.45 + resolution: "moment-timezone@npm:0.5.45" + dependencies: + moment: ^2.29.4 + checksum: a22e9f983fbe1a01757ce30685bce92e3f6efa692eb682afd47b82da3ff960b3c8c2c3883ec6715c124bc985a342b57cba1f6ba25a1c8b4c7ad766db3cd5e1d0 + languageName: node + linkType: hard + "moment@npm:^2.10.2, moment@npm:^2.29.1, moment@npm:^2.29.4": version: 2.29.4 resolution: "moment@npm:2.29.4" @@ -31136,6 +31558,15 @@ __metadata: languageName: node linkType: hard +"nan@npm:^2.18.0": + version: 2.20.0 + resolution: "nan@npm:2.20.0" + dependencies: + node-gyp: latest + checksum: eb09286e6c238a3582db4d88c875db73e9b5ab35f60306090acd2f3acae21696c9b653368b4a0e32abcef64ee304a923d6223acaddd16169e5eaaf5c508fb533 + languageName: node + linkType: hard + "nanoid@npm:3.3.1": version: 3.3.1 resolution: "nanoid@npm:3.3.1" @@ -31154,6 +31585,15 @@ __metadata: languageName: node linkType: hard +"nanoid@npm:^3.3.7": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" + bin: + nanoid: bin/nanoid.cjs + checksum: d36c427e530713e4ac6567d488b489a36582ef89da1d6d4e3b87eded11eb10d7042a877958c6f104929809b2ab0bafa17652b076cdf84324aa75b30b722204f2 + languageName: node + linkType: hard + "nanomatch@npm:^1.2.9": version: 1.2.13 resolution: "nanomatch@npm:1.2.13" @@ -31412,7 +31852,7 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2, node-fetch@npm:^2.6.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.11, node-fetch@npm:^2.6.7": +"node-fetch@npm:^2.6.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.11, node-fetch@npm:^2.6.7, node-fetch@npm:^2.7.0": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" dependencies: @@ -31462,6 +31902,17 @@ __metadata: languageName: node linkType: hard +"node-gyp-build@npm:^4.8.0": + version: 4.8.2 + resolution: "node-gyp-build@npm:4.8.2" + bin: + node-gyp-build: bin.js + node-gyp-build-optional: optional.js + node-gyp-build-test: build-test.js + checksum: 1a57bba8c4c193f808bd8ad1484d4ebdd8106dd9f04a3e82554dc716e3a2d87d7e369e9503c145e0e6a7e2c663fec0d8aaf52bd8156342ec7fc388195f37824e + languageName: node + linkType: hard + "node-gyp@npm:^9.4.1": version: 9.4.1 resolution: "node-gyp@npm:9.4.1" @@ -31988,7 +32439,7 @@ __metadata: languageName: node linkType: hard -"object-is@npm:^1.0.1, object-is@npm:^1.1.5": +"object-is@npm:^1.1.5": version: 1.1.6 resolution: "object-is@npm:1.1.6" dependencies: @@ -32734,6 +33185,20 @@ __metadata: languageName: node linkType: hard +"parse-asn1@npm:^5.1.7": + version: 5.1.7 + resolution: "parse-asn1@npm:5.1.7" + dependencies: + asn1.js: ^4.10.1 + browserify-aes: ^1.2.0 + evp_bytestokey: ^1.0.3 + hash-base: ~3.0 + pbkdf2: ^3.1.2 + safe-buffer: ^5.2.1 + checksum: 93c7194c1ed63a13e0b212d854b5213ad1aca0ace41c66b311e97cca0519cf9240f79435a0306a3b412c257f0ea3f1953fd0d9549419a0952c9e995ab361fd6c + languageName: node + linkType: hard + "parse-entities@npm:^2.0.0": version: 2.0.0 resolution: "parse-entities@npm:2.0.0" @@ -32859,7 +33324,7 @@ __metadata: languageName: node linkType: hard -"path-browserify@npm:^1.0.0, path-browserify@npm:^1.0.1": +"path-browserify@npm:^1.0.1": version: 1.0.1 resolution: "path-browserify@npm:1.0.1" checksum: c6d7fa376423fe35b95b2d67990060c3ee304fc815ff0a2dc1c6c3cfaff2bd0d572ee67e18f19d0ea3bbe32e8add2a05021132ac40509416459fffee35200699 @@ -33056,7 +33521,7 @@ __metadata: languageName: node linkType: hard -"pbkdf2@npm:^3.0.3": +"pbkdf2@npm:^3.0.3, pbkdf2@npm:^3.1.2": version: 3.1.2 resolution: "pbkdf2@npm:3.1.2" dependencies: @@ -33131,6 +33596,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.0.1": + version: 1.1.0 + resolution: "picocolors@npm:1.1.0" + checksum: a64d653d3a188119ff45781dfcdaeedd7625583f45280aea33fcb032c7a0d3959f2368f9b192ad5e8aade75b74dbd954ffe3106c158509a45e4c18ab379a2acd + languageName: node + linkType: hard + "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.3, picomatch@npm:^2.3.0, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" @@ -33325,14 +33797,14 @@ __metadata: languageName: node linkType: hard -"playwright-qase-reporter@npm:^1.2.1": - version: 1.2.1 - resolution: "playwright-qase-reporter@npm:1.2.1" +"playwright-qase-reporter@npm:^1.2.2": + version: 1.2.2 + resolution: "playwright-qase-reporter@npm:1.2.2" dependencies: chalk: ^4.1.0 form-data: ^3.0.0 qaseio: ^2.0.2 - checksum: 8b4d2f5902a8d655b781e9dd6898d5d2f25739033f1fda2b600b07ac3fc7680f9a1ee917a969b7315f4f05211e36f1a6699155f9ead05a435afa695932bde9fa + checksum: c2d7c5e990357b5cc029d51179ca2af7b61fb7d871eeea05e78300749e7829ca5dd9eef00820ec45422b5036a06a3fa383c76b1dda052aadd490fdd66d6ffe15 languageName: node linkType: hard @@ -34223,7 +34695,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.2.15, postcss@npm:^8.3.11, postcss@npm:^8.4.14, postcss@npm:^8.4.23, postcss@npm:~8.4.31": +"postcss@npm:^8.2.15, postcss@npm:^8.3.11, postcss@npm:^8.4.14, postcss@npm:^8.4.23": version: 8.4.31 resolution: "postcss@npm:8.4.31" dependencies: @@ -34234,6 +34706,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:~8.4.45": + version: 8.4.45 + resolution: "postcss@npm:8.4.45" + dependencies: + nanoid: ^3.3.7 + picocolors: ^1.0.1 + source-map-js: ^1.2.0 + checksum: 3223cdad4a9392c0b334ee3ee7e4e8041c631cb6160609cef83c18d2b2580e931dd8068ab13cc6000c1a254d57492ac6c38717efc397c5dcc9756d06bc9c44f3 + languageName: node + linkType: hard + "postis@npm:^2.2.0": version: 2.2.0 resolution: "postis@npm:2.2.0" @@ -34367,7 +34850,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^2.7.1, prettier@npm:^2.8.4, prettier@npm:~2.8.7, prettier@npm:~2.8.8": +"prettier@npm:^2.7.1, prettier@npm:^2.8.4, prettier@npm:~2.8.8": version: 2.8.8 resolution: "prettier@npm:2.8.8" bin: @@ -34692,7 +35175,7 @@ __metadata: languageName: node linkType: hard -"public-encrypt@npm:^4.0.0": +"public-encrypt@npm:^4.0.0, public-encrypt@npm:^4.0.3": version: 4.0.3 resolution: "public-encrypt@npm:4.0.3" dependencies: @@ -34802,6 +35285,15 @@ __metadata: languageName: node linkType: hard +"qs@npm:6.13.0, qs@npm:^6.12.3": + version: 6.13.0 + resolution: "qs@npm:6.13.0" + dependencies: + side-channel: ^1.0.6 + checksum: e9404dc0fc2849245107108ce9ec2766cde3be1b271de0bf1021d049dc5b98d1a2901e67b431ac5509f865420a7ed80b7acb3980099fe1c118a1c5d2e1432ad8 + languageName: node + linkType: hard + "qs@npm:6.9.3": version: 6.9.3 resolution: "qs@npm:6.9.3" @@ -34986,7 +35478,7 @@ __metadata: languageName: node linkType: hard -"randomfill@npm:^1.0.3": +"randomfill@npm:^1.0.3, randomfill@npm:^1.0.4": version: 1.0.4 resolution: "randomfill@npm:1.0.4" dependencies: @@ -35146,13 +35638,13 @@ __metadata: languageName: node linkType: hard -"re-resizable@npm:^6.9.9": - version: 6.9.9 - resolution: "re-resizable@npm:6.9.9" +"re-resizable@npm:^6.9.18": + version: 6.9.18 + resolution: "re-resizable@npm:6.9.18" peerDependencies: react: ^16.13.1 || ^17.0.0 || ^18.0.0 react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - checksum: a2c8bfe86646fb02d5c9c624b1da26f9e6a5e2f552cd96ce4db690588bee6b21177065ce8e98646c6ca0b1a9c4ce233824b75eb346800d8248ac8a87b40f1b28 + checksum: 46ef26f45d4bf37f4db0d0758fdc0a1b97b29398ac0e8404c556118e15b5df7f47dba2acd60f9e4a9cc66ed536b9566c71d7fc0d2f9bf939609a3016da30704d languageName: node linkType: hard @@ -35219,21 +35711,20 @@ __metadata: languageName: node linkType: hard -"react-docgen-typescript-plugin@npm:^1.0.5, react-docgen-typescript-plugin@npm:~1.0.5": - version: 1.0.5 - resolution: "react-docgen-typescript-plugin@npm:1.0.5" +"react-docgen-typescript-plugin@npm:^1.0.8, react-docgen-typescript-plugin@npm:~1.0.8": + version: 1.0.8 + resolution: "react-docgen-typescript-plugin@npm:1.0.8" dependencies: debug: ^4.1.1 - endent: ^2.0.1 find-cache-dir: ^3.3.1 flat-cache: ^3.0.4 micromatch: ^4.0.2 react-docgen-typescript: ^2.2.2 - tslib: ^2.0.0 + tslib: ^2.6.2 peerDependencies: typescript: ">= 4.x" webpack: ">= 4" - checksum: 0f83d33c7b6dc82fef34ee820c94485c374d853774c5c26b04754ba3674fe4db2c7fc210b30fa0ca77c5033633553c12742aab6305a7f16cd263c70fedf27589 + checksum: c4fe1ae821be97270de370257747ec4f927f8ee291599f0e67b8bb13ba343da79894ac84a2836af428f877e88d1d96edbef6ee808ed23ecdb4b230fe4f268f1e languageName: node linkType: hard @@ -35833,6 +36324,21 @@ __metadata: languageName: node linkType: hard +"readable-stream@npm:^2.3.8": + version: 2.3.8 + resolution: "readable-stream@npm:2.3.8" + dependencies: + core-util-is: ~1.0.0 + inherits: ~2.0.3 + isarray: ~1.0.0 + process-nextick-args: ~2.0.0 + safe-buffer: ~5.1.1 + string_decoder: ~1.1.1 + util-deprecate: ~1.0.1 + checksum: 65645467038704f0c8aaf026a72fbb588a9e2ef7a75cd57a01702ee9db1c4a1e4b03aaad36861a6a0926546a74d174149c8c207527963e0c2d3eee2f37678a42 + languageName: node + linkType: hard + "readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": version: 3.6.0 resolution: "readable-stream@npm:3.6.0" @@ -35844,6 +36350,17 @@ __metadata: languageName: node linkType: hard +"readable-stream@npm:^3.6.2": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: ^2.0.3 + string_decoder: ^1.1.1 + util-deprecate: ^1.0.1 + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + languageName: node + linkType: hard + "readable-stream@npm:^4.0.0": version: 4.1.0 resolution: "readable-stream@npm:4.1.0" @@ -36670,11 +37187,11 @@ __metadata: resolution: "rocket.chat@workspace:." dependencies: "@changesets/cli": ^2.26.2 - "@types/chart.js": ^2.9.39 - "@types/js-yaml": ^4.0.8 + "@types/chart.js": ^2.9.41 + "@types/js-yaml": ^4.0.9 node-gyp: ^9.4.1 ts-node: ^10.9.2 - turbo: latest + turbo: ^2.1.2 languageName: unknown linkType: soft @@ -36693,16 +37210,16 @@ __metadata: "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 "@rocket.chat/ui-kit": "workspace:~" - "@types/cookie": ^0.5.3 - "@types/cookie-parser": ^1.4.5 - "@types/ejson": ^2.2.1 - "@types/express": ^4.17.20 - "@types/fibers": ^3.1.3 + "@types/cookie": ^0.5.4 + "@types/cookie-parser": ^1.4.7 + "@types/ejson": ^2.2.2 + "@types/express": ^4.17.21 + "@types/fibers": ^3.1.4 "@types/node": ^14.18.63 - "@types/ws": ^8.5.8 + "@types/ws": ^8.5.12 ajv: ^8.11.0 bcrypt: ^5.0.1 - body-parser: ^1.20.2 + body-parser: ^1.20.3 colorette: ^2.0.20 cookie: ^0.5.0 cookie-parser: ^1.4.6 @@ -36712,7 +37229,7 @@ __metadata: fibers: ^5.0.3 jaeger-client: ^3.19.0 mem: ^8.1.1 - moleculer: ^0.14.31 + moleculer: ^0.14.34 mongodb: ^4.17.2 nats: ^2.6.1 npm-run-all: ^4.1.5 @@ -36721,7 +37238,7 @@ __metadata: pm2: ^5.2.0 sodium-native: ^3.3.0 sodium-plus: ^0.9.0 - ts-node: ^10.9.1 + ts-node: ^10.9.2 typescript: ~5.5.4 uuid: ^8.3.2 ws: ^8.8.1 @@ -37562,6 +38079,18 @@ __metadata: languageName: node linkType: hard +"side-channel@npm:^1.0.6": + version: 1.0.6 + resolution: "side-channel@npm:1.0.6" + dependencies: + call-bind: ^1.0.7 + es-errors: ^1.3.0 + get-intrinsic: ^1.2.4 + object-inspect: ^1.13.1 + checksum: bfc1afc1827d712271453e91b7cd3878ac0efd767495fd4e594c4c2afaa7963b7b510e249572bfd54b0527e66e4a12b61b80c061389e129755f34c493aad9b97 + languageName: node + linkType: hard + "signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" @@ -37877,6 +38406,13 @@ __metadata: languageName: node linkType: hard +"source-map-js@npm:^1.2.0": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 4eb0cd997cdf228bc253bcaff9340afeb706176e64868ecd20efbe6efea931465f43955612346d6b7318789e5265bdc419bc7669c1cebe3db0eb255f57efa76b + languageName: node + linkType: hard + "source-map-resolve@npm:^0.5.0": version: 0.5.3 resolution: "source-map-resolve@npm:0.5.3" @@ -38282,15 +38818,15 @@ __metadata: languageName: node linkType: hard -"storybook-dark-mode@npm:~3.0.1": - version: 3.0.1 - resolution: "storybook-dark-mode@npm:3.0.1" +"storybook-dark-mode@npm:~3.0.3": + version: 3.0.3 + resolution: "storybook-dark-mode@npm:3.0.3" dependencies: "@storybook/addons": ^7.0.0 - "@storybook/api": ^7.0.0 "@storybook/components": ^7.0.0 "@storybook/core-events": ^7.0.0 "@storybook/global": ^5.0.0 + "@storybook/manager-api": ^7.0.0 "@storybook/theming": ^7.0.0 fast-deep-equal: ^3.1.3 memoizerific: ^1.11.3 @@ -38302,7 +38838,7 @@ __metadata: optional: true react-dom: optional: true - checksum: d04213c92e8a4af0035e80eb02b75b8da725ba7b1ecbfe050eb04cb4018d91394f08c8fe7c1b106c971b2047ef5a1ba776e78050ae1f6d7563cdfdba5e701a29 + checksum: 7db89470168e9d15f36c44554ddb80b5aeac7276664904adc7b2d1f1913a4a514b86769eb80d4fcc43070e75d4e79a53b2467e51d628298e2e35e3c47c30bc7f languageName: node linkType: hard @@ -38326,10 +38862,10 @@ __metadata: languageName: node linkType: hard -"stream-buffers@npm:^3.0.2": - version: 3.0.2 - resolution: "stream-buffers@npm:3.0.2" - checksum: b09fdeea606e3113ebd0e07010ed0cf038608fa396130add9e45deaff5cc3ba845dc25c31ad24f8341f85907846344cb7c85f75ea52c6572e2ac646e9b6072d0 +"stream-buffers@npm:^3.0.3": + version: 3.0.3 + resolution: "stream-buffers@npm:3.0.3" + checksum: 3f0bdc4b1fd3ff370cef5a2103dd930b8981d42d97741eeb087a660771e27f0fc35fa8a351bb36e15bbbbce0eea00fefed60d6cdff4c6c3f527580529f183807 languageName: node linkType: hard @@ -38419,6 +38955,21 @@ __metadata: languageName: node linkType: hard +"streamx@npm:^2.20.0": + version: 2.20.1 + resolution: "streamx@npm:2.20.1" + dependencies: + bare-events: ^2.2.0 + fast-fifo: ^1.3.2 + queue-tick: ^1.0.1 + text-decoder: ^1.1.0 + dependenciesMeta: + bare-events: + optional: true + checksum: 48605ddd3abdd86d2e3ee945ec7c9317f36abb5303347a8fff6e4c7926a72c33ec7ac86b50734ccd1cf65602b6a38e247966e8199b24e5a7485d9cec8f5327bd + languageName: node + linkType: hard + "strict-uri-encode@npm:^1.0.0": version: 1.1.0 resolution: "strict-uri-encode@npm:1.1.0" @@ -39174,7 +39725,7 @@ __metadata: languageName: node linkType: hard -"tar-fs@npm:^2.0.0, tar-fs@npm:^2.1.1": +"tar-fs@npm:^2.0.0": version: 2.1.1 resolution: "tar-fs@npm:2.1.1" dependencies: @@ -39197,6 +39748,23 @@ __metadata: languageName: node linkType: hard +"tar-fs@npm:^3.0.5": + version: 3.0.6 + resolution: "tar-fs@npm:3.0.6" + dependencies: + bare-fs: ^2.1.1 + bare-path: ^2.1.0 + pump: ^3.0.0 + tar-stream: ^3.1.5 + dependenciesMeta: + bare-fs: + optional: true + bare-path: + optional: true + checksum: b4fa09c70f75caf05bf5cf87369cd2862f1ac5fb75c4ddf9d25d55999f7736a94b58ad679d384196cba837c5f5ff14086e060fafccef5474a16e2d3058ffa488 + languageName: node + linkType: hard + "tar-stream@npm:^1.5.2, tar-stream@npm:^1.6.2": version: 1.6.2 resolution: "tar-stream@npm:1.6.2" @@ -39312,6 +39880,15 @@ __metadata: languageName: node linkType: hard +"telejson@npm:^7.2.0": + version: 7.2.0 + resolution: "telejson@npm:7.2.0" + dependencies: + memoizerific: ^1.11.3 + checksum: 55a3380c9ff3c5ad84581bb6bda28fc33c6b7c4a0c466894637da687639b8db0d21b0ff4c1bc1a7a92ae6b70662549d09e7b9e8b1ec334b2ef93078762ecdfb9 + languageName: node + linkType: hard + "temp-dir@npm:^1.0.0": version: 1.0.0 resolution: "temp-dir@npm:1.0.0" @@ -39467,6 +40044,15 @@ __metadata: languageName: node linkType: hard +"text-decoder@npm:^1.1.0": + version: 1.2.0 + resolution: "text-decoder@npm:1.2.0" + dependencies: + b4a: ^1.6.4 + checksum: 9f4c23900b42153af0e4a902577eba37cb70cd1d5b187732b81c74c705d3206952cf1dcecf97537794374f55aac6c547ac3860f1facc9560007ca9a06b0e309d + languageName: node + linkType: hard + "text-hex@npm:1.0.x": version: 1.0.0 resolution: "text-hex@npm:1.0.0" @@ -39876,7 +40462,7 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:~29.1.1": +"ts-jest@npm:~29.1.5": version: 29.1.5 resolution: "ts-jest@npm:29.1.5" dependencies: @@ -39912,7 +40498,7 @@ __metadata: languageName: node linkType: hard -"ts-loader@npm:~9.4.2": +"ts-loader@npm:~9.4.4": version: 9.4.4 resolution: "ts-loader@npm:9.4.4" dependencies: @@ -39927,7 +40513,7 @@ __metadata: languageName: node linkType: hard -"ts-node@npm:^10.9.1, ts-node@npm:^10.9.2, ts-node@npm:~10.9.1": +"ts-node@npm:^10.9.2, ts-node@npm:~10.9.2": version: 10.9.2 resolution: "ts-node@npm:10.9.2" dependencies: @@ -40032,6 +40618,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.6.2": + version: 2.7.0 + resolution: "tslib@npm:2.7.0" + checksum: 1606d5c89f88d466889def78653f3aab0f88692e80bb2066d090ca6112ae250ec1cfa9dbfaab0d17b60da15a4186e8ec4d893801c67896b277c17374e36e1d28 + languageName: node + linkType: hard + "tsscmp@npm:^1.0.6": version: 1.0.6 resolution: "tsscmp@npm:1.0.6" @@ -40104,58 +40697,58 @@ __metadata: languageName: node linkType: hard -"turbo-darwin-64@npm:2.0.11": - version: 2.0.11 - resolution: "turbo-darwin-64@npm:2.0.11" +"turbo-darwin-64@npm:2.1.2": + version: 2.1.2 + resolution: "turbo-darwin-64@npm:2.1.2" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"turbo-darwin-arm64@npm:2.0.11": - version: 2.0.11 - resolution: "turbo-darwin-arm64@npm:2.0.11" +"turbo-darwin-arm64@npm:2.1.2": + version: 2.1.2 + resolution: "turbo-darwin-arm64@npm:2.1.2" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"turbo-linux-64@npm:2.0.11": - version: 2.0.11 - resolution: "turbo-linux-64@npm:2.0.11" +"turbo-linux-64@npm:2.1.2": + version: 2.1.2 + resolution: "turbo-linux-64@npm:2.1.2" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"turbo-linux-arm64@npm:2.0.11": - version: 2.0.11 - resolution: "turbo-linux-arm64@npm:2.0.11" +"turbo-linux-arm64@npm:2.1.2": + version: 2.1.2 + resolution: "turbo-linux-arm64@npm:2.1.2" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"turbo-windows-64@npm:2.0.11": - version: 2.0.11 - resolution: "turbo-windows-64@npm:2.0.11" +"turbo-windows-64@npm:2.1.2": + version: 2.1.2 + resolution: "turbo-windows-64@npm:2.1.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"turbo-windows-arm64@npm:2.0.11": - version: 2.0.11 - resolution: "turbo-windows-arm64@npm:2.0.11" +"turbo-windows-arm64@npm:2.1.2": + version: 2.1.2 + resolution: "turbo-windows-arm64@npm:2.1.2" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"turbo@npm:latest": - version: 2.0.11 - resolution: "turbo@npm:2.0.11" - dependencies: - turbo-darwin-64: 2.0.11 - turbo-darwin-arm64: 2.0.11 - turbo-linux-64: 2.0.11 - turbo-linux-arm64: 2.0.11 - turbo-windows-64: 2.0.11 - turbo-windows-arm64: 2.0.11 +"turbo@npm:^2.1.2": + version: 2.1.2 + resolution: "turbo@npm:2.1.2" + dependencies: + turbo-darwin-64: 2.1.2 + turbo-darwin-arm64: 2.1.2 + turbo-linux-64: 2.1.2 + turbo-linux-arm64: 2.1.2 + turbo-windows-64: 2.1.2 + turbo-windows-arm64: 2.1.2 dependenciesMeta: turbo-darwin-64: optional: true @@ -40171,7 +40764,7 @@ __metadata: optional: true bin: turbo: bin/turbo - checksum: a2fcb17b2549102dcd912799319a5c31cbabc3fcb76241bac1d2231ee4e1911789cd4e6b4eb050f9e8548ef89143ee77be59eb35b1843cf12b42f136ef176a0c + checksum: ee3d12a69fa512d30b325369c49a490cd2112547a59aca7bd3c9407b12bd9bd9ffd682e801c1e2e5711669c155ef06b0a090b0bbffa84fd60ddc5df0a1c855e6 languageName: node linkType: hard @@ -40410,7 +41003,7 @@ __metadata: languageName: node linkType: hard -"typedoc@npm:~0.24.1": +"typedoc@npm:~0.24.8": version: 0.24.8 resolution: "typedoc@npm:0.24.8" dependencies: @@ -40480,10 +41073,10 @@ __metadata: languageName: node linkType: hard -"ua-parser-js@npm:^1.0.37": - version: 1.0.37 - resolution: "ua-parser-js@npm:1.0.37" - checksum: 4d481c720d523366d7762dc8a46a1b58967d979aacf786f9ceceb1cd767de069f64a4bdffb63956294f1c0696eb465ddb950f28ba90571709e33521b4bd75e07 +"ua-parser-js@npm:^1.0.38": + version: 1.0.38 + resolution: "ua-parser-js@npm:1.0.38" + checksum: d0772b22b027338d806ab17d1ac2896ee7485bdf9217c526028159f3cd6bb10272bb18f6196d2f94dde83e3b36dc9d2533daf08a414764f6f4f1844842383838 languageName: node linkType: hard @@ -40532,10 +41125,10 @@ __metadata: languageName: node linkType: hard -"underscore@npm:^1.13.6": - version: 1.13.6 - resolution: "underscore@npm:1.13.6" - checksum: d5cedd14a9d0d91dd38c1ce6169e4455bb931f0aaf354108e47bd46d3f2da7464d49b2171a5cf786d61963204a42d01ea1332a903b7342ad428deaafaf70ec36 +"underscore@npm:^1.13.7": + version: 1.13.7 + resolution: "underscore@npm:1.13.7" + checksum: 174b011af29e4fbe2c70eb2baa8bfab0d0336cf2f5654f364484967bc6264a86224d0134b9176e4235c8cceae00d11839f0fd4824268de04b11c78aca1241684 languageName: node linkType: hard @@ -41040,6 +41633,16 @@ __metadata: languageName: node linkType: hard +"url@npm:^0.11.4": + version: 0.11.4 + resolution: "url@npm:0.11.4" + dependencies: + punycode: ^1.4.1 + qs: ^6.12.3 + checksum: c25e587723d343d5d4248892393bfa5039ded9c2c07095a9d005bc64b7cb8956d623c0d8da8d1a28f71986a7a8d80fc2e9f9cf84235e48fa435a5cb4451062c6 + languageName: node + linkType: hard + "use-callback-ref@npm:^1.3.0": version: 1.3.0 resolution: "use-callback-ref@npm:1.3.0" @@ -41099,14 +41702,14 @@ __metadata: languageName: node linkType: hard -"use-subscription@npm:^1.8.0": - version: 1.8.0 - resolution: "use-subscription@npm:1.8.0" +"use-subscription@npm:^1.8.2": + version: 1.8.2 + resolution: "use-subscription@npm:1.8.2" dependencies: - use-sync-external-store: ^1.2.0 + use-sync-external-store: ^1.2.2 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: beac1f0ff14fe23fd6ae9c34681258936729f343bf6532bbce36caa8f4c1019ff380783e35b4aeb7f3faaec1a83af242d7833bf7e660816d24555dbdd2c934da + checksum: 6b17f92a75405a4e6015d7762b459a43435f34d0bb9a72e512e305d6d3a61bd170e6666c3a62c2c3c7af1b7ba0b45c5a597b7eeea54c46e1cabf8ef0f971d44e languageName: node linkType: hard @@ -41128,7 +41731,7 @@ __metadata: languageName: node linkType: hard -"use-sync-external-store@npm:^1.2.0, use-sync-external-store@npm:~1.2.0, use-sync-external-store@npm:~1.2.2": +"use-sync-external-store@npm:^1.2.0, use-sync-external-store@npm:^1.2.2, use-sync-external-store@npm:~1.2.0, use-sync-external-store@npm:~1.2.2": version: 1.2.2 resolution: "use-sync-external-store@npm:1.2.2" peerDependencies: @@ -41226,7 +41829,7 @@ __metadata: languageName: node linkType: hard -"util@npm:^0.12.0, util@npm:^0.12.4": +"util@npm:^0.12.4, util@npm:^0.12.5": version: 0.12.5 resolution: "util@npm:0.12.5" dependencies: @@ -41664,9 +42267,9 @@ __metadata: languageName: node linkType: hard -"webdav@npm:^4.11.3": - version: 4.11.3 - resolution: "webdav@npm:4.11.3" +"webdav@npm:^4.11.4": + version: 4.11.4 + resolution: "webdav@npm:4.11.4" dependencies: axios: ^0.27.2 base-64: ^1.0.0 @@ -41681,7 +42284,7 @@ __metadata: path-posix: ^1.0.0 url-join: ^4.0.1 url-parse: ^1.5.10 - checksum: e5bfc66149088cd857c23a3a549650d7483dd5615cf1c4b6251a5b290a4ad8fef4975bfd99fca2d5842a0eaadc056bc0044e37893e0ad5447e6ce2e2dbd81da5 + checksum: 941a8f239d483cc283b893132675746461fe42b0932afe81ee2cad36065aeb657d722813a34966f6c6f6e95e7058453a7869e238ae1e1d1d29df9a28508dee27 languageName: node linkType: hard @@ -41772,7 +42375,7 @@ __metadata: languageName: node linkType: hard -"webpack-cli@npm:~5.0.1": +"webpack-cli@npm:~5.0.2": version: 5.0.2 resolution: "webpack-cli@npm:5.0.2" dependencies: @@ -42166,10 +42769,10 @@ __metadata: languageName: node linkType: hard -"whatwg-fetch@npm:^3.6.19": - version: 3.6.19 - resolution: "whatwg-fetch@npm:3.6.19" - checksum: 2896bc9ca867ea514392c73e2a272f65d5c4916248fe0837a9df5b1b92f247047bc76cf7c29c28a01ac6c5fb4314021d2718958c8a08292a96d56f72b2f56806 +"whatwg-fetch@npm:^3.6.20": + version: 3.6.20 + resolution: "whatwg-fetch@npm:3.6.20" + checksum: c58851ea2c4efe5c2235f13450f426824cf0253c1d45da28f45900290ae602a20aff2ab43346f16ec58917d5562e159cd691efa368354b2e82918c2146a519c5 languageName: node linkType: hard From 2e10a451c4756f64978a0658e7ffff68a0691774 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Sat, 14 Sep 2024 09:05:11 -0300 Subject: [PATCH 082/170] ci: Include hidden files when uploading artifacts (#33286) --- .github/actions/meteor-build/action.yml | 1 + .github/workflows/ci-test-e2e.yml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.github/actions/meteor-build/action.yml b/.github/actions/meteor-build/action.yml index 525595146700..551a57d28a7c 100644 --- a/.github/actions/meteor-build/action.yml +++ b/.github/actions/meteor-build/action.yml @@ -133,3 +133,4 @@ runs: name: build path: /tmp/Rocket.Chat.tar.gz overwrite: true + include-hidden-files: true diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index e6c02b7b6417..3ed6f07e725d 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -293,6 +293,7 @@ jobs: with: name: playwright-test-trace-${{ matrix.mongodb-version }}-${{ matrix.shard }} path: ./apps/meteor/tests/e2e/.playwright* + include-hidden-files: true - name: Show server logs if E2E test failed if: failure() @@ -326,6 +327,7 @@ jobs: with: name: e2e-api-ee-coverage-${{ matrix.mongodb-version }}-${{ matrix.shard }} path: /tmp/coverage + include-hidden-files: true - name: Store e2e-ee-coverage if: inputs.type == 'ui' && inputs.release == 'ee' @@ -333,3 +335,4 @@ jobs: with: name: e2e-ee-coverage-${{ matrix.mongodb-version }}-${{ matrix.shard }} path: ./apps/meteor/coverage* + include-hidden-files: true From fad7f974c0fdfc5517adb389755f64eddff7c07b Mon Sep 17 00:00:00 2001 From: Rafael Tapia Date: Mon, 16 Sep 2024 10:42:54 -0300 Subject: [PATCH 083/170] feat: get contact by id endpoint (#33041) --- .../server/constant/permissions.ts | 4 ++ .../app/livechat/server/api/v1/contact.ts | 24 ++++++- .../tests/end-to-end/api/livechat/contacts.ts | 63 +++++++++++++++++++ packages/rest-typings/src/v1/omnichannel.ts | 18 ++++++ 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/authorization/server/constant/permissions.ts b/apps/meteor/app/authorization/server/constant/permissions.ts index e5e8f7fb05dd..46d40713bad1 100644 --- a/apps/meteor/app/authorization/server/constant/permissions.ts +++ b/apps/meteor/app/authorization/server/constant/permissions.ts @@ -101,6 +101,10 @@ export const permissions = [ _id: 'update-livechat-contact', roles: ['livechat-manager', 'livechat-monitor', 'livechat-agent', 'admin'], }, + { + _id: 'view-livechat-contact', + roles: ['livechat-manager', 'livechat-monitor', 'livechat-agent', 'admin'], + }, { _id: 'view-livechat-manager', roles: ['livechat-manager', 'livechat-monitor', 'admin'] }, { _id: 'view-omnichannel-contact-center', diff --git a/apps/meteor/app/livechat/server/api/v1/contact.ts b/apps/meteor/app/livechat/server/api/v1/contact.ts index 7e9457d2f185..f3fec80b23fe 100644 --- a/apps/meteor/app/livechat/server/api/v1/contact.ts +++ b/apps/meteor/app/livechat/server/api/v1/contact.ts @@ -1,5 +1,9 @@ -import { LivechatCustomField, LivechatVisitors } from '@rocket.chat/models'; -import { isPOSTOmnichannelContactsProps, isPOSTUpdateOmnichannelContactsProps } from '@rocket.chat/rest-typings'; +import { LivechatContacts, LivechatCustomField, LivechatVisitors } from '@rocket.chat/models'; +import { + isPOSTOmnichannelContactsProps, + isPOSTUpdateOmnichannelContactsProps, + isGETOmnichannelContactsProps, +} from '@rocket.chat/rest-typings'; import { escapeRegExp } from '@rocket.chat/string-helpers'; import { Match, check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; @@ -101,6 +105,7 @@ API.v1.addRoute( }, }, ); + API.v1.addRoute( 'omnichannel/contacts.update', { authRequired: true, permissionsRequired: ['update-livechat-contact'], validateParams: isPOSTUpdateOmnichannelContactsProps }, @@ -116,3 +121,18 @@ API.v1.addRoute( }, }, ); + +API.v1.addRoute( + 'omnichannel/contacts.get', + { authRequired: true, permissionsRequired: ['view-livechat-contact'], validateParams: isGETOmnichannelContactsProps }, + { + async get() { + if (process.env.TEST_MODE?.toUpperCase() !== 'TRUE') { + throw new Meteor.Error('error-not-allowed', 'This endpoint is only allowed in test mode'); + } + const contact = await LivechatContacts.findOneById(this.queryParams.contactId); + + return API.v1.success({ contact }); + }, + }, +); diff --git a/apps/meteor/tests/end-to-end/api/livechat/contacts.ts b/apps/meteor/tests/end-to-end/api/livechat/contacts.ts index 957d22ba92ae..c33ef255c25c 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/contacts.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/contacts.ts @@ -569,4 +569,67 @@ describe('LIVECHAT - contacts', () => { }); }); }); + + describe('[GET] omnichannel/contacts.get', () => { + let contactId: string; + const contact = { + name: faker.person.fullName(), + emails: [faker.internet.email().toLowerCase()], + phones: [faker.phone.number()], + contactManager: agentUser?._id, + }; + + before(async () => { + await updatePermission('view-livechat-contact', ['admin']); + const { body } = await request + .post(api('omnichannel/contacts')) + .set(credentials) + .send({ ...contact }); + contactId = body.contactId; + }); + + after(async () => { + await restorePermissionToRoles('view-livechat-contact'); + }); + + it('should be able get a contact by id', async () => { + const res = await request.get(api(`omnichannel/contacts.get`)).set(credentials).query({ contactId }); + + expect(res.status).to.be.equal(200); + expect(res.body).to.have.property('success', true); + expect(res.body.contact._id).to.be.equal(contactId); + expect(res.body.contact.name).to.be.equal(contact.name); + expect(res.body.contact.emails).to.be.deep.equal(contact.emails); + expect(res.body.contact.phones).to.be.deep.equal(contact.phones); + expect(res.body.contact.contactManager).to.be.equal(contact.contactManager); + }); + + it('should return null if contact does not exist', async () => { + const res = await request.get(api(`omnichannel/contacts.get`)).set(credentials).query({ contactId: 'invalid' }); + + expect(res.status).to.be.equal(200); + expect(res.body).to.have.property('success', true); + expect(res.body.contact).to.be.null; + }); + + it("should return an error if user doesn't have 'view-livechat-contact' permission", async () => { + await removePermissionFromAllRoles('view-livechat-contact'); + + const res = await request.get(api(`omnichannel/contacts.get`)).set(credentials).query({ contactId }); + + expect(res.body).to.have.property('success', false); + expect(res.body.error).to.be.equal('User does not have the permissions required for this action [error-unauthorized]'); + + await restorePermissionToRoles('view-livechat-contact'); + }); + + it('should return an error if contactId is missing', async () => { + const res = await request.get(api(`omnichannel/contacts.get`)).set(credentials); + + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error'); + expect(res.body.error).to.be.equal("must have required property 'contactId' [invalid-params]"); + expect(res.body.errorType).to.be.equal('invalid-params'); + }); + }); }); diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index 1ed249f5dd55..a1c714c013b8 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -1304,6 +1304,21 @@ const POSTUpdateOmnichannelContactsSchema = { export const isPOSTUpdateOmnichannelContactsProps = ajv.compile(POSTUpdateOmnichannelContactsSchema); +type GETOmnichannelContactsProps = { contactId: string }; + +const GETOmnichannelContactsSchema = { + type: 'object', + properties: { + contactId: { + type: 'string', + }, + }, + required: ['contactId'], + additionalProperties: false, +}; + +export const isGETOmnichannelContactsProps = ajv.compile(GETOmnichannelContactsSchema); + type GETOmnichannelContactProps = { contactId: string }; const GETOmnichannelContactSchema = { @@ -3748,6 +3763,9 @@ export type OmnichannelEndpoints = { '/v1/omnichannel/contacts.update': { POST: (params: POSTUpdateOmnichannelContactsProps) => { contact: ILivechatContact }; }; + '/v1/omnichannel/contacts.get': { + GET: (params: GETOmnichannelContactsProps) => { contact: ILivechatContact | null }; + }; '/v1/omnichannel/contact.search': { GET: (params: GETOmnichannelContactSearchProps) => { contact: ILivechatVisitor | null }; From c6478fec74bd87a30e31b70b485bb5f659addde5 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 16 Sep 2024 12:20:47 -0600 Subject: [PATCH 084/170] ci: Add `ee` or `ce` to the playwright trace uploaded file (#33299) --- .github/workflows/ci-test-e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index 3ed6f07e725d..a80a40419e9f 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -291,7 +291,7 @@ jobs: if: inputs.type == 'ui' && always() uses: actions/upload-artifact@v4 with: - name: playwright-test-trace-${{ matrix.mongodb-version }}-${{ matrix.shard }} + name: playwright-test-trace-${{ inputs.release }}-${{ matrix.mongodb-version }}-${{ matrix.shard }} path: ./apps/meteor/tests/e2e/.playwright* include-hidden-files: true From b919221b475c90789f665bcd13267a05ecd64f9c Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 16 Sep 2024 14:46:24 -0600 Subject: [PATCH 085/170] fix: Federation callback not awaiting model call (#33298) --- .changeset/great-humans-live.md | 5 +++++ .../meteor/app/federation/server/hooks/afterUnsetReaction.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/great-humans-live.md diff --git a/.changeset/great-humans-live.md b/.changeset/great-humans-live.md new file mode 100644 index 000000000000..1d97d9da23ae --- /dev/null +++ b/.changeset/great-humans-live.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed a Federation callback not awaiting db call diff --git a/apps/meteor/app/federation/server/hooks/afterUnsetReaction.js b/apps/meteor/app/federation/server/hooks/afterUnsetReaction.js index 51181d88ab9e..995146b290bf 100644 --- a/apps/meteor/app/federation/server/hooks/afterUnsetReaction.js +++ b/apps/meteor/app/federation/server/hooks/afterUnsetReaction.js @@ -6,7 +6,7 @@ import { getFederationDomain } from '../lib/getFederationDomain'; import { clientLogger } from '../lib/logger'; async function afterUnsetReaction(message, { user, reaction }) { - const room = Rooms.findOneById(message.rid, { fields: { federation: 1 } }); + const room = await Rooms.findOneById(message.rid, { projection: { federation: 1 } }); // If there are not federated users on this room, ignore it if (!hasExternalDomain(room)) { From 636d32d78374e943cb8b416d2172f9a6c4f68917 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Tue, 17 Sep 2024 11:06:11 -0300 Subject: [PATCH 086/170] fix: correct parameter order in afterSaveMessage to restore outgoing webhooks and related features (#33295) --- .changeset/rotten-rabbits-brush.md | 5 +++++ apps/meteor/app/autotranslate/server/autotranslate.ts | 7 ++++++- apps/meteor/app/integrations/server/triggers.ts | 7 ++++++- apps/meteor/app/irc/server/irc-bridge/index.js | 2 +- apps/meteor/ee/server/lib/engagementDashboard/startup.ts | 7 ++++++- 5 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 .changeset/rotten-rabbits-brush.md diff --git a/.changeset/rotten-rabbits-brush.md b/.changeset/rotten-rabbits-brush.md new file mode 100644 index 000000000000..916f4cc8034a --- /dev/null +++ b/.changeset/rotten-rabbits-brush.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Resolves the issue where outgoing integrations failed to trigger after the version 6.12.0 upgrade by correcting the parameter order from the `afterSaveMessage` callback to listener functions. This ensures the correct room information is passed, restoring the functionality of outgoing webhooks, IRC bridge, Autotranslate, and Engagement Dashboard. diff --git a/apps/meteor/app/autotranslate/server/autotranslate.ts b/apps/meteor/app/autotranslate/server/autotranslate.ts index f3c6d9e55fdb..23e1b189a792 100644 --- a/apps/meteor/app/autotranslate/server/autotranslate.ts +++ b/apps/meteor/app/autotranslate/server/autotranslate.ts @@ -113,7 +113,12 @@ export class TranslationProviderRegistry { return; } - callbacks.add('afterSaveMessage', provider.translateMessage.bind(provider), callbacks.priority.MEDIUM, 'autotranslate'); + callbacks.add( + 'afterSaveMessage', + (message, { room }) => provider.translateMessage(message, { room }), + callbacks.priority.MEDIUM, + 'autotranslate', + ); } } diff --git a/apps/meteor/app/integrations/server/triggers.ts b/apps/meteor/app/integrations/server/triggers.ts index cdf8acda6a21..64b95827645f 100644 --- a/apps/meteor/app/integrations/server/triggers.ts +++ b/apps/meteor/app/integrations/server/triggers.ts @@ -8,7 +8,12 @@ const callbackHandler = function _callbackHandler(eventType: string) { }; }; -callbacks.add('afterSaveMessage', callbackHandler('sendMessage'), callbacks.priority.LOW, 'integrations-sendMessage'); +callbacks.add( + 'afterSaveMessage', + (message, { room }) => callbackHandler('sendMessage')(message, room), + callbacks.priority.LOW, + 'integrations-sendMessage', +); callbacks.add('afterCreateChannel', callbackHandler('roomCreated'), callbacks.priority.LOW, 'integrations-roomCreated'); callbacks.add('afterCreatePrivateGroup', callbackHandler('roomCreated'), callbacks.priority.LOW, 'integrations-roomCreated'); callbacks.add('afterCreateUser', callbackHandler('userCreated'), callbacks.priority.LOW, 'integrations-userCreated'); diff --git a/apps/meteor/app/irc/server/irc-bridge/index.js b/apps/meteor/app/irc/server/irc-bridge/index.js index 09b7a3568362..bc5b4f0bc33f 100644 --- a/apps/meteor/app/irc/server/irc-bridge/index.js +++ b/apps/meteor/app/irc/server/irc-bridge/index.js @@ -209,7 +209,7 @@ class Bridge { // Chatting callbacks.add( 'afterSaveMessage', - this.onMessageReceived.bind(this, 'local', 'onSaveMessage'), + (message, { room }) => this.onMessageReceived('local', 'onSaveMessage', message, room), callbacks.priority.LOW, 'irc-on-save-message', ); diff --git a/apps/meteor/ee/server/lib/engagementDashboard/startup.ts b/apps/meteor/ee/server/lib/engagementDashboard/startup.ts index 159b121f7043..415e0323d525 100644 --- a/apps/meteor/ee/server/lib/engagementDashboard/startup.ts +++ b/apps/meteor/ee/server/lib/engagementDashboard/startup.ts @@ -3,7 +3,12 @@ import { fillFirstDaysOfMessagesIfNeeded, handleMessagesDeleted, handleMessagesS import { fillFirstDaysOfUsersIfNeeded, handleUserCreated } from './users'; export const attachCallbacks = (): void => { - callbacks.add('afterSaveMessage', handleMessagesSent, callbacks.priority.MEDIUM, 'engagementDashboard.afterSaveMessage'); + callbacks.add( + 'afterSaveMessage', + (message, { room }) => handleMessagesSent(message, { room }), + callbacks.priority.MEDIUM, + 'engagementDashboard.afterSaveMessage', + ); callbacks.add('afterDeleteMessage', handleMessagesDeleted, callbacks.priority.MEDIUM, 'engagementDashboard.afterDeleteMessage'); callbacks.add('afterCreateUser', handleUserCreated, callbacks.priority.MEDIUM, 'engagementDashboard.afterCreateUser'); }; From 3a161c43103433553442ef1d27ada9f2fd88d531 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 17 Sep 2024 10:39:21 -0600 Subject: [PATCH 087/170] feat: New endpoint for listing rooms & discussions from teams (#33177) --- .changeset/soft-mirrors-remember.md | 8 + apps/meteor/app/api/server/v1/teams.ts | 39 +++ apps/meteor/server/models/raw/Rooms.ts | 81 +++++ apps/meteor/server/services/team/service.ts | 39 ++- apps/meteor/tests/data/teams.helper.ts | 19 +- apps/meteor/tests/end-to-end/api/teams.ts | 321 ++++++++++++++++++ .../core-services/src/types/ITeamService.ts | 11 +- .../model-typings/src/models/IRoomsModel.ts | 8 + .../src/v1/teams/TeamsListChildren.ts | 36 ++ packages/rest-typings/src/v1/teams/index.ts | 6 + 10 files changed, 559 insertions(+), 9 deletions(-) create mode 100644 .changeset/soft-mirrors-remember.md create mode 100644 packages/rest-typings/src/v1/teams/TeamsListChildren.ts diff --git a/.changeset/soft-mirrors-remember.md b/.changeset/soft-mirrors-remember.md new file mode 100644 index 000000000000..78b005ee6b6e --- /dev/null +++ b/.changeset/soft-mirrors-remember.md @@ -0,0 +1,8 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/core-services": minor +"@rocket.chat/model-typings": minor +"@rocket.chat/rest-typings": minor +--- + +New `teams.listChildren` endpoint that allows users listing rooms & discussions from teams. Only the discussions from the team's main room are returned. diff --git a/apps/meteor/app/api/server/v1/teams.ts b/apps/meteor/app/api/server/v1/teams.ts index f64f8c820575..acb6cba2bac7 100644 --- a/apps/meteor/app/api/server/v1/teams.ts +++ b/apps/meteor/app/api/server/v1/teams.ts @@ -11,6 +11,7 @@ import { isTeamsDeleteProps, isTeamsLeaveProps, isTeamsUpdateProps, + isTeamsListChildrenProps, } from '@rocket.chat/rest-typings'; import { escapeRegExp } from '@rocket.chat/string-helpers'; import { Match, check } from 'meteor/check'; @@ -375,6 +376,44 @@ API.v1.addRoute( }, ); +const getTeamByIdOrNameOrParentRoom = async ( + params: { teamId: string } | { teamName: string } | { roomId: string }, +): Promise | null> => { + if ('teamId' in params && params.teamId) { + return Team.getOneById(params.teamId, { projection: { type: 1, roomId: 1 } }); + } + if ('teamName' in params && params.teamName) { + return Team.getOneByName(params.teamName, { projection: { type: 1, roomId: 1 } }); + } + if ('roomId' in params && params.roomId) { + return Team.getOneByRoomId(params.roomId, { projection: { type: 1, roomId: 1 } }); + } + return null; +}; + +// This should accept a teamId, filter (search by name on rooms collection) and sort/pagination +// should return a list of rooms/discussions from the team. the discussions will only be returned from the main room +API.v1.addRoute( + 'teams.listChildren', + { authRequired: true, validateParams: isTeamsListChildrenProps }, + { + async get() { + const { offset, count } = await getPaginationItems(this.queryParams); + const { sort } = await this.parseJsonQuery(); + const { filter, type } = this.queryParams; + + const team = await getTeamByIdOrNameOrParentRoom(this.queryParams); + if (!team) { + return API.v1.notFound(); + } + + const data = await Team.listChildren(this.userId, team, filter, type, sort, offset, count); + + return API.v1.success({ ...data, offset, count }); + }, + }, +); + API.v1.addRoute( 'teams.members', { authRequired: true }, diff --git a/apps/meteor/server/models/raw/Rooms.ts b/apps/meteor/server/models/raw/Rooms.ts index ec3bd6fe8d40..7d4a0a54dedf 100644 --- a/apps/meteor/server/models/raw/Rooms.ts +++ b/apps/meteor/server/models/raw/Rooms.ts @@ -2063,4 +2063,85 @@ export class RoomsRaw extends BaseRaw implements IRoomsModel { return this.updateMany(query, update); } + + findChildrenOfTeam( + teamId: string, + teamRoomId: string, + userId: string, + filter?: string, + type?: 'channels' | 'discussions', + options?: FindOptions, + ): AggregationCursor<{ totalCount: { count: number }[]; paginatedResults: IRoom[] }> { + const nameFilter = filter ? new RegExp(escapeRegExp(filter), 'i') : undefined; + return this.col.aggregate<{ totalCount: { count: number }[]; paginatedResults: IRoom[] }>([ + { + $match: { + $and: [ + { + $or: [ + ...(!type || type === 'channels' ? [{ teamId }] : []), + ...(!type || type === 'discussions' ? [{ prid: teamRoomId }] : []), + ], + }, + ...(nameFilter ? [{ $or: [{ fname: nameFilter }, { name: nameFilter }] }] : []), + ], + }, + }, + { + $lookup: { + from: 'rocketchat_subscription', + let: { + roomId: '$_id', + }, + pipeline: [ + { + $match: { + $and: [ + { + $expr: { + $eq: ['$rid', '$$roomId'], + }, + }, + { + $expr: { + $eq: ['$u._id', userId], + }, + }, + { + $expr: { + $ne: ['$t', 'c'], + }, + }, + ], + }, + }, + { + $project: { _id: 1 }, + }, + ], + as: 'subscription', + }, + }, + { + $match: { + $or: [ + { t: 'c' }, + { + $expr: { + $ne: [{ $size: '$subscription' }, 0], + }, + }, + ], + }, + }, + { $project: { subscription: 0 } }, + { $sort: options?.sort || { ts: 1 } }, + { + $facet: { + totalCount: [{ $count: 'count' }], + paginatedResults: [{ $skip: options?.skip || 0 }, { $limit: options?.limit || 50 }], + }, + }, + ]); + } } diff --git a/apps/meteor/server/services/team/service.ts b/apps/meteor/server/services/team/service.ts index 27f7af1f1b1c..f5218c88402a 100644 --- a/apps/meteor/server/services/team/service.ts +++ b/apps/meteor/server/services/team/service.ts @@ -913,8 +913,8 @@ export class TeamService extends ServiceClassInternal implements ITeamService { }); } - async getOneByRoomId(roomId: string): Promise { - const room = await Rooms.findOneById(roomId); + async getOneByRoomId(roomId: string, options?: FindOptions): Promise { + const room = await Rooms.findOneById(roomId, { projection: { teamId: 1 } }); if (!room) { throw new Error('invalid-room'); @@ -924,7 +924,7 @@ export class TeamService extends ServiceClassInternal implements ITeamService { throw new Error('room-not-on-team'); } - return Team.findOneById(room.teamId); + return Team.findOneById(room.teamId, options); } async addRolesToMember(teamId: string, userId: string, roles: Array): Promise { @@ -1078,4 +1078,37 @@ export class TeamService extends ServiceClassInternal implements ITeamService { const parentRoom = await this.getParentRoom(team); return { team, ...(parentRoom && { parentRoom }) }; } + + // Returns the list of rooms and discussions a user has access to inside a team + // Rooms returned are a composition of the rooms the user is in + public rooms + discussions from the main room (if any) + async listChildren( + userId: string, + team: AtLeast, + filter?: string, + type?: 'channels' | 'discussions', + sort?: Record, + skip = 0, + limit = 10, + ): Promise<{ total: number; data: IRoom[] }> { + const mainRoom = await Rooms.findOneById(team.roomId, { projection: { _id: 1 } }); + if (!mainRoom) { + throw new Error('error-invalid-team-no-main-room'); + } + + const isMember = await TeamMember.findOneByUserIdAndTeamId(userId, team._id, { + projection: { _id: 1 }, + }); + + if (!isMember) { + throw new Error('error-invalid-team-not-a-member'); + } + + const [{ totalCount: [{ count: total }] = [], paginatedResults: data = [] }] = + (await Rooms.findChildrenOfTeam(team._id, mainRoom._id, userId, filter, type, { skip, limit, sort }).toArray()) || []; + + return { + total, + data, + }; + } } diff --git a/apps/meteor/tests/data/teams.helper.ts b/apps/meteor/tests/data/teams.helper.ts index 8fc60bd19fd4..f6cba25f86c9 100644 --- a/apps/meteor/tests/data/teams.helper.ts +++ b/apps/meteor/tests/data/teams.helper.ts @@ -2,11 +2,20 @@ import type { ITeam, TEAM_TYPE } from '@rocket.chat/core-typings'; import { api, request } from './api-data'; -export const createTeam = async (credentials: Record, teamName: string, type: TEAM_TYPE): Promise => { - const response = await request.post(api('teams.create')).set(credentials).send({ - name: teamName, - type, - }); +export const createTeam = async ( + credentials: Record, + teamName: string, + type: TEAM_TYPE, + members?: string[], +): Promise => { + const response = await request + .post(api('teams.create')) + .set(credentials) + .send({ + name: teamName, + type, + ...(members && { members }), + }); return response.body.team; }; diff --git a/apps/meteor/tests/end-to-end/api/teams.ts b/apps/meteor/tests/end-to-end/api/teams.ts index ca07d3e32679..b630a97b1727 100644 --- a/apps/meteor/tests/end-to-end/api/teams.ts +++ b/apps/meteor/tests/end-to-end/api/teams.ts @@ -2217,4 +2217,325 @@ describe('[Teams]', () => { }); }); }); + + describe('[teams.listChildren]', () => { + const teamName = `team-${Date.now()}`; + let testTeam: ITeam; + let testPrivateTeam: ITeam; + let testUser: IUser; + let testUserCredentials: Credentials; + + let privateRoom: IRoom; + let privateRoom2: IRoom; + let publicRoom: IRoom; + let publicRoom2: IRoom; + + let discussionOnPrivateRoom: IRoom; + let discussionOnPublicRoom: IRoom; + let discussionOnMainRoom: IRoom; + + before('Create test team', async () => { + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + + const members = testUser.username ? [testUser.username] : []; + testTeam = await createTeam(credentials, teamName, 0, members); + testPrivateTeam = await createTeam(testUserCredentials, `${teamName}private`, 1, []); + }); + + before('make user owner', async () => { + await request + .post(api('teams.updateMember')) + .set(credentials) + .send({ + teamName: testTeam.name, + member: { + userId: testUser._id, + roles: ['member', 'owner'], + }, + }) + .expect('Content-Type', 'application/json') + .expect(200); + }); + + before('create rooms', async () => { + privateRoom = (await createRoom({ type: 'p', name: `test-p-${Date.now()}` })).body.group; + privateRoom2 = (await createRoom({ type: 'p', name: `test-p2-${Date.now()}`, credentials: testUserCredentials })).body.group; + publicRoom = (await createRoom({ type: 'c', name: `test-c-${Date.now()}` })).body.channel; + publicRoom2 = (await createRoom({ type: 'c', name: `test-c2-${Date.now()}` })).body.channel; + + await Promise.all([ + request + .post(api('teams.addRooms')) + .set(credentials) + .send({ + rooms: [privateRoom._id, publicRoom._id, publicRoom2._id], + teamId: testTeam._id, + }) + .expect(200), + request + .post(api('teams.addRooms')) + .set(testUserCredentials) + .send({ + rooms: [privateRoom2._id], + teamId: testTeam._id, + }) + .expect(200), + ]); + }); + + before('Create discussions', async () => { + discussionOnPrivateRoom = ( + await request + .post(api('rooms.createDiscussion')) + .set(credentials) + .send({ + prid: privateRoom._id, + t_name: `test-d-${Date.now()}`, + }) + ).body.discussion; + discussionOnPublicRoom = ( + await request + .post(api('rooms.createDiscussion')) + .set(credentials) + .send({ + prid: publicRoom._id, + t_name: `test-d-${Date.now()}`, + }) + ).body.discussion; + discussionOnMainRoom = ( + await request + .post(api('rooms.createDiscussion')) + .set(credentials) + .send({ + prid: testTeam.roomId, + t_name: `test-d-${Date.now()}`, + }) + ).body.discussion; + }); + + after(async () => { + await Promise.all([ + deleteRoom({ type: 'p', roomId: privateRoom._id }), + deleteRoom({ type: 'p', roomId: privateRoom2._id }), + deleteRoom({ type: 'c', roomId: publicRoom._id }), + deleteRoom({ type: 'c', roomId: publicRoom2._id }), + deleteRoom({ type: 'p', roomId: discussionOnPrivateRoom._id }), + deleteRoom({ type: 'c', roomId: discussionOnPublicRoom._id }), + deleteRoom({ type: 'c', roomId: discussionOnMainRoom._id }), + deleteTeam(credentials, teamName), + deleteTeam(credentials, testPrivateTeam.name), + deleteUser({ _id: testUser._id }), + ]); + }); + + it('should fail if user is not logged in', async () => { + await request.get(api('teams.listChildren')).expect(401); + }); + + it('should fail if teamId is not passed as queryparam', async () => { + await request.get(api('teams.listChildren')).set(credentials).expect(400); + }); + + it('should fail if teamId is not valid', async () => { + await request.get(api('teams.listChildren')).set(credentials).query({ teamId: 'invalid' }).expect(404); + }); + + it('should fail if teamId is empty', async () => { + await request.get(api('teams.listChildren')).set(credentials).query({ teamId: '' }).expect(404); + }); + + it('should fail if both properties are passed', async () => { + await request.get(api('teams.listChildren')).set(credentials).query({ teamId: testTeam._id, teamName: testTeam.name }).expect(400); + }); + + it('should fail if teamName is empty', async () => { + await request.get(api('teams.listChildren')).set(credentials).query({ teamName: '' }).expect(404); + }); + + it('should fail if teamName is invalid', async () => { + await request.get(api('teams.listChildren')).set(credentials).query({ teamName: 'invalid' }).expect(404); + }); + + it('should fail if roomId is empty', async () => { + await request.get(api('teams.listChildren')).set(credentials).query({ roomId: '' }).expect(404); + }); + + it('should fail if roomId is invalid', async () => { + await request.get(api('teams.listChildren')).set(credentials).query({ teamName: 'invalid' }).expect(404); + }); + + it('should return a list of valid rooms for user', async () => { + const res = await request.get(api('teams.listChildren')).query({ teamId: testTeam._id }).set(credentials).expect(200); + + expect(res.body).to.have.property('total').to.be.equal(5); + expect(res.body).to.have.property('data').to.be.an('array'); + expect(res.body.data).to.have.lengthOf(5); + + const mainRoom = res.body.data.find((room: IRoom) => room._id === testTeam.roomId); + expect(mainRoom).to.be.an('object'); + + const publicChannel1 = res.body.data.find((room: IRoom) => room._id === publicRoom._id); + expect(publicChannel1).to.be.an('object'); + + const publicChannel2 = res.body.data.find((room: IRoom) => room._id === publicRoom2._id); + expect(publicChannel2).to.be.an('object'); + + const privateChannel1 = res.body.data.find((room: IRoom) => room._id === privateRoom._id); + expect(privateChannel1).to.be.an('object'); + + const privateChannel2 = res.body.data.find((room: IRoom) => room._id === privateRoom2._id); + expect(privateChannel2).to.be.undefined; + + const discussionOnP = res.body.data.find((room: IRoom) => room._id === discussionOnPrivateRoom._id); + expect(discussionOnP).to.be.undefined; + + const discussionOnC = res.body.data.find((room: IRoom) => room._id === discussionOnPublicRoom._id); + expect(discussionOnC).to.be.undefined; + + const mainDiscussion = res.body.data.find((room: IRoom) => room._id === discussionOnMainRoom._id); + expect(mainDiscussion).to.be.an('object'); + }); + + it('should return a valid list of rooms for non admin member too', async () => { + const res = await request.get(api('teams.listChildren')).query({ teamName: testTeam.name }).set(testUserCredentials).expect(200); + + expect(res.body).to.have.property('total').to.be.equal(5); + expect(res.body).to.have.property('data').to.be.an('array'); + expect(res.body.data).to.have.lengthOf(5); + + const mainRoom = res.body.data.find((room: IRoom) => room._id === testTeam.roomId); + expect(mainRoom).to.be.an('object'); + + const publicChannel1 = res.body.data.find((room: IRoom) => room._id === publicRoom._id); + expect(publicChannel1).to.be.an('object'); + + const publicChannel2 = res.body.data.find((room: IRoom) => room._id === publicRoom2._id); + expect(publicChannel2).to.be.an('object'); + + const privateChannel1 = res.body.data.find((room: IRoom) => room._id === privateRoom._id); + expect(privateChannel1).to.be.undefined; + + const privateChannel2 = res.body.data.find((room: IRoom) => room._id === privateRoom2._id); + expect(privateChannel2).to.be.an('object'); + + const discussionOnP = res.body.data.find((room: IRoom) => room._id === discussionOnPrivateRoom._id); + expect(discussionOnP).to.be.undefined; + + const discussionOnC = res.body.data.find((room: IRoom) => room._id === discussionOnPublicRoom._id); + expect(discussionOnC).to.be.undefined; + + const mainDiscussion = res.body.data.find((room: IRoom) => room._id === discussionOnMainRoom._id); + expect(mainDiscussion).to.be.an('object'); + }); + + it('should return a valid list of rooms for non admin member too when filtering by teams main room id', async () => { + const res = await request.get(api('teams.listChildren')).query({ roomId: testTeam.roomId }).set(testUserCredentials).expect(200); + + expect(res.body).to.have.property('total').to.be.equal(5); + expect(res.body).to.have.property('data').to.be.an('array'); + expect(res.body.data).to.have.lengthOf(5); + + const mainRoom = res.body.data.find((room: IRoom) => room._id === testTeam.roomId); + expect(mainRoom).to.be.an('object'); + + const publicChannel1 = res.body.data.find((room: IRoom) => room._id === publicRoom._id); + expect(publicChannel1).to.be.an('object'); + + const publicChannel2 = res.body.data.find((room: IRoom) => room._id === publicRoom2._id); + expect(publicChannel2).to.be.an('object'); + + const privateChannel1 = res.body.data.find((room: IRoom) => room._id === privateRoom._id); + expect(privateChannel1).to.be.undefined; + + const privateChannel2 = res.body.data.find((room: IRoom) => room._id === privateRoom2._id); + expect(privateChannel2).to.be.an('object'); + + const discussionOnP = res.body.data.find((room: IRoom) => room._id === discussionOnPrivateRoom._id); + expect(discussionOnP).to.be.undefined; + + const discussionOnC = res.body.data.find((room: IRoom) => room._id === discussionOnPublicRoom._id); + expect(discussionOnC).to.be.undefined; + + const mainDiscussion = res.body.data.find((room: IRoom) => room._id === discussionOnMainRoom._id); + expect(mainDiscussion).to.be.an('object'); + }); + + it('should return a list of rooms filtered by name using the filter parameter', async () => { + const res = await request + .get(api('teams.listChildren')) + .query({ teamId: testTeam._id, filter: 'test-p' }) + .set(credentials) + .expect(200); + + expect(res.body).to.have.property('total').to.be.equal(1); + expect(res.body).to.have.property('data').to.be.an('array'); + expect(res.body.data[0]._id).to.be.equal(privateRoom._id); + expect(res.body.data.find((room: IRoom) => room._id === privateRoom2._id)).to.be.undefined; + }); + + it('should paginate results', async () => { + const res = await request + .get(api('teams.listChildren')) + .query({ teamId: testTeam._id, offset: 1, count: 2 }) + .set(credentials) + .expect(200); + + expect(res.body).to.have.property('total').to.be.equal(5); + expect(res.body).to.have.property('data').to.be.an('array'); + expect(res.body.data).to.have.lengthOf(2); + }); + + it('should return only items of type channel', async () => { + const res = await request + .get(api('teams.listChildren')) + .query({ teamId: testTeam._id, type: 'channels' }) + .set(credentials) + .expect(200); + + expect(res.body).to.have.property('total').to.be.equal(4); + expect(res.body).to.have.property('data').to.be.an('array'); + expect(res.body.data).to.have.lengthOf(4); + expect(res.body.data.some((room: IRoom) => !!room.prid)).to.be.false; + }); + + it('should return only items of type discussion', async () => { + const res = await request + .get(api('teams.listChildren')) + .query({ teamId: testTeam._id, type: 'discussions' }) + .set(credentials) + .expect(200); + + expect(res.body).to.have.property('total').to.be.equal(1); + expect(res.body).to.have.property('data').to.be.an('array'); + expect(res.body.data).to.have.lengthOf(1); + expect(res.body.data.every((room: IRoom) => !!room.prid)).to.be.true; + }); + + it('should return both when type is not passed', async () => { + const res = await request.get(api('teams.listChildren')).query({ teamId: testTeam._id }).set(credentials).expect(200); + + expect(res.body).to.have.property('total').to.be.equal(5); + expect(res.body).to.have.property('data').to.be.an('array'); + expect(res.body.data).to.have.lengthOf(5); + expect(res.body.data.some((room: IRoom) => !!room.prid)).to.be.true; + expect(res.body.data.some((room: IRoom) => !room.prid)).to.be.true; + }); + + it('should fail if type is other than channel or discussion', async () => { + await request.get(api('teams.listChildren')).query({ teamId: testTeam._id, type: 'other' }).set(credentials).expect(400); + }); + + it('should properly list children of a private team', async () => { + const res = await request.get(api('teams.listChildren')).query({ teamId: testPrivateTeam._id }).set(testUserCredentials).expect(200); + + expect(res.body).to.have.property('total').to.be.equal(1); + expect(res.body).to.have.property('data').to.be.an('array'); + expect(res.body.data).to.have.lengthOf(1); + }); + + it('should throw an error when a non member user tries to fetch info for team', async () => { + await request.get(api('teams.listChildren')).query({ teamId: testPrivateTeam._id }).set(credentials).expect(400); + }); + }); }); diff --git a/packages/core-services/src/types/ITeamService.ts b/packages/core-services/src/types/ITeamService.ts index 3caa6a2e97df..132df89470ca 100644 --- a/packages/core-services/src/types/ITeamService.ts +++ b/packages/core-services/src/types/ITeamService.ts @@ -112,7 +112,7 @@ export interface ITeamService { getOneById

(teamId: string, options?: FindOptions

): Promise; getOneByName(teamName: string | RegExp, options?: FindOptions): Promise; getOneByMainRoomId(teamId: string): Promise | null>; - getOneByRoomId(teamId: string): Promise; + getOneByRoomId(teamId: string, options?: FindOptions): Promise; getMatchingTeamRooms(teamId: string, rids: Array): Promise>; autocomplete(uid: string, name: string): Promise; getAllPublicTeams(options?: FindOptions): Promise>; @@ -129,4 +129,13 @@ export interface ITeamService { getRoomInfo( room: AtLeast, ): Promise<{ team?: Pick; parentRoom?: Pick }>; + listChildren( + userId: string, + team: AtLeast, + filter?: string, + type?: 'channels' | 'discussions', + sort?: Record, + skip?: number, + limit?: number, + ): Promise<{ total: number; data: IRoom[] }>; } diff --git a/packages/model-typings/src/models/IRoomsModel.ts b/packages/model-typings/src/models/IRoomsModel.ts index 9097a89c1413..91802f836719 100644 --- a/packages/model-typings/src/models/IRoomsModel.ts +++ b/packages/model-typings/src/models/IRoomsModel.ts @@ -282,4 +282,12 @@ export interface IRoomsModel extends IBaseModel { getSubscribedRoomIdsWithoutE2EKeys(uid: IUser['_id']): Promise; removeUsersFromE2EEQueueByRoomId(roomId: IRoom['_id'], uids: IUser['_id'][]): Promise; removeUserFromE2EEQueue(uid: IUser['_id']): Promise; + findChildrenOfTeam( + teamId: string, + teamRoomId: string, + userId: string, + filter?: string, + type?: 'channels' | 'discussions', + options?: FindOptions, + ): AggregationCursor<{ totalCount: { count: number }[]; paginatedResults: IRoom[] }>; } diff --git a/packages/rest-typings/src/v1/teams/TeamsListChildren.ts b/packages/rest-typings/src/v1/teams/TeamsListChildren.ts new file mode 100644 index 000000000000..41128e18a05f --- /dev/null +++ b/packages/rest-typings/src/v1/teams/TeamsListChildren.ts @@ -0,0 +1,36 @@ +import type { ITeam } from '@rocket.chat/core-typings'; + +import type { PaginatedRequest } from '../../helpers/PaginatedRequest'; +import { ajv } from '../Ajv'; + +type GeneralProps = { + filter?: string; + type?: 'channels' | 'discussions'; +}; + +export type TeamsListChildrenProps = + | PaginatedRequest< + { + teamId: ITeam['_id']; + } & GeneralProps + > + | PaginatedRequest<{ teamName: ITeam['name'] } & GeneralProps> + | PaginatedRequest<{ roomId: ITeam['roomId'] } & GeneralProps>; + +const TeamsListChildrenPropsSchema = { + type: 'object', + properties: { + teamId: { type: 'string' }, + teamName: { type: 'string' }, + type: { type: 'string', enum: ['channels', 'discussions'] }, + roomId: { type: 'string' }, + filter: { type: 'string' }, + offset: { type: 'number' }, + count: { type: 'number' }, + sort: { type: 'string' }, + }, + additionalProperties: false, + oneOf: [{ required: ['teamId'] }, { required: ['teamName'] }, { required: ['roomId'] }], +}; + +export const isTeamsListChildrenProps = ajv.compile(TeamsListChildrenPropsSchema); diff --git a/packages/rest-typings/src/v1/teams/index.ts b/packages/rest-typings/src/v1/teams/index.ts index d63e6da8bd8a..a4ae6c7bca0f 100644 --- a/packages/rest-typings/src/v1/teams/index.ts +++ b/packages/rest-typings/src/v1/teams/index.ts @@ -6,6 +6,7 @@ import type { TeamsAddMembersProps } from './TeamsAddMembersProps'; import type { TeamsConvertToChannelProps } from './TeamsConvertToChannelProps'; import type { TeamsDeleteProps } from './TeamsDeleteProps'; import type { TeamsLeaveProps } from './TeamsLeaveProps'; +import type { TeamsListChildrenProps } from './TeamsListChildren'; import type { TeamsRemoveMemberProps } from './TeamsRemoveMemberProps'; import type { TeamsRemoveRoomProps } from './TeamsRemoveRoomProps'; import type { TeamsUpdateMemberProps } from './TeamsUpdateMemberProps'; @@ -19,6 +20,7 @@ export * from './TeamsRemoveMemberProps'; export * from './TeamsRemoveRoomProps'; export * from './TeamsUpdateMemberProps'; export * from './TeamsUpdateProps'; +export * from './TeamsListChildren'; type ITeamAutocompleteResult = Pick; @@ -184,4 +186,8 @@ export type TeamsEndpoints = { room: IRoom; }; }; + + '/v1/teams.listChildren': { + GET: (params: TeamsListChildrenProps) => PaginatedResult<{ data: IRoom[] }>; + }; }; From f27092b94d5e4070a4eb74ce49b6b4eec191446e Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 17 Sep 2024 13:30:43 -0600 Subject: [PATCH 088/170] chore: Update typings on callbacks to accept less than a full room object (#33305) --- apps/meteor/app/lib/server/functions/isTheLastMessage.ts | 4 ++-- .../server/services/messages/hooks/BeforeFederationActions.ts | 3 ++- apps/meteor/server/services/messages/service.ts | 4 ++-- packages/core-services/src/types/IMessageService.ts | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/meteor/app/lib/server/functions/isTheLastMessage.ts b/apps/meteor/app/lib/server/functions/isTheLastMessage.ts index f8e5be94002c..f1f1fb4c1497 100644 --- a/apps/meteor/app/lib/server/functions/isTheLastMessage.ts +++ b/apps/meteor/app/lib/server/functions/isTheLastMessage.ts @@ -1,7 +1,7 @@ -import type { IMessage, IRoom } from '@rocket.chat/core-typings'; +import type { IMessage, IRoom, AtLeast } from '@rocket.chat/core-typings'; import { settings } from '../../../settings/server'; // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -export const isTheLastMessage = (room: IRoom, message: Pick) => +export const isTheLastMessage = (room: AtLeast, message: Pick) => settings.get('Store_Last_Message') && (!room.lastMessage || room.lastMessage._id === message._id); diff --git a/apps/meteor/server/services/messages/hooks/BeforeFederationActions.ts b/apps/meteor/server/services/messages/hooks/BeforeFederationActions.ts index a954e4899970..19f42626c216 100644 --- a/apps/meteor/server/services/messages/hooks/BeforeFederationActions.ts +++ b/apps/meteor/server/services/messages/hooks/BeforeFederationActions.ts @@ -1,9 +1,10 @@ +import type { AtLeast } from '@rocket.chat/core-typings'; import { type IMessage, type IRoom, isMessageFromMatrixFederation, isRoomFederated } from '@rocket.chat/core-typings'; import { isFederationEnabled, isFederationReady } from '../../federation/utils'; export class FederationActions { - public static shouldPerformAction(message: IMessage, room: IRoom): boolean { + public static shouldPerformAction(message: IMessage, room: AtLeast): boolean { if (isMessageFromMatrixFederation(message) || isRoomFederated(room)) { return isFederationEnabled() && isFederationReady(); } diff --git a/apps/meteor/server/services/messages/service.ts b/apps/meteor/server/services/messages/service.ts index b20b5236b7fe..85afcf394f28 100644 --- a/apps/meteor/server/services/messages/service.ts +++ b/apps/meteor/server/services/messages/service.ts @@ -1,6 +1,6 @@ import type { IMessageService } from '@rocket.chat/core-services'; import { Authorization, ServiceClassInternal } from '@rocket.chat/core-services'; -import { type IMessage, type MessageTypesValues, type IUser, type IRoom, isEditedMessage } from '@rocket.chat/core-typings'; +import { type IMessage, type MessageTypesValues, type IUser, type IRoom, isEditedMessage, type AtLeast } from '@rocket.chat/core-typings'; import { Messages, Rooms } from '@rocket.chat/models'; import { deleteMessage } from '../../../app/lib/server/functions/deleteMessage'; @@ -244,7 +244,7 @@ export class MessageService extends ServiceClassInternal implements IMessageServ // await Room.join({ room, user }); // } - async beforeReacted(message: IMessage, room: IRoom) { + async beforeReacted(message: IMessage, room: AtLeast) { if (!FederationActions.shouldPerformAction(message, room)) { throw new FederationMatrixInvalidConfigurationError('Unable to react to message'); } diff --git a/packages/core-services/src/types/IMessageService.ts b/packages/core-services/src/types/IMessageService.ts index ca84f78ea677..29da139ef63c 100644 --- a/packages/core-services/src/types/IMessageService.ts +++ b/packages/core-services/src/types/IMessageService.ts @@ -1,4 +1,4 @@ -import type { IMessage, MessageTypesValues, IUser, IRoom } from '@rocket.chat/core-typings'; +import type { IMessage, MessageTypesValues, IUser, IRoom, AtLeast } from '@rocket.chat/core-typings'; export interface IMessageService { sendMessage({ fromId, rid, msg }: { fromId: string; rid: string; msg: string }): Promise; @@ -21,6 +21,6 @@ export interface IMessageService { deleteMessage(user: IUser, message: IMessage): Promise; updateMessage(message: IMessage, user: IUser, originalMsg?: IMessage): Promise; reactToMessage(userId: string, reaction: string, messageId: IMessage['_id'], shouldReact?: boolean): Promise; - beforeReacted(message: IMessage, room: IRoom): Promise; + beforeReacted(message: IMessage, room: AtLeast): Promise; beforeDelete(message: IMessage, room: IRoom): Promise; } From 4202d6570cfa870cd196a5b10bc29041fbff50eb Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Tue, 17 Sep 2024 17:56:33 -0300 Subject: [PATCH 089/170] fix: resolve avatar download issue on setUsername by refining service selection logic (#33193) --- .changeset/small-crabs-travel.md | 5 + .../app/lib/server/functions/setUsername.ts | 23 +- .../lib/server/functions/setUsername.spec.ts | 271 ++++++++++++++++++ 3 files changed, 287 insertions(+), 12 deletions(-) create mode 100644 .changeset/small-crabs-travel.md create mode 100644 apps/meteor/tests/unit/app/lib/server/functions/setUsername.spec.ts diff --git a/.changeset/small-crabs-travel.md b/.changeset/small-crabs-travel.md new file mode 100644 index 000000000000..201494a5b70f --- /dev/null +++ b/.changeset/small-crabs-travel.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixed avatar blob image setting in setUserAvatar method by correcting service handling logic. diff --git a/apps/meteor/app/lib/server/functions/setUsername.ts b/apps/meteor/app/lib/server/functions/setUsername.ts index 5b2b1923da75..c4d2c47c6d9d 100644 --- a/apps/meteor/app/lib/server/functions/setUsername.ts +++ b/apps/meteor/app/lib/server/functions/setUsername.ts @@ -102,23 +102,22 @@ export const _setUsername = async function (userId: string, u: string, fullUser: // Set new username* await Users.setUsername(user._id, username); user.username = username; + if (!previousUsername && settings.get('Accounts_SetDefaultAvatar') === true) { - // eslint-disable-next-line @typescript-eslint/ban-types - const avatarSuggestions = (await getAvatarSuggestionForUser(user)) as {}; - let gravatar; - for await (const service of Object.keys(avatarSuggestions)) { - const avatarData = avatarSuggestions[+service as keyof typeof avatarSuggestions]; + const avatarSuggestions = await getAvatarSuggestionForUser(user); + let avatarData; + let serviceName = 'gravatar'; + + for (const service of Object.keys(avatarSuggestions)) { + avatarData = avatarSuggestions[service]; if (service !== 'gravatar') { - // eslint-disable-next-line dot-notation - await setUserAvatar(user, avatarData['blob'], avatarData['contentType'], service); - gravatar = null; + serviceName = service; break; } - gravatar = avatarData; } - if (gravatar != null) { - // eslint-disable-next-line dot-notation - await setUserAvatar(user, gravatar['blob'], gravatar['contentType'], 'gravatar'); + + if (avatarData) { + await setUserAvatar(user, avatarData.blob, avatarData.contentType, serviceName); } } diff --git a/apps/meteor/tests/unit/app/lib/server/functions/setUsername.spec.ts b/apps/meteor/tests/unit/app/lib/server/functions/setUsername.spec.ts new file mode 100644 index 000000000000..c6b6f9a26fae --- /dev/null +++ b/apps/meteor/tests/unit/app/lib/server/functions/setUsername.spec.ts @@ -0,0 +1,271 @@ +import { expect } from 'chai'; +import proxyquire from 'proxyquire'; +import sinon from 'sinon'; + +describe('setUsername', () => { + const userId = 'userId'; + const username = 'validUsername'; + + const stubs = { + Users: { + findOneById: sinon.stub(), + setUsername: sinon.stub(), + }, + Accounts: { + sendEnrollmentEmail: sinon.stub(), + }, + settings: { + get: sinon.stub(), + }, + api: { + broadcast: sinon.stub(), + }, + Invites: { + findOneById: sinon.stub(), + }, + callbacks: { + run: sinon.stub(), + }, + checkUsernameAvailability: sinon.stub(), + validateUsername: sinon.stub(), + saveUserIdentity: sinon.stub(), + joinDefaultChannels: sinon.stub(), + getAvatarSuggestionForUser: sinon.stub(), + setUserAvatar: sinon.stub(), + addUserToRoom: sinon.stub(), + notifyOnUserChange: sinon.stub(), + RateLimiter: { + limitFunction: sinon.stub(), + }, + underscore: { + escape: sinon.stub(), + }, + SystemLogger: sinon.stub(), + }; + + const { setUsernameWithValidation, _setUsername } = proxyquire + .noCallThru() + .load('../../../../../../app/lib/server/functions/setUsername', { + 'meteor/meteor': { Meteor: { Error } }, + '@rocket.chat/core-services': { api: stubs.api }, + '@rocket.chat/models': { Users: stubs.Users, Invites: stubs.Invites }, + 'meteor/accounts-base': { Accounts: stubs.Accounts }, + 'underscore': stubs.underscore, + '../../../settings/server': { settings: stubs.settings }, + '../lib': { notifyOnUserChange: stubs.notifyOnUserChange, RateLimiter: stubs.RateLimiter }, + './addUserToRoom': { addUserToRoom: stubs.addUserToRoom }, + './checkUsernameAvailability': { checkUsernameAvailability: stubs.checkUsernameAvailability }, + './getAvatarSuggestionForUser': { getAvatarSuggestionForUser: stubs.getAvatarSuggestionForUser }, + './joinDefaultChannels': { joinDefaultChannels: stubs.joinDefaultChannels }, + './saveUserIdentity': { saveUserIdentity: stubs.saveUserIdentity }, + './setUserAvatar': { setUserAvatar: stubs.setUserAvatar }, + './validateUsername': { validateUsername: stubs.validateUsername }, + '../../../../lib/callbacks': { callbacks: stubs.callbacks }, + '../../../../server/lib/logger/system': { SystemLogger: stubs.SystemLogger }, + }); + + afterEach(() => { + stubs.Users.findOneById.reset(); + stubs.Users.setUsername.reset(); + stubs.Accounts.sendEnrollmentEmail.reset(); + stubs.settings.get.reset(); + stubs.api.broadcast.reset(); + stubs.Invites.findOneById.reset(); + stubs.callbacks.run.reset(); + stubs.checkUsernameAvailability.reset(); + stubs.validateUsername.reset(); + stubs.saveUserIdentity.reset(); + stubs.joinDefaultChannels.reset(); + stubs.getAvatarSuggestionForUser.reset(); + stubs.setUserAvatar.reset(); + stubs.addUserToRoom.reset(); + stubs.notifyOnUserChange.reset(); + stubs.RateLimiter.limitFunction.reset(); + stubs.underscore.escape.reset(); + stubs.SystemLogger.reset(); + }); + + describe('setUsernameWithValidation', () => { + it('should throw an error if username is invalid', async () => { + try { + await setUsernameWithValidation(userId, ''); + } catch (error: any) { + expect(error.message).to.equal('error-invalid-username'); + } + }); + + it('should throw an error if user is not found', async () => { + stubs.Users.findOneById.withArgs(userId).returns(null); + + try { + await setUsernameWithValidation(userId, username); + } catch (error: any) { + expect(stubs.Users.findOneById.calledOnce).to.be.true; + expect(error.message).to.equal('error-invalid-user'); + } + }); + + it('should throw an error if username change is not allowed', async () => { + stubs.Users.findOneById.resolves({ username: 'oldUsername' }); + stubs.settings.get.withArgs('Accounts_AllowUsernameChange').returns(false); + + try { + await setUsernameWithValidation(userId, username); + } catch (error: any) { + expect(stubs.settings.get.calledOnce).to.be.true; + expect(error.message).to.equal('error-not-allowed'); + } + }); + + it('should throw an error if username is not valid', async () => { + stubs.Users.findOneById.resolves({ username: null }); + stubs.validateUsername.returns(false); + + try { + await setUsernameWithValidation(userId, 'invalid-username'); + } catch (error: any) { + expect(stubs.validateUsername.calledOnce).to.be.true; + expect(error.message).to.equal('username-invalid'); + } + }); + + it('should throw an error if username is already in use', async () => { + stubs.Users.findOneById.resolves({ username: null }); + stubs.validateUsername.returns(true); + stubs.checkUsernameAvailability.resolves(false); + + try { + await setUsernameWithValidation(userId, 'existingUsername'); + } catch (error: any) { + expect(stubs.checkUsernameAvailability.calledOnce).to.be.true; + expect(error.message).to.equal('error-field-unavailable'); + } + }); + + it('should save the user identity when valid username is set', async () => { + stubs.Users.findOneById.resolves({ _id: userId, username: null }); + stubs.settings.get.withArgs('Accounts_AllowUsernameChange').returns(true); + stubs.validateUsername.returns(true); + stubs.checkUsernameAvailability.resolves(true); + stubs.saveUserIdentity.resolves(true); + + await setUsernameWithValidation(userId, 'newUsername'); + + expect(stubs.saveUserIdentity.calledOnce).to.be.true; + expect(stubs.joinDefaultChannels.calledOnceWith(userId, undefined)).to.be.true; + }); + }); + + describe('_setUsername', () => { + it('should return false if userId or username is missing', async () => { + const result = await _setUsername(null, '', {}); + expect(result).to.be.false; + }); + + it('should return false if username is invalid', async () => { + stubs.validateUsername.returns(false); + + const result = await _setUsername(userId, 'invalid-username', {}); + expect(result).to.be.false; + }); + + it('should return user if username is already set', async () => { + stubs.validateUsername.returns(true); + const mockUser = { username }; + + const result = await _setUsername(userId, username, mockUser); + expect(result).to.equal(mockUser); + }); + + it('should set username when user has no previous username', async () => { + const mockUser = { _id: userId, emails: [{ address: 'test@example.com' }] }; + stubs.validateUsername.returns(true); + stubs.Users.findOneById.resolves(mockUser); + stubs.checkUsernameAvailability.resolves(true); + + await _setUsername(userId, username, mockUser); + + expect(stubs.Users.setUsername.calledOnceWith(userId, username)); + expect(stubs.checkUsernameAvailability.calledOnceWith(username)); + expect(stubs.api.broadcast.calledOnceWith('user.autoupdate', { user: mockUser })); + }); + + it('should set username when user has and old that is different from new', async () => { + const mockUser = { _id: userId, username: 'oldUsername', emails: [{ address: 'test@example.com' }] }; + stubs.validateUsername.returns(true); + stubs.Users.findOneById.resolves(mockUser); + stubs.checkUsernameAvailability.resolves(true); + + await _setUsername(userId, username, mockUser); + + expect(stubs.Users.setUsername.calledOnceWith(userId, username)); + expect(stubs.checkUsernameAvailability.calledOnceWith(username)); + expect(stubs.api.broadcast.calledOnceWith('user.autoupdate', { user: mockUser })); + }); + + it('should set username when user has and old that is different from new', async () => { + const mockUser = { _id: userId, username: 'oldUsername', emails: [{ address: 'test@example.com' }] }; + stubs.validateUsername.returns(true); + stubs.Users.findOneById.resolves(mockUser); + stubs.checkUsernameAvailability.resolves(true); + + await _setUsername(userId, username, mockUser); + + expect(stubs.Users.setUsername.calledOnceWith(userId, username)); + expect(stubs.checkUsernameAvailability.calledOnceWith(username)); + expect(stubs.api.broadcast.calledOnceWith('user.autoupdate', { user: mockUser })); + }); + + it('should set avatar if Accounts_SetDefaultAvatar is enabled', async () => { + const mockUser = { _id: userId, username: null }; + stubs.validateUsername.returns(true); + stubs.Users.findOneById.resolves(mockUser); + stubs.checkUsernameAvailability.resolves(true); + stubs.settings.get.withArgs('Accounts_SetDefaultAvatar').returns(true); + stubs.getAvatarSuggestionForUser.resolves({ gravatar: { blob: 'blobData', contentType: 'image/png' } }); + + await _setUsername(userId, username, mockUser); + + expect(stubs.setUserAvatar.calledOnceWith(mockUser, 'blobData', 'image/png', 'gravatar')).to.be.true; + }); + + it('should not set avatar if Accounts_SetDefaultAvatar is disabled', async () => { + const mockUser = { _id: userId, username: null }; + stubs.validateUsername.returns(true); + stubs.Users.findOneById.resolves(mockUser); + stubs.checkUsernameAvailability.resolves(true); + stubs.settings.get.withArgs('Accounts_SetDefaultAvatar').returns(false); + + await _setUsername(userId, username, mockUser); + + expect(stubs.setUserAvatar.called).to.be.false; + }); + + it('should not set avatar if no avatar suggestions are available', async () => { + const mockUser = { _id: userId, username: null }; + stubs.validateUsername.returns(true); + stubs.Users.findOneById.resolves(mockUser); + stubs.checkUsernameAvailability.resolves(true); + stubs.settings.get.withArgs('Accounts_SetDefaultAvatar').returns(true); + stubs.getAvatarSuggestionForUser.resolves({}); + + await _setUsername(userId, username, mockUser); + + expect(stubs.setUserAvatar.called).to.be.false; + }); + + it('should add user to room if inviteToken is present', async () => { + const mockUser = { _id: userId, username: null, inviteToken: 'invite token' }; + stubs.validateUsername.returns(true); + stubs.Users.findOneById.resolves(mockUser); + stubs.checkUsernameAvailability.resolves(true); + stubs.settings.get.withArgs('Accounts_SetDefaultAvatar').returns(true); + stubs.getAvatarSuggestionForUser.resolves({ gravatar: { blob: 'blobData', contentType: 'image/png' } }); + stubs.Invites.findOneById.resolves({ rid: 'room id' }); + + await _setUsername(userId, username, mockUser); + + expect(stubs.addUserToRoom.calledOnceWith('room id', mockUser)).to.be.true; + }); + }); +}); From 9a38c8e13f925d88ece6955333773bce45ba7536 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:31:32 -0300 Subject: [PATCH 090/170] feat: Allow managing association to business units on departments' creation and update (#32682) --- .changeset/dirty-stingrays-beg.md | 7 + .../imports/server/rest/departments.ts | 15 +- .../app/livechat/server/lib/LivechatTyped.ts | 25 +- .../livechat/server/methods/saveDepartment.ts | 5 +- .../livechat-enterprise/server/hooks/index.ts | 1 + .../server/hooks/manageDepartmentUnit.ts | 53 ++ .../ee/server/models/raw/LivechatUnit.ts | 29 +- .../server/hooks/manageDepartmentUnit.spec.ts | 183 ++++++ apps/meteor/lib/callbacks.ts | 2 + .../server/models/raw/LivechatDepartment.ts | 12 + apps/meteor/tests/data/livechat/department.ts | 40 +- apps/meteor/tests/data/livechat/rooms.ts | 47 +- apps/meteor/tests/data/livechat/units.ts | 38 +- .../tests/end-to-end/api/livechat/14-units.ts | 556 +++++++++++++++++- .../core-typings/src/ILivechatDepartment.ts | 1 + .../src/models/ILivechatDepartmentModel.ts | 3 + .../src/models/ILivechatUnitModel.ts | 2 + packages/rest-typings/src/v1/omnichannel.ts | 12 +- 18 files changed, 982 insertions(+), 49 deletions(-) create mode 100644 .changeset/dirty-stingrays-beg.md create mode 100644 apps/meteor/ee/app/livechat-enterprise/server/hooks/manageDepartmentUnit.ts create mode 100644 apps/meteor/ee/tests/unit/apps/livechat-enterprise/server/hooks/manageDepartmentUnit.spec.ts diff --git a/.changeset/dirty-stingrays-beg.md b/.changeset/dirty-stingrays-beg.md new file mode 100644 index 000000000000..cf5e3a4ca839 --- /dev/null +++ b/.changeset/dirty-stingrays-beg.md @@ -0,0 +1,7 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/model-typings": minor +"@rocket.chat/rest-typings": minor +--- + +Added support for specifying a unit on departments' creation and update diff --git a/apps/meteor/app/livechat/imports/server/rest/departments.ts b/apps/meteor/app/livechat/imports/server/rest/departments.ts index 252a83855700..e56feeac2fa3 100644 --- a/apps/meteor/app/livechat/imports/server/rest/departments.ts +++ b/apps/meteor/app/livechat/imports/server/rest/departments.ts @@ -57,10 +57,18 @@ API.v1.addRoute( check(this.bodyParams, { department: Object, agents: Match.Maybe(Array), + departmentUnit: Match.Maybe({ _id: Match.Optional(String) }), }); const agents = this.bodyParams.agents ? { upsert: this.bodyParams.agents } : {}; - const department = await LivechatTs.saveDepartment(null, this.bodyParams.department as ILivechatDepartment, agents); + const { departmentUnit } = this.bodyParams; + const department = await LivechatTs.saveDepartment( + this.userId, + null, + this.bodyParams.department as ILivechatDepartment, + agents, + departmentUnit || {}, + ); if (department) { return API.v1.success({ @@ -112,17 +120,18 @@ API.v1.addRoute( check(this.bodyParams, { department: Object, agents: Match.Maybe(Array), + departmentUnit: Match.Maybe({ _id: Match.Optional(String) }), }); const { _id } = this.urlParams; - const { department, agents } = this.bodyParams; + const { department, agents, departmentUnit } = this.bodyParams; if (!permissionToSave) { throw new Error('error-not-allowed'); } const agentParam = permissionToAddAgents && agents ? { upsert: agents } : {}; - await LivechatTs.saveDepartment(_id, department, agentParam); + await LivechatTs.saveDepartment(this.userId, _id, department, agentParam, departmentUnit || {}); return API.v1.success({ department: await LivechatDepartment.findOneById(_id), diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts index 89d125033977..ade6726336ec 100644 --- a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts +++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts @@ -1789,18 +1789,37 @@ class LivechatClass { * @param {string|null} _id - The department id * @param {Partial} departmentData * @param {{upsert?: { agentId: string; count?: number; order?: number; }[], remove?: { agentId: string; count?: number; order?: number; }}} [departmentAgents] - The department agents + * @param {{_id?: string}} [departmentUnit] - The department's unit id */ async saveDepartment( + userId: string, _id: string | null, departmentData: LivechatDepartmentDTO, departmentAgents?: { upsert?: { agentId: string; count?: number; order?: number }[]; remove?: { agentId: string; count?: number; order?: number }; }, + departmentUnit?: { _id?: string }, ) { check(_id, Match.Maybe(String)); + if (departmentUnit?._id !== undefined && typeof departmentUnit._id !== 'string') { + throw new Meteor.Error('error-invalid-department-unit', 'Invalid department unit id provided', { + method: 'livechat:saveDepartment', + }); + } - const department = _id ? await LivechatDepartment.findOneById(_id, { projection: { _id: 1, archived: 1, enabled: 1 } }) : null; + const department = _id + ? await LivechatDepartment.findOneById(_id, { projection: { _id: 1, archived: 1, enabled: 1, parentId: 1 } }) + : null; + + if (departmentUnit && !departmentUnit._id && department && department.parentId) { + const isLastDepartmentInUnit = (await LivechatDepartment.countDepartmentsInUnit(department.parentId)) === 1; + if (isLastDepartmentInUnit) { + throw new Meteor.Error('error-unit-cant-be-empty', "The last department in a unit can't be removed", { + method: 'livechat:saveDepartment', + }); + } + } if (!department && !(await isDepartmentCreationAvailable())) { throw new Meteor.Error('error-max-departments-number-reached', 'Maximum number of departments reached', { @@ -1887,6 +1906,10 @@ class LivechatClass { await callbacks.run('livechat.afterDepartmentDisabled', departmentDB); } + if (departmentUnit) { + await callbacks.run('livechat.manageDepartmentUnit', { userId, departmentId: departmentDB._id, unitId: departmentUnit._id }); + } + return departmentDB; } } diff --git a/apps/meteor/app/livechat/server/methods/saveDepartment.ts b/apps/meteor/app/livechat/server/methods/saveDepartment.ts index b4833523ab3f..659f85f49945 100644 --- a/apps/meteor/app/livechat/server/methods/saveDepartment.ts +++ b/apps/meteor/app/livechat/server/methods/saveDepartment.ts @@ -30,12 +30,13 @@ declare module '@rocket.chat/ddp-client' { order?: number | undefined; }[] | undefined, + departmentUnit?: { _id?: string }, ) => ILivechatDepartment; } } Meteor.methods({ - async 'livechat:saveDepartment'(_id, departmentData, departmentAgents) { + async 'livechat:saveDepartment'(_id, departmentData, departmentAgents, departmentUnit) { const uid = Meteor.userId(); if (!uid || !(await hasPermissionAsync(uid, 'manage-livechat-departments'))) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { @@ -43,6 +44,6 @@ Meteor.methods({ }); } - return Livechat.saveDepartment(_id, departmentData, { upsert: departmentAgents }); + return Livechat.saveDepartment(uid, _id, departmentData, { upsert: departmentAgents }, departmentUnit); }, }); diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/index.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/index.ts index c5bf0a5aa392..a4b66087be2e 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/index.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/index.ts @@ -26,3 +26,4 @@ import './afterInquiryQueued'; import './sendPdfTranscriptOnClose'; import './applyRoomRestrictions'; import './afterTagRemoved'; +import './manageDepartmentUnit'; diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/manageDepartmentUnit.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/manageDepartmentUnit.ts new file mode 100644 index 000000000000..7de7ef0d6bf6 --- /dev/null +++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/manageDepartmentUnit.ts @@ -0,0 +1,53 @@ +import type { ILivechatDepartment, IOmnichannelBusinessUnit } from '@rocket.chat/core-typings'; +import { LivechatDepartment, LivechatUnit } from '@rocket.chat/models'; + +import { hasAnyRoleAsync } from '../../../../../app/authorization/server/functions/hasRole'; +import { callbacks } from '../../../../../lib/callbacks'; +import { getUnitsFromUser } from '../methods/getUnitsFromUserRoles'; + +export const manageDepartmentUnit = async ({ userId, departmentId, unitId }: { userId: string; departmentId: string; unitId: string }) => { + const accessibleUnits = await getUnitsFromUser(userId); + const isLivechatManager = await hasAnyRoleAsync(userId, ['admin', 'livechat-manager']); + const department = await LivechatDepartment.findOneById>(departmentId, { + projection: { ancestors: 1, parentId: 1 }, + }); + + const isDepartmentAlreadyInUnit = unitId && department?.ancestors?.includes(unitId); + if (!department || isDepartmentAlreadyInUnit) { + return; + } + + const currentDepartmentUnitId = department.parentId; + const canManageNewUnit = !unitId || isLivechatManager || (Array.isArray(accessibleUnits) && accessibleUnits.includes(unitId)); + const canManageCurrentUnit = + !currentDepartmentUnitId || isLivechatManager || (Array.isArray(accessibleUnits) && accessibleUnits.includes(currentDepartmentUnitId)); + if (!canManageNewUnit || !canManageCurrentUnit) { + return; + } + + if (unitId) { + const unit = await LivechatUnit.findOneById>(unitId, { + projection: { ancestors: 1 }, + }); + + if (!unit) { + return; + } + + if (currentDepartmentUnitId) { + await LivechatUnit.decrementDepartmentsCount(currentDepartmentUnitId); + } + + await LivechatDepartment.addDepartmentToUnit(departmentId, unitId, [unitId, ...(unit.ancestors || [])]); + await LivechatUnit.incrementDepartmentsCount(unitId); + return; + } + + if (currentDepartmentUnitId) { + await LivechatUnit.decrementDepartmentsCount(currentDepartmentUnitId); + } + + await LivechatDepartment.removeDepartmentFromUnit(departmentId); +}; + +callbacks.add('livechat.manageDepartmentUnit', manageDepartmentUnit, callbacks.priority.HIGH, 'livechat-manage-department-unit'); diff --git a/apps/meteor/ee/server/models/raw/LivechatUnit.ts b/apps/meteor/ee/server/models/raw/LivechatUnit.ts index fcabf12fa4f8..c198ee04fbb0 100644 --- a/apps/meteor/ee/server/models/raw/LivechatUnit.ts +++ b/apps/meteor/ee/server/models/raw/LivechatUnit.ts @@ -11,7 +11,6 @@ const addQueryRestrictions = async (originalQuery: Filter implement // remove other departments for await (const departmentId of savedDepartments) { if (!departmentsToSave.includes(departmentId)) { - await LivechatDepartment.updateOne( - { _id: departmentId }, - { - $set: { - parentId: null, - ancestors: null, - }, - }, - ); + await LivechatDepartment.removeDepartmentFromUnit(departmentId); } } for await (const departmentId of departmentsToSave) { - await LivechatDepartment.updateOne( - { _id: departmentId }, - { - $set: { - parentId: _id, - ancestors, - }, - }, - ); + await LivechatDepartment.addDepartmentToUnit(departmentId, _id, ancestors); } await LivechatRooms.associateRoomsWithDepartmentToUnit(departmentsToSave, _id); @@ -154,6 +137,14 @@ export class LivechatUnitRaw extends BaseRaw implement return this.updateMany(query, update); } + incrementDepartmentsCount(_id: string): Promise { + return this.updateOne({ _id }, { $inc: { numDepartments: 1 } }); + } + + decrementDepartmentsCount(_id: string): Promise { + return this.updateOne({ _id }, { $inc: { numDepartments: -1 } }); + } + async removeById(_id: string): Promise { await LivechatUnitMonitors.removeByUnitId(_id); await this.removeParentAndAncestorById(_id); diff --git a/apps/meteor/ee/tests/unit/apps/livechat-enterprise/server/hooks/manageDepartmentUnit.spec.ts b/apps/meteor/ee/tests/unit/apps/livechat-enterprise/server/hooks/manageDepartmentUnit.spec.ts new file mode 100644 index 000000000000..8fbf0dcf97a2 --- /dev/null +++ b/apps/meteor/ee/tests/unit/apps/livechat-enterprise/server/hooks/manageDepartmentUnit.spec.ts @@ -0,0 +1,183 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import proxyquire from 'proxyquire'; +import sinon from 'sinon'; + +const livechatDepartmentStub = { + findOneById: sinon.stub(), + addDepartmentToUnit: sinon.stub(), + removeDepartmentFromUnit: sinon.stub(), +}; + +const livechatUnitStub = { + findOneById: sinon.stub(), + decrementDepartmentsCount: sinon.stub(), + incrementDepartmentsCount: sinon.stub(), +}; + +const hasAnyRoleStub = sinon.stub(); +const getUnitsFromUserStub = sinon.stub(); + +const { manageDepartmentUnit } = proxyquire + .noCallThru() + .load('../../../../../../app/livechat-enterprise/server/hooks/manageDepartmentUnit.ts', { + '../methods/getUnitsFromUserRoles': { + getUnitsFromUser: getUnitsFromUserStub, + }, + '../../../../../app/authorization/server/functions/hasRole': { + hasAnyRoleAsync: hasAnyRoleStub, + }, + '@rocket.chat/models': { + LivechatDepartment: livechatDepartmentStub, + LivechatUnit: livechatUnitStub, + }, + }); + +describe('hooks/manageDepartmentUnit', () => { + beforeEach(() => { + livechatDepartmentStub.findOneById.reset(); + livechatDepartmentStub.addDepartmentToUnit.reset(); + livechatDepartmentStub.removeDepartmentFromUnit.reset(); + livechatUnitStub.findOneById.reset(); + livechatUnitStub.decrementDepartmentsCount.reset(); + livechatUnitStub.incrementDepartmentsCount.reset(); + hasAnyRoleStub.reset(); + }); + + it('should not perform any operation when an invalid department is provided', async () => { + livechatDepartmentStub.findOneById.resolves(null); + hasAnyRoleStub.resolves(true); + getUnitsFromUserStub.resolves(['unit-id']); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: 'unit-id' }); + expect(livechatDepartmentStub.addDepartmentToUnit.notCalled).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.notCalled).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.notCalled).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.notCalled).to.be.true; + }); + + it('should not perform any operation if the provided department is already in unit', async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id', ancestors: ['unit-id'], parentId: 'unit-id' }); + hasAnyRoleStub.resolves(true); + getUnitsFromUserStub.resolves(['unit-id']); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: 'unit-id' }); + expect(livechatDepartmentStub.addDepartmentToUnit.notCalled).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.notCalled).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.notCalled).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.notCalled).to.be.true; + }); + + it("should not perform any operation if user is a monitor and can't manage new unit", async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id', ancestors: ['unit-id'], parentId: 'unit-id' }); + hasAnyRoleStub.resolves(false); + getUnitsFromUserStub.resolves(['unit-id']); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: 'new-unit-id' }); + expect(livechatDepartmentStub.addDepartmentToUnit.notCalled).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.notCalled).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.notCalled).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.notCalled).to.be.true; + }); + + it("should not perform any operation if user is a monitor and can't manage current unit", async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id', ancestors: ['unit-id'], parentId: 'unit-id' }); + hasAnyRoleStub.resolves(false); + getUnitsFromUserStub.resolves(['new-unit-id']); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: 'new-unit-id' }); + expect(livechatDepartmentStub.addDepartmentToUnit.notCalled).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.notCalled).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.notCalled).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.notCalled).to.be.true; + }); + + it('should not perform any operation if user is an admin/manager but an invalid unit is provided', async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id', ancestors: ['unit-id'], parentId: 'unit-id' }); + livechatUnitStub.findOneById.resolves(undefined); + hasAnyRoleStub.resolves(true); + getUnitsFromUserStub.resolves(undefined); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: 'new-unit-id' }); + expect(livechatDepartmentStub.addDepartmentToUnit.notCalled).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.notCalled).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.notCalled).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.notCalled).to.be.true; + }); + + it('should remove department from its current unit if user is an admin/manager', async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id', ancestors: ['unit-id'], parentId: 'unit-id' }); + hasAnyRoleStub.resolves(true); + getUnitsFromUserStub.resolves(undefined); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: undefined }); + expect(livechatDepartmentStub.addDepartmentToUnit.notCalled).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.notCalled).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.calledOnceWith('department-id')).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.calledOnceWith('unit-id')).to.be.true; + }); + + it('should add department to a unit if user is an admin/manager', async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id' }); + livechatUnitStub.findOneById.resolves({ _id: 'unit-id' }); + hasAnyRoleStub.resolves(true); + getUnitsFromUserStub.resolves(undefined); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: 'unit-id' }); + expect(livechatDepartmentStub.addDepartmentToUnit.calledOnceWith('department-id', 'unit-id', ['unit-id'])).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.calledOnceWith('unit-id')).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.notCalled).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.notCalled).to.be.true; + }); + + it('should move department to a new unit if user is an admin/manager', async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id', ancestors: ['unit-id'], parentId: 'unit-id' }); + livechatUnitStub.findOneById.resolves({ _id: 'new-unit-id' }); + hasAnyRoleStub.resolves(true); + getUnitsFromUserStub.resolves(undefined); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: 'new-unit-id' }); + expect(livechatDepartmentStub.addDepartmentToUnit.calledOnceWith('department-id', 'new-unit-id', ['new-unit-id'])).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.calledOnceWith('new-unit-id')).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.notCalled).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.calledOnceWith('unit-id')).to.be.true; + }); + + it('should remove department from its current unit if user is a monitor that supervises the current unit', async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id', ancestors: ['unit-id'], parentId: 'unit-id' }); + hasAnyRoleStub.resolves(false); + getUnitsFromUserStub.resolves(['unit-id']); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: undefined }); + expect(livechatDepartmentStub.addDepartmentToUnit.notCalled).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.notCalled).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.calledOnceWith('department-id')).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.calledOnceWith('unit-id')).to.be.true; + }); + + it('should add department to a unit if user is a monitor that supervises the new unit', async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id' }); + livechatUnitStub.findOneById.resolves({ _id: 'unit-id' }); + hasAnyRoleStub.resolves(false); + getUnitsFromUserStub.resolves(['unit-id']); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: 'unit-id' }); + expect(livechatDepartmentStub.addDepartmentToUnit.calledOnceWith('department-id', 'unit-id', ['unit-id'])).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.calledOnceWith('unit-id')).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.notCalled).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.notCalled).to.be.true; + }); + + it('should move department to a new unit if user is a monitor that supervises the current and new units', async () => { + livechatDepartmentStub.findOneById.resolves({ _id: 'department-id', ancestors: ['unit-id'], parentId: 'unit-id' }); + livechatUnitStub.findOneById.resolves({ _id: 'unit-id' }); + hasAnyRoleStub.resolves(false); + getUnitsFromUserStub.resolves(['unit-id', 'new-unit-id']); + + await manageDepartmentUnit({ userId: 'user-id', departmentId: 'department-id', unitId: 'new-unit-id' }); + expect(livechatDepartmentStub.addDepartmentToUnit.calledOnceWith('department-id', 'new-unit-id', ['new-unit-id'])).to.be.true; + expect(livechatUnitStub.incrementDepartmentsCount.calledOnceWith('new-unit-id')).to.be.true; + expect(livechatDepartmentStub.removeDepartmentFromUnit.notCalled).to.be.true; + expect(livechatUnitStub.decrementDepartmentsCount.calledOnceWith('unit-id')).to.be.true; + }); +}); diff --git a/apps/meteor/lib/callbacks.ts b/apps/meteor/lib/callbacks.ts index 7eaa9ed7595d..57b8527d5008 100644 --- a/apps/meteor/lib/callbacks.ts +++ b/apps/meteor/lib/callbacks.ts @@ -225,6 +225,7 @@ type ChainedCallbackSignatures = { 'unarchiveRoom': (room: IRoom) => void; 'roomAvatarChanged': (room: IRoom) => void; 'beforeGetMentions': (mentionIds: string[], teamMentions: MessageMention[]) => Promise; + 'livechat.manageDepartmentUnit': (params: { userId: string; departmentId: string; unitId?: string }) => void; }; export type Hook = @@ -247,6 +248,7 @@ export type Hook = | 'livechat.offlineMessage' | 'livechat.onCheckRoomApiParams' | 'livechat.onLoadConfigApi' + | 'livechat.manageDepartmentUnit' | 'loginPageStateChange' | 'mapLDAPUserData' | 'onCreateUser' diff --git a/apps/meteor/server/models/raw/LivechatDepartment.ts b/apps/meteor/server/models/raw/LivechatDepartment.ts index b8263af030a8..9ecee34df5e9 100644 --- a/apps/meteor/server/models/raw/LivechatDepartment.ts +++ b/apps/meteor/server/models/raw/LivechatDepartment.ts @@ -222,6 +222,14 @@ export class LivechatDepartmentRaw extends BaseRaw implemen return this.updateOne({ _id }, { $set: { archived: true, enabled: false } }); } + addDepartmentToUnit(_id: string, unitId: string, ancestors: string[]): Promise { + return this.updateOne({ _id }, { $set: { parentId: unitId, ancestors } }); + } + + removeDepartmentFromUnit(_id: string): Promise { + return this.updateOne({ _id }, { $set: { parentId: null, ancestors: null } }); + } + async createOrUpdateDepartment( _id: string | null, data: { @@ -328,6 +336,10 @@ export class LivechatDepartmentRaw extends BaseRaw implemen return this.find(query, options); } + countDepartmentsInUnit(unitId: string): Promise { + return this.countDocuments({ parentId: unitId }); + } + findActiveByUnitIds(unitIds: string[], options: FindOptions = {}): FindCursor { const query = { enabled: true, diff --git a/apps/meteor/tests/data/livechat/department.ts b/apps/meteor/tests/data/livechat/department.ts index 72ab0af9f267..d7f22fca970b 100644 --- a/apps/meteor/tests/data/livechat/department.ts +++ b/apps/meteor/tests/data/livechat/department.ts @@ -42,36 +42,44 @@ const updateDepartment = async (departmentId: string, departmentData: Partial

  • +export const createDepartmentWithMethod = ({ + initialAgents = [], + allowReceiveForwardOffline = false, + fallbackForwardDepartment, + name, + departmentUnit, + userCredentials = credentials, + departmentId = '', +}: { + initialAgents?: { agentId: string; username: string }[]; + allowReceiveForwardOffline?: boolean; + fallbackForwardDepartment?: string; + name?: string; + departmentUnit?: { _id?: string }; + userCredentials?: Credentials; + departmentId?: string; +} = {}): Promise => new Promise((resolve, reject) => { void request .post(methodCall('livechat:saveDepartment')) - .set(credentials) + .set(userCredentials) .send({ message: JSON.stringify({ method: 'livechat:saveDepartment', params: [ - '', + departmentId, { enabled: true, email: faker.internet.email(), showOnRegistration: true, showOnOfflineForm: true, - name: `new department ${Date.now()}`, + name: name || `new department ${Date.now()}`, description: 'created from api', allowReceiveForwardOffline, fallbackForwardDepartment, }, initialAgents, + departmentUnit, ], id: 'id', msg: 'method', @@ -93,7 +101,7 @@ type OnlineAgent = { export const createDepartmentWithAnOnlineAgent = async (): Promise<{ department: ILivechatDepartment; agent: OnlineAgent }> => { const { user, credentials } = await createAnOnlineAgent(); - const department = (await createDepartmentWithMethod()) as ILivechatDepartment; + const department = await createDepartmentWithMethod(); await addOrRemoveAgentFromDepartment(department._id, { agentId: user._id, username: user.username }, true); @@ -108,7 +116,7 @@ export const createDepartmentWithAnOnlineAgent = async (): Promise<{ department: export const createDepartmentWithAgent = async (agent: OnlineAgent): Promise<{ department: ILivechatDepartment; agent: OnlineAgent }> => { const { user, credentials } = agent; - const department = (await createDepartmentWithMethod()) as ILivechatDepartment; + const department = await createDepartmentWithMethod(); await addOrRemoveAgentFromDepartment(department._id, { agentId: user._id, username: user.username }, true); @@ -153,7 +161,7 @@ export const createDepartmentWithAnOfflineAgent = async ({ }> => { const { user, credentials } = await createAnOfflineAgent(); - const department = (await createDepartmentWithMethod(undefined, { + const department = (await createDepartmentWithMethod({ allowReceiveForwardOffline, fallbackForwardDepartment, })) as ILivechatDepartment; diff --git a/apps/meteor/tests/data/livechat/rooms.ts b/apps/meteor/tests/data/livechat/rooms.ts index b5d89762c614..46e5cbe489a9 100644 --- a/apps/meteor/tests/data/livechat/rooms.ts +++ b/apps/meteor/tests/data/livechat/rooms.ts @@ -98,11 +98,55 @@ export const createDepartment = ( name?: string, enabled = true, opts: Record = {}, + departmentUnit?: { _id?: string }, + userCredentials: Credentials = credentials, ): Promise => { return new Promise((resolve, reject) => { void request .post(api('livechat/department')) - .set(credentials) + .set(userCredentials) + .send({ + department: { + name: name || `Department ${Date.now()}`, + enabled, + showOnOfflineForm: true, + showOnRegistration: true, + email: 'a@b.com', + ...opts, + }, + agents, + departmentUnit, + }) + .end((err: Error, res: DummyResponse) => { + if (err) { + return reject(err); + } + resolve(res.body.department); + }); + }); +}; + +export const updateDepartment = ({ + departmentId, + userCredentials, + agents, + name, + enabled = true, + opts = {}, + departmentUnit, +}: { + departmentId: string; + userCredentials: Credentials; + agents?: { agentId: string }[]; + name?: string; + enabled?: boolean; + opts?: Record; + departmentUnit?: { _id?: string }; +}): Promise => { + return new Promise((resolve, reject) => { + void request + .put(api(`livechat/department/${departmentId}`)) + .set(userCredentials) .send({ department: { name: name || `Department ${Date.now()}`, @@ -113,6 +157,7 @@ export const createDepartment = ( ...opts, }, agents, + departmentUnit, }) .end((err: Error, res: DummyResponse) => { if (err) { diff --git a/apps/meteor/tests/data/livechat/units.ts b/apps/meteor/tests/data/livechat/units.ts index 03ea578e654d..8a2d0f5a833a 100644 --- a/apps/meteor/tests/data/livechat/units.ts +++ b/apps/meteor/tests/data/livechat/units.ts @@ -1,7 +1,7 @@ import { faker } from '@faker-js/faker'; import type { IOmnichannelBusinessUnit } from '@rocket.chat/core-typings'; -import { methodCall, credentials, request } from '../api-data'; +import { methodCall, credentials, request, api } from '../api-data'; import type { DummyResponse } from './utils'; export const createMonitor = async (username: string): Promise<{ _id: string; username: string }> => { @@ -57,3 +57,39 @@ export const createUnit = async ( }); }); }; + +export const deleteUnit = async (unit: IOmnichannelBusinessUnit): Promise => { + return new Promise((resolve, reject) => { + void request + .post(methodCall(`livechat:removeUnit`)) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'livechat:removeUnit', + params: [unit._id], + id: '101', + msg: 'method', + }), + }) + .end((err: Error, res: DummyResponse) => { + if (err) { + return reject(err); + } + resolve(JSON.parse(res.body.message).result); + }); + }); +}; + +export const getUnit = (unitId: string): Promise => { + return new Promise((resolve, reject) => { + void request + .get(api(`livechat/units/${unitId}`)) + .set(credentials) + .end((err: Error, res: DummyResponse) => { + if (err) { + return reject(err); + } + resolve(res.body); + }); + }); +}; diff --git a/apps/meteor/tests/end-to-end/api/livechat/14-units.ts b/apps/meteor/tests/end-to-end/api/livechat/14-units.ts index 425c776fecdb..e0c079ece243 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/14-units.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/14-units.ts @@ -1,12 +1,14 @@ import type { ILivechatDepartment, IOmnichannelBusinessUnit } from '@rocket.chat/core-typings'; import { expect } from 'chai'; -import { before, describe, it } from 'mocha'; +import { before, after, describe, it } from 'mocha'; -import { getCredentials, api, request, credentials } from '../../../data/api-data'; -import { createDepartment } from '../../../data/livechat/rooms'; -import { createMonitor, createUnit } from '../../../data/livechat/units'; +import { getCredentials, api, request, credentials, methodCall } from '../../../data/api-data'; +import { deleteDepartment, getDepartmentById, createDepartmentWithMethod } from '../../../data/livechat/department'; +import { createDepartment, updateDepartment } from '../../../data/livechat/rooms'; +import { createMonitor, createUnit, deleteUnit, getUnit } from '../../../data/livechat/units'; import { updatePermission, updateSetting } from '../../../data/permissions.helper'; -import { createUser, deleteUser } from '../../../data/users.helper'; +import { password } from '../../../data/user'; +import { createUser, deleteUser, login } from '../../../data/users.helper'; import { IS_EE } from '../../../e2e/config/constants'; (IS_EE ? describe : describe.skip)('[EE] LIVECHAT - Units', () => { @@ -14,6 +16,7 @@ import { IS_EE } from '../../../e2e/config/constants'; before(async () => { await updateSetting('Livechat_enabled', true); + await updatePermission('manage-livechat-departments', ['livechat-manager', 'livechat-monitor', 'admin']); }); describe('[GET] livechat/units', () => { @@ -409,4 +412,547 @@ import { IS_EE } from '../../../e2e/config/constants'; await deleteUser(user); }); }); + + describe('[POST] livechat/department', () => { + let monitor1: Awaited>; + let monitor1Credentials: Awaited>; + let monitor2: Awaited>; + let monitor2Credentials: Awaited>; + let unit: IOmnichannelBusinessUnit; + + before(async () => { + monitor1 = await createUser(); + monitor2 = await createUser(); + await createMonitor(monitor1.username); + monitor1Credentials = await login(monitor1.username, password); + await createMonitor(monitor2.username); + monitor2Credentials = await login(monitor2.username, password); + unit = await createUnit(monitor1._id, monitor1.username, []); + }); + + after(async () => Promise.all([deleteUser(monitor1), deleteUser(monitor2), deleteUnit(unit)])); + + it('should fail creating department when providing an invalid property in the department unit object', () => { + return request + .post(api('livechat/department')) + .set(credentials) + .send({ + department: { name: 'Fail-Test', enabled: true, showOnOfflineForm: true, showOnRegistration: true, email: 'bla@bla' }, + departmentUnit: { invalidProperty: true }, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'invalid-params'); + }); + }); + + it('should fail creating a department into an existing unit that a monitor does not supervise', async () => { + const department = await createDepartment(undefined, undefined, undefined, undefined, { _id: unit._id }, monitor2Credentials); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 0); + + const fullDepartment = await getDepartmentById(department._id); + expect(fullDepartment).to.not.have.property('parentId'); + expect(fullDepartment).to.not.have.property('ancestors'); + + await deleteDepartment(department._id); + }); + + it('should succesfully create a department into an existing unit as an admin', async () => { + const department = await createDepartment(undefined, undefined, undefined, undefined, { _id: unit._id }); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 1); + + const fullDepartment = await getDepartmentById(department._id); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + + await deleteDepartment(department._id); + }); + + it('should succesfully create a department into an existing unit that a monitor supervises', async () => { + const department = await createDepartment(undefined, undefined, undefined, undefined, { _id: unit._id }, monitor1Credentials); + + // Deleting a department currently does not decrease its unit's counter. We must adjust this check when this is fixed + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 2); + + const fullDepartment = await getDepartmentById(department._id); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + + await deleteDepartment(department._id); + }); + }); + + describe('[PUT] livechat/department', () => { + let monitor1: Awaited>; + let monitor1Credentials: Awaited>; + let monitor2: Awaited>; + let monitor2Credentials: Awaited>; + let unit: IOmnichannelBusinessUnit; + let department: ILivechatDepartment; + let baseDepartment: ILivechatDepartment; + + before(async () => { + monitor1 = await createUser(); + monitor2 = await createUser(); + await createMonitor(monitor1.username); + monitor1Credentials = await login(monitor1.username, password); + await createMonitor(monitor2.username); + monitor2Credentials = await login(monitor2.username, password); + department = await createDepartment(); + baseDepartment = await createDepartment(); + unit = await createUnit(monitor1._id, monitor1.username, [baseDepartment._id]); + }); + + after(async () => + Promise.all([ + deleteUser(monitor1), + deleteUser(monitor2), + deleteUnit(unit), + deleteDepartment(department._id), + deleteDepartment(baseDepartment._id), + ]), + ); + + it("should fail updating a department's unit when providing an invalid property in the department unit object", () => { + const updatedName = 'updated-department-name'; + return request + .put(api(`livechat/department/${department._id}`)) + .set(credentials) + .send({ + department: { name: updatedName, enabled: true, showOnOfflineForm: true, showOnRegistration: true, email: 'bla@bla' }, + departmentUnit: { invalidProperty: true }, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'Match error: Unknown key in field departmentUnit.invalidProperty'); + }); + }); + + it("should fail updating a department's unit when providing an invalid _id type in the department unit object", () => { + const updatedName = 'updated-department-name'; + return request + .put(api(`livechat/department/${department._id}`)) + .set(credentials) + .send({ + department: { name: updatedName, enabled: true, showOnOfflineForm: true, showOnRegistration: true, email: 'bla@bla' }, + departmentUnit: { _id: true }, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'Match error: Expected string, got boolean in field departmentUnit._id'); + }); + }); + + it('should fail removing the last department from a unit', () => { + const updatedName = 'updated-department-name'; + return request + .put(api(`livechat/department/${baseDepartment._id}`)) + .set(credentials) + .send({ + department: { name: updatedName, enabled: true, showOnOfflineForm: true, showOnRegistration: true, email: 'bla@bla' }, + departmentUnit: {}, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-unit-cant-be-empty'); + }); + }); + + it('should succesfully add an existing department to a unit as an admin', async () => { + const updatedName = 'updated-department-name'; + + const updatedDepartment = await updateDepartment({ + userCredentials: credentials, + departmentId: department._id, + name: updatedName, + departmentUnit: { _id: unit._id }, + }); + expect(updatedDepartment).to.have.property('name', updatedName); + expect(updatedDepartment).to.have.property('type', 'd'); + expect(updatedDepartment).to.have.property('_id', department._id); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 2); + + const fullDepartment = await getDepartmentById(department._id); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + }); + + it('should succesfully remove an existing department from a unit as an admin', async () => { + const updatedName = 'updated-department-name'; + + const updatedDepartment = await updateDepartment({ + userCredentials: credentials, + departmentId: department._id, + name: updatedName, + departmentUnit: {}, + }); + expect(updatedDepartment).to.have.property('name', updatedName); + expect(updatedDepartment).to.have.property('type', 'd'); + expect(updatedDepartment).to.have.property('_id', department._id); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 1); + + const fullDepartment = await getDepartmentById(department._id); + expect(fullDepartment).to.have.property('parentId').that.is.null; + expect(fullDepartment).to.have.property('ancestors').that.is.null; + }); + + it('should fail adding a department into an existing unit that a monitor does not supervise', async () => { + const updatedName = 'updated-department-name2'; + + const updatedDepartment = await updateDepartment({ + userCredentials: monitor2Credentials, + departmentId: department._id, + name: updatedName, + departmentUnit: { _id: unit._id }, + }); + expect(updatedDepartment).to.have.property('name', updatedName); + expect(updatedDepartment).to.have.property('type', 'd'); + expect(updatedDepartment).to.have.property('_id', department._id); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 1); + + const fullDepartment = await getDepartmentById(department._id); + expect(fullDepartment).to.have.property('parentId').that.is.null; + expect(fullDepartment).to.have.property('ancestors').that.is.null; + }); + + it('should succesfully add a department into an existing unit that a monitor supervises', async () => { + const updatedName = 'updated-department-name3'; + + const updatedDepartment = await updateDepartment({ + userCredentials: monitor1Credentials, + departmentId: department._id, + name: updatedName, + departmentUnit: { _id: unit._id }, + }); + expect(updatedDepartment).to.have.property('name', updatedName); + expect(updatedDepartment).to.have.property('type', 'd'); + expect(updatedDepartment).to.have.property('_id', department._id); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 2); + + const fullDepartment = await getDepartmentById(department._id); + expect(fullDepartment).to.have.property('name', updatedName); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + }); + + it('should fail removing a department from a unit that a monitor does not supervise', async () => { + const updatedName = 'updated-department-name4'; + + const updatedDepartment = await updateDepartment({ + userCredentials: monitor2Credentials, + departmentId: department._id, + name: updatedName, + departmentUnit: {}, + }); + expect(updatedDepartment).to.have.property('name', updatedName); + expect(updatedDepartment).to.have.property('type', 'd'); + expect(updatedDepartment).to.have.property('_id', department._id); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 2); + + const fullDepartment = await getDepartmentById(department._id); + expect(fullDepartment).to.have.property('name', updatedName); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + }); + + it('should succesfully remove a department from a unit that a monitor supervises', async () => { + const updatedName = 'updated-department-name5'; + + const updatedDepartment = await updateDepartment({ + userCredentials: monitor1Credentials, + departmentId: department._id, + name: updatedName, + departmentUnit: {}, + }); + expect(updatedDepartment).to.have.property('name', updatedName); + expect(updatedDepartment).to.have.property('type', 'd'); + expect(updatedDepartment).to.have.property('_id', department._id); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 1); + + const fullDepartment = await getDepartmentById(department._id); + expect(fullDepartment).to.have.property('name', updatedName); + expect(fullDepartment).to.have.property('parentId').that.is.null; + expect(fullDepartment).to.have.property('ancestors').that.is.null; + }); + }); + + describe('[POST] livechat:saveDepartment', () => { + let monitor1: Awaited>; + let monitor1Credentials: Awaited>; + let monitor2: Awaited>; + let monitor2Credentials: Awaited>; + let unit: IOmnichannelBusinessUnit; + const departmentName = 'Test-Department-Livechat-Method'; + let testDepartmentId = ''; + let baseDepartment: ILivechatDepartment; + + before(async () => { + monitor1 = await createUser(); + monitor2 = await createUser(); + await createMonitor(monitor1.username); + monitor1Credentials = await login(monitor1.username, password); + await createMonitor(monitor2.username); + monitor2Credentials = await login(monitor2.username, password); + baseDepartment = await createDepartment(); + unit = await createUnit(monitor1._id, monitor1.username, [baseDepartment._id]); + }); + + after(async () => + Promise.all([ + deleteUser(monitor1), + deleteUser(monitor2), + deleteUnit(unit), + deleteDepartment(testDepartmentId), + deleteDepartment(baseDepartment._id), + ]), + ); + + it('should fail creating department when providing an invalid _id type in the department unit object', () => { + return request + .post(methodCall('livechat:saveDepartment')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'livechat:saveDepartment', + params: [ + '', + { name: 'Fail-Test', enabled: true, showOnOfflineForm: true, showOnRegistration: true, email: 'bla@bla' }, + [], + { _id: true }, + ], + id: 'id', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.property('error').that.is.an('object'); + expect(data.error).to.have.property('errorType', 'Meteor.Error'); + expect(data.error).to.have.property('error', 'error-invalid-department-unit'); + }); + }); + + it('should fail removing last department from unit', () => { + return request + .post(methodCall('livechat:saveDepartment')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'livechat:saveDepartment', + params: [ + baseDepartment._id, + { name: 'Fail-Test', enabled: true, showOnOfflineForm: true, showOnRegistration: true, email: 'bla@bla' }, + [], + {}, + ], + id: 'id', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.property('error').that.is.an('object'); + expect(data.error).to.have.property('errorType', 'Meteor.Error'); + expect(data.error).to.have.property('error', 'error-unit-cant-be-empty'); + }); + }); + + it('should fail creating a department into an existing unit that a monitor does not supervise', async () => { + const departmentName = 'Fail-Test'; + + const department = await createDepartmentWithMethod({ + userCredentials: monitor2Credentials, + name: departmentName, + departmentUnit: { _id: unit._id }, + }); + testDepartmentId = department._id; + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 1); + + const fullDepartment = await getDepartmentById(testDepartmentId); + expect(fullDepartment).to.not.have.property('parentId'); + expect(fullDepartment).to.not.have.property('ancestors'); + + await deleteDepartment(testDepartmentId); + }); + + it('should succesfully create a department into an existing unit as an admin', async () => { + const testDepartment = await createDepartmentWithMethod({ name: departmentName, departmentUnit: { _id: unit._id } }); + testDepartmentId = testDepartment._id; + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 2); + + const fullDepartment = await getDepartmentById(testDepartmentId); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + }); + + it('should succesfully remove an existing department from a unit as an admin', async () => { + await createDepartmentWithMethod({ name: departmentName, departmentUnit: {}, departmentId: testDepartmentId }); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 1); + + const fullDepartment = await getDepartmentById(testDepartmentId); + expect(fullDepartment).to.have.property('parentId').that.is.null; + expect(fullDepartment).to.have.property('ancestors').that.is.null; + }); + + it('should succesfully add an existing department to a unit as an admin', async () => { + await createDepartmentWithMethod({ name: departmentName, departmentUnit: { _id: unit._id }, departmentId: testDepartmentId }); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 2); + + const fullDepartment = await getDepartmentById(testDepartmentId); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + }); + + it('should succesfully remove a department from a unit that a monitor supervises', async () => { + await createDepartmentWithMethod({ + name: departmentName, + departmentUnit: {}, + departmentId: testDepartmentId, + userCredentials: monitor1Credentials, + }); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 1); + + const fullDepartment = await getDepartmentById(testDepartmentId); + expect(fullDepartment).to.have.property('parentId').that.is.null; + expect(fullDepartment).to.have.property('ancestors').that.is.null; + }); + + it('should succesfully add an existing department to a unit that a monitor supervises', async () => { + await createDepartmentWithMethod({ + name: departmentName, + departmentUnit: { _id: unit._id }, + departmentId: testDepartmentId, + userCredentials: monitor1Credentials, + }); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 2); + + const fullDepartment = await getDepartmentById(testDepartmentId); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + }); + + it('should fail removing a department from a unit that a monitor does not supervise', async () => { + await createDepartmentWithMethod({ + name: departmentName, + departmentUnit: {}, + departmentId: testDepartmentId, + userCredentials: monitor2Credentials, + }); + + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 2); + + const fullDepartment = await getDepartmentById(testDepartmentId); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + + await deleteDepartment(testDepartmentId); + }); + + it('should succesfully create a department in a unit that a monitor supervises', async () => { + const testDepartment = await createDepartmentWithMethod({ + name: departmentName, + departmentUnit: { _id: unit._id }, + userCredentials: monitor1Credentials, + }); + testDepartmentId = testDepartment._id; + + // Deleting a department currently does not decrease its unit's counter. We must adjust this check when this is fixed + const updatedUnit = await getUnit(unit._id); + expect(updatedUnit).to.have.property('name', unit.name); + expect(updatedUnit).to.have.property('numMonitors', 1); + expect(updatedUnit).to.have.property('numDepartments', 3); + + const fullDepartment = await getDepartmentById(testDepartmentId); + expect(fullDepartment).to.have.property('parentId', unit._id); + expect(fullDepartment).to.have.property('ancestors').that.is.an('array').with.lengthOf(1); + expect(fullDepartment.ancestors?.[0]).to.equal(unit._id); + }); + }); }); diff --git a/packages/core-typings/src/ILivechatDepartment.ts b/packages/core-typings/src/ILivechatDepartment.ts index a73cf55cb235..0138a88226fb 100644 --- a/packages/core-typings/src/ILivechatDepartment.ts +++ b/packages/core-typings/src/ILivechatDepartment.ts @@ -16,6 +16,7 @@ export interface ILivechatDepartment { archived?: boolean; departmentsAllowedToForward?: string[]; maxNumberSimultaneousChat?: number; + parentId?: string; ancestors?: string[]; allowReceiveForwardOffline?: boolean; // extra optional fields diff --git a/packages/model-typings/src/models/ILivechatDepartmentModel.ts b/packages/model-typings/src/models/ILivechatDepartmentModel.ts index 75fe0f54b2eb..fe366256eff7 100644 --- a/packages/model-typings/src/models/ILivechatDepartmentModel.ts +++ b/packages/model-typings/src/models/ILivechatDepartmentModel.ts @@ -59,6 +59,7 @@ export interface ILivechatDepartmentModel extends IBaseModel>; findOneByIdOrName(_idOrName: string, options?: FindOptions): Promise; findByUnitIds(unitIds: string[], options?: FindOptions): FindCursor; + countDepartmentsInUnit(unitId: string): Promise; findActiveByUnitIds(unitIds: string[], options?: FindOptions): FindCursor; findNotArchived(options?: FindOptions): FindCursor; getBusinessHoursWithDepartmentStatuses(): Promise< @@ -73,4 +74,6 @@ export interface ILivechatDepartmentModel extends IBaseModel): FindCursor; archiveDepartment(_id: string): Promise; unarchiveDepartment(_id: string): Promise; + addDepartmentToUnit(_id: string, unitId: string, ancestors: string[]): Promise; + removeDepartmentFromUnit(_id: string): Promise; } diff --git a/packages/model-typings/src/models/ILivechatUnitModel.ts b/packages/model-typings/src/models/ILivechatUnitModel.ts index 8858ee5b580e..24a482eccd0e 100644 --- a/packages/model-typings/src/models/ILivechatUnitModel.ts +++ b/packages/model-typings/src/models/ILivechatUnitModel.ts @@ -32,6 +32,8 @@ export interface ILivechatUnitModel extends IBaseModel departments: { departmentId: string }[], ): Promise>; removeParentAndAncestorById(parentId: string): Promise; + incrementDepartmentsCount(_id: string): Promise; + decrementDepartmentsCount(_id: string): Promise; removeById(_id: string): Promise; findOneByIdOrName(_idOrName: string, options: FindOptions): Promise; findByMonitorId(monitorId: string): Promise; diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index a1c714c013b8..b494e5d0e5a9 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -576,7 +576,8 @@ type POSTLivechatDepartmentProps = { chatClosingTags?: string[]; fallbackForwardDepartment?: string; }; - agents: { agentId: string; count?: number; order?: number }[]; + agents?: { agentId: string; count?: number; order?: number }[]; + departmentUnit?: { _id?: string }; }; const POSTLivechatDepartmentSchema = { @@ -645,6 +646,15 @@ const POSTLivechatDepartmentSchema = { }, nullable: true, }, + departmentUnit: { + type: 'object', + properties: { + _id: { + type: 'string', + }, + }, + additionalProperties: false, + }, }, required: ['department'], additionalProperties: false, From fdde637f92928f0f59d3b089c889fdfe979100d0 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Wed, 18 Sep 2024 11:29:22 -0300 Subject: [PATCH 091/170] fix: Local avatars prioritized over external avatar provider and remove remnant references on client of `Accounts_AvatarExternalProviderUrl` (#33296) Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com> --- .changeset/strong-grapes-brake.md | 9 +++++++++ apps/meteor/app/utils/client/getUserAvatarURL.ts | 5 ----- apps/meteor/app/utils/server/getUserAvatarURL.ts | 5 ----- apps/meteor/client/providers/AvatarUrlProvider.tsx | 8 ++------ apps/meteor/server/routes/avatar/user.js | 14 +++++++------- 5 files changed, 18 insertions(+), 23 deletions(-) create mode 100644 .changeset/strong-grapes-brake.md diff --git a/.changeset/strong-grapes-brake.md b/.changeset/strong-grapes-brake.md new file mode 100644 index 000000000000..c867600a8cd2 --- /dev/null +++ b/.changeset/strong-grapes-brake.md @@ -0,0 +1,9 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixed remaining direct references to external user avatar URLs + +Fixed local avatars having priority over external provider + +It mainly corrects the behavior of E2E encryption messages and desktop notifications. diff --git a/apps/meteor/app/utils/client/getUserAvatarURL.ts b/apps/meteor/app/utils/client/getUserAvatarURL.ts index 1a825a44fc27..d5fdd2b2d427 100644 --- a/apps/meteor/app/utils/client/getUserAvatarURL.ts +++ b/apps/meteor/app/utils/client/getUserAvatarURL.ts @@ -1,11 +1,6 @@ -import { settings } from '../../settings/client'; import { getAvatarURL } from './getAvatarURL'; export const getUserAvatarURL = function (username: string, cache = ''): string | undefined { - const externalSource = (settings.get('Accounts_AvatarExternalProviderUrl') || '').trim().replace(/\/$/, ''); - if (externalSource !== '') { - return externalSource.replace('{username}', username); - } if (username == null) { return; } diff --git a/apps/meteor/app/utils/server/getUserAvatarURL.ts b/apps/meteor/app/utils/server/getUserAvatarURL.ts index b83efea1d842..d5fdd2b2d427 100644 --- a/apps/meteor/app/utils/server/getUserAvatarURL.ts +++ b/apps/meteor/app/utils/server/getUserAvatarURL.ts @@ -1,11 +1,6 @@ -import { settings } from '../../settings/server'; import { getAvatarURL } from './getAvatarURL'; export const getUserAvatarURL = function (username: string, cache = ''): string | undefined { - const externalSource = (settings.get('Accounts_AvatarExternalProviderUrl') || '').trim().replace(/\/$/, ''); - if (externalSource !== '') { - return externalSource.replace('{username}', username); - } if (username == null) { return; } diff --git a/apps/meteor/client/providers/AvatarUrlProvider.tsx b/apps/meteor/client/providers/AvatarUrlProvider.tsx index b5a92c9117f2..606da39360d5 100644 --- a/apps/meteor/client/providers/AvatarUrlProvider.tsx +++ b/apps/meteor/client/providers/AvatarUrlProvider.tsx @@ -1,4 +1,4 @@ -import { AvatarUrlContext, useSetting } from '@rocket.chat/ui-contexts'; +import { AvatarUrlContext } from '@rocket.chat/ui-contexts'; import type { ReactNode } from 'react'; import React, { useMemo } from 'react'; @@ -10,19 +10,15 @@ type AvatarUrlProviderProps = { }; const AvatarUrlProvider = ({ children }: AvatarUrlProviderProps) => { - const cdnAvatarUrl = String(useSetting('CDN_PREFIX') || ''); const contextValue = useMemo( () => ({ getUserPathAvatar: ((): ((uid: string, etag?: string) => string) => { - if (cdnAvatarUrl) { - return (uid: string, etag?: string): string => `${cdnAvatarUrl}/avatar/${uid}${etag ? `?etag=${etag}` : ''}`; - } return (uid: string, etag?: string): string => getURL(`/avatar/${uid}${etag ? `?etag=${etag}` : ''}`); })(), getRoomPathAvatar: ({ type, ...room }: any): string => roomCoordinator.getRoomDirectives(type || room.t).getAvatarPath({ username: room._id, ...room }) || '', }), - [cdnAvatarUrl], + [], ); return ; diff --git a/apps/meteor/server/routes/avatar/user.js b/apps/meteor/server/routes/avatar/user.js index 269c2e90019a..1c92d24fe300 100644 --- a/apps/meteor/server/routes/avatar/user.js +++ b/apps/meteor/server/routes/avatar/user.js @@ -32,6 +32,13 @@ export const userAvatar = async function (req, res) { return; } + if (settings.get('Accounts_AvatarExternalProviderUrl')) { + const response = await fetch(settings.get('Accounts_AvatarExternalProviderUrl').replace('{username}', requestUsername)); + response.headers.forEach((value, key) => res.setHeader(key, value)); + response.body.pipe(res); + return; + } + const reqModifiedHeader = req.headers['if-modified-since']; const file = await Avatars.findOneByName(requestUsername); @@ -52,13 +59,6 @@ export const userAvatar = async function (req, res) { return FileUpload.get(file, req, res); } - if (settings.get('Accounts_AvatarExternalProviderUrl')) { - const response = await fetch(settings.get('Accounts_AvatarExternalProviderUrl').replace('{username}', requestUsername)); - response.headers.forEach((value, key) => res.setHeader(key, value)); - response.body.pipe(res); - return; - } - // if still using "letters fallback" if (!wasFallbackModified(reqModifiedHeader, res)) { res.writeHead(304); From ba8bee484b77fd83359f95a3c9c52a33e46b667b Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Wed, 18 Sep 2024 12:21:29 -0300 Subject: [PATCH 092/170] fix: Mark as unread not working (#32939) Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com> --- .changeset/hot-balloons-travel.md | 5 ++ .../client/actionButton.ts | 4 +- .../RoomList/SideBarItemTemplateWithData.tsx | 5 +- apps/meteor/client/sidebar/RoomMenu.tsx | 10 ++- .../RoomList/SidebarItemTemplateWithData.tsx | 3 +- apps/meteor/client/sidebarv2/RoomMenu.tsx | 10 ++- apps/meteor/tests/e2e/mark-unread.spec.ts | 71 +++++++++++++++++++ .../page-objects/fragments/home-sidenav.ts | 22 +++++- .../tests/e2e/page-objects/home-channel.ts | 4 ++ 9 files changed, 125 insertions(+), 9 deletions(-) create mode 100644 .changeset/hot-balloons-travel.md create mode 100644 apps/meteor/tests/e2e/mark-unread.spec.ts diff --git a/.changeset/hot-balloons-travel.md b/.changeset/hot-balloons-travel.md new file mode 100644 index 000000000000..d6154babc49d --- /dev/null +++ b/.changeset/hot-balloons-travel.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed issue where when you marked a room as unread and you were part of it, sometimes it would mark it as read right after diff --git a/apps/meteor/app/message-mark-as-unread/client/actionButton.ts b/apps/meteor/app/message-mark-as-unread/client/actionButton.ts index fc4a9d80c43c..e1e35d216029 100644 --- a/apps/meteor/app/message-mark-as-unread/client/actionButton.ts +++ b/apps/meteor/app/message-mark-as-unread/client/actionButton.ts @@ -19,7 +19,6 @@ Meteor.startup(() => { const { message = messageArgs(this).msg } = props; try { - await sdk.call('unreadMessages', message); const subscription = ChatSubscription.findOne({ rid: message.rid, }); @@ -27,8 +26,9 @@ Meteor.startup(() => { if (subscription == null) { return; } + router.navigate('/home'); await LegacyRoomManager.close(subscription.t + subscription.name); - return router.navigate('/home'); + await sdk.call('unreadMessages', message); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } diff --git a/apps/meteor/client/sidebar/RoomList/SideBarItemTemplateWithData.tsx b/apps/meteor/client/sidebar/RoomList/SideBarItemTemplateWithData.tsx index cc7cdfbe7761..35d098151204 100644 --- a/apps/meteor/client/sidebar/RoomList/SideBarItemTemplateWithData.tsx +++ b/apps/meteor/client/sidebar/RoomList/SideBarItemTemplateWithData.tsx @@ -167,7 +167,7 @@ function SideBarItemTemplateWithData({ const badges = ( {showBadge && isUnread && ( - + {unread + tunread?.length} )} @@ -180,6 +180,7 @@ function SideBarItemTemplateWithData({ is='a' id={id} data-qa='sidebar-item' + data-unread={highlighted} unread={highlighted} selected={selected} href={href} @@ -205,7 +206,7 @@ function SideBarItemTemplateWithData({ threadUnread={threadUnread} rid={rid} unread={!!unread} - roomOpen={false} + roomOpen={selected} type={type} cl={cl} name={title} diff --git a/apps/meteor/client/sidebar/RoomMenu.tsx b/apps/meteor/client/sidebar/RoomMenu.tsx index 06b1352d2803..05f02220104b 100644 --- a/apps/meteor/client/sidebar/RoomMenu.tsx +++ b/apps/meteor/client/sidebar/RoomMenu.tsx @@ -13,6 +13,7 @@ import { useTranslation, useEndpoint, } from '@rocket.chat/ui-contexts'; +import { useQueryClient } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React, { memo, useMemo } from 'react'; @@ -100,6 +101,8 @@ const RoomMenu = ({ const isOmnichannelRoom = type === 'l'; const prioritiesMenu = useOmnichannelPrioritiesMenu(rid); + const queryClient = useQueryClient(); + const canLeave = ((): boolean => { if (type === 'c' && !canLeaveChannel) { return false; @@ -173,17 +176,22 @@ const RoomMenu = ({ const handleToggleRead = useMutableCallback(async () => { try { + queryClient.invalidateQueries(['sidebar/search/spotlight']); + if (isUnread) { await readMessages({ rid, readThreads: true }); return; } - await unreadMessages(undefined, rid); + if (subscription == null) { return; } + LegacyRoomManager.close(subscription.t + subscription.name); router.navigate('/home'); + + await unreadMessages(undefined, rid); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } diff --git a/apps/meteor/client/sidebarv2/RoomList/SidebarItemTemplateWithData.tsx b/apps/meteor/client/sidebarv2/RoomList/SidebarItemTemplateWithData.tsx index 51b8ce495af6..e1f66ba93b4e 100644 --- a/apps/meteor/client/sidebarv2/RoomList/SidebarItemTemplateWithData.tsx +++ b/apps/meteor/client/sidebarv2/RoomList/SidebarItemTemplateWithData.tsx @@ -180,6 +180,7 @@ const SidebarItemTemplateWithData = ({ is='a' id={id} data-qa='sidebar-item' + data-unread={highlighted} unread={highlighted} selected={selected} href={href} @@ -205,7 +206,7 @@ const SidebarItemTemplateWithData = ({ threadUnread={threadUnread} rid={rid} unread={!!unread} - roomOpen={false} + roomOpen={selected} type={type} cl={cl} name={title} diff --git a/apps/meteor/client/sidebarv2/RoomMenu.tsx b/apps/meteor/client/sidebarv2/RoomMenu.tsx index e88225df40ca..aac68b9ef79e 100644 --- a/apps/meteor/client/sidebarv2/RoomMenu.tsx +++ b/apps/meteor/client/sidebarv2/RoomMenu.tsx @@ -13,6 +13,7 @@ import { useTranslation, useEndpoint, } from '@rocket.chat/ui-contexts'; +import { useQueryClient } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React, { memo, useMemo } from 'react'; @@ -100,6 +101,8 @@ const RoomMenu = ({ const isOmnichannelRoom = type === 'l'; const prioritiesMenu = useOmnichannelPrioritiesMenu(rid); + const queryClient = useQueryClient(); + const canLeave = ((): boolean => { if (type === 'c' && !canLeaveChannel) { return false; @@ -173,17 +176,22 @@ const RoomMenu = ({ const handleToggleRead = useEffectEvent(async () => { try { + queryClient.invalidateQueries(['sidebar/search/spotlight']); + if (isUnread) { await readMessages({ rid, readThreads: true }); return; } - await unreadMessages(undefined, rid); + if (subscription == null) { return; } + LegacyRoomManager.close(subscription.t + subscription.name); router.navigate('/home'); + + await unreadMessages(undefined, rid); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } diff --git a/apps/meteor/tests/e2e/mark-unread.spec.ts b/apps/meteor/tests/e2e/mark-unread.spec.ts new file mode 100644 index 000000000000..81ae93965856 --- /dev/null +++ b/apps/meteor/tests/e2e/mark-unread.spec.ts @@ -0,0 +1,71 @@ +import { createAuxContext } from './fixtures/createAuxContext'; +import { Users } from './fixtures/userStates'; +import { HomeChannel } from './page-objects'; +import { createTargetChannel } from './utils'; +import { test, expect } from './utils/test'; + +test.use({ storageState: Users.admin.state }); + +test.describe.serial('mark-unread', () => { + let poHomeChannel: HomeChannel; + let targetChannel: string; + + test.beforeEach(async ({ page, api }) => { + poHomeChannel = new HomeChannel(page); + targetChannel = await createTargetChannel(api, { members: ['user2'] }); + + await page.emulateMedia({ reducedMotion: 'reduce' }); + await page.goto('/home'); + }); + + test.afterEach(async ({ api }) => { + await api.post('/channels.delete', { roomName: targetChannel }); + }); + + test.describe('Mark Unread - Sidebar Action', () => { + test('should not mark empty room as unread', async () => { + await poHomeChannel.sidenav.selectMarkAsUnread(targetChannel); + + await expect(poHomeChannel.sidenav.getRoomBadge(targetChannel)).not.toBeVisible(); + }); + + test('should mark a populated room as unread', async () => { + await poHomeChannel.sidenav.openChat(targetChannel); + await poHomeChannel.content.sendMessage('this is a message for reply'); + await poHomeChannel.sidenav.selectMarkAsUnread(targetChannel); + + await expect(poHomeChannel.sidenav.getRoomBadge(targetChannel)).toBeVisible(); + }); + + test('should mark a populated room as unread - search', async () => { + await poHomeChannel.sidenav.openChat(targetChannel); + await poHomeChannel.content.sendMessage('this is a message for reply'); + await poHomeChannel.sidenav.selectMarkAsUnread(targetChannel); + await poHomeChannel.sidenav.searchRoom(targetChannel); + + await expect(poHomeChannel.sidenav.getSearchChannelBadge(targetChannel)).toBeVisible(); + }); + }); + + test.describe('Mark Unread - Message Action', () => { + let poHomeChannelUser2: HomeChannel; + + test('should mark a populated room as unread', async ({ browser }) => { + const { page: user2Page } = await createAuxContext(browser, Users.user2); + poHomeChannelUser2 = new HomeChannel(user2Page); + + await poHomeChannelUser2.sidenav.openChat(targetChannel); + await poHomeChannelUser2.content.sendMessage('this is a message for reply'); + await user2Page.close(); + + await poHomeChannel.sidenav.openChat(targetChannel); + + // wait for the sidebar item to be read + await poHomeChannel.sidenav.getSidebarItemByName(targetChannel, true).waitFor(); + await poHomeChannel.content.openLastMessageMenu(); + await poHomeChannel.markUnread.click(); + + await expect(poHomeChannel.sidenav.getRoomBadge(targetChannel)).toBeVisible(); + }); + }); +}); diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts index d0bdd5028010..823469d02a96 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts @@ -68,8 +68,18 @@ export class HomeSidenav { return this.page.locator('role=menuitemcheckbox[name="Profile"]'); } - getSidebarItemByName(name: string): Locator { - return this.page.locator(`[data-qa="sidebar-item"][aria-label="${name}"]`); + // TODO: refactor getSidebarItemByName to not use data-qa + getSidebarItemByName(name: string, isRead?: boolean): Locator { + return this.page.locator( + ['[data-qa="sidebar-item"]', `[aria-label="${name}"]`, isRead && '[data-unread="false"]'].filter(Boolean).join(''), + ); + } + + async selectMarkAsUnread(name: string) { + const sidebarItem = this.getSidebarItemByName(name); + await sidebarItem.focus(); + await sidebarItem.locator('.rcx-sidebar-item__menu').click(); + await this.page.getByRole('option', { name: 'Mark Unread' }).click(); } async selectPriority(name: string, priority: string) { @@ -170,4 +180,12 @@ export class HomeSidenav { await this.checkboxEncryption.click(); await this.btnCreate.click(); } + + getRoomBadge(roomName: string): Locator { + return this.getSidebarItemByName(roomName).getByRole('status', { exact: true }); + } + + getSearchChannelBadge(name: string): Locator { + return this.page.locator(`[data-qa="sidebar-item"][aria-label="${name}"]`).first().getByRole('status', { exact: true }); + } } diff --git a/apps/meteor/tests/e2e/page-objects/home-channel.ts b/apps/meteor/tests/e2e/page-objects/home-channel.ts index a2784ea4c67b..ce51896eb449 100644 --- a/apps/meteor/tests/e2e/page-objects/home-channel.ts +++ b/apps/meteor/tests/e2e/page-objects/home-channel.ts @@ -59,4 +59,8 @@ export class HomeChannel { get roomHeaderToolbar(): Locator { return this.page.locator('[role=toolbar][aria-label="Primary Room actions"]'); } + + get markUnread(): Locator { + return this.page.locator('role=menuitem[name="Mark Unread"]'); + } } From 6a3c25c62c33e81fb286e364dedf084c64ad8ef8 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Wed, 18 Sep 2024 10:39:21 -0600 Subject: [PATCH 093/170] refactor: Remove old `setreaction` callbacks and use new after/before callbacks (#33309) --- .../reactions/client/methods/setReaction.ts | 4 ---- .../app/reactions/server/setReaction.ts | 2 -- .../app/slackbridge/server/RocketAdapter.js | 22 +++++++++---------- apps/meteor/lib/callbacks.ts | 2 -- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/apps/meteor/app/reactions/client/methods/setReaction.ts b/apps/meteor/app/reactions/client/methods/setReaction.ts index ed15cda9ab8e..1744d49c0ceb 100644 --- a/apps/meteor/app/reactions/client/methods/setReaction.ts +++ b/apps/meteor/app/reactions/client/methods/setReaction.ts @@ -3,7 +3,6 @@ import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Meteor } from 'meteor/meteor'; import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator'; -import { callbacks } from '../../../../lib/callbacks'; import { emoji } from '../../../emoji/client'; import { Messages, ChatRoom, Subscriptions } from '../../../models/client'; @@ -55,10 +54,8 @@ Meteor.methods({ if (!message.reactions || typeof message.reactions !== 'object' || Object.keys(message.reactions).length === 0) { delete message.reactions; Messages.update({ _id: messageId }, { $unset: { reactions: 1 } }); - await callbacks.run('unsetReaction', messageId, reaction); } else { Messages.update({ _id: messageId }, { $set: { reactions: message.reactions } }); - await callbacks.run('setReaction', messageId, reaction); } } else { if (!message.reactions) { @@ -72,7 +69,6 @@ Meteor.methods({ message.reactions[reaction].usernames.push(user.username); Messages.update({ _id: messageId }, { $set: { reactions: message.reactions } }); - await callbacks.run('setReaction', messageId, reaction); } }, }); diff --git a/apps/meteor/app/reactions/server/setReaction.ts b/apps/meteor/app/reactions/server/setReaction.ts index d513c8dda6a5..8f9c24633407 100644 --- a/apps/meteor/app/reactions/server/setReaction.ts +++ b/apps/meteor/app/reactions/server/setReaction.ts @@ -85,7 +85,6 @@ async function setReaction(room: IRoom, user: IUser, message: IMessage, reaction await Rooms.setReactionsInLastMessage(room._id, message.reactions); } } - await callbacks.run('unsetReaction', message._id, reaction); await callbacks.run('afterUnsetReaction', message, { user, reaction, shouldReact, oldMessage }); isReacted = false; @@ -104,7 +103,6 @@ async function setReaction(room: IRoom, user: IUser, message: IMessage, reaction await Rooms.setReactionsInLastMessage(room._id, message.reactions); void notifyOnRoomChangedById(room._id); } - await callbacks.run('setReaction', message._id, reaction); await callbacks.run('afterSetReaction', message, { user, reaction, shouldReact }); isReacted = true; diff --git a/apps/meteor/app/slackbridge/server/RocketAdapter.js b/apps/meteor/app/slackbridge/server/RocketAdapter.js index f76c33fa1f81..8ba2a76dcbc2 100644 --- a/apps/meteor/app/slackbridge/server/RocketAdapter.js +++ b/apps/meteor/app/slackbridge/server/RocketAdapter.js @@ -45,16 +45,16 @@ export default class RocketAdapter { rocketLogger.debug('Register for events'); callbacks.add('afterSaveMessage', this.onMessage.bind(this), callbacks.priority.LOW, 'SlackBridge_Out'); callbacks.add('afterDeleteMessage', this.onMessageDelete.bind(this), callbacks.priority.LOW, 'SlackBridge_Delete'); - callbacks.add('setReaction', this.onSetReaction.bind(this), callbacks.priority.LOW, 'SlackBridge_SetReaction'); - callbacks.add('unsetReaction', this.onUnSetReaction.bind(this), callbacks.priority.LOW, 'SlackBridge_UnSetReaction'); + callbacks.add('afterSetReaction', this.onSetReaction.bind(this), callbacks.priority.LOW, 'SlackBridge_SetReaction'); + callbacks.add('afterUnsetReaction', this.onUnSetReaction.bind(this), callbacks.priority.LOW, 'SlackBridge_UnSetReaction'); } unregisterForEvents() { rocketLogger.debug('Unregister for events'); callbacks.remove('afterSaveMessage', 'SlackBridge_Out'); callbacks.remove('afterDeleteMessage', 'SlackBridge_Delete'); - callbacks.remove('setReaction', 'SlackBridge_SetReaction'); - callbacks.remove('unsetReaction', 'SlackBridge_UnSetReaction'); + callbacks.remove('afterSetReaction', 'SlackBridge_SetReaction'); + callbacks.remove('afterUnsetReaction', 'SlackBridge_UnSetReaction'); } async onMessageDelete(rocketMessageDeleted) { @@ -72,7 +72,7 @@ export default class RocketAdapter { } } - async onSetReaction(rocketMsgID, reaction) { + async onSetReaction(rocketMsg, { reaction }) { try { if (!this.slackBridge.isReactionsEnabled) { return; @@ -80,12 +80,11 @@ export default class RocketAdapter { rocketLogger.debug('onRocketSetReaction'); - if (rocketMsgID && reaction) { - if (this.slackBridge.reactionsMap.delete(`set${rocketMsgID}${reaction}`)) { + if (rocketMsg._id && reaction) { + if (this.slackBridge.reactionsMap.delete(`set${rocketMsg._id}${reaction}`)) { // This was a Slack reaction, we don't need to tell Slack about it return; } - const rocketMsg = await Messages.findOneById(rocketMsgID); if (rocketMsg) { for await (const slack of this.slackAdapters) { const slackChannel = slack.getSlackChannel(rocketMsg.rid); @@ -101,7 +100,7 @@ export default class RocketAdapter { } } - async onUnSetReaction(rocketMsgID, reaction) { + async onUnSetReaction(rocketMsg, { reaction }) { try { if (!this.slackBridge.isReactionsEnabled) { return; @@ -109,13 +108,12 @@ export default class RocketAdapter { rocketLogger.debug('onRocketUnSetReaction'); - if (rocketMsgID && reaction) { - if (this.slackBridge.reactionsMap.delete(`unset${rocketMsgID}${reaction}`)) { + if (rocketMsg._id && reaction) { + if (this.slackBridge.reactionsMap.delete(`unset${rocketMsg._id}${reaction}`)) { // This was a Slack unset reaction, we don't need to tell Slack about it return; } - const rocketMsg = await Messages.findOneById(rocketMsgID); if (rocketMsg) { for await (const slack of this.slackAdapters) { const slackChannel = slack.getSlackChannel(rocketMsg.rid); diff --git a/apps/meteor/lib/callbacks.ts b/apps/meteor/lib/callbacks.ts index 57b8527d5008..dcfd7a021c5e 100644 --- a/apps/meteor/lib/callbacks.ts +++ b/apps/meteor/lib/callbacks.ts @@ -256,10 +256,8 @@ export type Hook = | 'onValidateLogin' | 'openBroadcast' | 'renderNotification' - | 'setReaction' | 'streamMessage' | 'streamNewMessage' - | 'unsetReaction' | 'userAvatarSet' | 'userConfirmationEmailRequested' | 'userForgotPasswordEmailRequested' From d0595a398050b55386eab8330752a24114a23bfa Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Wed, 18 Sep 2024 12:24:47 -0600 Subject: [PATCH 094/170] fix: `LivechatSessionTaken` webhook event called without `agent` param (#33209) --- .changeset/spicy-rocks-burn.md | 5 +++++ .../app/livechat/server/lib/RoutingManager.ts | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 .changeset/spicy-rocks-burn.md diff --git a/.changeset/spicy-rocks-burn.md b/.changeset/spicy-rocks-burn.md new file mode 100644 index 000000000000..6468dbbec241 --- /dev/null +++ b/.changeset/spicy-rocks-burn.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed `LivechatSessionTaken` webhook event being called without the `agent` param, which represents the agent serving the room. diff --git a/apps/meteor/app/livechat/server/lib/RoutingManager.ts b/apps/meteor/app/livechat/server/lib/RoutingManager.ts index f4a2288305e5..28e5c72efc16 100644 --- a/apps/meteor/app/livechat/server/lib/RoutingManager.ts +++ b/apps/meteor/app/livechat/server/lib/RoutingManager.ts @@ -265,11 +265,20 @@ export const RoutingManager: Routing = { logger.info(`Inquiry ${inquiry._id} taken by agent ${agent.agentId}`); + // assignAgent changes the room data to add the agent serving the conversation. afterTakeInquiry expects room object to be updated + const inq = await this.assignAgent(inquiry as InquiryWithAgentInfo, room, agent); + const roomAfterUpdate = await LivechatRooms.findOneById(rid); + + if (!roomAfterUpdate) { + // This should never happen + throw new Error('error-room-not-found'); + } + callbacks.runAsync( 'livechat.afterTakeInquiry', { - inquiry: await this.assignAgent(inquiry as InquiryWithAgentInfo, room, agent), - room, + inquiry: inq, + room: roomAfterUpdate, }, agent, ); @@ -282,7 +291,7 @@ export const RoutingManager: Routing = { queuedAt: undefined, }); - return LivechatRooms.findOneById(rid); + return roomAfterUpdate; }, async transferRoom(room, guest, transferData) { From a541f64c8ca02e4448a4bfbff2699d6e96f17b69 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 19 Sep 2024 10:42:07 -0300 Subject: [PATCH 095/170] fix: error on sendmessage stub (#33317) --- .changeset/cyan-ladybugs-thank.md | 5 +++++ apps/meteor/app/lib/client/methods/sendMessage.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/cyan-ladybugs-thank.md diff --git a/.changeset/cyan-ladybugs-thank.md b/.changeset/cyan-ladybugs-thank.md new file mode 100644 index 000000000000..377a014fcb72 --- /dev/null +++ b/.changeset/cyan-ladybugs-thank.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed error during sendmessage client stub diff --git a/apps/meteor/app/lib/client/methods/sendMessage.ts b/apps/meteor/app/lib/client/methods/sendMessage.ts index bdaca587493a..19220f901458 100644 --- a/apps/meteor/app/lib/client/methods/sendMessage.ts +++ b/apps/meteor/app/lib/client/methods/sendMessage.ts @@ -43,7 +43,7 @@ Meteor.methods({ await onClientMessageReceived(message as IMessage).then((message) => { ChatMessage.insert(message); - return callbacks.run('afterSaveMessage', message, room); + return callbacks.run('afterSaveMessage', message, { room }); }); }, }); From 40339749b3682e0c7f804787fab6e49eb9cef080 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 19 Sep 2024 15:34:50 -0300 Subject: [PATCH 096/170] feat: contextualbar based on chat size (#33321) --- .changeset/kind-llamas-grin.md | 5 + .../Contextualbar/ContextualbarDialog.tsx | 6 +- .../client/views/room/layout/RoomLayout.tsx | 104 +++++++++++++----- 3 files changed, 83 insertions(+), 32 deletions(-) create mode 100644 .changeset/kind-llamas-grin.md diff --git a/.changeset/kind-llamas-grin.md b/.changeset/kind-llamas-grin.md new file mode 100644 index 000000000000..fd349e82d7f9 --- /dev/null +++ b/.changeset/kind-llamas-grin.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Changed the contextualbar behavior based on chat size instead the viewport diff --git a/apps/meteor/client/components/Contextualbar/ContextualbarDialog.tsx b/apps/meteor/client/components/Contextualbar/ContextualbarDialog.tsx index 23def16a94a1..4e4640270087 100644 --- a/apps/meteor/client/components/Contextualbar/ContextualbarDialog.tsx +++ b/apps/meteor/client/components/Contextualbar/ContextualbarDialog.tsx @@ -18,7 +18,7 @@ type ContextualbarDialogProps = AriaDialogProps & ComponentProps { const ref = useRef(null); const { dialogProps } = useDialog({ 'aria-labelledby': 'contextualbarTitle', ...props }, ref); - const sizes = useLayoutSizes(); + const { contextualBar } = useLayoutSizes(); const position = useLayoutContextualBarPosition(); const { closeTab } = useRoomToolbox(); @@ -42,12 +42,12 @@ const ContextualbarDialog = (props: ContextualbarDialogProps) => { - + - + diff --git a/apps/meteor/client/views/room/layout/RoomLayout.tsx b/apps/meteor/client/views/room/layout/RoomLayout.tsx index fd080b916b70..b5e29c05799f 100644 --- a/apps/meteor/client/views/room/layout/RoomLayout.tsx +++ b/apps/meteor/client/views/room/layout/RoomLayout.tsx @@ -1,7 +1,11 @@ +/* eslint-disable no-nested-ternary */ import { Box } from '@rocket.chat/fuselage'; +import { useResizeObserver } from '@rocket.chat/fuselage-hooks'; +import breakpointsDefinitions from '@rocket.chat/fuselage-tokens/breakpoints.json'; import { FeaturePreview, FeaturePreviewOff, FeaturePreviewOn } from '@rocket.chat/ui-client'; +import { LayoutContext, useLayout } from '@rocket.chat/ui-contexts'; import type { ComponentProps, ReactElement, ReactNode } from 'react'; -import React, { Suspense } from 'react'; +import React, { Suspense, useMemo } from 'react'; import { ContextualbarDialog } from '../../../components/Contextualbar'; import HeaderSkeleton from '../Header/HeaderSkeleton'; @@ -14,36 +18,78 @@ type RoomLayoutProps = { aside?: ReactNode; } & ComponentProps; -const RoomLayout = ({ header, body, footer, aside, ...props }: RoomLayoutProps): ReactElement => ( - - - - - - - - - - } +const useBreakpointsElement = () => { + const { ref, borderBoxSize } = useResizeObserver({ + debounceDelay: 30, + }); + + const breakpoints = useMemo( + () => + breakpointsDefinitions + .filter(({ minViewportWidth }) => minViewportWidth && borderBoxSize.inlineSize && borderBoxSize.inlineSize >= minViewportWidth) + .map(({ name }) => name), + [borderBoxSize], + ); + + return { + ref, + breakpoints, + }; +}; + +const RoomLayout = ({ header, body, footer, aside, ...props }: RoomLayoutProps): ReactElement => { + const { ref, breakpoints } = useBreakpointsElement(); + + const contextualbarPosition = breakpoints.includes('md') ? 'relative' : 'absolute'; + const contextualbarSize = breakpoints.includes('sm') ? (breakpoints.includes('xl') ? '38%' : '380px') : '100%'; + + const layout = useLayout(); + + return ( + ({ + ...layout, + contextualBarPosition: contextualbarPosition, + size: { + ...layout.size, + contextualBar: contextualbarSize, + }, + }), + [layout, contextualbarPosition, contextualbarSize], + )} > - {header} - - - - - {body} + + + + + + + + + + } + > + {header} + + + + + {body} + + {footer && {footer}} + + {aside && ( + + {aside} + + )} - {footer && {footer}} - {aside && ( - - {aside} - - )} - - -); + + ); +}; export default RoomLayout; From 12d630799827e75e4b3964881e79fe28d0ad81d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?= <60678893+juliajforesti@users.noreply.github.com> Date: Thu, 19 Sep 2024 23:24:05 +0100 Subject: [PATCH 097/170] feat: `RoomSidepanel` (#33225) Co-authored-by: Guilherme Gazzo <5263975+ggazzo@users.noreply.github.com> --- .changeset/witty-lemons-type.md | 10 ++ apps/meteor/app/api/server/v1/rooms.ts | 2 +- .../FeaturePreviewSidePanelNavigation.tsx | 10 ++ .../client/hooks/useRoomInfoEndpoint.ts | 4 +- .../client/hooks/useSidePanelNavigation.ts | 14 +++ apps/meteor/client/lib/RoomManager.ts | 28 ++++- .../sidebarv2/header/CreateTeamModal.tsx | 62 ++++++++++ .../client/sidebarv2/header/SearchSection.tsx | 30 ++++- apps/meteor/client/views/room/RoomOpener.tsx | 80 +++++++------ .../views/room/Sidepanel/RoomSidepanel.tsx | 66 +++++++++++ .../Sidepanel/RoomSidepanelListWrapper.tsx | 19 ++++ .../room/Sidepanel/RoomSidepanelLoading.tsx | 20 ++++ .../SidepanelItem/RoomSidepanelItem.tsx | 29 +++++ .../room/Sidepanel/SidepanelItem/index.ts | 1 + .../room/Sidepanel/hooks/useItemData.tsx | 68 +++++++++++ .../Sidepanel/hooks/useTeamslistChildren.ts | 106 ++++++++++++++++++ .../client/views/room/Sidepanel/index.ts | 1 + .../Info/EditRoomInfo/EditRoomInfo.tsx | 68 ++++++++++- .../EditRoomInfo/useEditRoomInitialValues.ts | 18 ++- .../client/views/room/layout/RoomLayout.tsx | 4 +- .../views/room/providers/RoomProvider.tsx | 77 +++++++++++-- apps/meteor/lib/publishFields.ts | 1 + apps/meteor/server/services/team/service.ts | 6 +- packages/core-typings/src/IRoom.ts | 3 + packages/i18n/src/locales/en.i18n.json | 4 +- packages/rest-typings/src/v1/rooms.ts | 2 +- .../FeaturePreview/FeaturePreview.tsx | 12 +- .../src/hooks/useFeaturePreviewList.ts | 2 +- 28 files changed, 689 insertions(+), 58 deletions(-) create mode 100644 .changeset/witty-lemons-type.md create mode 100644 apps/meteor/client/components/FeaturePreviewSidePanelNavigation.tsx create mode 100644 apps/meteor/client/hooks/useSidePanelNavigation.ts create mode 100644 apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx create mode 100644 apps/meteor/client/views/room/Sidepanel/RoomSidepanelListWrapper.tsx create mode 100644 apps/meteor/client/views/room/Sidepanel/RoomSidepanelLoading.tsx create mode 100644 apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx create mode 100644 apps/meteor/client/views/room/Sidepanel/SidepanelItem/index.ts create mode 100644 apps/meteor/client/views/room/Sidepanel/hooks/useItemData.tsx create mode 100644 apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts create mode 100644 apps/meteor/client/views/room/Sidepanel/index.ts diff --git a/.changeset/witty-lemons-type.md b/.changeset/witty-lemons-type.md new file mode 100644 index 000000000000..a007cbe6260e --- /dev/null +++ b/.changeset/witty-lemons-type.md @@ -0,0 +1,10 @@ +--- +'@rocket.chat/core-services': minor +'@rocket.chat/model-typings': minor +'@rocket.chat/core-typings': minor +'@rocket.chat/rest-typings': minor +'@rocket.chat/ui-client': minor +'@rocket.chat/meteor': minor +--- + +Implemented new feature preview for Sidepanel diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index 5da59d977fb1..3dc62e462ddf 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -420,7 +420,7 @@ API.v1.addRoute( const discussionParent = room.prid && (await Rooms.findOneById>(room.prid, { - projection: { name: 1, fname: 1, t: 1, prid: 1, u: 1 }, + projection: { name: 1, fname: 1, t: 1, prid: 1, u: 1, sidepanel: 1 }, })); const { team, parentRoom } = await Team.getRoomInfo(room); const parent = discussionParent || parentRoom; diff --git a/apps/meteor/client/components/FeaturePreviewSidePanelNavigation.tsx b/apps/meteor/client/components/FeaturePreviewSidePanelNavigation.tsx new file mode 100644 index 000000000000..f5d658ccb2f2 --- /dev/null +++ b/apps/meteor/client/components/FeaturePreviewSidePanelNavigation.tsx @@ -0,0 +1,10 @@ +import { FeaturePreview } from '@rocket.chat/ui-client'; +import type { ReactElement } from 'react'; +import React from 'react'; + +import { useSidePanelNavigationScreenSize } from '../hooks/useSidePanelNavigation'; + +export const FeaturePreviewSidePanelNavigation = ({ children }: { children: ReactElement[] }) => { + const disabled = !useSidePanelNavigationScreenSize(); + return ; +}; diff --git a/apps/meteor/client/hooks/useRoomInfoEndpoint.ts b/apps/meteor/client/hooks/useRoomInfoEndpoint.ts index 47ea84af20b6..0bac1d7eb413 100644 --- a/apps/meteor/client/hooks/useRoomInfoEndpoint.ts +++ b/apps/meteor/client/hooks/useRoomInfoEndpoint.ts @@ -1,6 +1,6 @@ import type { IRoom } from '@rocket.chat/core-typings'; import type { OperationResult } from '@rocket.chat/rest-typings'; -import { useEndpoint } from '@rocket.chat/ui-contexts'; +import { useEndpoint, useUserId } from '@rocket.chat/ui-contexts'; import type { UseQueryResult } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query'; import { minutesToMilliseconds } from 'date-fns'; @@ -8,6 +8,7 @@ import type { Meteor } from 'meteor/meteor'; export const useRoomInfoEndpoint = (rid: IRoom['_id']): UseQueryResult> => { const getRoomInfo = useEndpoint('GET', '/v1/rooms.info'); + const uid = useUserId(); return useQuery(['/v1/rooms.info', rid], () => getRoomInfo({ roomId: rid }), { cacheTime: minutesToMilliseconds(15), staleTime: minutesToMilliseconds(5), @@ -17,5 +18,6 @@ export const useRoomInfoEndpoint = (rid: IRoom['_id']): UseQueryResult { + const isSidepanelFeatureEnabled = useFeaturePreview('sidepanelNavigation'); + // ["xs", "sm", "md", "lg", "xl", xxl"] + return useSidePanelNavigationScreenSize() && isSidepanelFeatureEnabled; +}; + +export const useSidePanelNavigationScreenSize = () => { + const breakpoints = useBreakpoints(); + // ["xs", "sm", "md", "lg", "xl", xxl"] + return breakpoints.includes('lg'); +}; diff --git a/apps/meteor/client/lib/RoomManager.ts b/apps/meteor/client/lib/RoomManager.ts index 34f64e4f4c78..840493aae406 100644 --- a/apps/meteor/client/lib/RoomManager.ts +++ b/apps/meteor/client/lib/RoomManager.ts @@ -55,6 +55,8 @@ export const RoomManager = new (class RoomManager extends Emitter<{ private rooms: Map = new Map(); + private parentRid?: IRoom['_id'] | undefined; + constructor() { super(); debugRoomManager && @@ -78,6 +80,13 @@ export const RoomManager = new (class RoomManager extends Emitter<{ } get opened(): IRoom['_id'] | undefined { + return this.parentRid ?? this.rid; + } + + get openedSecondLevel(): IRoom['_id'] | undefined { + if (!this.parentRid) { + return undefined; + } return this.rid; } @@ -106,20 +115,28 @@ export const RoomManager = new (class RoomManager extends Emitter<{ this.emit('changed', this.rid); } - open(rid: IRoom['_id']): void { + private _open(rid: IRoom['_id'], parent?: IRoom['_id']): void { if (rid === this.rid) { return; } - this.back(rid); if (!this.rooms.has(rid)) { this.rooms.set(rid, new RoomStore(rid)); } this.rid = rid; + this.parentRid = parent; this.emit('opened', this.rid); this.emit('changed', this.rid); } + open(rid: IRoom['_id']): void { + this._open(rid); + } + + openSecondLevel(parentId: IRoom['_id'], rid: IRoom['_id']): void { + this._open(rid, parentId); + } + getStore(rid: IRoom['_id']): RoomStore | undefined { return this.rooms.get(rid); } @@ -130,4 +147,11 @@ const subscribeOpenedRoom = [ (): IRoom['_id'] | undefined => RoomManager.opened, ] as const; +const subscribeOpenedSecondLevelRoom = [ + (callback: () => void): (() => void) => RoomManager.on('changed', callback), + (): IRoom['_id'] | undefined => RoomManager.openedSecondLevel, +] as const; + export const useOpenedRoom = (): IRoom['_id'] | undefined => useSyncExternalStore(...subscribeOpenedRoom); + +export const useSecondLevelOpenedRoom = (): IRoom['_id'] | undefined => useSyncExternalStore(...subscribeOpenedSecondLevelRoom); diff --git a/apps/meteor/client/sidebarv2/header/CreateTeamModal.tsx b/apps/meteor/client/sidebarv2/header/CreateTeamModal.tsx index a7e7b506de0f..9de721d8bbcd 100644 --- a/apps/meteor/client/sidebarv2/header/CreateTeamModal.tsx +++ b/apps/meteor/client/sidebarv2/header/CreateTeamModal.tsx @@ -1,3 +1,4 @@ +import type { SidepanelItem } from '@rocket.chat/core-typings'; import { Box, Button, @@ -16,6 +17,7 @@ import { AccordionItem, } from '@rocket.chat/fuselage'; import { useUniqueId } from '@rocket.chat/fuselage-hooks'; +import { FeaturePreview, FeaturePreviewOff, FeaturePreviewOn } from '@rocket.chat/ui-client'; import { useEndpoint, usePermission, @@ -40,6 +42,8 @@ type CreateTeamModalInputs = { encrypted: boolean; broadcast: boolean; members?: string[]; + showDiscussions?: boolean; + showChannels?: boolean; }; type CreateTeamModalProps = { onClose: () => void }; @@ -50,6 +54,7 @@ const CreateTeamModal = ({ onClose }: CreateTeamModalProps) => { const e2eEnabledForPrivateByDefault = useSetting('E2E_Enabled_Default_PrivateRooms'); const namesValidation = useSetting('UTF8_Channel_Names_Validation'); const allowSpecialNames = useSetting('UI_Allow_room_names_with_special_chars'); + const dispatchToastMessage = useToastMessageDispatch(); const canCreateTeam = usePermission('create-team'); const canSetReadOnly = usePermissionWithScopedRoles('set-readonly', ['owner']); @@ -94,6 +99,8 @@ const CreateTeamModal = ({ onClose }: CreateTeamModalProps) => { encrypted: (e2eEnabledForPrivateByDefault as boolean) ?? false, broadcast: false, members: [], + showChannels: true, + showDiscussions: true, }, }); @@ -123,7 +130,10 @@ const CreateTeamModal = ({ onClose }: CreateTeamModalProps) => { topic, broadcast, encrypted, + showChannels, + showDiscussions, }: CreateTeamModalInputs): Promise => { + const sidepanelItem = [showChannels && 'channels', showDiscussions && 'discussions'].filter(Boolean) as [SidepanelItem, SidepanelItem?]; const params = { name, members, @@ -136,6 +146,7 @@ const CreateTeamModal = ({ onClose }: CreateTeamModalProps) => { encrypted, }, }, + ...((showChannels || showDiscussions) && { sidepanel: { items: sidepanelItem } }), }; try { @@ -157,6 +168,8 @@ const CreateTeamModal = ({ onClose }: CreateTeamModalProps) => { const encryptedId = useUniqueId(); const broadcastId = useUniqueId(); const addMembersId = useUniqueId(); + const showChannelsId = useUniqueId(); + const showDiscussionsId = useUniqueId(); return ( { + + {null} + + + + {t('Navigation')} + + + + {t('Channels')} + ( + + )} + /> + + {t('Show_channels_description')} + + + + + {t('Discussions')} + ( + + )} + /> + + {t('Show_discussions_description')} + + + + {t('Security_and_permissions')} diff --git a/apps/meteor/client/sidebarv2/header/SearchSection.tsx b/apps/meteor/client/sidebarv2/header/SearchSection.tsx index 660b8ee19cd5..71b26b2e4053 100644 --- a/apps/meteor/client/sidebarv2/header/SearchSection.tsx +++ b/apps/meteor/client/sidebarv2/header/SearchSection.tsx @@ -22,6 +22,32 @@ const wrapperStyle = css` background-color: ${Palette.surface['surface-sidebar']}; `; +const mobileCheck = function () { + let check = false; + (function (a: string) { + if ( + /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test( + a, + ) || + /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test( + a.substr(0, 4), + ) + ) + check = true; + })(navigator.userAgent || navigator.vendor || window.opera || ''); + return check; +}; + +const shortcut = ((): string => { + if (navigator.userAgentData?.mobile || mobileCheck()) { + return ''; + } + if (window.navigator.platform.toLowerCase().includes('mac')) { + return '(\u2318+K)'; + } + return '(Ctrl+K)'; +})(); + const SearchSection = () => { const t = useTranslation(); const user = useUser(); @@ -68,11 +94,13 @@ const SearchSection = () => { }; }, [handleEscSearch, setFocus]); + const placeholder = [t('Search'), shortcut].filter(Boolean).join(' '); + return ( import('./providers/RoomProvider')); @@ -23,46 +26,59 @@ type RoomOpenerProps = { reference: string; }; +const isDirectOrOmnichannelRoom = (type: RoomType) => type === 'd' || type === 'l'; + const RoomOpener = ({ type, reference }: RoomOpenerProps): ReactElement => { const { data, error, isSuccess, isError, isLoading } = useOpenRoom({ type, reference }); const { t } = useTranslation(); return ( - }> - {isLoading && } - {isSuccess && ( - - - + + {!isDirectOrOmnichannelRoom(type) && ( + + {null} + + + + )} - {isError && - (() => { - if (error instanceof OldUrlRoomError) { - return ; - } - if (error instanceof RoomNotFoundError) { - return ; - } + }> + {isLoading && } + {isSuccess && ( + + + + )} + {isError && + (() => { + if (error instanceof OldUrlRoomError) { + return ; + } + + if (error instanceof RoomNotFoundError) { + return ; + } - if (error instanceof NotAuthorizedError) { - return ; - } + if (error instanceof NotAuthorizedError) { + return ; + } - return ( - } - body={ - - - {t('core.Error')} - {getErrorMessage(error)} - - } - /> - ); - })()} - + return ( + } + body={ + + + {t('core.Error')} + {getErrorMessage(error)} + + } + /> + ); + })()} + + ); }; diff --git a/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx b/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx new file mode 100644 index 000000000000..27c45e2774e8 --- /dev/null +++ b/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx @@ -0,0 +1,66 @@ +/* eslint-disable react/no-multi-comp */ +import { Box, Sidepanel, SidepanelListItem } from '@rocket.chat/fuselage'; +import { useUserPreference } from '@rocket.chat/ui-contexts'; +import React, { memo } from 'react'; +import { Virtuoso } from 'react-virtuoso'; + +import { VirtuosoScrollbars } from '../../../components/CustomScrollbars'; +import { useRoomInfoEndpoint } from '../../../hooks/useRoomInfoEndpoint'; +import { useOpenedRoom, useSecondLevelOpenedRoom } from '../../../lib/RoomManager'; +import RoomSidepanelListWrapper from './RoomSidepanelListWrapper'; +import RoomSidepanelLoading from './RoomSidepanelLoading'; +import RoomSidepanelItem from './SidepanelItem'; +import { useTeamsListChildrenUpdate } from './hooks/useTeamslistChildren'; + +const RoomSidepanel = () => { + const parentRid = useOpenedRoom(); + const secondLevelOpenedRoom = useSecondLevelOpenedRoom() ?? parentRid; + + if (!parentRid || !secondLevelOpenedRoom) { + return null; + } + + return ; +}; + +const RoomSidepanelWithData = ({ parentRid, openedRoom }: { parentRid: string; openedRoom: string }) => { + const sidebarViewMode = useUserPreference<'extended' | 'medium' | 'condensed'>('sidebarViewMode'); + + const roomInfo = useRoomInfoEndpoint(parentRid); + const sidepanelItems = roomInfo.data?.room?.sidepanel?.items || roomInfo.data?.parent?.sidepanel?.items; + + const result = useTeamsListChildrenUpdate( + parentRid, + !roomInfo.data ? null : roomInfo.data.room?.teamId, + // eslint-disable-next-line no-nested-ternary + !sidepanelItems ? null : sidepanelItems?.length === 1 ? sidepanelItems[0] : undefined, + ); + if (roomInfo.isSuccess && !roomInfo.data.room?.sidepanel && !roomInfo.data.parent?.sidepanel) { + return null; + } + + if (roomInfo.isLoading || (roomInfo.isSuccess && result.isLoading)) { + return ; + } + + if (!result.isSuccess || !roomInfo.isSuccess) { + return null; + } + + return ( + + + ( + + )} + /> + + + ); +}; + +export default memo(RoomSidepanel); diff --git a/apps/meteor/client/views/room/Sidepanel/RoomSidepanelListWrapper.tsx b/apps/meteor/client/views/room/Sidepanel/RoomSidepanelListWrapper.tsx new file mode 100644 index 000000000000..dd9e6e6ec221 --- /dev/null +++ b/apps/meteor/client/views/room/Sidepanel/RoomSidepanelListWrapper.tsx @@ -0,0 +1,19 @@ +import { SidepanelList } from '@rocket.chat/fuselage'; +import { useMergedRefs } from '@rocket.chat/fuselage-hooks'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import type { ForwardedRef, HTMLAttributes } from 'react'; +import React, { forwardRef } from 'react'; + +import { useSidebarListNavigation } from '../../../sidebar/RoomList/useSidebarListNavigation'; + +type RoomListWrapperProps = HTMLAttributes; + +const RoomSidepanelListWrapper = forwardRef(function RoomListWrapper(props: RoomListWrapperProps, ref: ForwardedRef) { + const t = useTranslation(); + const { sidebarListRef } = useSidebarListNavigation(); + const mergedRefs = useMergedRefs(ref, sidebarListRef); + + return ; +}); + +export default RoomSidepanelListWrapper; diff --git a/apps/meteor/client/views/room/Sidepanel/RoomSidepanelLoading.tsx b/apps/meteor/client/views/room/Sidepanel/RoomSidepanelLoading.tsx new file mode 100644 index 000000000000..00609ae6c496 --- /dev/null +++ b/apps/meteor/client/views/room/Sidepanel/RoomSidepanelLoading.tsx @@ -0,0 +1,20 @@ +import { SidebarV2Item as SidebarItem, Sidepanel, SidepanelList, Skeleton } from '@rocket.chat/fuselage'; +import React from 'react'; + +const RoomSidepanelLoading = () => ( + + + + + + + + + + + + + +); + +export default RoomSidepanelLoading; diff --git a/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx b/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx new file mode 100644 index 000000000000..dceb69e1aba3 --- /dev/null +++ b/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx @@ -0,0 +1,29 @@ +import type { IRoom, ISubscription, Serialized } from '@rocket.chat/core-typings'; +import { useUserSubscription } from '@rocket.chat/ui-contexts'; +import React, { memo } from 'react'; + +import { goToRoomById } from '../../../../lib/utils/goToRoomById'; +import { useTemplateByViewMode } from '../../../../sidebarv2/hooks/useTemplateByViewMode'; +import { useItemData } from '../hooks/useItemData'; + +export type RoomSidepanelItemProps = { + openedRoom?: string; + room: Serialized; + parentRid: string; + viewMode?: 'extended' | 'medium' | 'condensed'; +}; + +const RoomSidepanelItem = ({ room, openedRoom, viewMode }: RoomSidepanelItemProps) => { + const SidepanelItem = useTemplateByViewMode(); + const subscription = useUserSubscription(room._id); + + const itemData = useItemData({ ...room, ...subscription } as ISubscription & IRoom, { viewMode, openedRoom }); // as any because of divergent and overlaping timestamp types in subs and room (type Date vs type string) + + if (!subscription) { + return ; + } + + return ; +}; + +export default memo(RoomSidepanelItem); diff --git a/apps/meteor/client/views/room/Sidepanel/SidepanelItem/index.ts b/apps/meteor/client/views/room/Sidepanel/SidepanelItem/index.ts new file mode 100644 index 000000000000..5cfc0da3055b --- /dev/null +++ b/apps/meteor/client/views/room/Sidepanel/SidepanelItem/index.ts @@ -0,0 +1 @@ +export { default } from './RoomSidepanelItem'; diff --git a/apps/meteor/client/views/room/Sidepanel/hooks/useItemData.tsx b/apps/meteor/client/views/room/Sidepanel/hooks/useItemData.tsx new file mode 100644 index 000000000000..a6de01e22084 --- /dev/null +++ b/apps/meteor/client/views/room/Sidepanel/hooks/useItemData.tsx @@ -0,0 +1,68 @@ +import type { IRoom, ISubscription } from '@rocket.chat/core-typings'; +import { SidebarV2ItemBadge as SidebarItemBadge, SidebarV2ItemIcon as SidebarItemIcon } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import React, { useMemo } from 'react'; + +import { RoomIcon } from '../../../../components/RoomIcon'; +import { roomCoordinator } from '../../../../lib/rooms/roomCoordinator'; +import { getBadgeTitle, getMessage } from '../../../../sidebarv2/RoomList/SidebarItemTemplateWithData'; +import { useAvatarTemplate } from '../../../../sidebarv2/hooks/useAvatarTemplate'; + +export const useItemData = ( + room: ISubscription & IRoom, + { openedRoom, viewMode }: { openedRoom: string | undefined; viewMode?: 'extended' | 'medium' | 'condensed' }, +) => { + const t = useTranslation(); + const AvatarTemplate = useAvatarTemplate(); + + const highlighted = Boolean(!room.hideUnreadStatus && (room.alert || room.unread)); + + const icon = useMemo( + () => } />, + [highlighted, room], + ); + const time = 'lastMessage' in room ? room.lastMessage?.ts : undefined; + const message = viewMode === 'extended' && getMessage(room, room.lastMessage, t); + + const threadUnread = Number(room.tunread?.length) > 0; + const isUnread = room.unread > 0 || threadUnread; + const showBadge = + !room.hideUnreadStatus || (!room.hideMentionStatus && (Boolean(room.userMentions) || Number(room.tunreadUser?.length) > 0)); + const badgeTitle = getBadgeTitle(room.userMentions, Number(room.tunread?.length), room.groupMentions, room.unread, t); + const variant = + ((room.userMentions || room.tunreadUser?.length) && 'danger') || + (threadUnread && 'primary') || + (room.groupMentions && 'warning') || + 'secondary'; + + const badges = useMemo( + () => ( + <> + {showBadge && isUnread && ( + + {room.unread + (room.tunread?.length || 0)} + + )} + + ), + [badgeTitle, isUnread, room.tunread?.length, room.unread, showBadge, variant], + ); + + const itemData = useMemo( + () => ({ + unread: highlighted, + selected: room.rid === openedRoom, + t, + href: roomCoordinator.getRouteLink(room.t, room) || '', + title: roomCoordinator.getRoomName(room.t, room) || '', + icon, + time, + badges, + avatar: AvatarTemplate && , + subtitle: message, + }), + [AvatarTemplate, badges, highlighted, icon, message, openedRoom, room, t, time], + ); + + return itemData; +}; diff --git a/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts new file mode 100644 index 000000000000..5791a6e5d547 --- /dev/null +++ b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts @@ -0,0 +1,106 @@ +import type { IRoom } from '@rocket.chat/core-typings'; +import { useEndpoint } from '@rocket.chat/ui-contexts'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useEffect, useMemo } from 'react'; + +import { ChatRoom } from '../../../../../app/models/client'; + +const sortRoomByLastMessage = (a: IRoom, b: IRoom) => { + if (!a.lm) { + return 1; + } + if (!b.lm) { + return -1; + } + return new Date(b.lm).toUTCString().localeCompare(new Date(a.lm).toUTCString()); +}; + +export const useTeamsListChildrenUpdate = ( + parentRid: string, + teamId?: string | null, + sidepanelItems?: 'channels' | 'discussions' | null, +) => { + const queryClient = useQueryClient(); + + const query = useMemo(() => { + const query: Parameters[0] = { + $or: [ + { + _id: parentRid, + }, + { + prid: parentRid, + }, + ], + }; + + if (teamId && query.$or) { + query.$or.push({ + teamId, + }); + } + return query; + }, [parentRid, teamId]); + + const teamList = useEndpoint('GET', '/v1/teams.listChildren'); + + const listRoomsAndDiscussions = useEndpoint('GET', '/v1/teams.listChildren'); + const result = useQuery({ + queryKey: ['sidepanel', 'list', parentRid, sidepanelItems], + queryFn: () => + listRoomsAndDiscussions({ + roomId: parentRid, + sort: JSON.stringify({ lm: -1 }), + type: sidepanelItems || undefined, + }), + enabled: sidepanelItems !== null && teamId !== null, + refetchInterval: 5 * 60 * 1000, + keepPreviousData: true, + }); + + const { mutate: update } = useMutation({ + mutationFn: async (params?: { action: 'add' | 'remove' | 'update'; data: IRoom }) => { + queryClient.setQueryData(['sidepanel', 'list', parentRid, sidepanelItems], (data: Awaited> | void) => { + if (!data) { + return; + } + + if (params?.action === 'add') { + data.data = [JSON.parse(JSON.stringify(params.data)), ...data.data].sort(sortRoomByLastMessage); + } + + if (params?.action === 'remove') { + data.data = data.data.filter((item) => item._id !== params.data?._id); + } + + if (params?.action === 'update') { + data.data = data.data + .map((item) => (item._id === params.data?._id ? JSON.parse(JSON.stringify(params.data)) : item)) + .sort(sortRoomByLastMessage); + } + + return { ...data }; + }); + }, + }); + + useEffect(() => { + const liveQueryHandle = ChatRoom.find(query).observe({ + added: (item) => { + queueMicrotask(() => update({ action: 'add', data: item })); + }, + changed: (item) => { + queueMicrotask(() => update({ action: 'update', data: item })); + }, + removed: (item) => { + queueMicrotask(() => update({ action: 'remove', data: item })); + }, + }); + + return () => { + liveQueryHandle.stop(); + }; + }, [update, query]); + + return result; +}; diff --git a/apps/meteor/client/views/room/Sidepanel/index.ts b/apps/meteor/client/views/room/Sidepanel/index.ts new file mode 100644 index 000000000000..c236142b8b0f --- /dev/null +++ b/apps/meteor/client/views/room/Sidepanel/index.ts @@ -0,0 +1 @@ +export { default } from './RoomSidepanel'; diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx index b2aac49927a1..1233768a671c 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx +++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx @@ -1,5 +1,5 @@ /* eslint-disable complexity */ -import type { IRoomWithRetentionPolicy } from '@rocket.chat/core-typings'; +import type { IRoomWithRetentionPolicy, SidepanelItem } from '@rocket.chat/core-typings'; import { isRoomFederated } from '@rocket.chat/core-typings'; import type { SelectOption } from '@rocket.chat/fuselage'; import { @@ -21,10 +21,13 @@ import { Box, TextAreaInput, AccordionItem, + Divider, } from '@rocket.chat/fuselage'; import { useEffectEvent, useUniqueId } from '@rocket.chat/fuselage-hooks'; +import { FeaturePreview, FeaturePreviewOff, FeaturePreviewOn } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useSetting, useTranslation, useToastMessageDispatch, useEndpoint } from '@rocket.chat/ui-contexts'; +import { useQueryClient } from '@tanstack/react-query'; import type { ChangeEvent } from 'react'; import React, { useMemo } from 'react'; import { useForm, Controller } from 'react-hook-form'; @@ -72,11 +75,12 @@ const getRetentionSetting = (roomType: IRoomWithRetentionPolicy['t']): string => }; const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) => { + const query = useQueryClient(); const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); const isFederated = useMemo(() => isRoomFederated(room), [room]); // eslint-disable-next-line no-nested-ternary - const roomType = 'prid' in room ? 'discussion' : room.teamId ? 'team' : 'channel'; + const roomType = 'prid' in room ? 'discussion' : room.teamMain ? 'team' : 'channel'; const retentionPolicy = useRetentionPolicy(room); const retentionMaxAgeDefault = msToTimeUnit(TIMEUNIT.days, Number(useSetting(getRetentionSetting(room.t)))) ?? 30; @@ -118,6 +122,8 @@ const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) => retentionOverrideGlobal, roomType: roomTypeP, reactWhenReadOnly, + showChannels, + showDiscussions, } = watch(); const { @@ -158,13 +164,23 @@ const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) => retentionIgnoreThreads, ...formData }) => { - const data = getDirtyFields(formData, dirtyFields); + const data = getDirtyFields>(formData, dirtyFields); delete data.archived; + delete data.showChannels; + delete data.showDiscussions; + + const sidepanelItems = [showChannels && 'channels', showDiscussions && 'discussions'].filter(Boolean) as [ + SidepanelItem, + SidepanelItem?, + ]; + + const sidepanel = sidepanelItems.length > 0 ? { items: sidepanelItems } : null; try { await saveAction({ rid: room._id, ...data, + ...(roomType === 'team' ? { sidepanel } : null), ...((data.joinCode || 'joinCodeRequired' in data) && { joinCode: joinCodeRequired ? data.joinCode : '' }), ...((data.systemMessages || !hideSysMes) && { systemMessages: hideSysMes && data.systemMessages, @@ -180,6 +196,7 @@ const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) => }), }); + await query.invalidateQueries(['/v1/rooms.info', room._id]); dispatchToastMessage({ type: 'success', message: t('Room_updated_successfully') }); onClickClose(); } catch (error) { @@ -224,6 +241,8 @@ const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) => const retentionExcludePinnedField = useUniqueId(); const retentionFilesOnlyField = useUniqueId(); const retentionIgnoreThreads = useUniqueId(); + const showDiscussionsField = useUniqueId(); + const showChannelsField = useUniqueId(); const showAdvancedSettings = canViewEncrypted || canViewReadOnly || readOnly || canViewArchived || canViewJoinCode || canViewHideSysMes; const showRetentionPolicy = canEditRoomRetentionPolicy && retentionPolicy?.enabled; @@ -355,6 +374,49 @@ const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) => {showAdvancedSettings && ( + {roomType === 'team' && ( + + {null} + + + + {t('Navigation')} + + + + {t('Channels')} + ( + + )} + /> + + + {t('Show_channels_description')} + + + + + {t('Discussions')} + ( + + )} + /> + + + {t('Show_discussions_description')} + + + + + + + )} {t('Security_and_permissions')} diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts index 1a002727358f..b71f8e1b5bc5 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts +++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts @@ -10,7 +10,20 @@ export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy) => { const retentionPolicy = useRetentionPolicy(room); const canEditRoomRetentionPolicy = usePermission('edit-room-retention-policy', room._id); - const { t, ro, archived, topic, description, announcement, joinCodeRequired, sysMes, encrypted, retention, reactWhenReadOnly } = room; + const { + t, + ro, + archived, + topic, + description, + announcement, + joinCodeRequired, + sysMes, + encrypted, + retention, + reactWhenReadOnly, + sidepanel, + } = room; return useMemo( () => ({ @@ -37,6 +50,8 @@ export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy) => { retentionFilesOnly: retention?.filesOnly ?? retentionPolicy.filesOnly, retentionIgnoreThreads: retention?.ignoreThreads ?? retentionPolicy.ignoreThreads, }), + showDiscussions: sidepanel?.items.includes('discussions'), + showChannels: sidepanel?.items.includes('channels'), }), [ announcement, @@ -53,6 +68,7 @@ export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy) => { encrypted, reactWhenReadOnly, canEditRoomRetentionPolicy, + sidepanel, ], ); }; diff --git a/apps/meteor/client/views/room/layout/RoomLayout.tsx b/apps/meteor/client/views/room/layout/RoomLayout.tsx index b5e29c05799f..3c0c4c313c99 100644 --- a/apps/meteor/client/views/room/layout/RoomLayout.tsx +++ b/apps/meteor/client/views/room/layout/RoomLayout.tsx @@ -59,7 +59,7 @@ const RoomLayout = ({ header, body, footer, aside, ...props }: RoomLayoutProps): [layout, contextualbarPosition, contextualbarSize], )} > - + @@ -82,7 +82,7 @@ const RoomLayout = ({ header, body, footer, aside, ...props }: RoomLayoutProps): {footer && {footer}} {aside && ( - + {aside} )} diff --git a/apps/meteor/client/views/room/providers/RoomProvider.tsx b/apps/meteor/client/views/room/providers/RoomProvider.tsx index 65c83100b1c0..d67c8566e3c6 100644 --- a/apps/meteor/client/views/room/providers/RoomProvider.tsx +++ b/apps/meteor/client/views/room/providers/RoomProvider.tsx @@ -8,12 +8,15 @@ import { RoomHistoryManager } from '../../../../app/ui-utils/client'; import { UserAction } from '../../../../app/ui/client/lib/UserAction'; import { useReactiveQuery } from '../../../hooks/useReactiveQuery'; import { useReactiveValue } from '../../../hooks/useReactiveValue'; +import { useRoomInfoEndpoint } from '../../../hooks/useRoomInfoEndpoint'; +import { useSidePanelNavigation } from '../../../hooks/useSidePanelNavigation'; import { RoomManager } from '../../../lib/RoomManager'; import { roomCoordinator } from '../../../lib/rooms/roomCoordinator'; import ImageGalleryProvider from '../../../providers/ImageGalleryProvider'; import RoomNotFound from '../RoomNotFound'; import RoomSkeleton from '../RoomSkeleton'; import { useRoomRolesManagement } from '../body/hooks/useRoomRolesManagement'; +import type { IRoomWithFederationOriginalName } from '../contexts/RoomContext'; import { RoomContext } from '../contexts/RoomContext'; import ComposerPopupProvider from './ComposerPopupProvider'; import RoomToolboxProvider from './RoomToolboxProvider'; @@ -30,15 +33,17 @@ type RoomProviderProps = { const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { useRoomRolesManagement(rid); - const { data: room, isSuccess } = useRoomQuery(rid); + const resultFromServer = useRoomInfoEndpoint(rid); + + const resultFromLocal = useRoomQuery(rid); // TODO: the following effect is a workaround while we don't have a general and definitive solution for it const router = useRouter(); useEffect(() => { - if (isSuccess && !room) { + if (resultFromLocal.isSuccess && !resultFromLocal.data) { router.navigate('/home'); } - }, [isSuccess, room, router]); + }, [resultFromLocal.data, resultFromLocal.isSuccess, resultFromServer, router]); const subscriptionQuery = useReactiveQuery(['subscriptions', { rid }], () => ChatSubscription.findOne({ rid }) ?? null); @@ -46,7 +51,8 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { useUsersNameChanged(); - const pseudoRoom = useMemo(() => { + const pseudoRoom: IRoomWithFederationOriginalName | null = useMemo(() => { + const room = resultFromLocal.data; if (!room) { return null; } @@ -57,7 +63,7 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { name: roomCoordinator.getRoomName(room.t, room), federationOriginalName: room.name, }; - }, [room, subscriptionQuery.data]); + }, [resultFromLocal.data, subscriptionQuery.data]); const { hasMorePreviousMessages, hasMoreNextMessages, isLoadingMoreMessages } = useReactiveValue( useCallback(() => { @@ -86,12 +92,69 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { }; }, [hasMoreNextMessages, hasMorePreviousMessages, isLoadingMoreMessages, pseudoRoom, rid, subscriptionQuery.data]); + const isSidepanelFeatureEnabled = useSidePanelNavigation(); + useEffect(() => { + if (isSidepanelFeatureEnabled) { + if (resultFromServer.isSuccess) { + if (resultFromServer.data.room?.teamMain) { + if ( + resultFromServer.data.room.sidepanel?.items.includes('channels') || + resultFromServer.data.room?.sidepanel?.items.includes('discussions') + ) { + RoomManager.openSecondLevel(rid, rid); + } else { + RoomManager.open(rid); + } + return (): void => { + RoomManager.back(rid); + }; + } + + switch (true) { + case resultFromServer.data.room?.prid && + resultFromServer.data.parent && + resultFromServer.data.parent.sidepanel?.items.includes('discussions'): + RoomManager.openSecondLevel(resultFromServer.data.parent._id, rid); + break; + case resultFromServer.data.team?.roomId && + !resultFromServer.data.room?.teamMain && + resultFromServer.data.parent?.sidepanel?.items.includes('channels'): + RoomManager.openSecondLevel(resultFromServer.data.team.roomId, rid); + break; + + default: + if ( + resultFromServer.data.parent?.sidepanel?.items.includes('channels') || + resultFromServer.data.parent?.sidepanel?.items.includes('discussions') + ) { + RoomManager.openSecondLevel(rid, rid); + } else { + RoomManager.open(rid); + } + break; + } + } + return (): void => { + RoomManager.back(rid); + }; + } + RoomManager.open(rid); return (): void => { RoomManager.back(rid); }; - }, [rid]); + }, [ + isSidepanelFeatureEnabled, + rid, + resultFromServer.data?.room?.prid, + resultFromServer.data?.room?.teamId, + resultFromServer.data?.room?.teamMain, + resultFromServer.isSuccess, + resultFromServer.data?.parent, + resultFromServer.data?.team?.roomId, + resultFromServer.data, + ]); const subscribed = !!subscriptionQuery.data; @@ -104,7 +167,7 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { }, [rid, subscribed]); if (!pseudoRoom) { - return isSuccess && !room ? : ; + return resultFromLocal.isSuccess && !resultFromLocal.data ? : ; } return ( diff --git a/apps/meteor/lib/publishFields.ts b/apps/meteor/lib/publishFields.ts index c1483ea86cd1..48d0f9c87d5c 100644 --- a/apps/meteor/lib/publishFields.ts +++ b/apps/meteor/lib/publishFields.ts @@ -74,6 +74,7 @@ export const roomFields = { avatarETag: 1, usersCount: 1, msgs: 1, + sidepanel: 1, // @TODO create an API to register this fields based on room type tags: 1, diff --git a/apps/meteor/server/services/team/service.ts b/apps/meteor/server/services/team/service.ts index f5218c88402a..4be96bff9866 100644 --- a/apps/meteor/server/services/team/service.ts +++ b/apps/meteor/server/services/team/service.ts @@ -1055,8 +1055,10 @@ export class TeamService extends ServiceClassInternal implements ITeamService { return rooms; } - private getParentRoom(team: AtLeast): Promise | null> { - return Rooms.findOneById>(team.roomId, { projection: { name: 1, fname: 1, t: 1 } }); + private getParentRoom(team: AtLeast): Promise | null> { + return Rooms.findOneById>(team.roomId, { + projection: { name: 1, fname: 1, t: 1, sidepanel: 1 }, + }); } async getRoomInfo( diff --git a/packages/core-typings/src/IRoom.ts b/packages/core-typings/src/IRoom.ts index 0ce1b1041de6..95f2836da1e7 100644 --- a/packages/core-typings/src/IRoom.ts +++ b/packages/core-typings/src/IRoom.ts @@ -99,6 +99,9 @@ export const isSidepanelItem = (item: any): item is SidepanelItem => { }; export const isValidSidepanel = (sidepanel: IRoom['sidepanel']) => { + if (sidepanel === null) { + return true; + } if (!sidepanel?.items) { return false; } diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 796e9d0519ff..728ca256952d 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -6541,8 +6541,8 @@ "Incoming_Calls": "Incoming calls", "Advanced_settings": "Advanced settings", "Security_and_permissions": "Security and permissions", - "Sidepanel_navigation": "Sidepanel navigation for teams", - "Sidepanel_navigation_description": "Option to open a sidepanel with channels and/or discussions associated with the team. This allows team owners to customize communication methods to best meet their team’s needs. This feature is only available when Enhanced navigation experience is enabled.", + "Sidepanel_navigation": "Secondary navigation for teams", + "Sidepanel_navigation_description": "Display channels and/or discussions associated with teams by default. This allows team owners to customize communication methods to best meet their team’s needs. This is currently in feature preview and will be a premium capability once fully released.", "Show_channels_description": "Show team channels in second sidebar", "Show_discussions_description": "Show team discussions in second sidebar" } diff --git a/packages/rest-typings/src/v1/rooms.ts b/packages/rest-typings/src/v1/rooms.ts index c837ba7186bd..16debe87e44c 100644 --- a/packages/rest-typings/src/v1/rooms.ts +++ b/packages/rest-typings/src/v1/rooms.ts @@ -626,7 +626,7 @@ export type RoomsEndpoints = { '/v1/rooms.info': { GET: (params: RoomsInfoProps) => { room: IRoom | undefined; - parent?: Pick; + parent?: Pick; team?: Pick; }; }; diff --git a/packages/ui-client/src/components/FeaturePreview/FeaturePreview.tsx b/packages/ui-client/src/components/FeaturePreview/FeaturePreview.tsx index 09ec0700cb79..c297cc839abc 100644 --- a/packages/ui-client/src/components/FeaturePreview/FeaturePreview.tsx +++ b/packages/ui-client/src/components/FeaturePreview/FeaturePreview.tsx @@ -5,8 +5,16 @@ import { Children, Suspense, cloneElement } from 'react'; import { useFeaturePreview } from '../../hooks/useFeaturePreview'; import { FeaturesAvailable } from '../../hooks/useFeaturePreviewList'; -export const FeaturePreview = ({ feature, children }: { feature: FeaturesAvailable; children: ReactElement[] }) => { - const featureToggleEnabled = useFeaturePreview(feature); +export const FeaturePreview = ({ + feature, + disabled = false, + children, +}: { + disabled?: boolean; + feature: FeaturesAvailable; + children: ReactElement[]; +}) => { + const featureToggleEnabled = useFeaturePreview(feature) && !disabled; const toggledChildren = Children.map(children, (child) => cloneElement(child, { diff --git a/packages/ui-client/src/hooks/useFeaturePreviewList.ts b/packages/ui-client/src/hooks/useFeaturePreviewList.ts index 172045197f8c..ff103a8d84ef 100644 --- a/packages/ui-client/src/hooks/useFeaturePreviewList.ts +++ b/packages/ui-client/src/hooks/useFeaturePreviewList.ts @@ -72,7 +72,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ description: 'Sidepanel_navigation_description', group: 'Navigation', value: false, - enabled: false, + enabled: true, enableQuery: { name: 'newNavigation', value: true, From 015c862c999517ad74710b951a7c47b2c00ed091 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 19 Sep 2024 20:02:19 -0300 Subject: [PATCH 098/170] ci: auto candidate releases (#33325) Co-authored-by: Diego Sampaio --- .github/workflows/release-candidate.yml | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/release-candidate.yml diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml new file mode 100644 index 000000000000..4a1e67fca33a --- /dev/null +++ b/.github/workflows/release-candidate.yml @@ -0,0 +1,35 @@ +name: Release candidate cut +on: + schedule: + - cron: '28 0 20 * *' # run at minute 28 to avoid the chance of delay due to high load on GH +jobs: + new-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.ref_name }} + fetch-depth: 0 + token: ${{ secrets.CI_PAT }} + + - name: Setup NodeJS + uses: ./.github/actions/setup-node + with: + node-version: 14.21.3 + cache-modules: true + install: true + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + + - uses: rharkor/caching-for-turbo@v1.5 + + - name: Build packages + run: yarn build + + - name: 'Start release candidate' + uses: ./packages/release-action + with: + action: next + base-ref: ${{ github.ref_name }} + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GITHUB_TOKEN: ${{ secrets.CI_PAT }} From 7faba775f0967ce745bfbe48c51561e8c1c33c48 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Thu, 19 Sep 2024 17:57:54 -0600 Subject: [PATCH 099/170] refactor: Reactions set/unset (#32994) --- apps/meteor/app/api/server/v1/chat.ts | 2 +- .../app/reactions/server/setReaction.ts | 109 +++-- apps/meteor/server/models/raw/EmojiCustom.ts | 8 + .../app/reactions/server/setReaction.spec.ts | 428 ++++++++++++++++++ .../src/models/IEmojiCustomModel.ts | 1 + 5 files changed, 499 insertions(+), 49 deletions(-) create mode 100644 apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts diff --git a/apps/meteor/app/api/server/v1/chat.ts b/apps/meteor/app/api/server/v1/chat.ts index 3ccc9caeafa0..d04d1a2418b5 100644 --- a/apps/meteor/app/api/server/v1/chat.ts +++ b/apps/meteor/app/api/server/v1/chat.ts @@ -376,7 +376,7 @@ API.v1.addRoute( throw new Meteor.Error('error-emoji-param-not-provided', 'The required "emoji" param is missing.'); } - await executeSetReaction(this.userId, emoji, msg._id, this.bodyParams.shouldReact); + await executeSetReaction(this.userId, emoji, msg, this.bodyParams.shouldReact); return API.v1.success(); }, diff --git a/apps/meteor/app/reactions/server/setReaction.ts b/apps/meteor/app/reactions/server/setReaction.ts index 8f9c24633407..be6e5aed4a54 100644 --- a/apps/meteor/app/reactions/server/setReaction.ts +++ b/apps/meteor/app/reactions/server/setReaction.ts @@ -4,7 +4,6 @@ import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Messages, EmojiCustom, Rooms, Users } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; -import _ from 'underscore'; import { callbacks } from '../../../lib/callbacks'; import { i18n } from '../../../server/lib/i18n'; @@ -12,26 +11,39 @@ import { canAccessRoomAsync } from '../../authorization/server'; import { hasPermissionAsync } from '../../authorization/server/functions/hasPermission'; import { emoji } from '../../emoji/server'; import { isTheLastMessage } from '../../lib/server/functions/isTheLastMessage'; -import { notifyOnRoomChangedById, notifyOnMessageChange } from '../../lib/server/lib/notifyListener'; +import { notifyOnMessageChange } from '../../lib/server/lib/notifyListener'; -const removeUserReaction = (message: IMessage, reaction: string, username: string) => { +export const removeUserReaction = (message: IMessage, reaction: string, username: string) => { if (!message.reactions) { return message; } - message.reactions[reaction].usernames.splice(message.reactions[reaction].usernames.indexOf(username), 1); - if (message.reactions[reaction].usernames.length === 0) { + const idx = message.reactions[reaction].usernames.indexOf(username); + + // user not found in reaction array + if (idx === -1) { + return message; + } + + message.reactions[reaction].usernames.splice(idx, 1); + if (!message.reactions[reaction].usernames.length) { delete message.reactions[reaction]; } return message; }; -async function setReaction(room: IRoom, user: IUser, message: IMessage, reaction: string, shouldReact?: boolean) { - reaction = `:${reaction.replace(/:/g, '')}:`; +export async function setReaction( + room: Pick, + user: IUser, + message: IMessage, + reaction: string, + userAlreadyReacted?: boolean, +) { + await Message.beforeReacted(message, room); - if (!emoji.list[reaction] && (await EmojiCustom.findByNameOrAlias(reaction, {}).count()) === 0) { - throw new Meteor.Error('error-not-allowed', 'Invalid emoji provided.', { - method: 'setReaction', + if (Array.isArray(room.muted) && room.muted.includes(user.username as string)) { + throw new Meteor.Error('error-not-allowed', i18n.t('You_have_been_muted', { lng: user.language }), { + rid: room._id, }); } @@ -42,50 +54,23 @@ async function setReaction(room: IRoom, user: IUser, message: IMessage, reaction } } - if (Array.isArray(room.muted) && room.muted.indexOf(user.username as string) !== -1) { - throw new Meteor.Error('error-not-allowed', i18n.t('You_have_been_muted', { lng: user.language }), { - rid: room._id, - }); - } - - // if (!('reactions' in message)) { - // return; - // } - - await Message.beforeReacted(message, room); - - const userAlreadyReacted = - message.reactions && - Boolean(message.reactions[reaction]) && - message.reactions[reaction].usernames.indexOf(user.username as string) !== -1; - // When shouldReact was not informed, toggle the reaction. - if (shouldReact === undefined) { - shouldReact = !userAlreadyReacted; - } - - if (userAlreadyReacted === shouldReact) { - return; - } - let isReacted; - if (userAlreadyReacted) { const oldMessage = JSON.parse(JSON.stringify(message)); removeUserReaction(message, reaction, user.username as string); - if (_.isEmpty(message.reactions)) { + if (Object.keys(message.reactions || {}).length === 0) { delete message.reactions; + await Messages.unsetReactions(message._id); if (isTheLastMessage(room, message)) { await Rooms.unsetReactionsInLastMessage(room._id); - void notifyOnRoomChangedById(room._id); } - await Messages.unsetReactions(message._id); } else { await Messages.setReactions(message._id, message.reactions); if (isTheLastMessage(room, message)) { await Rooms.setReactionsInLastMessage(room._id, message.reactions); } } - await callbacks.run('afterUnsetReaction', message, { user, reaction, shouldReact, oldMessage }); + void callbacks.run('afterUnsetReaction', message, { user, reaction, shouldReact: false, oldMessage }); isReacted = false; } else { @@ -101,33 +86,61 @@ async function setReaction(room: IRoom, user: IUser, message: IMessage, reaction await Messages.setReactions(message._id, message.reactions); if (isTheLastMessage(room, message)) { await Rooms.setReactionsInLastMessage(room._id, message.reactions); - void notifyOnRoomChangedById(room._id); } - await callbacks.run('afterSetReaction', message, { user, reaction, shouldReact }); + + void callbacks.run('afterSetReaction', message, { user, reaction, shouldReact: true }); isReacted = true; } - await Apps.self?.triggerEvent(AppEvents.IPostMessageReacted, message, user, reaction, isReacted); + void Apps.self?.triggerEvent(AppEvents.IPostMessageReacted, message, user, reaction, isReacted); void notifyOnMessageChange({ id: message._id, }); } -export async function executeSetReaction(userId: string, reaction: string, messageId: IMessage['_id'], shouldReact?: boolean) { - const user = await Users.findOneById(userId); +export async function executeSetReaction( + userId: string, + reaction: string, + messageParam: IMessage['_id'] | IMessage, + shouldReact?: boolean, +) { + // Check if the emoji is valid before proceeding + const reactionWithoutColons = reaction.replace(/:/g, ''); + reaction = `:${reactionWithoutColons}:`; + + if (!emoji.list[reaction] && (await EmojiCustom.countByNameOrAlias(reactionWithoutColons)) === 0) { + throw new Meteor.Error('error-not-allowed', 'Invalid emoji provided.', { + method: 'setReaction', + }); + } + const user = await Users.findOneById(userId); if (!user) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'setReaction' }); } - const message = await Messages.findOneById(messageId); + const message = typeof messageParam === 'string' ? await Messages.findOneById(messageParam) : messageParam; if (!message) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'setReaction' }); } - const room = await Rooms.findOneById(message.rid); + const userAlreadyReacted = + message.reactions && Boolean(message.reactions[reaction]) && message.reactions[reaction].usernames.includes(user.username as string); + + // When shouldReact was not informed, toggle the reaction. + if (shouldReact === undefined) { + shouldReact = !userAlreadyReacted; + } + + if (userAlreadyReacted === shouldReact) { + return; + } + + const room = await Rooms.findOneById< + Pick + >(message.rid, { projection: { _id: 1, ro: 1, muted: 1, reactWhenReadOnly: 1, lastMessage: 1, t: 1, prid: 1, federated: 1 } }); if (!room) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'setReaction' }); } @@ -136,7 +149,7 @@ export async function executeSetReaction(userId: string, reaction: string, messa throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'setReaction' }); } - return setReaction(room, user, message, reaction, shouldReact); + return setReaction(room, user, message, reaction, userAlreadyReacted); } declare module '@rocket.chat/ddp-client' { diff --git a/apps/meteor/server/models/raw/EmojiCustom.ts b/apps/meteor/server/models/raw/EmojiCustom.ts index 300721f60d7b..ec3c6390f64d 100644 --- a/apps/meteor/server/models/raw/EmojiCustom.ts +++ b/apps/meteor/server/models/raw/EmojiCustom.ts @@ -72,4 +72,12 @@ export class EmojiCustomRaw extends BaseRaw implements IEmojiCusto create(data: InsertionModel): Promise>> { return this.insertOne(data); } + + countByNameOrAlias(name: string): Promise { + const query = { + $or: [{ name }, { aliases: name }], + }; + + return this.countDocuments(query); + } } diff --git a/apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts b/apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts new file mode 100644 index 000000000000..e267825a6a18 --- /dev/null +++ b/apps/meteor/tests/unit/app/reactions/server/setReaction.spec.ts @@ -0,0 +1,428 @@ +import { expect } from 'chai'; +import { beforeEach, describe, it } from 'mocha'; +import p from 'proxyquire'; +import sinon from 'sinon'; + +const meteorMethodsMock = sinon.stub(); +const emojiList: Record = {}; +const modelsMock = { + EmojiCustom: { + countByNameOrAlias: sinon.stub(), + }, + Users: { + findOneById: sinon.stub(), + }, + Messages: { + findOneById: sinon.stub(), + setReactions: sinon.stub(), + unsetReactions: sinon.stub(), + }, + Rooms: { + findOneById: sinon.stub(), + unsetReactionsInLastMessage: sinon.stub(), + setReactionsInLastMessage: sinon.stub(), + }, +}; +const canAccessRoomAsyncMock = sinon.stub(); +const isTheLastMessageMock = sinon.stub(); +const notifyOnMessageChangeMock = sinon.stub(); +const hasPermissionAsyncMock = sinon.stub(); +const i18nMock = { t: sinon.stub() }; +const callbacksRunMock = sinon.stub(); +const meteorErrorMock = class extends Error { + constructor(message: string) { + super(message); + } +}; + +const { removeUserReaction, executeSetReaction, setReaction } = p.noCallThru().load('../../../../../app/reactions/server/setReaction.ts', { + '@rocket.chat/models': modelsMock, + '@rocket.chat/core-services': { Message: { beforeReacted: sinon.stub() } }, + 'meteor/meteor': { Meteor: { methods: meteorMethodsMock, Error: meteorErrorMock } }, + '../../../lib/callbacks': { callbacks: { run: callbacksRunMock } }, + '../../../server/lib/i18n': { i18n: i18nMock }, + '../../authorization/server': { canAccessRoomAsync: canAccessRoomAsyncMock }, + '../../authorization/server/functions/hasPermission': { hasPermissionAsync: hasPermissionAsyncMock }, + '../../emoji/server': { emoji: { list: emojiList } }, + '../../lib/server/functions/isTheLastMessage': { isTheLastMessage: isTheLastMessageMock }, + '../../lib/server/lib/notifyListener': { + notifyOnMessageChange: notifyOnMessageChangeMock, + }, +}); + +describe('Reactions', () => { + describe('removeUserReaction', () => { + it('should return the message unmodified when no reactions exist', () => { + const message = {}; + + const result = removeUserReaction(message as any, 'test', 'test'); + expect(result).to.equal(message); + }); + it('should remove the reaction from a message', () => { + const message = { + reactions: { + test: { + usernames: ['test', 'test2'], + }, + }, + }; + + const result = removeUserReaction(message as any, 'test', 'test'); + expect(result.reactions.test.usernames).to.not.include('test'); + expect(result.reactions.test.usernames).to.include('test2'); + }); + it('should remove the reaction from a message when the user is the last one on the array', () => { + const message = { + reactions: { + test: { + usernames: ['test'], + }, + }, + }; + + const result = removeUserReaction(message as any, 'test', 'test'); + expect(result.reactions.test).to.be.undefined; + }); + it('should remove username only from the reaction thats passed in', () => { + const message = { + reactions: { + test: { + usernames: ['test', 'test2'], + }, + other: { + usernames: ['test', 'test2'], + }, + }, + }; + + const result = removeUserReaction(message as any, 'test', 'test'); + expect(result.reactions.test.usernames).to.not.include('test'); + expect(result.reactions.test.usernames).to.include('test2'); + expect(result.reactions.other.usernames).to.include('test'); + expect(result.reactions.other.usernames).to.include('test2'); + }); + it('should do nothing if username is not in the reaction', () => { + const message = { + reactions: { + test: { + usernames: ['test', 'test2'], + }, + }, + }; + + const result = removeUserReaction(message as any, 'test', 'test3'); + expect(result.reactions.test.usernames).to.not.include('test3'); + expect(result.reactions.test.usernames).to.include('test'); + expect(result.reactions.test.usernames).to.include('test2'); + }); + }); + describe('executeSetReaction', () => { + beforeEach(() => { + modelsMock.EmojiCustom.countByNameOrAlias.reset(); + }); + it('should throw an error if reaction is not on emojione list', async () => { + modelsMock.EmojiCustom.countByNameOrAlias.resolves(0); + await expect(executeSetReaction('test', 'test', 'test')).to.be.rejectedWith('error-not-allowed'); + }); + it('should fail if user does not exist', async () => { + modelsMock.EmojiCustom.countByNameOrAlias.resolves(1); + await expect(executeSetReaction('test', 'test', 'test')).to.be.rejectedWith('error-invalid-user'); + }); + it('should fail if message does not exist', async () => { + modelsMock.EmojiCustom.countByNameOrAlias.resolves(1); + modelsMock.Users.findOneById.resolves({ username: 'test' }); + await expect(executeSetReaction('test', 'test', 'test')).to.be.rejectedWith('error-not-allowed'); + }); + it('should return nothing if user already reacted and its trying to react again', async () => { + modelsMock.EmojiCustom.countByNameOrAlias.resolves(1); + modelsMock.Users.findOneById.resolves({ username: 'test' }); + modelsMock.Messages.findOneById.resolves({ reactions: { ':test:': { usernames: ['test'] } } }); + expect(await executeSetReaction('test', 'test', 'test', true)).to.be.undefined; + }); + it('should return nothing if user hasnt reacted and its trying to unreact', async () => { + modelsMock.EmojiCustom.countByNameOrAlias.resolves(1); + modelsMock.Users.findOneById.resolves({ username: 'test' }); + modelsMock.Messages.findOneById.resolves({ reactions: { ':test:': { usernames: ['testxxxx'] } } }); + expect(await executeSetReaction('test', 'test', 'test', false)).to.be.undefined; + }); + it('should fail if room does not exist', async () => { + modelsMock.EmojiCustom.countByNameOrAlias.resolves(1); + modelsMock.Users.findOneById.resolves({ username: 'test' }); + modelsMock.Messages.findOneById.resolves({ reactions: { ':test:': { usernames: ['test'] } } }); + modelsMock.Rooms.findOneById.resolves(undefined); + await expect(executeSetReaction('test', 'test', 'test')).to.be.rejectedWith('error-not-allowed'); + }); + it('should fail if user doesnt have acccess to the room', async () => { + modelsMock.EmojiCustom.countByNameOrAlias.resolves(1); + modelsMock.Users.findOneById.resolves({ username: 'test' }); + modelsMock.Messages.findOneById.resolves({ reactions: { ':test:': { usernames: ['test'] } } }); + modelsMock.Rooms.findOneById.resolves({ t: 'd' }); + canAccessRoomAsyncMock.resolves(false); + await expect(executeSetReaction('test', 'test', 'test')).to.be.rejectedWith('not-authorized'); + }); + it('should call setReaction with correct params', async () => { + modelsMock.EmojiCustom.countByNameOrAlias.resolves(1); + modelsMock.Users.findOneById.resolves({ username: 'test' }); + modelsMock.Messages.findOneById.resolves({ reactions: { ':test:': { usernames: ['test'] } } }); + modelsMock.Rooms.findOneById.resolves({ t: 'c' }); + canAccessRoomAsyncMock.resolves(true); + + const res = await executeSetReaction('test', 'test', 'test'); + expect(res).to.be.undefined; + }); + it('should use the message from param when the type is not an string', async () => { + modelsMock.EmojiCustom.countByNameOrAlias.resolves(1); + modelsMock.Users.findOneById.resolves({ username: 'test' }); + modelsMock.Rooms.findOneById.resolves({ t: 'c' }); + canAccessRoomAsyncMock.resolves(true); + + await executeSetReaction('test', 'test', { reactions: { ':test:': { usernames: ['test'] } } }); + expect(modelsMock.Messages.findOneById.calledOnce).to.be.false; + }); + }); + describe('setReaction', () => { + beforeEach(() => { + canAccessRoomAsyncMock.reset(); + hasPermissionAsyncMock.reset(); + isTheLastMessageMock.reset(); + modelsMock.Messages.setReactions.reset(); + modelsMock.Rooms.setReactionsInLastMessage.reset(); + modelsMock.Rooms.unsetReactionsInLastMessage.reset(); + modelsMock.Messages.unsetReactions.reset(); + callbacksRunMock.reset(); + }); + it('should throw an error if user is muted from the room', async () => { + const room = { + muted: ['test'], + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + }; + await expect(setReaction(room, user, message, ':test:')).to.be.rejectedWith('error-not-allowed'); + }); + it('should throw an error if room is readonly and cannot be reacted when readonly and user trying doesnt have permissions and user is not unmuted from room', async () => { + const room = { + ro: true, + reactWhenReadOnly: false, + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + }; + canAccessRoomAsyncMock.resolves(false); + await expect(setReaction(room, user, message, ':test:')).to.be.rejectedWith("You can't send messages because the room is readonly."); + }); + it('should remove the user reaction if userAlreadyReacted is true and call unsetReaction if reaction is the last one on message', async () => { + const room = { + _id: 'test', + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + reactions: { + ':test:': { + usernames: ['test'], + }, + }, + }; + const reaction = ':test:'; + + await setReaction(room, user, message, reaction, true); + expect(modelsMock.Messages.unsetReactions.calledWith(message._id)).to.be.true; + }); + it('should call Rooms.unsetReactionsInLastMessage when userAlreadyReacted is true and reaction is the last one on message', async () => { + const room = { + _id: 'test', + lastMessage: 'test', + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + reactions: { + ':test:': { + usernames: ['test'], + }, + }, + }; + const reaction = ':test:'; + + isTheLastMessageMock.resolves(true); + + await setReaction(room, user, message, reaction, true); + expect(modelsMock.Messages.unsetReactions.calledWith(message._id)).to.be.true; + expect(modelsMock.Rooms.unsetReactionsInLastMessage.calledWith(room._id)).to.be.true; + }); + it('should update the reactions object when userAlreadyReacted is true and there is more reactions on message', async () => { + const room = { + _id: 'test', + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + reactions: { + ':test:': { + usernames: ['test'], + }, + ':test2:': { + usernames: ['test'], + }, + }, + }; + const reaction = ':test:'; + + await setReaction(room, user, message, reaction, true); + expect(modelsMock.Messages.setReactions.calledWith(message._id, sinon.match({ ':test2:': { usernames: ['test'] } }))).to.be.true; + }); + it('should call Rooms.setReactionsInLastMessage when userAlreadyReacted is true and reaction is not the last one on message', async () => { + const room = { + _id: 'test', + lastMessage: 'test', + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + reactions: { + ':test:': { + usernames: ['test'], + }, + ':test2:': { + usernames: ['test'], + }, + }, + }; + const reaction = ':test:'; + + isTheLastMessageMock.resolves(true); + + await setReaction(room, user, message, reaction, true); + expect(modelsMock.Messages.setReactions.calledWith(message._id, sinon.match({ ':test2:': { usernames: ['test'] } }))).to.be.true; + expect(modelsMock.Rooms.setReactionsInLastMessage.calledWith(room._id, sinon.match({ ':test2:': { usernames: ['test'] } }))).to.be + .true; + }); + it('should call afterUnsetReaction callback when userAlreadyReacted is true', async () => { + const room = { + _id: 'test', + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + reactions: { + ':test:': { + usernames: ['test'], + }, + }, + }; + const reaction = ':test:'; + + await setReaction(room, user, message, reaction, true); + expect( + callbacksRunMock.calledWith( + 'afterUnsetReaction', + sinon.match({ _id: 'test' }), + sinon.match({ user, reaction, shouldReact: false, oldMessage: message }), + ), + ).to.be.true; + }); + it('should set reactions when userAlreadyReacted is false', async () => { + const room = { + _id: 'test', + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + }; + const reaction = ':test:'; + await setReaction(room, user, message, reaction, false); + expect(modelsMock.Messages.setReactions.calledWith(message._id, sinon.match({ ':test:': { usernames: ['test'] } }))).to.be.true; + }); + it('should properly add username to the list of reactions when userAlreadyReacted is false', async () => { + const room = { + _id: 'test', + }; + const user = { + username: 'test2', + }; + const message = { + _id: 'test', + reactions: { + ':test:': { + usernames: ['test'], + }, + }, + }; + const reaction = ':test:'; + + await setReaction(room, user, message, reaction, false); + expect(modelsMock.Messages.setReactions.calledWith(message._id, sinon.match({ ':test:': { usernames: ['test', 'test2'] } }))).to.be + .true; + }); + it('should call Rooms.setReactionInLastMessage when userAlreadyReacted is false', async () => { + const room = { + _id: 'x5', + lastMessage: 'test', + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + }; + const reaction = ':test:'; + + isTheLastMessageMock.resolves(true); + + await setReaction(room, user, message, reaction, false); + expect(modelsMock.Messages.setReactions.calledWith(message._id, sinon.match({ ':test:': { usernames: ['test'] } }))).to.be.true; + expect(modelsMock.Rooms.setReactionsInLastMessage.calledWith(room._id, sinon.match({ ':test:': { usernames: ['test'] } }))).to.be + .true; + }); + it('should call afterSetReaction callback when userAlreadyReacted is false', async () => { + const room = { + _id: 'test', + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + }; + const reaction = ':test:'; + + await setReaction(room, user, message, reaction, false); + expect( + callbacksRunMock.calledWith('afterSetReaction', sinon.match({ _id: 'test' }), sinon.match({ user, reaction, shouldReact: true })), + ).to.be.true; + }); + it('should return undefined on a successful reaction', async () => { + const room = { + _id: 'test', + }; + const user = { + username: 'test', + }; + const message = { + _id: 'test', + }; + const reaction = ':test:'; + + expect(await setReaction(room, user, message, reaction, false)).to.be.undefined; + }); + }); +}); diff --git a/packages/model-typings/src/models/IEmojiCustomModel.ts b/packages/model-typings/src/models/IEmojiCustomModel.ts index fba5f1c3ea10..30f0323c1ec7 100644 --- a/packages/model-typings/src/models/IEmojiCustomModel.ts +++ b/packages/model-typings/src/models/IEmojiCustomModel.ts @@ -10,4 +10,5 @@ export interface IEmojiCustomModel extends IBaseModel { setAliases(_id: string, aliases: string[]): Promise; setExtension(_id: string, extension: string): Promise; create(data: InsertionModel): Promise>>; + countByNameOrAlias(name: string): Promise; } From 274f4f58812cc0409c62380ca4292a64b6ab04b5 Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Thu, 19 Sep 2024 21:15:14 -0300 Subject: [PATCH 100/170] feat: E2EE messages mentions (#32510) --- .changeset/late-planes-sniff.md | 7 ++ .../app/lib/server/methods/updateMessage.ts | 2 +- apps/meteor/app/mentions/server/Mentions.ts | 20 ++++-- apps/meteor/client/startup/e2e.ts | 22 ++++++ apps/meteor/server/settings/e2e.ts | 6 ++ apps/meteor/tests/e2e/e2e-encryption.spec.ts | 71 +++++++++++++++++++ .../page-objects/fragments/home-content.ts | 2 +- .../core-typings/src/IMessage/IMessage.ts | 1 + packages/i18n/src/locales/en.i18n.json | 2 + 9 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 .changeset/late-planes-sniff.md diff --git a/.changeset/late-planes-sniff.md b/.changeset/late-planes-sniff.md new file mode 100644 index 000000000000..d702a938da78 --- /dev/null +++ b/.changeset/late-planes-sniff.md @@ -0,0 +1,7 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/core-typings": patch +"@rocket.chat/i18n": patch +--- + +Added a new setting to enable mentions in end to end encrypted channels diff --git a/apps/meteor/app/lib/server/methods/updateMessage.ts b/apps/meteor/app/lib/server/methods/updateMessage.ts index 8cebe563cd23..c03208a438e9 100644 --- a/apps/meteor/app/lib/server/methods/updateMessage.ts +++ b/apps/meteor/app/lib/server/methods/updateMessage.ts @@ -10,7 +10,7 @@ import { hasPermissionAsync } from '../../../authorization/server/functions/hasP import { settings } from '../../../settings/server'; import { updateMessage } from '../functions/updateMessage'; -const allowedEditedFields = ['tshow', 'alias', 'attachments', 'avatar', 'emoji', 'msg', 'customFields', 'content']; +const allowedEditedFields = ['tshow', 'alias', 'attachments', 'avatar', 'emoji', 'msg', 'customFields', 'content', 'e2eMentions']; export async function executeUpdateMessage( uid: IUser['_id'], diff --git a/apps/meteor/app/mentions/server/Mentions.ts b/apps/meteor/app/mentions/server/Mentions.ts index 9eda56fea21c..779af2087932 100644 --- a/apps/meteor/app/mentions/server/Mentions.ts +++ b/apps/meteor/app/mentions/server/Mentions.ts @@ -2,7 +2,7 @@ * Mentions is a named function that will process Mentions * @param {Object} message - The message object */ -import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings'; +import { isE2EEMessage, type IMessage, type IRoom, type IUser } from '@rocket.chat/core-typings'; import { type MentionsParserArgs, MentionsParser } from '../lib/MentionsParser'; @@ -43,8 +43,13 @@ export class MentionsServer extends MentionsParser { }); } - async getUsersByMentions({ msg, rid, u: sender }: Pick): Promise { - const mentions = this.getUserMentions(msg); + async getUsersByMentions(message: IMessage): Promise { + const { msg, rid, u: sender, e2eMentions }: Pick = message; + + const mentions = + isE2EEMessage(message) && e2eMentions?.e2eUserMentions && e2eMentions?.e2eUserMentions.length > 0 + ? e2eMentions?.e2eUserMentions + : this.getUserMentions(msg); const mentionsAll: { _id: string; username: string }[] = []; const userMentions = []; @@ -67,8 +72,13 @@ export class MentionsServer extends MentionsParser { return [...mentionsAll, ...(userMentions.length ? await this.getUsers(userMentions) : [])]; } - async getChannelbyMentions({ msg }: Pick) { - const channels = this.getChannelMentions(msg); + async getChannelbyMentions(message: IMessage) { + const { msg, e2eMentions }: Pick = message; + + const channels = + isE2EEMessage(message) && e2eMentions?.e2eChannelMentions && e2eMentions?.e2eChannelMentions.length > 0 + ? e2eMentions?.e2eChannelMentions + : this.getChannelMentions(msg); return this.getChannels(channels.map((c) => c.trim().substr(1))); } diff --git a/apps/meteor/client/startup/e2e.ts b/apps/meteor/client/startup/e2e.ts index de615e8f45de..e45b62563726 100644 --- a/apps/meteor/client/startup/e2e.ts +++ b/apps/meteor/client/startup/e2e.ts @@ -5,6 +5,7 @@ import { Tracker } from 'meteor/tracker'; import { E2EEState } from '../../app/e2e/client/E2EEState'; import { e2e } from '../../app/e2e/client/rocketchat.e2e'; +import { MentionsParser } from '../../app/mentions/lib/MentionsParser'; import { ChatRoom } from '../../app/models/client'; import { settings } from '../../app/settings/client'; import { onClientBeforeSendMessage } from '../lib/onClientBeforeSendMessage'; @@ -88,6 +89,27 @@ Meteor.startup(() => { return message; } + const mentionsEnabled = settings.get('E2E_Enabled_Mentions'); + + if (mentionsEnabled) { + const me = Meteor.user()?.username || ''; + const pattern = settings.get('UTF8_User_Names_Validation'); + const useRealName = settings.get('UI_Use_Real_Name'); + + const mentions = new MentionsParser({ + pattern: () => pattern, + useRealName: () => useRealName, + me: () => me, + }); + + const e2eMentions: IMessage['e2eMentions'] = { + e2eUserMentions: mentions.getUserMentions(message.msg), + e2eChannelMentions: mentions.getChannelMentions(message.msg), + }; + + message.e2eMentions = e2eMentions; + } + // Should encrypt this message. return e2eRoom.encryptMessage(message); }); diff --git a/apps/meteor/server/settings/e2e.ts b/apps/meteor/server/settings/e2e.ts index 6f22784f1709..c8a69757128b 100644 --- a/apps/meteor/server/settings/e2e.ts +++ b/apps/meteor/server/settings/e2e.ts @@ -35,4 +35,10 @@ export const createE2ESettings = () => public: true, enableQuery: { _id: 'E2E_Enable', value: true }, }); + + await this.add('E2E_Enabled_Mentions', false, { + type: 'boolean', + public: true, + enableQuery: { _id: 'E2E_Enable', value: true }, + }); }); diff --git a/apps/meteor/tests/e2e/e2e-encryption.spec.ts b/apps/meteor/tests/e2e/e2e-encryption.spec.ts index 8c6297e9975d..ad98df1aaa53 100644 --- a/apps/meteor/tests/e2e/e2e-encryption.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption.spec.ts @@ -133,11 +133,13 @@ test.describe.serial('e2e-encryption', () => { test.beforeAll(async ({ api }) => { expect((await api.post('/settings/E2E_Allow_Unencrypted_Messages', { value: true })).status()).toBe(200); + expect((await api.post('/settings/E2E_Enabled_Mentions', { value: true })).status()).toBe(200); }); test.afterAll(async ({ api }) => { expect((await api.post('/settings/E2E_Enable', { value: false })).status()).toBe(200); expect((await api.post('/settings/E2E_Allow_Unencrypted_Messages', { value: false })).status()).toBe(200); + expect((await api.post('/settings/E2E_Enabled_Mentions', { value: false })).status()).toBe(200); }); test('expect create a private channel encrypted and send an encrypted message', async ({ page }) => { @@ -265,6 +267,75 @@ test.describe.serial('e2e-encryption', () => { await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); }); + test('expect create a encrypted private channel and mention user', async ({ page }) => { + const channelName = faker.string.uuid(); + + await poHomeChannel.sidenav.createEncryptedChannel(channelName); + + await expect(page).toHaveURL(`/group/${channelName}`); + + await poHomeChannel.dismissToast(); + + await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); + + await poHomeChannel.content.sendMessage('hello @user1'); + + const userMention = await page.getByRole('button', { + name: 'user1', + }); + + await expect(userMention).toBeVisible(); + }); + + test('expect create a encrypted private channel, mention a channel and navigate to it', async ({ page }) => { + const channelName = faker.string.uuid(); + + await poHomeChannel.sidenav.createEncryptedChannel(channelName); + + await expect(page).toHaveURL(`/group/${channelName}`); + + await poHomeChannel.dismissToast(); + + await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); + + await poHomeChannel.content.sendMessage('Are you in the #general channel?'); + + const channelMention = await page.getByRole('button', { + name: 'general', + }); + + await expect(channelMention).toBeVisible(); + + await channelMention.click(); + + await expect(page).toHaveURL(`/channel/general`); + }); + + test('expect create a encrypted private channel, mention a channel and user', async ({ page }) => { + const channelName = faker.string.uuid(); + + await poHomeChannel.sidenav.createEncryptedChannel(channelName); + + await expect(page).toHaveURL(`/group/${channelName}`); + + await poHomeChannel.dismissToast(); + + await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); + + await poHomeChannel.content.sendMessage('Are you in the #general channel, @user1 ?'); + + const channelMention = await page.getByRole('button', { + name: 'general', + }); + + const userMention = await page.getByRole('button', { + name: 'user1', + }); + + await expect(userMention).toBeVisible(); + await expect(channelMention).toBeVisible(); + }); + test('should encrypted field be available on edit room', async ({ page }) => { const channelName = faker.string.uuid(); diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts index 9d5e2081ca93..519d9a4102aa 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts @@ -85,7 +85,7 @@ export class HomeContent { await this.joinRoomIfNeeded(); await this.page.waitForSelector('[name="msg"]:not([disabled])'); await this.page.locator('[name="msg"]').fill(text); - await this.page.keyboard.press('Enter'); + await this.page.getByLabel('Send').click(); } async dispatchSlashCommand(text: string): Promise { diff --git a/packages/core-typings/src/IMessage/IMessage.ts b/packages/core-typings/src/IMessage/IMessage.ts index 205cbaccd466..6c5511966ac8 100644 --- a/packages/core-typings/src/IMessage/IMessage.ts +++ b/packages/core-typings/src/IMessage/IMessage.ts @@ -170,6 +170,7 @@ export interface IMessage extends IRocketChatRecord { tcount?: number; t?: MessageTypesValues; e2e?: 'pending' | 'done'; + e2eMentions?: { e2eUserMentions?: string[]; e2eChannelMentions?: string[] }; otrAck?: string; urls?: MessageUrl[]; diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 728ca256952d..8ce6bea2e117 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -1805,6 +1805,8 @@ "E2E_Enabled": "E2E Enabled", "E2E_Enabled_Default_DirectRooms": "Enable encryption for Direct Rooms by default", "E2E_Enabled_Default_PrivateRooms": "Enable encryption for Private Rooms by default", + "E2E_Enabled_Mentions": "Mentions", + "E2E_Enabled_Mentions_Description": "Notify people, and highlight user, channel, and team mentions in encrypted content.", "E2E_Enable_Encrypt_Files": "Encrypt files", "E2E_Enable_Encrypt_Files_Description": "Encrypt files sent inside encrypted rooms. Check for possible conflicts in [file upload settings.](admin/settings/FileUpload)", "E2E_Encryption_Password_Change": "Change Encryption Password", From 9c119a0abd9963b5ef22f64240cb118e65498c7e Mon Sep 17 00:00:00 2001 From: csuadev <72958726+csuadev@users.noreply.github.com> Date: Thu, 19 Sep 2024 19:16:24 -0500 Subject: [PATCH 101/170] fix: markdown inconsistency with bold and italics (#33157) --- .changeset/sweet-nails-grin.md | 5 + .../client/components/MarkdownText.spec.tsx | 92 +++++++++++++++++++ .../meteor/client/components/MarkdownText.tsx | 14 ++- 3 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 .changeset/sweet-nails-grin.md create mode 100644 apps/meteor/client/components/MarkdownText.spec.tsx diff --git a/.changeset/sweet-nails-grin.md b/.changeset/sweet-nails-grin.md new file mode 100644 index 000000000000..de240bfc0e3f --- /dev/null +++ b/.changeset/sweet-nails-grin.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed inconsistency between the markdown parser from the composer and the rest of the application when using bold and italics in a text. diff --git a/apps/meteor/client/components/MarkdownText.spec.tsx b/apps/meteor/client/components/MarkdownText.spec.tsx new file mode 100644 index 000000000000..86ebadad8463 --- /dev/null +++ b/apps/meteor/client/components/MarkdownText.spec.tsx @@ -0,0 +1,92 @@ +import { mockAppRoot } from '@rocket.chat/mock-providers'; +import { render } from '@testing-library/react'; +import React from 'react'; + +import MarkdownText from './MarkdownText'; + +import '@testing-library/jest-dom'; + +const normalizeHtml = (html: any) => { + return html.replace(/\s+/g, ' ').trim(); +}; + +const markdownText = ` + # Heading 1 + **Paragraph text**: *Bold with one asterisk* **Bold with two asterisks** Lorem ipsum dolor sit amet, consectetur adipiscing elit. + ## Heading 2 + _Italic Text_: _Italic with one underscore_ __Italic with two underscores__ Lorem ipsum dolor sit amet, consectetur adipiscing elit. + ### Heading 3 + Lists, Links and elements + **Unordered List** + - List Item 1 + - List Item 2 + - List Item 3 + - List Item 4 + **Ordered List** + 1. List Item 1 + 2. List Item 2 + 3. List Item 3 + 4. List Item 4 + **Links:** + [Rocket.Chat](rocket.chat) + gabriel.engel@rocket.chat + +55991999999 + \`Inline code\` + \`\`\`typescript + const test = 'this is code' + \`\`\` +`; + +it('should render html elements as expected using default parser', async () => { + const { container } = render(, { + wrapper: mockAppRoot().build(), + legacyRoot: true, + }); + + const normalizedHtml = normalizeHtml(container.innerHTML); + + expect(normalizedHtml).toContain('

    Heading 1

    '); + expect(normalizedHtml).toContain( + 'Paragraph text: Bold with one asterisk Bold with two asterisks Lorem ipsum dolor sit amet', + ); + expect(normalizedHtml).toContain('

    Heading 2

    '); + expect(normalizedHtml).toContain( + 'Italic Text: Italic with one underscore Italic with two underscores Lorem ipsum dolor sit amet', + ); + expect(normalizedHtml).toContain('

    Heading 3

    '); + expect(normalizedHtml).toContain('
    • List Item 1
    • List Item 2
    • List Item 3
    • List Item 4'); + expect(normalizedHtml).toContain('
      1. List Item 1
      2. List Item 2
      3. List Item 3
      4. List Item 4'); + expect(normalizedHtml).toContain('Rocket.Chat'); + expect(normalizedHtml).toContain('gabriel.engel@rocket.chat'); + expect(normalizedHtml).toContain('+55991999999'); + expect(normalizedHtml).toContain('Inline code'); + expect(normalizedHtml).toContain('
        const test = \'this is code\' 
        '); +}); + +it('should render html elements as expected using inline parser', async () => { + const { container } = render(, { + wrapper: mockAppRoot().build(), + legacyRoot: true, + }); + + const normalizedHtml = normalizeHtml(container.innerHTML); + + expect(normalizedHtml).toContain('# Heading 1'); + expect(normalizedHtml).toContain( + 'Bold with one asterisk Bold with two asterisks Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + ); + expect(normalizedHtml).toContain('## Heading 2'); + expect(normalizedHtml).toContain( + 'Italic Text: Italic with one underscore Italic with two underscores Lorem ipsum dolor sit amet', + ); + expect(normalizedHtml).toContain('### Heading 3'); + expect(normalizedHtml).toContain('Unordered List - List Item 1 - List Item 2 - List Item 3 - List Item 4'); + expect(normalizedHtml).toContain('Ordered List 1. List Item 1 2. List Item 2 3. List Item 3 4. List Item 4'); + expect(normalizedHtml).toContain(`Rocket.Chat`); + expect(normalizedHtml).toContain( + `gabriel.engel@rocket.chat`, + ); + expect(normalizedHtml).toContain('+55991999999'); + expect(normalizedHtml).toContain('Inline code'); + expect(normalizedHtml).toContain(`typescript const test = 'this is code'`); +}); diff --git a/apps/meteor/client/components/MarkdownText.tsx b/apps/meteor/client/components/MarkdownText.tsx index 6426b24810ee..0b7d2efa780e 100644 --- a/apps/meteor/client/components/MarkdownText.tsx +++ b/apps/meteor/client/components/MarkdownText.tsx @@ -20,12 +20,18 @@ const documentRenderer = new marked.Renderer(); const inlineRenderer = new marked.Renderer(); const inlineWithoutBreaks = new marked.Renderer(); -marked.Lexer.rules.gfm = { - ...marked.Lexer.rules.gfm, - strong: /^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/, - em: /^__(?=\S)([\s\S]*?\S)__(?!_)|^_(?=\S)([\s\S]*?\S)_(?!_)/, +const walkTokens = (token: marked.Token) => { + const boldPattern = /^\*[^*]+\*$|^\*\*[^*]+\*\*$/; + const italicPattern = /^__(?=\S)([\s\S]*?\S)__(?!_)|^_(?=\S)([\s\S]*?\S)_(?!_)/; + if (boldPattern.test(token.raw)) { + token.type = 'strong'; + } else if (italicPattern.test(token.raw)) { + token.type = 'em'; + } }; +marked.use({ walkTokens }); + const linkMarked = (href: string | null, _title: string | null, text: string): string => `${text} `; const paragraphMarked = (text: string): string => text; From 599762739a71ee6b0f3a090db571a47498876a86 Mon Sep 17 00:00:00 2001 From: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:20:48 -0300 Subject: [PATCH 102/170] fix: conference calls are shown as "not answered" after they end (#33179) --- .changeset/five-coats-rhyme.md | 5 ++++ apps/uikit-playground/package.json | 1 + apps/uikit-playground/vite.config.ts | 4 +-- .../VideoConferenceBlock.tsx | 25 +++++++++++++------ 4 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 .changeset/five-coats-rhyme.md diff --git a/.changeset/five-coats-rhyme.md b/.changeset/five-coats-rhyme.md new file mode 100644 index 000000000000..c5359e3c978a --- /dev/null +++ b/.changeset/five-coats-rhyme.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/fuselage-ui-kit': patch +--- + +Fixed an error that incorrectly showed conference calls as not answered after they ended diff --git a/apps/uikit-playground/package.json b/apps/uikit-playground/package.json index 791526c46f9d..4cca93dc00e9 100644 --- a/apps/uikit-playground/package.json +++ b/apps/uikit-playground/package.json @@ -15,6 +15,7 @@ "@codemirror/lang-json": "^6.0.1", "@codemirror/tooltip": "^0.19.16", "@lezer/highlight": "^1.1.6", + "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/css-in-js": "~0.31.25", "@rocket.chat/fuselage": "^0.59.0", "@rocket.chat/fuselage-hooks": "^0.33.1", diff --git a/apps/uikit-playground/vite.config.ts b/apps/uikit-playground/vite.config.ts index 61a5ab30e647..4d382d652859 100644 --- a/apps/uikit-playground/vite.config.ts +++ b/apps/uikit-playground/vite.config.ts @@ -7,11 +7,11 @@ export default defineConfig(() => ({ esbuild: {}, plugins: [react()], optimizeDeps: { - include: ['@rocket.chat/ui-contexts', '@rocket.chat/message-parser'], + include: ['@rocket.chat/ui-contexts', '@rocket.chat/message-parser', '@rocket.chat/core-typings'], }, build: { commonjsOptions: { - include: [/ui-contexts/, /message-parser/, /node_modules/], + include: [/ui-contexts/, /core-typings/, /message-parser/, /node_modules/], }, }, })); diff --git a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx index 969ad0af1d7c..7125dbbf1bc4 100644 --- a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx @@ -1,3 +1,4 @@ +import { VideoConferenceStatus } from '@rocket.chat/core-typings'; import { useGoToRoom, useTranslation, @@ -133,9 +134,14 @@ const VideoConferenceBlock = ({ {isUserCaller ? t('Call_again') : t('Call_back')} - - {t('Call_was_not_answered')} - + {[ + VideoConferenceStatus.EXPIRED, + VideoConferenceStatus.DECLINED, + ].includes(data.status) && ( + + {t('Call_was_not_answered')} + + )} )} {data.type !== 'direct' && @@ -151,16 +157,21 @@ const VideoConferenceBlock = ({ ) : ( - - {t('Call_was_not_answered')} - + [ + VideoConferenceStatus.EXPIRED, + VideoConferenceStatus.DECLINED, + ].includes(data.status) && ( + + {t('Call_was_not_answered')} + + ) ))} ); } - if (data.type === 'direct' && data.status === 0) { + if (data.type === 'direct' && data.status === VideoConferenceStatus.CALLING) { return ( From 027183fc3e2ffe2b2c2b0875e43dd636aed99ae4 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Fri, 20 Sep 2024 00:47:27 +0000 Subject: [PATCH 103/170] Release 6.13.0-rc.0 --- .changeset/pre.json | 100 +++++++++++++++++ apps/meteor/CHANGELOG.md | 101 ++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 14 +++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- apps/uikit-playground/CHANGELOG.md | 16 +++ apps/uikit-playground/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 +++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 +++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 14 +++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 +++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 +++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 +++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 +++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 ++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 +++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 ++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 ++ ee/packages/presence/package.json | 2 +- ee/packages/ui-theming/CHANGELOG.md | 6 ++ ee/packages/ui-theming/package.json | 2 +- package.json | 2 +- packages/api-client/CHANGELOG.md | 10 ++ packages/api-client/package.json | 2 +- packages/apps/CHANGELOG.md | 10 ++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 20 ++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 17 +++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 ++ packages/cron/package.json | 2 +- packages/ddp-client/CHANGELOG.md | 11 ++ packages/ddp-client/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 21 ++++ packages/fuselage-ui-kit/package.json | 8 +- packages/gazzodown/CHANGELOG.md | 16 +++ packages/gazzodown/package.json | 8 +- packages/i18n/CHANGELOG.md | 14 +++ packages/i18n/package.json | 2 +- packages/instance-status/CHANGELOG.md | 9 ++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 15 +++ packages/livechat/package.json | 2 +- packages/message-parser/CHANGELOG.md | 6 ++ packages/message-parser/package.json | 2 +- packages/mock-providers/CHANGELOG.md | 9 ++ packages/mock-providers/package.json | 2 +- packages/model-typings/CHANGELOG.md | 19 ++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 13 +++ packages/models/package.json | 2 +- packages/peggy-loader/CHANGELOG.md | 6 ++ packages/peggy-loader/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 24 +++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 13 +++ packages/ui-avatar/package.json | 4 +- packages/ui-client/CHANGELOG.md | 18 ++++ packages/ui-client/package.json | 6 +- packages/ui-composer/CHANGELOG.md | 6 ++ packages/ui-composer/package.json | 2 +- packages/ui-contexts/CHANGELOG.md | 12 +++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 14 +++ packages/ui-video-conf/package.json | 6 +- packages/web-ui-registration/CHANGELOG.md | 9 ++ packages/web-ui-registration/package.json | 4 +- yarn.lock | 1 + 80 files changed, 727 insertions(+), 52 deletions(-) create mode 100644 .changeset/pre.json diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000000..6976ce2b60aa --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,100 @@ +{ + "mode": "pre", + "tag": "rc", + "initialVersions": { + "@rocket.chat/meteor": "6.13.0-develop", + "rocketchat-services": "1.3.3", + "@rocket.chat/uikit-playground": "0.4.0", + "@rocket.chat/account-service": "0.4.6", + "@rocket.chat/authorization-service": "0.4.6", + "@rocket.chat/ddp-streamer": "0.3.6", + "@rocket.chat/omnichannel-transcript": "0.4.6", + "@rocket.chat/presence-service": "0.4.6", + "@rocket.chat/queue-worker": "0.4.6", + "@rocket.chat/stream-hub-service": "0.4.6", + "@rocket.chat/license": "0.2.6", + "@rocket.chat/omnichannel-services": "0.3.3", + "@rocket.chat/pdf-worker": "0.2.3", + "@rocket.chat/presence": "0.2.6", + "@rocket.chat/ui-theming": "0.2.1", + "@rocket.chat/account-utils": "0.0.2", + "@rocket.chat/agenda": "0.1.0", + "@rocket.chat/api-client": "0.2.6", + "@rocket.chat/apps": "0.1.6", + "@rocket.chat/base64": "1.0.13", + "@rocket.chat/cas-validate": "0.0.2", + "@rocket.chat/core-services": "0.6.0", + "@rocket.chat/core-typings": "6.13.0-develop", + "@rocket.chat/cron": "0.1.6", + "@rocket.chat/ddp-client": "0.3.6", + "@rocket.chat/eslint-config": "0.7.0", + "@rocket.chat/favicon": "0.0.2", + "@rocket.chat/fuselage-ui-kit": "10.0.0", + "@rocket.chat/gazzodown": "10.0.0", + "@rocket.chat/i18n": "0.7.0", + "@rocket.chat/instance-status": "0.1.6", + "@rocket.chat/jest-presets": "0.0.1", + "@rocket.chat/jwt": "0.1.1", + "@rocket.chat/livechat": "1.19.3", + "@rocket.chat/log-format": "0.0.2", + "@rocket.chat/logger": "0.0.2", + "@rocket.chat/message-parser": "0.31.29", + "@rocket.chat/mock-providers": "0.1.2", + "@rocket.chat/model-typings": "0.7.0", + "@rocket.chat/models": "0.2.3", + "@rocket.chat/poplib": "0.0.2", + "@rocket.chat/password-policies": "0.0.2", + "@rocket.chat/patch-injection": "0.0.1", + "@rocket.chat/peggy-loader": "0.31.25", + "@rocket.chat/random": "1.2.2", + "@rocket.chat/release-action": "2.2.3", + "@rocket.chat/release-changelog": "0.1.0", + "@rocket.chat/rest-typings": "6.13.0-develop", + "@rocket.chat/server-cloud-communication": "0.0.2", + "@rocket.chat/server-fetch": "0.0.3", + "@rocket.chat/sha256": "1.0.10", + "@rocket.chat/tools": "0.2.2", + "@rocket.chat/ui-avatar": "6.0.0", + "@rocket.chat/ui-client": "10.0.0", + "@rocket.chat/ui-composer": "0.2.1", + "@rocket.chat/ui-contexts": "10.0.0", + "@rocket.chat/ui-kit": "0.36.1", + "@rocket.chat/ui-video-conf": "10.0.0", + "@rocket.chat/web-ui-registration": "10.0.0" + }, + "changesets": [ + "brown-singers-appear", + "cyan-ladybugs-thank", + "dirty-stingrays-beg", + "five-coats-rhyme", + "four-cherries-kneel", + "great-humans-live", + "healthy-rivers-nail", + "heavy-snails-help", + "hot-balloons-travel", + "khaki-cameras-glow", + "kind-llamas-grin", + "late-planes-sniff", + "many-balloons-scream", + "many-rules-shout", + "mighty-drinks-hide", + "nasty-tools-enjoy", + "pink-swans-teach", + "quiet-cherries-punch", + "rich-toes-bow", + "rotten-rabbits-brush", + "short-drinks-itch", + "sixty-spoons-own", + "small-crabs-travel", + "soft-mirrors-remember", + "spicy-rocks-burn", + "strong-grapes-brake", + "stupid-pigs-share", + "sweet-nails-grin", + "tame-mayflies-press", + "tiny-geckos-kiss", + "wet-hats-walk", + "wise-avocados-taste", + "witty-lemons-type" + ] +} diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index 97a246abaca6..dd941b905c3c 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,106 @@ # @rocket.chat/meteor +## 6.13.0-rc.0 + +### Minor Changes + +- ([#33156](https://github.com/RocketChat/Rocket.Chat/pull/33156)) added `sidepanelNavigation` to feature preview list + +- ([#32682](https://github.com/RocketChat/Rocket.Chat/pull/32682)) Added support for specifying a unit on departments' creation and update + +- ([#33139](https://github.com/RocketChat/Rocket.Chat/pull/33139)) Added new setting `Allow visitors to finish conversations` that allows admins to decide if omnichannel visitors can close a conversation or not. This doesn't affect agent's capabilities of room closing, neither apps using the livechat bridge to close rooms. + However, if currently your integration relies on `livechat/room.close` endpoint for closing conversations, it's advised to use the authenticated version `livechat/room.closeByUser` of it before turning off this setting. +- ([#32729](https://github.com/RocketChat/Rocket.Chat/pull/32729)) Implemented "omnichannel/contacts.update" endpoint to update contacts + +- ([#32510](https://github.com/RocketChat/Rocket.Chat/pull/32510)) Added a new setting to enable mentions in end to end encrypted channels + +- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview + +- ([#33011](https://github.com/RocketChat/Rocket.Chat/pull/33011)) Return `parent` and `team` information when calling `rooms.info` endpoint + +- ([#32693](https://github.com/RocketChat/Rocket.Chat/pull/32693)) Introduced "create contacts" endpoint to omnichannel + +- ([#33177](https://github.com/RocketChat/Rocket.Chat/pull/33177)) New `teams.listChildren` endpoint that allows users listing rooms & discussions from teams. Only the discussions from the team's main room are returned. + +- ([#33114](https://github.com/RocketChat/Rocket.Chat/pull/33114)) Wraps some room settings in an accordion advanced settings section in room edit contextual bar to improve organization + +- ([#33160](https://github.com/RocketChat/Rocket.Chat/pull/33160)) Implemented sending email via apps + +- ([#32945](https://github.com/RocketChat/Rocket.Chat/pull/32945)) Added a new setting which allows workspace admins to disable email two factor authentication for SSO (OAuth) users. If enabled, SSO users won't be asked for email two factor authentication. + +- ([#33225](https://github.com/RocketChat/Rocket.Chat/pull/33225)) Implemented new feature preview for Sidepanel + +### Patch Changes + +- ([#33317](https://github.com/RocketChat/Rocket.Chat/pull/33317)) Fixed error during sendmessage client stub + +- ([#33211](https://github.com/RocketChat/Rocket.Chat/pull/33211)) Allow to use the token from `room.v` when requesting transcript instead of visitor token. Visitors may change their tokens at any time, rendering old conversations impossible to access for them (or for APIs depending on token) as the visitor token won't match the `room.v` token. + +- ([#33298](https://github.com/RocketChat/Rocket.Chat/pull/33298)) Fixed a Federation callback not awaiting db call + +- ([#32939](https://github.com/RocketChat/Rocket.Chat/pull/32939)) Fixed issue where when you marked a room as unread and you were part of it, sometimes it would mark it as read right after + +- ([#33197](https://github.com/RocketChat/Rocket.Chat/pull/33197)) Fixes an issue where the retention policy warning keep displaying even if the retention is disabled inside the room + +- ([#33321](https://github.com/RocketChat/Rocket.Chat/pull/33321)) Changed the contextualbar behavior based on chat size instead the viewport + +- ([#33246](https://github.com/RocketChat/Rocket.Chat/pull/33246)) Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) + +- ([#32999](https://github.com/RocketChat/Rocket.Chat/pull/32999)) Fixes multiple selection for MultiStaticSelectElement in UiKit + +- ([#33155](https://github.com/RocketChat/Rocket.Chat/pull/33155)) Fixed a code issue on NPS service. It was passing `startAt` as the expiration date when creating a banner. + +- ([#33237](https://github.com/RocketChat/Rocket.Chat/pull/33237)) fixed retention policy max age settings not being respected after upgrade + +- ([#33216](https://github.com/RocketChat/Rocket.Chat/pull/33216)) Prevented uiInteraction to subscribe multiple times + +- ([#33295](https://github.com/RocketChat/Rocket.Chat/pull/33295)) Resolves the issue where outgoing integrations failed to trigger after the version 6.12.0 upgrade by correcting the parameter order from the `afterSaveMessage` callback to listener functions. This ensures the correct room information is passed, restoring the functionality of outgoing webhooks, IRC bridge, Autotranslate, and Engagement Dashboard. + +- ([#33193](https://github.com/RocketChat/Rocket.Chat/pull/33193)) Fixed avatar blob image setting in setUserAvatar method by correcting service handling logic. + +- ([#33209](https://github.com/RocketChat/Rocket.Chat/pull/33209)) Fixed `LivechatSessionTaken` webhook event being called without the `agent` param, which represents the agent serving the room. + +- ([#33296](https://github.com/RocketChat/Rocket.Chat/pull/33296)) Fixed remaining direct references to external user avatar URLs + + Fixed local avatars having priority over external provider + + It mainly corrects the behavior of E2E encryption messages and desktop notifications. + +- ([#33157](https://github.com/RocketChat/Rocket.Chat/pull/33157) by [@csuadev](https://github.com/csuadev)) Fixed inconsistency between the markdown parser from the composer and the rest of the application when using bold and italics in a text. + +- ([#33181](https://github.com/RocketChat/Rocket.Chat/pull/33181)) Fixed issue that caused an infinite loading state when uploading a private app to Rocket.Chat + +- ([#33158](https://github.com/RocketChat/Rocket.Chat/pull/33158)) Fixes an issue where multi-step modals were closing unexpectedly + +-
        Updated dependencies [bb94c9c67a, 9a38c8e13f, 599762739a, 7c14fd1a80, 9eaefdc892, 274f4f5881, cd0d50016e, 78e6ba4820, 532f08819e, 79c16d315a, 927710d778, 3a161c4310, 0f21fa01a3, 12d6307998]: + + - @rocket.chat/ui-client@11.0.0-rc.0 + - @rocket.chat/i18n@0.8.0-rc.0 + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/fuselage-ui-kit@11.0.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/ui-theming@0.3.0-rc.0 + - @rocket.chat/ui-video-conf@11.0.0-rc.0 + - @rocket.chat/ui-composer@0.3.0-rc.0 + - @rocket.chat/gazzodown@11.0.0-rc.0 + - @rocket.chat/ui-avatar@7.0.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/message-parser@0.31.30-rc.0 + - @rocket.chat/models@0.3.0-rc.0 + - @rocket.chat/web-ui-registration@11.0.0-rc.0 + - @rocket.chat/ui-contexts@11.0.0-rc.0 + - @rocket.chat/omnichannel-services@0.3.4-rc.0 + - @rocket.chat/apps@0.1.7-rc.0 + - @rocket.chat/presence@0.2.7-rc.0 + - @rocket.chat/api-client@0.2.7-rc.0 + - @rocket.chat/license@0.2.7-rc.0 + - @rocket.chat/pdf-worker@0.2.4-rc.0 + - @rocket.chat/cron@0.1.7-rc.0 + - @rocket.chat/instance-status@0.1.7-rc.0 + - @rocket.chat/server-cloud-communication@0.0.2 +
        + ## 6.12.0 ### Minor Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index cb3ad01b882a..fc41ef05cacd 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.13.0-develop" + "version": "6.13.0-rc.0" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 1d6e058d7597..6d9cafc01648 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,19 @@ # rocketchat-services +## 1.3.4-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 9eaefdc892, 274f4f5881, 532f08819e, 79c16d315a, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/message-parser@0.31.30-rc.0 + - @rocket.chat/models@0.3.0-rc.0 +
        + ## 1.3.3 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 43659382eb67..82a55122337e 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.3", + "version": "1.3.4-rc.0", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 9ee7e48d1794..a09dcb657466 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.13.0-develop", + "version": "6.13.0-rc.0", "private": true, "author": { "name": "Rocket.Chat", diff --git a/apps/uikit-playground/CHANGELOG.md b/apps/uikit-playground/CHANGELOG.md index 63a8eb47d7c6..27cdcb061719 100644 --- a/apps/uikit-playground/CHANGELOG.md +++ b/apps/uikit-playground/CHANGELOG.md @@ -1,5 +1,21 @@ # @rocket.chat/uikit-playground +## 0.5.0-rc.0 + +### Minor Changes + +- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview + +### Patch Changes + +-
        Updated dependencies [599762739a, 274f4f5881, cd0d50016e, 78e6ba4820, 927710d778, 12d6307998]: + + - @rocket.chat/fuselage-ui-kit@11.0.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/ui-avatar@7.0.0-rc.0 + - @rocket.chat/ui-contexts@11.0.0-rc.0 +
        + ## 0.4.0 ### Minor Changes diff --git a/apps/uikit-playground/package.json b/apps/uikit-playground/package.json index 4cca93dc00e9..48c099b8d9d1 100644 --- a/apps/uikit-playground/package.json +++ b/apps/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.4.0", + "version": "0.5.0-rc.0", "type": "module", "scripts": { "dev": "vite", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 8d306d7b1c17..40d597827934 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 9eaefdc892, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 +
        + ## 0.4.6 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index b9e45ed14eda..8438504f62f6 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.6", + "version": "0.4.7-rc.0", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index 494c052e8cf8..70479a00abdc 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 9eaefdc892, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 +
        + ## 0.4.6 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index b7912b8bc94d..19cbbd4035cf 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.6", + "version": "0.4.7-rc.0", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 97565b8bde88..2e13a89d03ec 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/ddp-streamer +## 0.3.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 9eaefdc892, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 + - @rocket.chat/instance-status@0.1.7-rc.0 +
        + ## 0.3.6 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 87029e4b8993..d3ae93df7264 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.6", + "version": "0.3.7-rc.0", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 21fc879f9fd9..b29eac976532 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 + - @rocket.chat/omnichannel-services@0.3.4-rc.0 + - @rocket.chat/pdf-worker@0.2.4-rc.0 +
        + ## 0.4.6 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 27290070b653..f28dd6a6d783 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.6", + "version": "0.4.7-rc.0", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index a1ed37bb6fde..a5ad6f38cfc5 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 + - @rocket.chat/presence@0.2.7-rc.0 +
        + ## 0.4.6 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 5968631341b0..898de184e655 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.6", + "version": "0.4.7-rc.0", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 16dc2590f38b..7517afb9c624 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 + - @rocket.chat/omnichannel-services@0.3.4-rc.0 +
        + ## 0.4.6 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index b3d8b0aff94e..c661ab840b9b 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.6", + "version": "0.4.7-rc.0", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index ccbb83e7de0b..3469df54a291 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 +
        + ## 0.4.6 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 9fd5cf0586f6..aecc6e9a9e99 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.6", + "version": "0.4.7-rc.0", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 181b6dfb0e7f..277ae4cbed4a 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [274f4f5881, 927710d778, 12d6307998]: + + - @rocket.chat/core-typings@6.13.0-rc.0 +
        + ## 0.2.6 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 3eceb35e27ff..4adcdae3826f 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.6", + "version": "0.2.7-rc.0", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index f54493a31cd1..9ee4cf76a087 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.4-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 9eaefdc892, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 + - @rocket.chat/pdf-worker@0.2.4-rc.0 +
        + ## 0.3.3 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 696ac6fee640..f6d4f34e8e1a 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.3", + "version": "0.3.4-rc.0", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index ccc01c92e84f..aa927a7b7c26 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.4-rc.0 + +### Patch Changes + +-
        Updated dependencies [274f4f5881, 927710d778, 12d6307998]: + + - @rocket.chat/core-typings@6.13.0-rc.0 +
        + ## 0.2.3 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 234463087a4e..824f196df01c 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.3", + "version": "0.2.4-rc.0", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index a4effccb5f2b..b4d74639e58f 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/core-services@0.7.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 +
        + ## 0.2.6 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 4d599562b278..80c6afe06875 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.6", + "version": "0.2.7-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/ee/packages/ui-theming/CHANGELOG.md b/ee/packages/ui-theming/CHANGELOG.md index 3a4956d146c3..b25ae24af33d 100644 --- a/ee/packages/ui-theming/CHANGELOG.md +++ b/ee/packages/ui-theming/CHANGELOG.md @@ -1,5 +1,11 @@ # @rocket.chat/ui-theming +## 0.3.0-rc.0 + +### Minor Changes + +- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview + ## 0.2.1 ### Patch Changes diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json index d6e3e93c01a4..0548f235c3fd 100644 --- a/ee/packages/ui-theming/package.json +++ b/ee/packages/ui-theming/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-theming", - "version": "0.2.1", + "version": "0.3.0-rc.0", "private": true, "devDependencies": { "@rocket.chat/css-in-js": "~0.31.25", diff --git a/package.json b/package.json index f3e3ce3d3e91..2f89cab55d2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.13.0-develop", + "version": "6.13.0-rc.0", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md index 50096d81e901..6ba6da8d6cb3 100644 --- a/packages/api-client/CHANGELOG.md +++ b/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 9eaefdc892, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 +
        + ## 0.2.6 ### Patch Changes diff --git a/packages/api-client/package.json b/packages/api-client/package.json index b8d9ac155144..7e08a4d4f4d7 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.6", + "version": "0.2.7-rc.0", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.13", diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index adb1b989bad0..4c7d0df77a29 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 274f4f5881, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 +
        + ## 0.1.6 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index ba7d008543b7..b50ad6b74309 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.6", + "version": "0.1.7-rc.0", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index a73f804408ba..58b5d0df4f6e 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,25 @@ # @rocket.chat/core-services +## 0.7.0-rc.0 + +### Minor Changes + +- ([#33011](https://github.com/RocketChat/Rocket.Chat/pull/33011)) Return `parent` and `team` information when calling `rooms.info` endpoint + +- ([#33177](https://github.com/RocketChat/Rocket.Chat/pull/33177)) New `teams.listChildren` endpoint that allows users listing rooms & discussions from teams. Only the discussions from the team's main room are returned. + +- ([#33225](https://github.com/RocketChat/Rocket.Chat/pull/33225)) Implemented new feature preview for Sidepanel + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 9eaefdc892, 274f4f5881, 532f08819e, 79c16d315a, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/message-parser@0.31.30-rc.0 + - @rocket.chat/models@0.3.0-rc.0 +
        + ## 0.6.0 ### Minor Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 74250ffa8c16..7326f3cd3617 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.6.0", + "version": "0.7.0-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index ac2c861590c0..1898fe2767c1 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,22 @@ # @rocket.chat/core-typings +## 6.13.0-rc.0 + +### Minor Changes + +- ([#32693](https://github.com/RocketChat/Rocket.Chat/pull/32693)) Introduced "create contacts" endpoint to omnichannel + +- ([#33225](https://github.com/RocketChat/Rocket.Chat/pull/33225)) Implemented new feature preview for Sidepanel + +### Patch Changes + +- ([#32510](https://github.com/RocketChat/Rocket.Chat/pull/32510)) Added a new setting to enable mentions in end to end encrypted channels + +-
        Updated dependencies [79c16d315a]: + + - @rocket.chat/message-parser@0.31.30-rc.0 +
        + ## 6.12.0 ### Minor Changes diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 86123a156e75..2c5cb3f64a2d 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.13.0-develop", + "version": "6.13.0-rc.0", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 9c0c43c6f16e..7dbf3c56c145 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [274f4f5881, 927710d778, 12d6307998]: + + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/models@0.3.0-rc.0 +
        + ## 0.1.6 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index aa1226271bba..a9f6a0583f78 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.6", + "version": "0.1.7-rc.0", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/ddp-client/CHANGELOG.md b/packages/ddp-client/CHANGELOG.md index 29e062a1374d..82ccc01d5a24 100644 --- a/packages/ddp-client/CHANGELOG.md +++ b/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ddp-client +## 0.3.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 9eaefdc892, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/api-client@0.2.7-rc.0 +
        + ## 0.3.6 ### Patch Changes diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index 0fc47dc9a122..5b78e5ebf1e9 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.6", + "version": "0.3.7-rc.0", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.13", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 41cc87932393..085dedb33bd1 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,26 @@ # Change Log +## 11.0.0-rc.0 + +### Minor Changes + +- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview + +### Patch Changes + +- ([#33179](https://github.com/RocketChat/Rocket.Chat/pull/33179)) Fixed an error that incorrectly showed conference calls as not answered after they ended + +- ([#32999](https://github.com/RocketChat/Rocket.Chat/pull/32999)) Fixes multiple selection for MultiStaticSelectElement in UiKit + +-
        Updated dependencies [274f4f5881, cd0d50016e, 927710d778, 12d6307998]: + + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/ui-video-conf@11.0.0-rc.0 + - @rocket.chat/gazzodown@11.0.0-rc.0 + - @rocket.chat/ui-avatar@7.0.0-rc.0 + - @rocket.chat/ui-contexts@11.0.0-rc.0 +
        + ## 10.0.0 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 80874491a951..8fb0ca254d68 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "10.0.0", + "version": "11.0.0-rc.0", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "*", - "@rocket.chat/ui-contexts": "*", + "@rocket.chat/ui-avatar": "7.0.0-rc.0", + "@rocket.chat/ui-contexts": "11.0.0-rc.0", "@rocket.chat/ui-kit": "*", - "@rocket.chat/ui-video-conf": "*", + "@rocket.chat/ui-video-conf": "11.0.0-rc.0", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 74cd44cc291c..5216831e8365 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,21 @@ # @rocket.chat/gazzodown +## 11.0.0-rc.0 + +### Minor Changes + +- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview + +### Patch Changes + +-
        Updated dependencies [bb94c9c67a, 274f4f5881, cd0d50016e, 79c16d315a, 927710d778, 12d6307998]: + + - @rocket.chat/ui-client@11.0.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/message-parser@0.31.30-rc.0 + - @rocket.chat/ui-contexts@11.0.0-rc.0 +
        + ## 10.0.0 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index c2fbf136b2d6..47bf2782226e 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "10.0.0", + "version": "11.0.0-rc.0", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", @@ -72,10 +72,10 @@ "@rocket.chat/css-in-js": "*", "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-tokens": "*", - "@rocket.chat/message-parser": "0.31.29", + "@rocket.chat/message-parser": "0.31.30-rc.0", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "*", - "@rocket.chat/ui-contexts": "*", + "@rocket.chat/ui-client": "11.0.0-rc.0", + "@rocket.chat/ui-contexts": "11.0.0-rc.0", "katex": "*", "react": "*" }, diff --git a/packages/i18n/CHANGELOG.md b/packages/i18n/CHANGELOG.md index 8a7e4f7317b9..27bb4b471c66 100644 --- a/packages/i18n/CHANGELOG.md +++ b/packages/i18n/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/i18n +## 0.8.0-rc.0 + +### Minor Changes + +- ([#33156](https://github.com/RocketChat/Rocket.Chat/pull/33156)) added `sidepanelNavigation` to feature preview list + +- ([#33139](https://github.com/RocketChat/Rocket.Chat/pull/33139)) Added new setting `Allow visitors to finish conversations` that allows admins to decide if omnichannel visitors can close a conversation or not. This doesn't affect agent's capabilities of room closing, neither apps using the livechat bridge to close rooms. + However, if currently your integration relies on `livechat/room.close` endpoint for closing conversations, it's advised to use the authenticated version `livechat/room.closeByUser` of it before turning off this setting. +- ([#32945](https://github.com/RocketChat/Rocket.Chat/pull/32945)) Added a new setting which allows workspace admins to disable email two factor authentication for SSO (OAuth) users. If enabled, SSO users won't be asked for email two factor authentication. + +### Patch Changes + +- ([#32510](https://github.com/RocketChat/Rocket.Chat/pull/32510)) Added a new setting to enable mentions in end to end encrypted channels + ## 0.7.0 ### Minor Changes diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 7c66e102d578..fe98e3b1f7fc 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/i18n", - "version": "0.7.0", + "version": "0.8.0-rc.0", "private": true, "type": "module", "main": "./dist/index.js", diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index bebd0fd56b85..e98235550ef8 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.7-rc.0 + +### Patch Changes + +-
        Updated dependencies [927710d778]: + + - @rocket.chat/models@0.3.0-rc.0 +
        + ## 0.1.6 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 5ea3b2cb6e0d..d092d649c80f 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.6", + "version": "0.1.7-rc.0", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index 598fae50d68d..3c9bde71c23a 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/livechat Change Log +## 1.20.0-rc.0 + +### Minor Changes + +- ([#33139](https://github.com/RocketChat/Rocket.Chat/pull/33139)) Added new setting `Allow visitors to finish conversations` that allows admins to decide if omnichannel visitors can close a conversation or not. This doesn't affect agent's capabilities of room closing, neither apps using the livechat bridge to close rooms. + However, if currently your integration relies on `livechat/room.close` endpoint for closing conversations, it's advised to use the authenticated version `livechat/room.closeByUser` of it before turning off this setting. + +### Patch Changes + +-
        Updated dependencies [cd0d50016e, 79c16d315a]: + + - @rocket.chat/gazzodown@11.0.0-rc.0 + - @rocket.chat/message-parser@0.31.30-rc.0 +
        + ## 1.19.3 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index ce7bb92d6b78..ab4a2a9b3a11 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.3", + "version": "1.20.0-rc.0", "files": [ "/build" ], diff --git a/packages/message-parser/CHANGELOG.md b/packages/message-parser/CHANGELOG.md index 39c82e350b58..f263b04e632c 100644 --- a/packages/message-parser/CHANGELOG.md +++ b/packages/message-parser/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 0.31.30-rc.0 + +### Patch Changes + +- ([#33227](https://github.com/RocketChat/Rocket.Chat/pull/33227)) Improved the performance of the message parser + ## 0.31.29 ### Patch Changes diff --git a/packages/message-parser/package.json b/packages/message-parser/package.json index e58727ba38c2..39fbb4bda5dd 100644 --- a/packages/message-parser/package.json +++ b/packages/message-parser/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/message-parser", "description": "Rocket.Chat parser for messages", - "version": "0.31.29", + "version": "0.31.30-rc.0", "author": { "name": "Rocket.Chat", "url": "https://rocket.chat/" diff --git a/packages/mock-providers/CHANGELOG.md b/packages/mock-providers/CHANGELOG.md index 3a2edfdf99ff..5bd539fda340 100644 --- a/packages/mock-providers/CHANGELOG.md +++ b/packages/mock-providers/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/mock-providers +## 0.1.3-rc.0 + +### Patch Changes + +-
        Updated dependencies [bb94c9c67a, 7c14fd1a80, 274f4f5881, 0f21fa01a3]: + + - @rocket.chat/i18n@0.8.0-rc.0 +
        + ## 0.1.2 ### Patch Changes diff --git a/packages/mock-providers/package.json b/packages/mock-providers/package.json index f9e9b4d06ab8..1a7051e87ff2 100644 --- a/packages/mock-providers/package.json +++ b/packages/mock-providers/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/mock-providers", - "version": "0.1.2", + "version": "0.1.3-rc.0", "private": true, "dependencies": { "@rocket.chat/emitter": "~0.31.25", diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index b743a1132b48..f0aa631439e9 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,24 @@ # @rocket.chat/model-typings +## 0.8.0-rc.0 + +### Minor Changes + +- ([#32682](https://github.com/RocketChat/Rocket.Chat/pull/32682)) Added support for specifying a unit on departments' creation and update + +- ([#32693](https://github.com/RocketChat/Rocket.Chat/pull/32693)) Introduced "create contacts" endpoint to omnichannel + +- ([#33177](https://github.com/RocketChat/Rocket.Chat/pull/33177)) New `teams.listChildren` endpoint that allows users listing rooms & discussions from teams. Only the discussions from the team's main room are returned. + +- ([#33225](https://github.com/RocketChat/Rocket.Chat/pull/33225)) Implemented new feature preview for Sidepanel + +### Patch Changes + +-
        Updated dependencies [274f4f5881, 927710d778, 12d6307998]: + + - @rocket.chat/core-typings@6.13.0-rc.0 +
        + ## 0.7.0 ### Minor Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index 30144dabb49a..10a2fd9b643c 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.7.0", + "version": "0.8.0-rc.0", "private": true, "devDependencies": { "@types/node-rsa": "^1.1.4", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 1238c213ec4f..1251d75001bb 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/models +## 0.3.0-rc.0 + +### Minor Changes + +- ([#32693](https://github.com/RocketChat/Rocket.Chat/pull/32693)) Introduced "create contacts" endpoint to omnichannel + +### Patch Changes + +-
        Updated dependencies [9a38c8e13f, 927710d778, 3a161c4310, 12d6307998]: + + - @rocket.chat/model-typings@0.8.0-rc.0 +
        + ## 0.2.3 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index e55ce8d5a0e1..35064171d9a6 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.3", + "version": "0.3.0-rc.0", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/peggy-loader/CHANGELOG.md b/packages/peggy-loader/CHANGELOG.md index 0c1ace99d7d4..422c09e4bc9a 100644 --- a/packages/peggy-loader/CHANGELOG.md +++ b/packages/peggy-loader/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 0.31.26-rc.0 + +### Patch Changes + +- ([#33227](https://github.com/RocketChat/Rocket.Chat/pull/33227)) Improved the performance of the message parser + All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. diff --git a/packages/peggy-loader/package.json b/packages/peggy-loader/package.json index 6eb584f62d24..464be6fdc297 100644 --- a/packages/peggy-loader/package.json +++ b/packages/peggy-loader/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/peggy-loader", - "version": "0.31.25", + "version": "0.31.26-rc.0", "description": "Peggy loader for webpack", "keywords": [ "peggy", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 7cce8dcc6e99..b11458549219 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,29 @@ # @rocket.chat/rest-typings +## 6.13.0-rc.0 + +### Minor Changes + +- ([#32682](https://github.com/RocketChat/Rocket.Chat/pull/32682)) Added support for specifying a unit on departments' creation and update + +- ([#32729](https://github.com/RocketChat/Rocket.Chat/pull/32729)) Implemented "omnichannel/contacts.update" endpoint to update contacts + +- ([#33011](https://github.com/RocketChat/Rocket.Chat/pull/33011)) Return `parent` and `team` information when calling `rooms.info` endpoint + +- ([#32693](https://github.com/RocketChat/Rocket.Chat/pull/32693)) Introduced "create contacts" endpoint to omnichannel + +- ([#33177](https://github.com/RocketChat/Rocket.Chat/pull/33177)) New `teams.listChildren` endpoint that allows users listing rooms & discussions from teams. Only the discussions from the team's main room are returned. + +- ([#33225](https://github.com/RocketChat/Rocket.Chat/pull/33225)) Implemented new feature preview for Sidepanel + +### Patch Changes + +-
        Updated dependencies [274f4f5881, 79c16d315a, 927710d778, 12d6307998]: + + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/message-parser@0.31.30-rc.0 +
        + ## 6.12.0 ### Minor Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 972577210f56..33aad6d64823 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.13.0-develop", + "version": "6.13.0-rc.0", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.13", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index a9fa21cf7195..cfb5f9e17d20 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/ui-avatar +## 7.0.0-rc.0 + +### Minor Changes + +- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview + +### Patch Changes + +-
        Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.0 +
        + ## 6.0.0 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 0423b68f2b43..a32a7a8be6bf 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "6.0.0", + "version": "7.0.0-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -30,7 +30,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "*", + "@rocket.chat/ui-contexts": "11.0.0-rc.0", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 1d172fe1054f..5471cf97ea1b 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,23 @@ # @rocket.chat/ui-client +## 11.0.0-rc.0 + +### Minor Changes + +- ([#33156](https://github.com/RocketChat/Rocket.Chat/pull/33156)) added `sidepanelNavigation` to feature preview list + +- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview + +- ([#33225](https://github.com/RocketChat/Rocket.Chat/pull/33225)) Implemented new feature preview for Sidepanel + +### Patch Changes + +-
        Updated dependencies [cd0d50016e]: + + - @rocket.chat/ui-avatar@7.0.0-rc.0 + - @rocket.chat/ui-contexts@11.0.0-rc.0 +
        + ## 10.0.0 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index a84317f37abc..82705ba026cb 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "10.0.0", + "version": "11.0.0-rc.0", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", @@ -61,8 +61,8 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-avatar": "*", - "@rocket.chat/ui-contexts": "*", + "@rocket.chat/ui-avatar": "7.0.0-rc.0", + "@rocket.chat/ui-contexts": "11.0.0-rc.0", "react": "*", "react-i18next": "*" }, diff --git a/packages/ui-composer/CHANGELOG.md b/packages/ui-composer/CHANGELOG.md index 757dee9a2549..20d5d6ac715d 100644 --- a/packages/ui-composer/CHANGELOG.md +++ b/packages/ui-composer/CHANGELOG.md @@ -1,5 +1,11 @@ # @rocket.chat/ui-composer +## 0.3.0-rc.0 + +### Minor Changes + +- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview + ## 0.2.1 ### Patch Changes diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index 0f97fef22508..363299698bfa 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-composer", - "version": "0.2.1", + "version": "0.3.0-rc.0", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index aa0f00bc0e83..21aeff09a896 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/ui-contexts +## 11.0.0-rc.0 + +### Patch Changes + +-
        Updated dependencies [bb94c9c67a, 9a38c8e13f, 7c14fd1a80, 9eaefdc892, 274f4f5881, 532f08819e, 927710d778, 3a161c4310, 0f21fa01a3, 12d6307998]: + + - @rocket.chat/i18n@0.8.0-rc.0 + - @rocket.chat/rest-typings@6.13.0-rc.0 + - @rocket.chat/core-typings@6.13.0-rc.0 + - @rocket.chat/ddp-client@0.3.7-rc.0 +
        + ## 10.0.0 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 3ef588432a7c..37f83e96a2aa 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "10.0.0", + "version": "11.0.0-rc.0", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 0ebba8028576..fe47f06728bd 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/ui-video-conf +## 11.0.0-rc.0 + +### Minor Changes + +- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview + +### Patch Changes + +-
        Updated dependencies [cd0d50016e]: + + - @rocket.chat/ui-avatar@7.0.0-rc.0 + - @rocket.chat/ui-contexts@11.0.0-rc.0 +
        + ## 10.0.0 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index eb363da1ceae..0f1f3e50eab8 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "10.0.0", + "version": "11.0.0-rc.0", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -39,8 +39,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "*", - "@rocket.chat/ui-contexts": "*", + "@rocket.chat/ui-avatar": "7.0.0-rc.0", + "@rocket.chat/ui-contexts": "11.0.0-rc.0", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 601f9aa63494..0a222203fdee 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 11.0.0-rc.0 + +### Patch Changes + +-
        Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.0 +
        + ## 10.0.0 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index ae08e05ee218..23fd80c89842 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "10.0.0", + "version": "11.0.0-rc.0", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -47,7 +47,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "*", + "@rocket.chat/ui-contexts": "11.0.0-rc.0", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", diff --git a/yarn.lock b/yarn.lock index 6b1123701996..c0fb2733310e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10493,6 +10493,7 @@ __metadata: "@codemirror/lang-json": ^6.0.1 "@codemirror/tooltip": ^0.19.16 "@lezer/highlight": ^1.1.6 + "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/css-in-js": ~0.31.25 "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/fuselage-hooks": ^0.33.1 From 65d2a453f0f0a5236d710ae0ef0587e6aabcb19d Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Fri, 20 Sep 2024 10:56:48 -0300 Subject: [PATCH 104/170] chore: update E2EE setting text (#33226) --- packages/i18n/src/locales/en.i18n.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 8ce6bea2e117..9f37642263da 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -1788,8 +1788,8 @@ "Duplicated_Email_address_will_be_ignored": "Duplicated email address will be ignored.", "Markdown_Marked_Tables": "Enable Marked Tables", "duplicated-account": "Duplicated account", - "E2E_Allow_Unencrypted_Messages": "Unencrypted messages in encrypted rooms", - "E2E_Allow_Unencrypted_Messages_Description": "Allow plain text messages to be sent in encrypted rooms. These messages will not be encrypted.", + "E2E_Allow_Unencrypted_Messages": "Access unencrypted content in encrypted rooms", + "E2E_Allow_Unencrypted_Messages_Description": "Allow access to encrypted rooms to people without room encryption keys. They'll be able to see and send unencrypted messages.", "E2E Encryption": "E2E Encryption", "E2E_Encryption_enabled_for_room": "End-to-end encryption enabled for #{{roomName}}", "E2E_Encryption_disabled_for_room": "End-to-end encryption disabled for #{{roomName}}", From 9bcb802fdcd2a458ae8f8cd69d94173b4f40861d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrique=20Guimar=C3=A3es=20Ribeiro?= <43561537+rique223@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:58:34 -0300 Subject: [PATCH 105/170] feat: Implement proper accessbility for report user modal (#33294) Co-authored-by: Tasso Evangelista <2263066+tassoevan@users.noreply.github.com> --- .changeset/late-hats-carry.md | 6 ++++ .../UserInfo/ReportUserModal.tsx | 31 +++++++++++-------- packages/i18n/src/locales/en.i18n.json | 2 ++ 3 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 .changeset/late-hats-carry.md diff --git a/.changeset/late-hats-carry.md b/.changeset/late-hats-carry.md new file mode 100644 index 000000000000..ec24c7cd5376 --- /dev/null +++ b/.changeset/late-hats-carry.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/i18n": minor +--- + +Improves the accessibility of the report user modal by adding an appropriate label, description, and ARIA attributes. diff --git a/apps/meteor/client/views/room/contextualBar/UserInfo/ReportUserModal.tsx b/apps/meteor/client/views/room/contextualBar/UserInfo/ReportUserModal.tsx index 5f94f7c407b0..86b4571d88d1 100644 --- a/apps/meteor/client/views/room/contextualBar/UserInfo/ReportUserModal.tsx +++ b/apps/meteor/client/views/room/contextualBar/UserInfo/ReportUserModal.tsx @@ -1,4 +1,4 @@ -import { Box, FieldGroup, Field, FieldLabel, FieldRow, FieldError, TextAreaInput } from '@rocket.chat/fuselage'; +import { Box, FieldGroup, Field, FieldLabel, FieldRow, FieldError, TextAreaInput, FieldDescription } from '@rocket.chat/fuselage'; import { useUniqueId } from '@rocket.chat/fuselage-hooks'; import { UserAvatar } from '@rocket.chat/ui-avatar'; import type { ComponentProps } from 'react'; @@ -45,27 +45,32 @@ const ReportUserModal = ({ username, displayName, onConfirm, onClose }: ReportUs onCancel={onClose} confirmText={t('Report')} > + + + + {displayName} + + - - - - - {displayName} - - - + {t('Report_reason')} + {t('Let_moderators_know_what_the_issue_is')} - {errors.reasonForReport && {errors.reasonForReport.message}} + {errors.reasonForReport && ( + + {errors.reasonForReport.message} + + )} diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 9f37642263da..0e99c1bdc1d8 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -3199,6 +3199,7 @@ "leave-p": "Leave Private Groups", "leave-p_description": "Permission to leave private groups", "Lets_get_you_new_one_": "Let's get you a new one!", + "Let_moderators_know_what_the_issue_is": "Let moderators know what the issue is", "Let_them_know": "Let them know", "Left": "Left", "License": "License", @@ -4490,6 +4491,7 @@ "Report_exclamation_mark": "Report!", "Report_has_been_sent": "Report has been sent", "Report_Number": "Report Number", + "Report_reason": "Report reason", "Report_this_message_question_mark": "Report this message?", "Report_User": "Report user", "Reporting": "Reporting", From 827850d545043896722b53d2ed81af3e4d0738b7 Mon Sep 17 00:00:00 2001 From: "Julio A." <52619625+julio-cfa@users.noreply.github.com> Date: Mon, 23 Sep 2024 21:36:58 +0200 Subject: [PATCH 106/170] fix: imported fixes (#33330) --- .changeset/little-bottles-peel.md | 5 +++ apps/meteor/app/api/server/v1/rooms.ts | 9 +++- .../lib/server/methods/cleanRoomHistory.ts | 8 ++++ .../content/urlPreviews/OEmbedHtmlPreview.tsx | 11 ++++- apps/meteor/tests/end-to-end/api/methods.ts | 43 ++++++++++++++++++- apps/meteor/tests/end-to-end/api/rooms.ts | 28 ++++++++++++ 6 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 .changeset/little-bottles-peel.md diff --git a/.changeset/little-bottles-peel.md b/.changeset/little-bottles-peel.md new file mode 100644 index 000000000000..eacb88108a0f --- /dev/null +++ b/.changeset/little-bottles-peel.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index 3dc62e462ddf..117ae3851c43 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -40,7 +40,7 @@ import { findRoomsAvailableForTeams, } from '../lib/rooms'; -async function findRoomByIdOrName({ +export async function findRoomByIdOrName({ params, checkedArchived = true, }: { @@ -365,7 +365,12 @@ API.v1.addRoute( { authRequired: true, validateParams: isRoomsCleanHistoryProps }, { async post() { - const { _id } = await findRoomByIdOrName({ params: this.bodyParams }); + const room = await findRoomByIdOrName({ params: this.bodyParams }); + const { _id } = room; + + if (!room || !(await canAccessRoomAsync(room, { _id: this.userId }))) { + return API.v1.failure('User does not have access to the room [error-not-allowed]', 'error-not-allowed'); + } const { latest, diff --git a/apps/meteor/app/lib/server/methods/cleanRoomHistory.ts b/apps/meteor/app/lib/server/methods/cleanRoomHistory.ts index d6136eee9131..c804128d27bd 100644 --- a/apps/meteor/app/lib/server/methods/cleanRoomHistory.ts +++ b/apps/meteor/app/lib/server/methods/cleanRoomHistory.ts @@ -2,6 +2,8 @@ import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Match, check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; +import { findRoomByIdOrName } from '../../../api/server/v1/rooms'; +import { canAccessRoomAsync } from '../../../authorization/server'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { cleanRoomHistory } from '../functions/cleanRoomHistory'; @@ -56,6 +58,12 @@ Meteor.methods({ throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'cleanRoomHistory' }); } + const room = await findRoomByIdOrName({ params: { roomId } }); + + if (!room || !(await canAccessRoomAsync(room, { _id: userId }))) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'cleanRoomHistory' }); + } + return cleanRoomHistory({ rid: roomId, latest, diff --git a/apps/meteor/client/components/message/content/urlPreviews/OEmbedHtmlPreview.tsx b/apps/meteor/client/components/message/content/urlPreviews/OEmbedHtmlPreview.tsx index e8dd4e1ddcc2..518f1ebad203 100644 --- a/apps/meteor/client/components/message/content/urlPreviews/OEmbedHtmlPreview.tsx +++ b/apps/meteor/client/components/message/content/urlPreviews/OEmbedHtmlPreview.tsx @@ -1,12 +1,21 @@ import { Box } from '@rocket.chat/fuselage'; +import DOMPurify from 'dompurify'; import type { ReactElement } from 'react'; import React from 'react'; import OEmbedCollapsible from './OEmbedCollapsible'; import type { OEmbedPreviewMetadata } from './OEmbedPreviewMetadata'; +const purifyOptions = { + ADD_TAGS: ['iframe'], + ADD_ATTR: ['frameborder', 'allow', 'allowfullscreen', 'scrolling', 'src', 'style', 'referrerpolicy'], + ALLOW_UNKNOWN_PROTOCOLS: true, +}; + const OEmbedHtmlPreview = ({ html, ...props }: OEmbedPreviewMetadata): ReactElement => ( - {html && } + + {html && } + ); export default OEmbedHtmlPreview; diff --git a/apps/meteor/tests/end-to-end/api/methods.ts b/apps/meteor/tests/end-to-end/api/methods.ts index 08945994e438..e3c42389e506 100644 --- a/apps/meteor/tests/end-to-end/api/methods.ts +++ b/apps/meteor/tests/end-to-end/api/methods.ts @@ -616,9 +616,19 @@ describe('Meteor.methods', () => { describe('[@cleanRoomHistory]', () => { let rid: IRoom['_id']; - + let testUser: IUser; + let testUserCredentials: Credentials; let channelName: string; + before('update permissions', async () => { + await updatePermission('clean-channel-history', ['admin', 'user']); + }); + + before('create test user', async () => { + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + }); + before('create room', (done) => { channelName = `methods-test-channel-${Date.now()}`; void request @@ -676,7 +686,36 @@ describe('Meteor.methods', () => { .end(done); }); - after(() => deleteRoom({ type: 'p', roomId: rid })); + after(() => + Promise.all([deleteRoom({ type: 'p', roomId: rid }), deleteUser(testUser), updatePermission('clean-channel-history', ['admin'])]), + ); + + it('should throw an error if user is not part of the room', async () => { + await request + .post(methodCall('cleanRoomHistory')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'cleanRoomHistory', + params: [ + { + roomId: rid, + oldest: { $date: new Date().getTime() }, + latest: { $date: new Date().getTime() }, + }, + ], + id: 'id', + msg: 'method', + }), + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('error').that.is.an('object'); + expect(data.error).to.have.a.property('error', 'error-not-allowed'); + }); + }); it('should not change the _updatedAt value when nothing is changed on the room', async () => { const roomBefore = await request.get(api('groups.info')).set(credentials).query({ diff --git a/apps/meteor/tests/end-to-end/api/rooms.ts b/apps/meteor/tests/end-to-end/api/rooms.ts index 15f85964ffff..5047af7956d8 100644 --- a/apps/meteor/tests/end-to-end/api/rooms.ts +++ b/apps/meteor/tests/end-to-end/api/rooms.ts @@ -1133,6 +1133,34 @@ describe('[Rooms]', () => { }) .end(done); }); + describe('test user is not part of room', async () => { + beforeEach(async () => { + await updatePermission('clean-channel-history', ['admin', 'user']); + }); + + afterEach(async () => { + await updatePermission('clean-channel-history', ['admin']); + }); + + it('should return an error when the user with right privileges is not part of the room', async () => { + await request + .post(api('rooms.cleanHistory')) + .set(userCredentials) + .send({ + roomId: privateChannel._id, + latest: '9999-12-31T23:59:59.000Z', + oldest: '0001-01-01T00:00:00.000Z', + limit: 2000, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-not-allowed'); + expect(res.body).to.have.property('error', 'User does not have access to the room [error-not-allowed]'); + }); + }); + }); }); describe('[/rooms.info]', () => { let testChannel: IRoom; From a6b91525a8c28a640a6e378a912abc06c4ef6bae Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 23 Sep 2024 19:00:02 -0300 Subject: [PATCH 107/170] chore: create network broker package (#33338) --- _templates/service/new/package.json.ejs.t | 1 + _templates/service/new/service.ejs.t | 4 +- .../ee/server/services/ecdh-proxy/service.ts | 3 +- apps/meteor/ee/server/services/package.json | 1 + apps/meteor/ee/server/startup/index.ts | 2 +- apps/meteor/package.json | 1 + ee/apps/account-service/Dockerfile | 3 ++ ee/apps/account-service/package.json | 1 + ee/apps/account-service/src/service.ts | 2 +- ee/apps/authorization-service/Dockerfile | 3 ++ ee/apps/authorization-service/package.json | 1 + ee/apps/authorization-service/src/service.ts | 2 +- ee/apps/ddp-streamer/Dockerfile | 3 ++ ee/apps/ddp-streamer/package.json | 1 + ee/apps/ddp-streamer/src/service.ts | 2 +- ee/apps/omnichannel-transcript/Dockerfile | 3 ++ ee/apps/omnichannel-transcript/package.json | 1 + ee/apps/omnichannel-transcript/src/service.ts | 2 +- ee/apps/presence-service/Dockerfile | 3 ++ ee/apps/presence-service/package.json | 1 + ee/apps/presence-service/src/service.ts | 2 +- ee/apps/queue-worker/Dockerfile | 3 ++ ee/apps/queue-worker/package.json | 1 + ee/apps/queue-worker/src/service.ts | 2 +- ee/apps/stream-hub-service/Dockerfile | 3 ++ ee/apps/stream-hub-service/package.json | 1 + ee/apps/stream-hub-service/src/service.ts | 2 +- ee/packages/network-broker/.eslintrc.json | 4 ++ ee/packages/network-broker/jest.config.ts | 6 +++ ee/packages/network-broker/package.json | 39 +++++++++++++++++++ .../network-broker/src}/EnterpriseCheck.ts | 0 .../network-broker/src/NetworkBroker.test.ts | 4 +- .../network-broker/src}/NetworkBroker.ts | 16 +++++--- .../packages/network-broker/src/index.ts | 2 +- ee/packages/network-broker/tsconfig.json | 9 +++++ yarn.lock | 31 +++++++++++++++ 36 files changed, 145 insertions(+), 20 deletions(-) create mode 100644 ee/packages/network-broker/.eslintrc.json create mode 100644 ee/packages/network-broker/jest.config.ts create mode 100644 ee/packages/network-broker/package.json rename {apps/meteor/ee/server/lib => ee/packages/network-broker/src}/EnterpriseCheck.ts (100%) rename apps/meteor/ee/tests/unit/server/NetworkBroker.tests.ts => ee/packages/network-broker/src/NetworkBroker.test.ts (85%) rename {apps/meteor/ee/server => ee/packages/network-broker/src}/NetworkBroker.ts (94%) rename apps/meteor/ee/server/startup/broker.ts => ee/packages/network-broker/src/index.ts (98%) create mode 100644 ee/packages/network-broker/tsconfig.json diff --git a/_templates/service/new/package.json.ejs.t b/_templates/service/new/package.json.ejs.t index 2c74278d1ced..0aa1bd69e995 100644 --- a/_templates/service/new/package.json.ejs.t +++ b/_templates/service/new/package.json.ejs.t @@ -20,6 +20,7 @@ to: ee/apps/<%= name %>/package.json "dependencies": { "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/emitter": "next", "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", diff --git a/_templates/service/new/service.ejs.t b/_templates/service/new/service.ejs.t index 54080d94cf08..77f02d2b7769 100644 --- a/_templates/service/new/service.ejs.t +++ b/_templates/service/new/service.ejs.t @@ -1,11 +1,11 @@ --- to: ee/apps/<%= name %>/src/service.ts --- +import { api } from '@rocket.chat/core-services'; +import { broker } from '@rocket.chat/network-broker'; import type { Document } from 'mongodb'; import polka from 'polka'; -import { api } from '@rocket.chat/core-services'; -import { broker } from '../../../../apps/meteor/ee/server/startup/broker'; import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; diff --git a/apps/meteor/ee/server/services/ecdh-proxy/service.ts b/apps/meteor/ee/server/services/ecdh-proxy/service.ts index 7ef3e8d26dcc..a795f157c9a5 100755 --- a/apps/meteor/ee/server/services/ecdh-proxy/service.ts +++ b/apps/meteor/ee/server/services/ecdh-proxy/service.ts @@ -1,5 +1,4 @@ -import '../../startup/broker'; - +import '@rocket.chat/network-broker'; import { api } from '@rocket.chat/core-services'; import { ECDHProxy } from './ECDHProxy'; diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 43659382eb67..a2adb5872ad2 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -25,6 +25,7 @@ "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@rocket.chat/string-helpers": "~0.31.25", "@rocket.chat/ui-kit": "workspace:~", diff --git a/apps/meteor/ee/server/startup/index.ts b/apps/meteor/ee/server/startup/index.ts index a8091f0e9a37..eb09ca6ed30f 100644 --- a/apps/meteor/ee/server/startup/index.ts +++ b/apps/meteor/ee/server/startup/index.ts @@ -13,7 +13,7 @@ import { isRunningMs } from '../../../server/lib/isRunningMs'; export const registerEEBroker = async (): Promise => { // only starts network broker if running in micro services mode if (isRunningMs()) { - const { broker } = await import('./broker'); + const { broker } = await import('@rocket.chat/network-broker'); api.setBroker(broker); void api.start(); diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 9ee7e48d1794..c7da95059475 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -262,6 +262,7 @@ "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", "@rocket.chat/mp3-encoder": "0.24.0", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/omnichannel-services": "workspace:^", "@rocket.chat/onboarding-ui": "~0.33.3", "@rocket.chat/password-policies": "workspace:^", diff --git a/ee/apps/account-service/Dockerfile b/ee/apps/account-service/Dockerfile index acbc5b0371d2..c80d4f2eb376 100644 --- a/ee/apps/account-service/Dockerfile +++ b/ee/apps/account-service/Dockerfile @@ -37,6 +37,9 @@ COPY ./packages/logger/dist packages/logger/dist COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ +COPY ./ee/packages/network-broker/package.json ee/packages/network-broker/package.json +COPY ./ee/packages/network-broker/dist ee/packages/network-broker/dist + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index b9e45ed14eda..6f92b8eb9078 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -20,6 +20,7 @@ "@rocket.chat/emitter": "~0.31.25", "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@rocket.chat/string-helpers": "~0.31.25", "@rocket.chat/tools": "workspace:^", diff --git a/ee/apps/account-service/src/service.ts b/ee/apps/account-service/src/service.ts index f166233ca137..07ca30ed748f 100755 --- a/ee/apps/account-service/src/service.ts +++ b/ee/apps/account-service/src/service.ts @@ -1,10 +1,10 @@ import { api } from '@rocket.chat/core-services'; +import { broker } from '@rocket.chat/network-broker'; import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; -import { broker } from '../../../../apps/meteor/ee/server/startup/broker'; const PORT = process.env.PORT || 3033; diff --git a/ee/apps/authorization-service/Dockerfile b/ee/apps/authorization-service/Dockerfile index c662d8765300..9a9e8ded922c 100644 --- a/ee/apps/authorization-service/Dockerfile +++ b/ee/apps/authorization-service/Dockerfile @@ -37,6 +37,9 @@ COPY ./packages/logger/dist packages/logger/dist COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ +COPY ./ee/packages/network-broker/package.json ee/packages/network-broker/package.json +COPY ./ee/packages/network-broker/dist ee/packages/network-broker/dist + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index b7912b8bc94d..262fb6789f9d 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -20,6 +20,7 @@ "@rocket.chat/emitter": "~0.31.25", "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@rocket.chat/string-helpers": "~0.31.25", "@types/node": "^14.18.63", diff --git a/ee/apps/authorization-service/src/service.ts b/ee/apps/authorization-service/src/service.ts index 29162b636229..4dcd466afa60 100755 --- a/ee/apps/authorization-service/src/service.ts +++ b/ee/apps/authorization-service/src/service.ts @@ -1,10 +1,10 @@ import { api } from '@rocket.chat/core-services'; +import { broker } from '@rocket.chat/network-broker'; import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; -import { broker } from '../../../../apps/meteor/ee/server/startup/broker'; const PORT = process.env.PORT || 3034; diff --git a/ee/apps/ddp-streamer/Dockerfile b/ee/apps/ddp-streamer/Dockerfile index f556cbde6752..32103dc3528b 100644 --- a/ee/apps/ddp-streamer/Dockerfile +++ b/ee/apps/ddp-streamer/Dockerfile @@ -40,6 +40,9 @@ COPY ./packages/logger/dist packages/logger/dist COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ +COPY ./ee/packages/network-broker/package.json ee/packages/network-broker/package.json +COPY ./ee/packages/network-broker/dist ee/packages/network-broker/dist + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 87029e4b8993..84859add8d7b 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -23,6 +23,7 @@ "@rocket.chat/logger": "workspace:^", "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@rocket.chat/string-helpers": "~0.31.25", "colorette": "^1.4.0", diff --git a/ee/apps/ddp-streamer/src/service.ts b/ee/apps/ddp-streamer/src/service.ts index b5cd20f7ec02..07666a265dbe 100755 --- a/ee/apps/ddp-streamer/src/service.ts +++ b/ee/apps/ddp-streamer/src/service.ts @@ -1,9 +1,9 @@ import { api } from '@rocket.chat/core-services'; +import { broker } from '@rocket.chat/network-broker'; import type { Document } from 'mongodb'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; -import { broker } from '../../../../apps/meteor/ee/server/startup/broker'; (async () => { const db = await getConnection(); diff --git a/ee/apps/omnichannel-transcript/Dockerfile b/ee/apps/omnichannel-transcript/Dockerfile index 6a93a8e5e8be..9b7e47968e68 100644 --- a/ee/apps/omnichannel-transcript/Dockerfile +++ b/ee/apps/omnichannel-transcript/Dockerfile @@ -37,6 +37,9 @@ COPY ./packages/logger/dist packages/logger/dist COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ +COPY ./ee/packages/network-broker/package.json ee/packages/network-broker/package.json +COPY ./ee/packages/network-broker/dist ee/packages/network-broker/dist + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 27290070b653..ced114bfb589 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -22,6 +22,7 @@ "@rocket.chat/logger": "workspace:^", "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/omnichannel-services": "workspace:^", "@rocket.chat/pdf-worker": "workspace:^", "@rocket.chat/tools": "workspace:^", diff --git a/ee/apps/omnichannel-transcript/src/service.ts b/ee/apps/omnichannel-transcript/src/service.ts index 14cbc5b8438a..66456456fb74 100644 --- a/ee/apps/omnichannel-transcript/src/service.ts +++ b/ee/apps/omnichannel-transcript/src/service.ts @@ -1,11 +1,11 @@ import { api } from '@rocket.chat/core-services'; import { Logger } from '@rocket.chat/logger'; +import { broker } from '@rocket.chat/network-broker'; import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; -import { broker } from '../../../../apps/meteor/ee/server/startup/broker'; const PORT = process.env.PORT || 3036; diff --git a/ee/apps/presence-service/Dockerfile b/ee/apps/presence-service/Dockerfile index aa9c1c0bd6c9..430880d29606 100644 --- a/ee/apps/presence-service/Dockerfile +++ b/ee/apps/presence-service/Dockerfile @@ -40,6 +40,9 @@ COPY ./packages/logger/dist packages/logger/dist COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ +COPY ./ee/packages/network-broker/package.json ee/packages/network-broker/package.json +COPY ./ee/packages/network-broker/dist ee/packages/network-broker/dist + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 5968631341b0..d8e47cc5c5ea 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -20,6 +20,7 @@ "@rocket.chat/emitter": "~0.31.25", "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/presence": "workspace:^", "@rocket.chat/string-helpers": "~0.31.25", "@types/node": "^14.18.63", diff --git a/ee/apps/presence-service/src/service.ts b/ee/apps/presence-service/src/service.ts index b7275a29106f..0e1c97f2daa2 100755 --- a/ee/apps/presence-service/src/service.ts +++ b/ee/apps/presence-service/src/service.ts @@ -1,10 +1,10 @@ import { api } from '@rocket.chat/core-services'; +import { broker } from '@rocket.chat/network-broker'; import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; -import { broker } from '../../../../apps/meteor/ee/server/startup/broker'; const PORT = process.env.PORT || 3031; diff --git a/ee/apps/queue-worker/Dockerfile b/ee/apps/queue-worker/Dockerfile index 6a93a8e5e8be..9b7e47968e68 100644 --- a/ee/apps/queue-worker/Dockerfile +++ b/ee/apps/queue-worker/Dockerfile @@ -37,6 +37,9 @@ COPY ./packages/logger/dist packages/logger/dist COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ +COPY ./ee/packages/network-broker/package.json ee/packages/network-broker/package.json +COPY ./ee/packages/network-broker/dist ee/packages/network-broker/dist + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index b3d8b0aff94e..4270818a6eb3 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -22,6 +22,7 @@ "@rocket.chat/logger": "workspace:^", "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/omnichannel-services": "workspace:^", "@types/node": "^14.18.63", "ejson": "^2.2.3", diff --git a/ee/apps/queue-worker/src/service.ts b/ee/apps/queue-worker/src/service.ts index 8583257a6860..4bc6c9642913 100644 --- a/ee/apps/queue-worker/src/service.ts +++ b/ee/apps/queue-worker/src/service.ts @@ -1,11 +1,11 @@ import { api } from '@rocket.chat/core-services'; import { Logger } from '@rocket.chat/logger'; +import { broker } from '@rocket.chat/network-broker'; import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; -import { broker } from '../../../../apps/meteor/ee/server/startup/broker'; const PORT = process.env.PORT || 3038; diff --git a/ee/apps/stream-hub-service/Dockerfile b/ee/apps/stream-hub-service/Dockerfile index c662d8765300..9a9e8ded922c 100644 --- a/ee/apps/stream-hub-service/Dockerfile +++ b/ee/apps/stream-hub-service/Dockerfile @@ -37,6 +37,9 @@ COPY ./packages/logger/dist packages/logger/dist COPY ./packages/server-cloud-communication/ packages/server-cloud-communication/ +COPY ./ee/packages/network-broker/package.json ee/packages/network-broker/package.json +COPY ./ee/packages/network-broker/dist ee/packages/network-broker/dist + COPY ./ee/packages/license/package.json packages/license/package.json COPY ./ee/packages/license/dist packages/license/dist diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 9fd5cf0586f6..66443ebeec68 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -21,6 +21,7 @@ "@rocket.chat/logger": "workspace:^", "@rocket.chat/model-typings": "workspace:^", "@rocket.chat/models": "workspace:^", + "@rocket.chat/network-broker": "workspace:^", "@rocket.chat/string-helpers": "~0.31.25", "@types/node": "^14.18.63", "ejson": "^2.2.3", diff --git a/ee/apps/stream-hub-service/src/service.ts b/ee/apps/stream-hub-service/src/service.ts index 4975b5b306be..eade703321d2 100755 --- a/ee/apps/stream-hub-service/src/service.ts +++ b/ee/apps/stream-hub-service/src/service.ts @@ -1,11 +1,11 @@ import { api } from '@rocket.chat/core-services'; import { Logger } from '@rocket.chat/logger'; +import { broker } from '@rocket.chat/network-broker'; import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; -import { broker } from '../../../../apps/meteor/ee/server/startup/broker'; import { DatabaseWatcher } from '../../../../apps/meteor/server/database/DatabaseWatcher'; import { StreamHub } from './StreamHub'; diff --git a/ee/packages/network-broker/.eslintrc.json b/ee/packages/network-broker/.eslintrc.json new file mode 100644 index 000000000000..a83aeda48e66 --- /dev/null +++ b/ee/packages/network-broker/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "extends": ["@rocket.chat/eslint-config"], + "ignorePatterns": ["**/dist"] +} diff --git a/ee/packages/network-broker/jest.config.ts b/ee/packages/network-broker/jest.config.ts new file mode 100644 index 000000000000..c18c8ae02465 --- /dev/null +++ b/ee/packages/network-broker/jest.config.ts @@ -0,0 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + +export default { + preset: server.preset, +} satisfies Config; diff --git a/ee/packages/network-broker/package.json b/ee/packages/network-broker/package.json new file mode 100644 index 000000000000..c4d3ea1b284b --- /dev/null +++ b/ee/packages/network-broker/package.json @@ -0,0 +1,39 @@ +{ + "name": "@rocket.chat/network-broker", + "version": "0.1.0", + "private": true, + "devDependencies": { + "@rocket.chat/eslint-config": "workspace:^", + "@types/chai": "~4.3.19", + "@types/ejson": "^2.2.2", + "@types/node": "^14.18.63", + "@types/sinon": "^10.0.20", + "chai": "^4.3.10", + "eslint": "~8.45.0", + "jest": "~29.7.0", + "sinon": "^14.0.2", + "typescript": "~5.5.4" + }, + "scripts": { + "lint": "eslint src", + "lint:fix": "eslint src --fix", + "test": "jest", + "build": "tsc", + "testunit": "jest", + "typecheck": "tsc --noEmit --skipLibCheck" + }, + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "files": [ + "/dist" + ], + "volta": { + "extends": "../../../package.json" + }, + "dependencies": { + "@rocket.chat/core-services": "workspace:^", + "ejson": "^2.2.3", + "moleculer": "^0.14.34", + "pino": "^8.15.0" + } +} diff --git a/apps/meteor/ee/server/lib/EnterpriseCheck.ts b/ee/packages/network-broker/src/EnterpriseCheck.ts similarity index 100% rename from apps/meteor/ee/server/lib/EnterpriseCheck.ts rename to ee/packages/network-broker/src/EnterpriseCheck.ts diff --git a/apps/meteor/ee/tests/unit/server/NetworkBroker.tests.ts b/ee/packages/network-broker/src/NetworkBroker.test.ts similarity index 85% rename from apps/meteor/ee/tests/unit/server/NetworkBroker.tests.ts rename to ee/packages/network-broker/src/NetworkBroker.test.ts index 1aac9c33fc33..c79fb12e7049 100644 --- a/apps/meteor/ee/tests/unit/server/NetworkBroker.tests.ts +++ b/ee/packages/network-broker/src/NetworkBroker.test.ts @@ -2,8 +2,8 @@ import { ServiceClass } from '@rocket.chat/core-services'; import { expect } from 'chai'; import sinon from 'sinon'; -import { BrokerMocked } from '../../../../tests/mocks/server/BrokerMocked'; -import { NetworkBroker } from '../../../server/NetworkBroker'; +import { BrokerMocked } from '../../../../apps/meteor/tests/mocks/server/BrokerMocked'; +import { NetworkBroker } from './NetworkBroker'; class DelayedStopBroker extends BrokerMocked { async destroyService(name: string) { diff --git a/apps/meteor/ee/server/NetworkBroker.ts b/ee/packages/network-broker/src/NetworkBroker.ts similarity index 94% rename from apps/meteor/ee/server/NetworkBroker.ts rename to ee/packages/network-broker/src/NetworkBroker.ts index 0fed6fca542d..e326357cba0a 100644 --- a/apps/meteor/ee/server/NetworkBroker.ts +++ b/ee/packages/network-broker/src/NetworkBroker.ts @@ -2,7 +2,7 @@ import { asyncLocalStorage } from '@rocket.chat/core-services'; import type { IBroker, IBrokerNode, IServiceMetrics, IServiceClass, EventSignatures } from '@rocket.chat/core-services'; import type { ServiceBroker, Context, ServiceSchema } from 'moleculer'; -import { EnterpriseCheck } from './lib/EnterpriseCheck'; +import { EnterpriseCheck } from './EnterpriseCheck'; const events: { [k: string]: string } = { onNodeConnected: '$node.connected', @@ -25,7 +25,7 @@ const waitForServicesTimeout = parseInt(WAIT_FOR_SERVICES_TIMEOUT, 10) || 10000; export class NetworkBroker implements IBroker { private broker: ServiceBroker; - private started: Promise; + private started: Promise = Promise.resolve(false); metrics: IServiceMetrics; @@ -36,7 +36,9 @@ export class NetworkBroker implements IBroker { } async call(method: string, data: any): Promise { - await this.started; + if (!(await this.started)) { + return; + } const context = asyncLocalStorage.getStore(); @@ -54,7 +56,9 @@ export class NetworkBroker implements IBroker { } async waitAndCall(method: string, data: any): Promise { - await this.started; + if (!(await this.started)) { + return; + } try { await this.broker.waitForServices(method.split('.')[0], waitForServicesTimeout); @@ -182,6 +186,8 @@ export class NetworkBroker implements IBroker { } async start(): Promise { - this.started = this.broker.start(); + await this.broker.start(); + + this.started = Promise.resolve(true); } } diff --git a/apps/meteor/ee/server/startup/broker.ts b/ee/packages/network-broker/src/index.ts similarity index 98% rename from apps/meteor/ee/server/startup/broker.ts rename to ee/packages/network-broker/src/index.ts index daae4ace4e05..caa12890b514 100644 --- a/apps/meteor/ee/server/startup/broker.ts +++ b/ee/packages/network-broker/src/index.ts @@ -3,7 +3,7 @@ import EJSON from 'ejson'; import { Errors, Serializers, ServiceBroker } from 'moleculer'; import { pino } from 'pino'; -import { NetworkBroker } from '../NetworkBroker'; +import { NetworkBroker } from './NetworkBroker'; const { MS_NAMESPACE = '', diff --git a/ee/packages/network-broker/tsconfig.json b/ee/packages/network-broker/tsconfig.json new file mode 100644 index 000000000000..ada83b80ff89 --- /dev/null +++ b/ee/packages/network-broker/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.base.server.json", + "compilerOptions": { + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + }, + "files": ["./src/index.ts"] +} diff --git a/yarn.lock b/yarn.lock index 6b1123701996..a7d363694243 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8441,6 +8441,7 @@ __metadata: "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" + "@rocket.chat/network-broker": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 "@rocket.chat/tools": "workspace:^" @@ -8556,6 +8557,7 @@ __metadata: "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" + "@rocket.chat/network-broker": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 "@types/gc-stats": ^1.4.3 @@ -8719,6 +8721,7 @@ __metadata: "@rocket.chat/logger": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" + "@rocket.chat/network-broker": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 "@types/ejson": ^2.2.2 @@ -9396,6 +9399,7 @@ __metadata: "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" "@rocket.chat/mp3-encoder": 0.24.0 + "@rocket.chat/network-broker": "workspace:^" "@rocket.chat/omnichannel-services": "workspace:^" "@rocket.chat/onboarding-ui": ~0.33.3 "@rocket.chat/password-policies": "workspace:^" @@ -9771,6 +9775,27 @@ __metadata: languageName: node linkType: hard +"@rocket.chat/network-broker@workspace:^, @rocket.chat/network-broker@workspace:ee/packages/network-broker": + version: 0.0.0-use.local + resolution: "@rocket.chat/network-broker@workspace:ee/packages/network-broker" + dependencies: + "@rocket.chat/core-services": "workspace:^" + "@rocket.chat/eslint-config": "workspace:^" + "@types/chai": ~4.3.19 + "@types/ejson": ^2.2.2 + "@types/node": ^14.18.63 + "@types/sinon": ^10.0.20 + chai: ^4.3.10 + ejson: ^2.2.3 + eslint: ~8.45.0 + jest: ~29.7.0 + moleculer: ^0.14.34 + pino: ^8.15.0 + sinon: ^14.0.2 + typescript: ~5.5.4 + languageName: unknown + linkType: soft + "@rocket.chat/omnichannel-services@workspace:^, @rocket.chat/omnichannel-services@workspace:ee/packages/omnichannel-services": version: 0.0.0-use.local resolution: "@rocket.chat/omnichannel-services@workspace:ee/packages/omnichannel-services" @@ -9817,6 +9842,7 @@ __metadata: "@rocket.chat/logger": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" + "@rocket.chat/network-broker": "workspace:^" "@rocket.chat/omnichannel-services": "workspace:^" "@rocket.chat/pdf-worker": "workspace:^" "@rocket.chat/tools": "workspace:^" @@ -9954,6 +9980,7 @@ __metadata: "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" + "@rocket.chat/network-broker": "workspace:^" "@rocket.chat/presence": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 "@types/gc-stats": ^1.4.3 @@ -10019,6 +10046,7 @@ __metadata: "@rocket.chat/logger": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" + "@rocket.chat/network-broker": "workspace:^" "@rocket.chat/omnichannel-services": "workspace:^" "@types/gc-stats": ^1.4.3 "@types/node": ^14.18.63 @@ -10176,6 +10204,7 @@ __metadata: "@rocket.chat/logger": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" + "@rocket.chat/network-broker": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 "@types/bcrypt": ^5.0.2 @@ -10493,6 +10522,7 @@ __metadata: "@codemirror/lang-json": ^6.0.1 "@codemirror/tooltip": ^0.19.16 "@lezer/highlight": ^1.1.6 + "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/css-in-js": ~0.31.25 "@rocket.chat/fuselage": ^0.59.0 "@rocket.chat/fuselage-hooks": ^0.33.1 @@ -37207,6 +37237,7 @@ __metadata: "@rocket.chat/message-parser": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" + "@rocket.chat/network-broker": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" "@rocket.chat/string-helpers": ~0.31.25 "@rocket.chat/ui-kit": "workspace:~" From 1f89f780bd205d36b572689e1103c860f787a13e Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Tue, 24 Sep 2024 09:54:31 -0300 Subject: [PATCH 108/170] feat: Adds new admin feature preview setting management (#33212) Co-authored-by: Guilherme Gazzo --- .changeset/quick-rings-wave.md | 7 + .../UserMenu/hooks/useAccountItems.tsx | 4 +- .../hooks/useFeaturePreviewEnableQuery.ts | 28 ++++ .../sidebar/header/hooks/useAccountItems.tsx | 4 +- .../AccountFeaturePreviewBadge.tsx | 21 --- .../AccountFeaturePreviewPage.tsx | 44 ++---- .../client/views/account/sidebarItems.tsx | 5 +- .../AdminFeaturePreviewPage.tsx | 127 ++++++++++++++++++ .../AdminFeaturePreviewRoute.tsx | 26 ++++ apps/meteor/client/views/admin/routes.tsx | 9 ++ .../meteor/client/views/admin/sidebarItems.ts | 8 ++ .../featurePreview/enhanced-navigation.png | Bin 0 -> 2372 bytes .../resizable-contextual-bar.png | Bin 0 -> 4776 bytes .../images/featurePreview/timestamp.png | Bin 0 -> 51432 bytes apps/meteor/server/settings/accounts.ts | 5 + .../tests/end-to-end/api/miscellaneous.ts | 1 + packages/i18n/src/locales/en.i18n.json | 16 ++- packages/i18n/src/locales/hi-IN.i18n.json | 6 +- .../FeaturePreview/FeaturePreviewBadge.tsx | 21 +++ .../src/components/FeaturePreview/index.ts | 2 + packages/ui-client/src/components/index.ts | 2 +- .../useDefaultSettingFeaturePreviewList.ts | 12 ++ .../ui-client/src/hooks/useFeaturePreview.ts | 5 +- .../src/hooks/useFeaturePreviewList.ts | 32 +++-- ... usePreferenceFeaturePreviewList.spec.tsx} | 13 +- .../hooks/usePreferenceFeaturePreviewList.ts | 16 +++ packages/ui-client/src/index.ts | 2 + 27 files changed, 324 insertions(+), 92 deletions(-) create mode 100644 .changeset/quick-rings-wave.md create mode 100644 apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts delete mode 100644 apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx create mode 100644 apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx create mode 100644 apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx create mode 100644 apps/meteor/public/images/featurePreview/enhanced-navigation.png create mode 100644 apps/meteor/public/images/featurePreview/resizable-contextual-bar.png create mode 100644 apps/meteor/public/images/featurePreview/timestamp.png create mode 100644 packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx create mode 100644 packages/ui-client/src/components/FeaturePreview/index.ts create mode 100644 packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts rename packages/ui-client/src/hooks/{useFeaturePreviewList.spec.tsx => usePreferenceFeaturePreviewList.spec.tsx} (79%) create mode 100644 packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts diff --git a/.changeset/quick-rings-wave.md b/.changeset/quick-rings-wave.md new file mode 100644 index 000000000000..0ea22897ff45 --- /dev/null +++ b/.changeset/quick-rings-wave.md @@ -0,0 +1,7 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/i18n": minor +"@rocket.chat/ui-client": minor +--- + +Added new Admin Feature Preview management view, this will allow the workspace admins to both enable feature previewing in the workspace as well as define which feature previews are enabled by default for the users in the workspace. diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx index 82c39c5c1b10..e54e2b72d675 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx @@ -1,7 +1,7 @@ import { Badge } from '@rocket.chat/fuselage'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; -import { defaultFeaturesPreview, useFeaturePreviewList } from '@rocket.chat/ui-client'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; +import { defaultFeaturesPreview, usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; @@ -9,7 +9,7 @@ export const useAccountItems = (): GenericMenuItemProps[] => { const t = useTranslation(); const router = useRouter(); - const { unseenFeatures, featurePreviewEnabled } = useFeaturePreviewList(); + const { unseenFeatures, featurePreviewEnabled } = usePreferenceFeaturePreviewList(); const handleMyAccount = useEffectEvent(() => { router.navigate('/account'); diff --git a/apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts b/apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts new file mode 100644 index 000000000000..fd88f0237d29 --- /dev/null +++ b/apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts @@ -0,0 +1,28 @@ +import type { FeaturePreviewProps } from '@rocket.chat/ui-client'; +import { useMemo } from 'react'; + +const handleFeaturePreviewEnableQuery = (item: FeaturePreviewProps, _: any, features: FeaturePreviewProps[]) => { + if (item.enableQuery) { + const expected = item.enableQuery.value; + const received = features.find((el) => el.name === item.enableQuery?.name)?.value; + if (expected !== received) { + item.disabled = true; + item.value = false; + } else { + item.disabled = false; + } + } + return item; +}; + +const groupFeaturePreview = (features: FeaturePreviewProps[]) => + Object.entries( + features.reduce((result, currentValue) => { + (result[currentValue.group] = result[currentValue.group] || []).push(currentValue); + return result; + }, {} as Record), + ); + +export const useFeaturePreviewEnableQuery = (features: FeaturePreviewProps[]) => { + return useMemo(() => groupFeaturePreview(features.map(handleFeaturePreviewEnableQuery)), [features]); +}; diff --git a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx index 2be6b2b1dea2..51ab7a198a67 100644 --- a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx @@ -1,7 +1,7 @@ import { Badge } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { defaultFeaturesPreview, useFeaturePreviewList } from '@rocket.chat/ui-client'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; +import { defaultFeaturesPreview, usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; @@ -9,7 +9,7 @@ export const useAccountItems = (): GenericMenuItemProps[] => { const t = useTranslation(); const router = useRouter(); - const { unseenFeatures, featurePreviewEnabled } = useFeaturePreviewList(); + const { unseenFeatures, featurePreviewEnabled } = usePreferenceFeaturePreviewList(); const handleMyAccount = useMutableCallback(() => { router.navigate('/account'); diff --git a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx deleted file mode 100644 index c109ca1aefb5..000000000000 --- a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Badge } from '@rocket.chat/fuselage'; -import { useFeaturePreviewList } from '@rocket.chat/ui-client'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; - -const AccountFeaturePreviewBadge = () => { - const { t } = useTranslation(); - const { unseenFeatures } = useFeaturePreviewList(); - - if (!unseenFeatures) { - return null; - } - - return ( - - {unseenFeatures} - - ); -}; - -export default AccountFeaturePreviewBadge; diff --git a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx index dd9ab6a90959..358d2394003b 100644 --- a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx +++ b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx @@ -1,4 +1,3 @@ -import { css } from '@rocket.chat/css-in-js'; import { ButtonGroup, Button, @@ -13,9 +12,10 @@ import { FieldLabel, FieldRow, FieldHint, + Callout, + Margins, } from '@rocket.chat/fuselage'; -import type { FeaturePreviewProps } from '@rocket.chat/ui-client'; -import { useFeaturePreviewList } from '@rocket.chat/ui-client'; +import { usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useToastMessageDispatch, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; import type { ChangeEvent } from 'react'; @@ -23,26 +23,12 @@ import React, { useEffect, Fragment } from 'react'; import { useForm } from 'react-hook-form'; import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../../components/Page'; +import { useFeaturePreviewEnableQuery } from '../../../hooks/useFeaturePreviewEnableQuery'; -const handleEnableQuery = (features: FeaturePreviewProps[]) => { - return features.map((item) => { - if (item.enableQuery) { - const expected = item.enableQuery.value; - const received = features.find((el) => el.name === item.enableQuery?.name)?.value; - if (expected !== received) { - item.disabled = true; - item.value = false; - } else { - item.disabled = false; - } - } - return item; - }); -}; const AccountFeaturePreviewPage = () => { const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const { features, unseenFeatures } = useFeaturePreviewList(); + const { features, unseenFeatures } = usePreferenceFeaturePreviewList(); const setUserPreferences = useEndpoint('POST', '/v1/users.setPreferences'); @@ -85,12 +71,7 @@ const AccountFeaturePreviewPage = () => { setValue('featuresPreview', updated, { shouldDirty: true }); }; - const grouppedFeaturesPreview = Object.entries( - handleEnableQuery(featuresPreview).reduce((result, currentValue) => { - (result[currentValue.group] = result[currentValue.group] || []).push(currentValue); - return result; - }, {} as Record), - ); + const grouppedFeaturesPreview = useFeaturePreviewEnableQuery(featuresPreview); return ( @@ -105,14 +86,11 @@ const AccountFeaturePreviewPage = () => { )} {featuresPreview.length > 0 && ( <> - - {t('Feature_preview_page_description')} + + + {t('Feature_preview_page_description')} + {t('Feature_preview_page_callout')} + {grouppedFeaturesPreview?.map(([group, features], index) => ( diff --git a/apps/meteor/client/views/account/sidebarItems.tsx b/apps/meteor/client/views/account/sidebarItems.tsx index ca0376be329d..fa2ab8bd5e40 100644 --- a/apps/meteor/client/views/account/sidebarItems.tsx +++ b/apps/meteor/client/views/account/sidebarItems.tsx @@ -1,10 +1,9 @@ -import { defaultFeaturesPreview } from '@rocket.chat/ui-client'; +import { defaultFeaturesPreview, FeaturePreviewBadge } from '@rocket.chat/ui-client'; import React from 'react'; import { hasPermission, hasAtLeastOnePermission } from '../../../app/authorization/client'; import { settings } from '../../../app/settings/client'; import { createSidebarItems } from '../../lib/createSidebarItems'; -import AccountFeaturePreviewBadge from './featurePreview/AccountFeaturePreviewBadge'; export const { registerSidebarItem: registerAccountSidebarItem, @@ -54,7 +53,7 @@ export const { href: '/account/feature-preview', i18nLabel: 'Feature_preview', icon: 'flask', - badge: () => , + badge: () => , permissionGranted: () => settings.get('Accounts_AllowFeaturePreview') && defaultFeaturesPreview?.length > 0, }, { diff --git a/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx new file mode 100644 index 000000000000..615fd20cf5a6 --- /dev/null +++ b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx @@ -0,0 +1,127 @@ +import { + ButtonGroup, + Button, + Box, + ToggleSwitch, + Accordion, + Field, + FieldGroup, + FieldLabel, + FieldRow, + FieldHint, + Callout, + Margins, +} from '@rocket.chat/fuselage'; +import { useDefaultSettingFeaturePreviewList } from '@rocket.chat/ui-client'; +import type { TranslationKey } from '@rocket.chat/ui-contexts'; +import { useToastMessageDispatch, useTranslation, useSettingsDispatch } from '@rocket.chat/ui-contexts'; +import type { ChangeEvent } from 'react'; +import React, { Fragment } from 'react'; +import { useForm } from 'react-hook-form'; + +import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../../components/Page'; +import { useFeaturePreviewEnableQuery } from '../../../hooks/useFeaturePreviewEnableQuery'; +import { useEditableSetting } from '../EditableSettingsContext'; +import Setting from '../settings/Setting'; +import SettingsGroupPageSkeleton from '../settings/SettingsGroupPage/SettingsGroupPageSkeleton'; + +const AdminFeaturePreviewPage = () => { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + const allowFeaturePreviewSetting = useEditableSetting('Accounts_AllowFeaturePreview'); + const { features } = useDefaultSettingFeaturePreviewList(); + + const { + watch, + formState: { isDirty }, + setValue, + handleSubmit, + reset, + } = useForm({ + defaultValues: { featuresPreview: features }, + }); + const { featuresPreview } = watch(); + const dispatch = useSettingsDispatch(); + + const handleSave = async () => { + try { + const featuresToBeSaved = featuresPreview.map((feature) => ({ name: feature.name, value: feature.value })); + + await dispatch([ + { _id: allowFeaturePreviewSetting!._id, value: allowFeaturePreviewSetting!.value }, + { _id: 'Accounts_Default_User_Preferences_featuresPreview', value: JSON.stringify(featuresToBeSaved) }, + ]); + dispatchToastMessage({ type: 'success', message: t('Preferences_saved') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + reset({ featuresPreview }); + } + }; + + const handleFeatures = (e: ChangeEvent) => { + const updated = featuresPreview.map((item) => (item.name === e.target.name ? { ...item, value: e.target.checked } : item)); + setValue('featuresPreview', updated, { shouldDirty: true }); + }; + + const grouppedFeaturesPreview = useFeaturePreviewEnableQuery(featuresPreview); + + if (!allowFeaturePreviewSetting) { + // TODO: Implement FeaturePreviewSkeleton component + return ; + } + + return ( + + + + + + + {t('Feature_preview_admin_page_description')} + {t('Feature_preview_page_callout')} + {t('Feature_preview_admin_page_callout')} + + + + + {grouppedFeaturesPreview?.map(([group, features], index) => ( + + + {features.map((feature) => ( + + + + {t(feature.i18n)} + + + {feature.description && {t(feature.description)}} + + {feature.imageUrl && } + + ))} + + + ))} + + + + + + + + + + + ); +}; + +export default AdminFeaturePreviewPage; diff --git a/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx new file mode 100644 index 000000000000..a7d6bd77d136 --- /dev/null +++ b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx @@ -0,0 +1,26 @@ +import { usePermission } from '@rocket.chat/ui-contexts'; +import type { ReactElement } from 'react'; +import React, { memo } from 'react'; + +import SettingsProvider from '../../../providers/SettingsProvider'; +import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage'; +import EditableSettingsProvider from '../settings/EditableSettingsProvider'; +import AdminFeaturePreviewPage from './AdminFeaturePreviewPage'; + +const AdminFeaturePreviewRoute = (): ReactElement => { + const canViewFeaturesPreview = usePermission('manage-cloud'); + + if (!canViewFeaturesPreview) { + return ; + } + + return ( + + + + + + ); +}; + +export default memo(AdminFeaturePreviewRoute); diff --git a/apps/meteor/client/views/admin/routes.tsx b/apps/meteor/client/views/admin/routes.tsx index f70df1625871..d244d5e2f19b 100644 --- a/apps/meteor/client/views/admin/routes.tsx +++ b/apps/meteor/client/views/admin/routes.tsx @@ -104,6 +104,10 @@ declare module '@rocket.chat/ui-contexts' { pathname: `/admin/subscription`; pattern: '/admin/subscription'; }; + 'admin-feature-preview': { + pathname: '/admin/feature-preview'; + pattern: '/admin/feature-preview'; + }; } } @@ -237,3 +241,8 @@ registerAdminRoute('/subscription', { name: 'subscription', component: lazy(() => import('./subscription/SubscriptionRoute')), }); + +registerAdminRoute('/feature-preview', { + name: 'admin-feature-preview', + component: lazy(() => import('./featurePreview/AdminFeaturePreviewRoute')), +}); diff --git a/apps/meteor/client/views/admin/sidebarItems.ts b/apps/meteor/client/views/admin/sidebarItems.ts index 013206d9e9a8..fc7d307396d4 100644 --- a/apps/meteor/client/views/admin/sidebarItems.ts +++ b/apps/meteor/client/views/admin/sidebarItems.ts @@ -1,3 +1,5 @@ +import { defaultFeaturesPreview } from '@rocket.chat/ui-client'; + import { hasPermission, hasAtLeastOnePermission, hasAllPermission } from '../../../app/authorization/client'; import { createSidebarItems } from '../../lib/createSidebarItems'; @@ -129,6 +131,12 @@ export const { icon: 'emoji', permissionGranted: (): boolean => hasPermission('manage-emoji'), }, + { + href: '/admin/feature-preview', + i18nLabel: 'Feature_preview', + icon: 'flask', + permissionGranted: () => defaultFeaturesPreview?.length > 0, + }, { href: '/admin/settings', i18nLabel: 'Settings', diff --git a/apps/meteor/public/images/featurePreview/enhanced-navigation.png b/apps/meteor/public/images/featurePreview/enhanced-navigation.png new file mode 100644 index 0000000000000000000000000000000000000000..4240326ba985d0a054ae5d9c8521b24c8d93e6f7 GIT binary patch literal 2372 zcmeHIYgCg*8lKz;k(*0VynsLp8%mX01@Ra$34#GB2w8)n2Lz6kXazzALMRv_YP;xG zVrfx?0*kHdhC)CtVh|D##7hAYg%TP_P1$fufB*?0CfSL{AKkOvo<04szxKyBGw<`h z^UgExH}gzEL^#D}&89T~0Gp8DKq>$zF&wv8TEKSeq4Rv$;nISm(*aoTVg3*yRQGuZ zBGRdp08rcKGzASbgB(T%puW)RWda5O%aM>k@?kbYDJ7;mXg7)%7}|_U^u0g_?-vIh z3PLLno>;U^yRy;Ip#U%U`gz?3Q9dbXM|jd~=gzm4M_kLikKsE!!V_rWmyy}L8oj)= zS2fb?Im$rG8QwM!!;_UE8Rx|HP0%OX2>m!4{!$M9@ zmzycKXS|vvx3jAFOuN;#LOx%@xz-bPQB~L4+B$H!?W8hJu;wTX4KMQ=yEwA+byHJQ z4Srntp0Hr<_>yuo%x4&B_O`IRa^*|1XD(Z^^k)!1hMgXbR43&u9)Lcv`iBcipXe%2 zq_vq)1Omaa`(22J@|`C&yL#jc-3GtCI}p2cuqKsjiPzA?P2zh4jxQVm;07eyMCq?+ zYV8fOwUa-ksVNIq0FcPLSd^mM+Od*DToGaEjy4EpBb~T5rBg*r>d@@<%gYepB7JF0 zqq_ZhTTbt4e99^Fl9eP{muC7SQ?As-T7ZUt1HXW7`egSV>XAs%dT2+~9d#BA(P*)j z(D0-Wc6F=Xq;Ez*19MWIbzS0osT7X6ozKk>&N3dh)U{&Re&fo8P%s&w0N~{VcrIKq z2x~}d4RQmV;DFu^gWmrCgjZEc@Ze_b(=Aoh-_d=XJZ8+v)lKA~z%BN~S86rpYMt?0u zFkC3)tSau`mnY25=B{g)dM3owSbf=Vw0-aZz2T~fTHkJ@F6pcLmqLRS&;Cv>BWR!I z+RPN!dq?ck6I|axSa+4|B7lNzG$S`NkbWu8%wj3c6P@vb)pL!5@#dmB^TW{?vN zBGfH=G3iH<==4p-aBGihHuu9{(zqJ-xB51NXv62_%8>>T@awGan@0K^3i((iN+xo%#ouHt&I7j7;gA~ zaM|kYft59-NVWnweEfy~obuR!X;>4?FtKhWk9LQc+ATc4!u|H0t|p=C4#)UkIs1b* zU~l>r;^|xj-Rs_fd+|eK`kzi4=TVAO6y`vwsAMd7!IrRlB4EwT%Irr}B_*-~AjVn(;{-)H)yq<^yYV&jM#%$9>QVh%U z%UJHItG`bwI}ZY}o0&klMYUn~qrAe2#ymoOtW#gr9Dz%HofNmdj`t8&#p7n_pOvuZ z=F?L2tj|bH_{0E*sl4L|c!c+jV` zeXy-WWIHdBNTLXs_UIBMDy?(d=pS%;{K~$(^7C(zfUTgQC0m#>rkYzG!&0srmo+zP z%uIJAf4!wl*sSe43silWOG&I~w3z|7=J<^(E=H1Jo*@0}lR+k4a4{Z+7t=?Z<-^16 z#HH**nNR$)vabV9KteLt5UV>qWh13{~`%a65CIDvwi8xxILa6 z!t*MO@WlMq>6uJgtPOPTCQBxzspEI!dI! CCsuy| literal 0 HcmV?d00001 diff --git a/apps/meteor/public/images/featurePreview/resizable-contextual-bar.png b/apps/meteor/public/images/featurePreview/resizable-contextual-bar.png new file mode 100644 index 0000000000000000000000000000000000000000..c36c7e44a29d8c27c9c035a77026f1cd7e7dabd0 GIT binary patch literal 4776 zcmb_gc|6o>+y4y{3PqAFw469i)`&`jifq|xQrRVB8`*};U@Ub)ksQe`Y7ApZSu&Ox z6)GY7))=y78T%}Z8PBitzUT9K&->SNp7Z=MGr#-3uj^jE_jP^0*KgviER2MAN$&yx zK-k3C;4%R4lELS<0({`NlI6W(@Mq^8;~Rkhu>a`K55(m1FUw#jB=EA)d7!N0z%1B+ zdYm&q2LKgGf?F;-0AMfN#NZqv6hfo;Jv`tM&cE!zND54gZ$Tjr8UJp7FxeF9e>=~- zNczd;?|U6ZGO+R3j65s?Iw<~pHX$#1*wnzw?C>E+k>1!?Q)OT2Rh}c~J?-;xh*DD@ z5&VuPfv6;!uDa`!Y;|D_5s9QkRjaLGpz021e>yNWI*E7UP9U*uPKlu$5l ze~mBdx$8HNP<@t@lk;O=yF-uBG)gm}vQ`FTX2=5oSi1PVK?_BPq3}?*Ii*IA>5n%v zbWfn2Z0%VeSS;40*OG6^x`g#gc6vG+0n4xqj%>2%a|E&SDoPm@8=~J!AF?cEymsTg zg9!IX{1QP(Ia9Y692SZ~j-v+Fzbsry_Do~5Q;7QVx)|1Hgr?kFWAI^!+ImZe`h7{@ z<7Wd?nvqU+hh0K`X#Te9Qv~+NQEfZlaS3p1E?Qj;@Lu62F^-=7@DAebv#>32$7(zZ z#2P$QKDTo&6i`vDH*Gffd5$i%t_F_vl8F?y%}h3Z8H@yM*BiosI8lh4P_(iF1@}}? zq{PzNEj#Cf+}E7=M~A1;!yU-VR(Iqja9E9a^KglbjG>o(CfIVWY-qIJ*IfOF9qsco zsP|zA0FZBI-ri@#KFBojJyDX#L`1fpMw(8}=y(;Qb50 ztG4g(e21#ii+lH)f6o-y6co%37_uw9=%rOG{I07yaBXcWTt!j*qfypbuNvD_ng%1S zswfOjww>h>)~7YAPcMAKJRN5mtgR)u*&%|zQM^a8U~`j4t7%8x1g0+hG$#bW$p^tB zc&WljyR{;5B?77{FJK2sZ+Y5Xbn=6bQF;65*X%HMlHJoVhw z6)82L1yy>U@X&1#ma6@IPERFLq98z_CBT>0j}WxM`2u5KK=^tyR#3-#w17MA|1nno zKD<)L2GDvPHBG2q=DbfuxLTun%p7zwTGyA<=9 zB!nyebHtGOAm~b6YDV#ihj{|_k6cGWtTxFs7vUX!*wNWgREa0gb-;1oeZ2iKt*DX@2Z)*70VGVg08F*ZA zN+mNp(=s7Jmf!Q?i^1xoFC8yoT1#hWss%)Q8AJ5+1%MCxP`1?Sl)meFbG2i$N3ZYy zP7t`h^XCM3EB)QYgZ=YwNe|}&eD~2#Z~og?)Df-6Nztk0Y_8`~07mCBDH(F1W8Bph#ys^|#42?=rT@YlU~u*~iG*si#l?3kX@Ir@UX9UT-FG>MBPYH$M)1rcwf_ z;mn;)0AK>};Xee7Ye)YOzvg2$uN+Y*A_Uwy0g-gp58g$BpH~COpPJh^Ieh5GDu!JXulYcLtS%E|89R1ose!2gV6*o1XuQdW zlBMFtWFVo>D8T~`o--ZUMT_o#V6D@lVOpcW-O*QU4kh*j>HHph>nY=I%_>z6m10y3;)SB_t2!g=fg5r4Cg)Ha6UgS$0${lJb;CW!A zg>Wj}CXM5UNb@eZ-C6$(Dwua((c)p%-L<=(4RojcV>}zLLeNMpX-^jyb^q5kgp9R8 z|5yEsawWp3DYK97@r$ZlS^QH*i7G@g@1|&U=R6-6Q@Iu)-~5ei{hY!ly=SXOkY)q+ zf#ytRq>^wQ9?;HgM+!I^Z(Vvb^c8*p=&(|UYmArxy)AKR=fXBSnmXi@vNg75awqhP zhlVzKXIZMp4Hip_339;X2g#odd21l^fk{FHI)dJ({@-}3!bAPT9gtb)?o%F}3kpFC8HXdb}#1X%B> zF8A`Zyq^jRmXwaIf6)NM15*goeIKRSRuO*H41K}}%=(Yl5%zPq_$5T^RKA>#6Brdj zGJi+T{=#AZL^QDv#SNuRKnClLp%H9{Q|O=&>bJxrNJly^x-S3!{hjDXYI|P|k6Y?S zp6tn+tNzo=<$t^ut!Hqk<0oZg(CbqCq(`pQm-sQ`w<>Lh@WIC7mvAZfQYdgsdAIHe zC8iT4t^9vh&FA@N^8Qcp0A&Ce%E(DKQN7gpVkSoip(`&hZ#LscdD7C_vX_h(1vCA` z8b@9?l}o2`k8sBLEpZ-u%$3<0f=-)Hf|_=ynp~@2U0tM!?{wY=-Umov%auzyRORFM z`S)-`O|bEEF3`eK%C7Hjs-#~WP_u2_{mPkQ^j9-7+gT{R)g(`%-3mOFw{z=ly`fbi z{qB1@DLG=Qiu5~h|HhxGV_4Ive3!ePP1Af(5y*$uTgOZhoGg=c87$9xg%P3|$U*M? z=X>5YZ0ZN|G!cgD(awmicwO9Dv`^nl1 zzjYT-L+eYT8PSo5+5)@fSFxM;O2cVM#iEOcKIf?8G3O<3kV^s3C1SZEnQ`{BY};A8}$L{)cZWe-He=7IuFnmhY#4 zY4E58i;gn|BRS3+r;6+SHcPc%%tvs7XD`vC?_eAskXhqi@US|;p8Cu(-kNgy~rVG>ghS%FC0N}9f?~Ks%GAz6J`Z%cVO}B zG04y@>b8#k=;z!%1hn-NM-L`XT9eg&nMqxp*7RR7oT3$9b4u=@sq`?pYiu|62LtEe z%mc7~s>k96X5&=9)5DSQm4rx_zJbV9Ro!gHS%&KD+~VuXk+#m1%{A39Yo-Bt%80P3 zq2VTDzf#=Rmdh&?bCCx)b*_Bg4-wI3l2pChar~jmn+7izL<}=qt?9DEhX7`ApQulH zMEj?4#;~_z$l3Lll0lC%>Vrf3=gSpgq(a-sPF?M*i6e<#oG7stWG;STlQSA38!4w~ z3fwm=Na;p^D=55k@_R@4!LT=E(c(nD&8r-6O_;~)0c9x82zM9b4Q1@Qgjqk8p)K@{ zcK3AGBaS(kU`DqS7yE$=&M+7`WhXH9jFNO9`v*QtIaJs+;+mMNJC&Z8+14tW6_(oX z(yMp>G?90}aC_5kKK5E+LFE1gZd^6s<@360Hi!Y%5J8nXe&u1I?-_5za#YY8N2io~ z)d6Pb9A<3nGbM^mLOZxeCnBdj&>VU~+1Mc>wzZnqD$ug>jHkb)X}j!B;NxhcUt~>v z(%iJEn2uq{z?DZ-4o!wy@AWID@3@mSA8wR2bf#TEmU@&Y3{wM7g6EWRrwA4qQ>PUk z#mD8H|03d$wnSxHxWE;p>Ncycy(|wRkQ)4Z8pLFPlU0T4+8T_bVCjIpvpmQe=!?D- z6hgZFIu&I%SkgPKEF8dj#lON z(7`duN{&Q@~nOMl(JXj*jar!?fu3+B&+@XnbY{$`_o+Q$CoF`g?Fl|#K^V#e7dx4>c9L#(ge z9RZ?he#Djbs<~Ae%4@Vry)%dBj=fmz4EWB5FSq<4?*_=p%jYiGL@lWxq96zDI2uw( z%zGJhR(P=ZMBc=HN^Sx13>@y@XoFWtaipVNh#B;d?L7F8 z6w2Jvt+Ti35do9N>Jqh!ewVXbv?v3~a~PY^VI#70y~7uhFuj{T2(>1Z}n9=S~tg zag~^B{YLWWt@Rd~Tn4Oex2nVkP$KB7x(Xx1wlOMix@6f)@|yvh(puJ?>s^t zrF5E9*fYD3k)B@buYR(O7BN=6*r^bo%Eu2@Y2+IsQ8j4oA*F7yzy!hV^*~owCtKxp a2K(3rHj$^VY%~U(889)lFep3k9Q`kU29J{f literal 0 HcmV?d00001 diff --git a/apps/meteor/public/images/featurePreview/timestamp.png b/apps/meteor/public/images/featurePreview/timestamp.png new file mode 100644 index 0000000000000000000000000000000000000000..7573f97db55b73e2d880af67e6705e3c4a2040c7 GIT binary patch literal 51432 zcmY&I;+-*YJcs>o%A*9CD*w zN8@p~9UFmUL=UF0QoDG?@49d!Nib-d(z9o%!x8dHFgHBma z;FAdYG|=i3(lb%mv0XS{G%RgGwlC0G(?ag$K}WC zMDG=9@0G`~6^a=6B`L4#ab&t}ChPwl85V{Xo1yhIBXYCzjdYj2D|& zuvLN}&X!r{32CJ|wcr$e*wx;B!(V`SW>hv21aq9N4$?uqmnkjcYSjfz?siuRy+Z-~pnMmF}bi{2MnX53H^ZZyt5^F7K<_zh~a^U!QWNzKK zK}YL~$PGB~pi0{MzjH{cjOwx%@~*^UhN-HbJ|_n?Ix;oaKP8r29dE%<+@SLW^Zl(h z+d*pei8t4OWo%FK17xmNIf|S*QshJf>Hp$%7^V<%Ka;6d`2pT_dfrg3Vxn1mgMJ5W zX*1DSFVEVnq%^}JFU~*DHbk$c(3)a#x2jp#$M0RYQgx+nq%$UO;9v|efVYONtva2Y zI`2}f>~@}5r7pVFG9so~qsNkrvPQG^sm!ILFp|O?phUFvXMZRYe5m(DzzLlFQkx*jT-z*@iWRQ=9_n9hVD1T1ysPgD z5M8p~nFKC5`Zeg`S`a6O*oIM)%&6e_D0%hV&lVrlF<0-nwmB#OUjz@Z4HrP)sl=DD z8%`HcePzsrDJ)bZkY(pSL^ES;IUG+TCe(8)qY}{mWnsU_6HGKLVTLGiG zjKipn)x;knxiZ<;9@Een3e%*r?wbs_G7b4~XyItAHbVVQHomW(5`kqcJk6jU)fS@ewU%1>cOg-kuj`+mWwGRphz-T2wWQZ7@e_``dv43CCikc-McrC+&y$a+lEr8U9Ux9Czq+H z53mSTAL&86%N(lGcVr%2-g#QtB$*ymVU0cv$vxEok(<9F){WgrOkV5%)giKhTEr*W zbQ=Sey7DQNv-=O9!V;0mZz&P!k<78P=s5c9%8EkP$iP6^fX?dJ%+|yI#0wgR2t5D^ zpn=D|!=9qDL})Rwr|Y+-Ha6kONsSfl6fTu{fRAfZ@x8>kXuQsdAC__O_;OjAKa^hS z3lOJ$VvbEO274{KPt!<;7UnuFBqqr5%VtO5Psc){ek^E#Z+?7aIAe9w{K8~gDF%io zt`h4(C%D1;4mb^YDr%5PJ7a=yg+Y(`XkD?Ok=7-?*U&Weuk`1!sC_?~mpRE##htP@ z1Slqgu6q%XHg8{Z)YLN;J1u?8-d8iPbbjPWmv;2ciPO zxFyW9Oi$o~J0SgNVTv|gFQefNj0Z?-DO27l$R;8A0kdrhZ@jodFOaTY4oW{p{%?-2 zf@`aC(9I`$7jHLAx-4SDH*ygtU|wrL8sHv^U2hM`FQ`6O?_0zXVoKsE*4e>NZM941 zkRn^Dz-LavhV5rX{;J5)YSRE_ta(eB%n9azFZgMBIvO3@ z{M^WK5)$W1MH^?GXd2(5mCQQY5InD;=>^9>$4(aGPn(XCieF%7w=0Y_sC^$+&H)E3 z${-m;)xOf)yT3)aSw8&Jxa(qt&~7=Rcet~v8u?%^+IY*5lZ?9hqT!QXGJv36oK4@W zM(q!}b68A&cxA@O+1XT1|6{5DGu`8LR@GZvX~91;run{BOQd{c84~7FZNC;iLk|ix zh}ZVFm2JWI>0W>z0~B*fKu@GQi(5srs&l1H0jb?G&8&_;eK@l4nMN)fFDzt6P6lV! z5tAZeS;e_ZiV}Zt?sci`=v==>@ZIF;6?{#k9-(w{V<8vp2eTs1@iAdny+|3W;-d6B z?<?x{F2A zIJ^M|GSi32N7sTA2$umDqYa9|cdoB-C2k+mkE-*V9CHlTA8euVG_k&BRjN|V!A^2@ zE1LdO$LEaVM5hxAC&T-PwFjGqEF@{@b~8!g*Ov&Uo=s0kT)ngr83&J|{d(J3B2PPH zAA$?B|Ez94pG=Jm(}(YdEbOY%0{E))GsdDU3doeTgt6*n7~*jQv)_)nmBU1B4w9uI zT7MXZn~$Md4;*!!HNR2GQIVc2YLqX0FD2o}D5J~v+!*12zwe(z(TT*_I%vijSVp-OQg9LS;jD%%EZ+0bmm{;}Bl%cT^@> zpWKXV)`-76>|p~<&RdIh(K~b!R0u8P_Q1`seP%P+F~>WrH>cI->A_16y1PwJFDZ*x zS#Bn@N?#M6r?F;D%nPO3eph!Smk1{3zg@$M9S5=a*Bz%6_kiP}32H*dF7TVjLJXNI zkur61BpmOS*+qx-L;tg=lH@-dke9%TetR5FFFtO({it)K8!{uK#lha1dtR%*?=M&B zqM%(=%LW+BP6~Ss`Kv2&Au5Ud&0JJRVkmZmY>i(#L*VL?Ks?n#0&d%1UqElT6S3Ar z>vBRU@Vkra-|>@K14gw|St@P~CdRFcK?%`3f!#J<^zkwgQoCx>CHD2nq{aOuljT(O z+1n`Ly$g(%t51hci*BnBz&eGn7p@E%-Xrt6VeF9Z_?Jr9OXBHbLnn@{*&CeaYR!fL z6L510i>HyA=@Cop5@NWzp3V=MCMm)ewyHeFd5ih2AApw{Pv|K+yoSg7FyJRa+vV@Z>R@S)NT>5(Jj)3CY>m0^%Arg0rNep4 zGwg~g3P38`Bq-;@%`Tk$dCy^Po0taJasZvCrLWz^ns zu06Rd``TQ^!q+G%*di*6O^s_3!>H+`6o@+V(T1zS6!f@M-~Y|_8rIfiX1uJCJ0a$k zy&h6!J%26arxIJ#>yHlU-pRqlMl-vKnwf7fE!(pTH9g)SsHe!L_xF4TF?t5y$S&iw z?+9^z;II}rnGmXD#=J}lMl4B<#Td?X6=WyWwqMiveY79x|A?Czy`;0xg!lg+#!*FG zh(VtudQHSpGXvPg^O=-E#F^)Rd!=?^XICvv`C=Ar+&|f_5zcP^w6j+_t^8T>*+nLP zv=<%2?unR7!BG>HDTj#0z_G6i>u%iH&VgV8q4yXYW%mcgD4MUY24Zo`;Z4C}3#MQQ zxllC`LBdkLD{Efp#NbrS#-f9d33bGV3foUG8FIz?@*SG&e93gtNen`pDdZBd$T3~5AtiobAp5{)w%hEy==^wm9RMnYujj0@Yd%l=HndNUrYwh;>>D= zUBOgz2PJt#MK^~Md^m9m5eznPycMx2an`zAMt=I-?*^W^DYUEHEvVB6! zD#Hki0Kx8R0JXoxtf|uHcxz{s4V2x(3%ST|oX&TXFiwkP-zJ9nwLw6zQFa%m zTyr``obU!1u_$Ghs`aBo(p2OvXh-cl#CHKmco%ZewKP8j{i6yd(A&CJl)h>8A=XD(ii z?2{i7DCz0_1=z&y=b*zOv|v0YeK%OGWI&(Ais&Y_C~~++=6E9{(%;`-n`NA7ZL=4n7Ggws6sPGLpIfNGHsr$qz<*~3 zE)Vk^dVd~8DJ|iO(&WH1Lfkf028aE)J!(Gc;kR^V>%2-6=?uNoulJxR`64JBdEQM_ z7FIEA2G#t8HtiidT{~<8rSG);c%h+!AE{J#ZHx&flKpbMg+MjUPXf(^V?+r2(kF2@ z1;#<2Gcj8RJE+AvmF`Y=`MT0IdgzlkmC4%ECaXnxo)zPYz0$baT1;LomGVpr2nMW# z=!VAjNMigGOZSk=s)!nn%^z|Pu#$!LeuqW5DiPTi`6ID6!;H-HIjJ!LK8E6vJAAT% z7ot!+_AY61akY$~HQqrpx^l>D0oXr7NB=#r$z&Jb<|H#d#a}vlB16sK8_`4z6z@ND zTSXqEt1=L>H;6Bu$eOe+SHH+kB0$_wXv0tE1Y|P()kXbT7SgGh3#j_au;pXAX!NV3 zt!{kO&q+-psi2y>kaF_SU{vjwRsh`TFA#vDfaH=BTMvBomB%&rNPdrphc&LXU`ORk zMWZvnVVaF%3bTMSKh>vXJ^FgFqG)EhkI2Ruef)MG>E|z^pp3B-HkM%J8stV4!WMY2 z5s{b_W3e*kY8#^bw2K;MtpL7$rI-C$7k#oe$W^=RHaXVc*ou&baUwBhS_I6j z7sE$i8taeCgSCPeR)5+P)p@gbW-urVXVeS8GHKLbEx{El@6oK8b1@C__}RN?bZar~ z2V)Wq-V&R}-BO|Y{U4&t2q(UnYxW7f`-q`{5#XBlM47fS;SrjX`&vV z3YBQ>wYkmHeh6UwtYE010L!@N{Rux!6kppU&l)Ar0HBSl?dVS00%ViI&(em9{ zSwhFUwi3|~ajlR}pdU%r%E3_PuYG!t!bu0$yY$;Qt5sP{%^^Ad2Y{i#NF#lWk)b~! z{$|f0pA~7STNRi>A@k!sAX@q&blJ_ePEHc%VCPCFlg3n)slty&5a==*n_Y4fAwQoU z!c!m?!Jgz;6)%eiVEwwAyjL`G$Sak{*g|cuVw}Ne8f=6%1R&dM#45jmM+XF7bv)h> zSrJ_qDy4F_>RFgL12L6DU91egMrx}|`|Q4tcwl@uDzg14WpW+t9ty@!u~6!tBz*}S z0CLi(4(RT#sj4jb`cU^v=s#phFb7uB`rHLxgV{_W&0}D>5w6uRUpmsau&O`{@U$pM zQVr-xi%&JmyI>&=&eK;~F1J$pv73lS7JS!S#PyZ9h(&jRlDe}myOxheo67$i7b$2?QJEz?h}Bdg2e3xo;)8wOY;Osb{r-+K7x&Djgaj?Ucc% zvbcmKL(qW9UpDA|Bi}hHY}Myo0I)?tS$)v%q@o9F+|A6$$;r6r3vn#W2)l!JrV?h} z6g@M58-WG4Ju`kUZ0iF{OF437Lq|Ltv2i|=J7UI>PRF6J;DmLdC8%rds+L zU%3ci=KhA*ruZp3IA}fNn9@6P=kUgLjnQ|iO0PjqB0GYXsxTUM{zM}e6GOropdMF~)igZ1iDtABYP1@mJa}W&LAwA6{OH%fc+)~F~tp0(pS#z|P ztlX5s{w89^xL#_?ehL?Owus(QkHQn*vtOU%y@by+7h;W)G+F!n;|k5~`TJzF|1opq zxqJ-aQ&&8OdRR(`*T~1s*RPHFjqPk3m^Xr5k`k&z&s+6xyEp$c6>Wyw!*SGpMdh|O ztFkF3)OLMoBBOuEWY*bKh2%lwK@fZOcTJ4>Z!~sxhE%_z`7hLoMhcyKr2F!;>9o-{ zZBq@LY4J=#*{pTVFnL2yN)s6*XG}=|G__CPE^J3-tg{yrs$K0zVU@P5AX;)bQu21G zR5&DYInGK^wI$M%jGqPRC2J|EeJPul=MzLtPew#hdOas=fN{zd?j1<&%BiRu)N~Q! zO5z-3Kjso|N_IwP_!$@`jI<%e?mva1zp13_4hY4QCq3zCR3Too2X9Yhv3zg1CI%cW)*IOWt*rzm z<5;7F-5cV)FYs!F*p~8orb@MFA58Xvl$;`m&O!2?Q?%Ue^Ol`5#B4U3JnD%GDIisH zRL;5|PR2ZUYkP1S(y0p0;a-_?a9VtL`kpFcN>h9Z-+}scd&IohG5BRb?hrIasg0dc?@$eV;s|?mQaGE7b!QPua{x~9Nc#lSREPP7hk=H`qW8q7g7;EZ z>R;y@<$SCW8zx@-JeC;f*WMH!U!ng;>fzWnDWy1k_jvlkCs^vV2ZkOI{rIQI=lNa1 z-ZnmNa$dZ74K;^p_JxbOMnP5&;xe-wI@T0n&CfEgb|ol=?)n*4;3g#e+Js}mSVT`2 zBeg6iBjwH&gFcPozHpmn?~T@#<~lmo+34(~$uv4~TnlM(YZI`BzZ;l_ZVVH5muebd z*qQ`IkI*!VaVd)f%0&Sb(WfQFhL<5t%3}`3zmb*8*ZxtiT#)$!8$KP;H^)!N>+U+d zB9BkC9oFrs*Yybl%^3+AxbhVvVF7>`P4isC{R5!BR{vF0WoHSNS%^`I`obFNZqqb6 zo)wsJGt<#a>ou~#3h+NDLQaq98onruqN|G81d&w=griB6RJ zVf`C@o6c*#X;FR4^??Sz zvyd(|$Wp%NC1`UijICam`33A{?WG{i7&l{_ju!RF`&6f36SCEGz15tU!%@#xUN+(M z7n8^9^-n(8QcDm~qb?s_4oyLk3|)uQnUw|Rn8VdN`lD;?3QQLD|K@+Iq`5G9$*Zh^ z6fV)HzGfL8hwojYNuS;!Mm1yjjejL@%-F7f{Vget&TN^&lZ)BV;3n_ATdDU+{KQ`H zx9_{Y>tXSpzMF*xgju=DC{d2BJFGYHMp+Lx+Fl$Si1YZNrbKiD&r)yT z!XzD<>QOyn%)rA zJaP^r^AAE8)+wu#K#2vooZ2apHD+@L5!8Bp$!%sm=@k|G$0u&<2ONKop#Gu;xa*VLZ5rrG&U&Vr0FeG|3#hs?Qu9bA$JWj?|@3`N`Rh ztAo~}ebOzOW^jU?H?1v|#nw;vTNKq0MshySFPN0aV)i_Sin>wT`@)c9IRP9i{}Fwp zg!`y#6hO*B$_)yMh8z^t{Cl^Yx(;KP=%K&vc#VP*;FKQ}L$guupnYmvSQER`(u@8f%i&7aq(7W0|VaXe3vf=>5|$^T|Yln zyQ;lV8z_Iy$p@e7fmp!nr}^yl%zv?ZB*oJM;30wnA0a~{O_m670JDUgap7?mMR81^ zzUU^Fg_~@bkj-RoX?A)$X1~G-AFKQsNjj6`b7Z3GM*A3BJ@`{g<_$dcXv|Tz?e0XR z=g*)6uZUN*V`X9k(C=0ss`Bl})+RZOT$&KUx|sT(K}!|MHXDTFy=Z(<64rMmswJKEW+ zyfThK`$0yr|Ba*1KK4t99gd}b>3nupKiPr16vA;ps<(B8u|7?v$<&m+26iTcCuQB( zJqnGaS9!$IL_};l>%>*77{!BPA1*5i)|ES4b1|F;h8=RttfXz`yaJbwMI%g>p*l(8 z2n2pp7-lEpvfS+u^R&ko29;TwwfQ!ifxX7rX~<^t=I&p3=y&gpBdfAaW57jU;w~y(b!?9iUiN$EJ8#sA1|#gy`0%)+<-^U&aWR z_wBy!+RfjZf~+O%6hQ->-a@F#lApm?@NzG#bgrrIw)(J$+a*vxlv?QS&epV@v1(Fo zF)~Hoy@5Pi{xDk62jb=@xX#Wz&j0~J7Ft(m8t7c=s>_TJJDfw6|2ak zc7-SU>%=gLO*@5UgjvaVB~_B3Y2$&1SdlhbU41EN#!Z@ew$b~B`4wE>Fm9yN;B%F{ zX#zZ+Y(C17JS*oZ8UARuIw8aYdts69|7}~Wx3;`wJGKWQQt|FfdGbVXieho;T(cxqVqeYl6$+9&!@^CgAyeAl)ZI9e78J{%jh!; z{QR2v33QF_CemN8G!4yMK{O@^N*z*;Dy4h5Isk3rG(AzpZ)+Fx@PoW`!e-W5!G}8> zE7t^m#Ef`!Sz%4x!z+o^@xv$rnOO88I4d{Td7vdHfbk?}9<5izEq69rzH#VLVkcV$ z(R%^F4W%AePHa1EI>vY{1u04@xp#4ndUet~ac1@+8RJ{Sa-Oo;KB>Zg5h8-puK|!J zX4fmD$h;U|T<=pMztgTJS&R2$S!2lAU_{cv({rTFbt zPk7-Kqc%$xm28iVO+9!owjJrJeXSUp8UNt(bOl0A-kW2 zzW|LifSI~i{e5k6aBbTPHHZ*CDr?tZ=fQrk4FOdbzOIjev1xJ-gLo!i0yD`072$~) z2J7!~!swOeHX7VwfKh6yG94e8mmH5(D45dJ{i1eG_PGlSf&{+J&b)ygmJe)o7 zvhpmRDTZ$CMcvl;!4}Y6$2j1JmJqf_XmmPlWO5fh_sywriD`($z zL2?=my7a8f5J#7BR7klmdjwHR$_xby5~a!WReT`7XuC7NQb_x< z$AayK5zezCb1a$vT$0hRk+;XcE7n{)-Sb&ey~er15BeT&i)WsXxqqR@HhO$JARaZM7)-RUjn*);p|=gzVAc{RP4GXCLLMoDn63EVwXlL??&|MxcQ@(j&{2LH74~rGERcUJZ!ZzyPnp474~+Qg}{_c`@F3-_URcNt$06f z3N9oX-qZHRlhOSCE}(Dn?tQW-=l3{?^dNLFV>y$1PyKoM%YbhH?c=T@?5EylFW8JQ z9)>y6g$F&BHgdv;!FmT930owFaXC2N5_(!_W6fyeOjh2}N)}(ilKDIfj_P6FeJ=sp z*@P_(p5~xR>L6tpEj(c-aII5VMV&xj6RLZIMs0ImB{fszgnlngq_G|!Rkd{7R%O>p zEh86t`MqfjrpkV>h6|y&aEs$=i_>HeXwb>-s;gAv>pu~v(i1xVaqQ_6N66|>`0LAg zb2^UTYS>X4mX*;_FVge3vixgXVmvhX0%&fv4Wugpn9)zzC6zebwAje-l*f3Jpx z6PVohg~JXYdcgA!pvjWNP2%=Y5BslRt1bkj3dgf}9R0wu0-l7_Xb% z2Bc71lN=QjX+8N91u?`;97SYwV0uf^2fsL zQlXJc?%5g2jt1Lu*4aMeUS0ksfQfSFZ;M^$$&tW9_SgK4ds^#ObM;{|S^ zW6(AaOn*@qPhW?kL^eVGz5*TiOe2S!R3&1wSYoc$Sx^C(k~;At(fO35kl^q_XL7R9 zmv_Vmx5tpvL4{}N4MvexmLBeyHhZ=!711!rC1)Hpln{cb+uhIh+vyIsQ$*6gTh^wa z-%4)nV_cZW+A2LJ&TTTwMGl$Y_n}M2kY?ZQa|TeLPb9{;tnw&&7bJCJ_&IGNy=P_} zGGGbM*}E~mcyJK1P=Yi(>qQ0;b}xS2yNLrbCt%?IrM9~zoFBVLfXw}H^ML=KrGu^LQ-)y*>!~Ulc z>>Oo3FCF0HqvRx#^m75%2SJ6jj>o3Uu*m$t{=nBixeN=6l7A3A(SDOC7vPlM9Ck1_u6z7IW*Q#F;q+T@(}k^pk?NwWv+;tnTg^h?|v~#Q_oKicsp#g zh2?yhK6oX*e9ovItuo`wvFBfJyCI1-o#I(Fn-dOYm!U13gC%=uy9uJJD}OOw3xcca zL`3ganwuALB%5-IXpg=9zqLqDn#RSgyO2NM!o2X?NgffY@eMn~WBD5X6tX#D?_`1g zsm=_657JifgWe|mF~MfBjgNHsS-*=fHuU_@$&F6egU3cc(&X;~yL_dDHW>PDttV2L zLyt#{a};Ys{scpdpb-3Z=b2po<$e4y1vwvC;2OHIhT>wjamv5VjE1eY*4tlUsST;2 z@4HNs;1jsQ;`uT)3&?f%>dJ{%=eZbTE*D&4R`+woPJXyD_Jsu8V`VGQaM0>4oQ8z7 zr)hCS-xGDP{#sFMES4EXe<5O2=%U&Gp_IpZ&cLIyVp4jozz&uI2oRd>MTA~6R4)>U z4AYmVbNZyvm9|pWFCFbALm!RzOU0foGK4rxI@+#u6M`uVDREqs=_l1OjCzW=ciPpR z72;x$^Y9($b5qXS>v84lZ=PEFr+Cq>u%Y)5kkR=ag$ED}z=eldzVH1kmyUSAe}-;>73!RK>#(vw^TnGt{up#yAYLpC z5G3+`XN}GB==CXC%~-uhKmOO`guCnPwoq>^lo(Rr7z?l)4WD?>TKZ(X=* zWJNW%G~F_dyWK8~ET*cu6G%HUd|P5)J`Wv^$MJ@`D}^*OHIQh2H3+khF0%=*RwQlX z%_r7hU9kO3>VZfmJ&x{{C6`H;o`e{d2k)JnYKyyUutKT<9f&p@!2UddfqI^VZe2vN z*90>nkzHA&J;zB2YBR0sgF3)LbHO{tUSm2HtY(T!J9x!|TK^|Q$bf+*7`V5wBc5un z%b(IhBDfU#{{XhRVd4Su#0PE{umHYE)X5(+?=y37ZG*|Jcr@!q_U`&H#!D z9RBneOd_`G!<^?YB8WA8O)|8(QCcW%>h&dQfw;}&150R^KWj`dB=}WP6_>0VZB$fj zAz1&BAeM5olUN4ca8IfE=xaxBRw;-Jo5Hq-iU`J0ak#=PSEGJRUYr#V-hWbxMhd}Z zIkOdm+Nq+*5xd(YZTgkQVsHbB>AQnm^#yBsG3&idtZb_(3B(&y|K=_oI~qh)EDPMW znXY^C&Gs&vY%mqE$|OB=cKw#2nnhJzK4|J^Ac;Q`cFZ2FDQzhb$OekBYWbBAZ635J zod`))6-qnJab^y~#iryp<+qk1(B$(}1eYo*7&uLZ?FmDg;9E-8P2F)8yzEb&LeS&r zlD57WZBm%gR*TBfD^)l&5@M%CNJz?_x=&1+w3`Z9FEwgW;O|k5R1;Q(#u#&Y;e8I* z{Z&hFR#w{ea7)QONqbI;lmSFMlq9|V9@U#tZ}D(a#G6Qr^nK9U$G@X7%vNl zNr0kL_A+WocE;6nWQM|J7U#d?Vzc?vt0}W&)Y^Zg!N;1+U^ZFeTM=yC6xpB8o-zk| z!|UE(=H3e%8T9Es?F--1$p*JM#?<8O;~;-k@oACsYp#wD5DKQMEicBn@jifa4WI- zwU7l_3`&JlWkl?U@n7d^A(vbQ;WK9wFvSOB8A)52|0DqbU%Py>Bg^cx^f#LOKoF;2_8HF?4^Z>ctpwF! zN-4~*=KIaOaIrLo08!3Bf|pl9-B=qVXiLR%$$X9ICNNL5X{42Ywn$E`XuSk#^5=@{ zA$=DHNpUKYroyAi@pd+<4ukn4M)HdtDvIRw?!tNCtRPT&pvT7Soi+zm+S;`J@`5Ep ze?VgwP#uvMA07{qZsW1>Os7%>xAEjOe5fIVd$G3p0|)W5x#6YUWa7UwGkV_c>#1xo zgxd@TtQL+KqLWYNzn#dfTrPWKRf|VFcx2>f-uhvHbvjYcp+bPMf z!C}>j^2luQdagF1pr6OWx#XbW$Ftmr8W#K?#TmY&%F=6HUo-yD0;y&t26cXy&pL-n z(Da#IQ1opGVe>zjjDL4*tSR_n0peKu0O<)5&aQA?2p( zJwpjSH))F>aliPk29wU&e%?hT>NI-kyJ1&8kgW)fT$#i6OZNr!x4^Eu?1nK;;+DS1 z_7qVb>mAvm4=i#?63ln@S^lT-Jwz|nxIaBTLE%>D9fuCp$DA;^7*)E48hO&S>sKRb z1iyXzw_@Z&RMCe_F_NVr@E|R0M0B5;7fC3J*YUZs$&|p^pp2`Pya@+~7OQhsD`Qr4 z1=N6S`PjilY4z9V43ebPl3R2T*C=e+9EoRYY_Fv`aP1^LO7(;H&Vh7{7d-zR2 zoG=Z&_Avz(v%iMWkhIII%8*<2^hKczya?4u;nNHZ)Y#EVlWH_Ix00ayQDoK@`S6oS z>8yk4%4^|vm2MWA!}xEA9>(G;?%6l4j96-=$umT?hvbc~sR;Uj24QKlR^n1;94VkuLin{Ik>rSJIZm+-^xXiy7keu$oat0)b7>n3ZtsA;#qoMycHJ{^^5EKtvu z%3I?mQ;0M@ldrGOiZ-*I^6_IMOU?s_)j#6_DauW}cD8BD)z?FdY?Ve4Lhyz9JI=RF^NEs8+lUxeceY zTGkPYY zeTub6Ul(7fG{_%X{b2(>+^_`dChAdc?DiVW3gJ_q$~*1z)@RC(Wj9lD7+Yp*=VOT{ z$e1l28;%8Ls21>$@VLDuqcmt`GX1<@*~^m0qMxS1vpdCyHmF927pR3~w&!U7&?x`qzESAKJZ=~|9uQ(h-TigRr5nZ8Yl^-3p+NFj*v4H?e; zzV?*Xh;b`F#pA?buCx|&kXy-&>N3t6H$5DZym8CVsr>uNQ+ay%^J1d1q8U}z^R-d9 z1}xBl$2^+KXRZL`8idYPZBkfMpS(~1_ zT~uhoZpZ7w6?^-?4ctJDg}}JL#4pXudorV zFQj+-ySW1(RQWzzOnLE@rxX66g9@6>d~5XL-|3i7pyf)DufNfM!tj=GTd)V0a79V! z!ihYWt~8*4AC* zfv#sLu_Zx8KuU@lv8Nlii#$$)ez7pJC_;=?u0ZHXby~#G69UxncU>o z`Jn^NWo^Q!@ui9P8AMp81#j?n0(8CY4duryn8O<1g0=8g_F&qT_6<58@LP>f#(`Cw zVee4B2stMIR5j|S4Lx%014^L)(JSxA^3xRKM5sSdCkWI=Ff@eU?LR@eoSO?;fq(n9 z9Q)34Kdmqxwen&|j*U=eDz#V)K#dXQKgRml%j^zEu#$TpU3*<_dMAM_SQD$e)$sTx zX5agN7{Zakn zkq)yfW(M3cY%%~-8f7BXxN>{Y^>XF>t%cj%dqFY^}*QfKBahQfbacEK}ZN$sWpEu zSs$k8F{bNB99@o_yo)od=ZiU_Z$wZEgv_r^L5fQzdUSL&Y0u!vN?>GTz1XlnCaE8t zqH7Fq9d6;b`I792<&Sydu&ej`#TIcrq>kpEyz>Zv+iZ9V z3=HJGQ1U(Ye-rJEDvXt^k3r47s=^#Igf;4{lU&5j9XfH@YuqNB3qR&wOWwk)GlWz= z6+uACO?)yg$BZBeft7j4h73GDMSt46V^`p4O-PQQdph`_BBoRc9WZUlwJLFX{ zlqOVHs^GB}3)QWzeqzdFRqU55|3x}p|2#|V{Ftp*YZ#Q+G{*6ykmvU)nqr+@JvFyX z6Z7-&UU7dB&#@(^mX$Hsh{+VX?o6j=P3qa{_2siN%P{hYP%M@q9d~W|_nI-Lrjj~1 zXQuAtl32N!oOlcwm*L8>F*A!hEpi-}b?=UUpf_MMgCEO~yS52b{U&`A1y`E<3iG9% z-~YN0n8s)r~uS@eASju|Ag413&-dkoZ|nio8Zj5gi-*pubh3g1q;0^Mrq& z54W@*wMdJ+EH!?a;xfA20~^TPkWE!P_m#08Ery-2+Rtl3k!E6nnOLXI)pvKGCBwvu zSXs8;Mh2|pnKB}mveEv@GFRBAEK>!4&vq}jK=jbn zv}4;+$m5P~lvz>4M>P4t7Ve)^{gVwUf{pLU>)_avOh-QKm+W_Ra=!n=*IRJa)ivw3 zXmBSu1ef6M8X&ksaDvOi-CcvbYjC$ka1ZY8?(VSAyWUUsz5BLy&R>{wwiwIzMeTe((wM205Ctm7J;tK<_0!%AQh(IJif*d~2e(#HE z=yk5|5L0(5Hq5YbeLiS{wE8+o=a&=GbSaXyZ#IKUZk6SweG+@w@)*>LRBR7*5LTxh`9fbF0V zEbH?X{Gm(N$wwXz1>YLZn>u^hC2=KM&J z2GZrCPOC&T8nna+U$;>Fi~4>P z&A8!{kRH$&a3ZTBEpD4GgO#y9^+>y*Ji3p1i1X(IH_yPUrI5Y?jb~MUx3tBLbNR{b z&iFVdFl(c}dDNduLEgL9)`M^@N!~>TQUA25&^ePX(si{HnFFs10SSXPR3>Pj3NB(Q z^26@qd~4ak5Z_21e-wszNkFxidL1jt`=2($)s^PEg7jM_tS|# z)QeX8na9`bocn5G5ifBM35zpJ9q)kX3za6alrO)(d^k@W=;`P-6F5F>zK+DUZeD&Y ze;<>C#x!*IC$NOQ8C=xvB~X~6C3k%r$mu>)oo$_VoNmF6LzJ)hz6)8Gk*c}*?zes% zOUA75&^&mkas{3=Wlh4Kx^jvT|5P-z^dciItF^N(pP=*qR$Y?o!8CPcHDuYE3m*3r z*d*|@GUme6EW%GE$h@F9ZTa?##cXA{OuRM2JAH5-3Nr%4LY? zM?Zzan@s77hq`^de;F%>d>$^6^~r^@IZ9#F(KblK(($|hAxCUvnf|LmpM`8Y>*{8= z?215}Fce2RDr3uFludQdn7q&-dxvh+wO<`}G6v3KkK2EKmcbtqyNiZhQ;mPnMDs)} zWcPPrP%!@Fyum(soXOTMfpN&Aat~%?ZE(+zz_phi#jCW^9u;SnkiGVGNrDe@_n>S0 zbDP1K?5q$pvvK{vCbWOLyI33s&S*bSr)&d%eyOxEMNRY>Uem|#+}lzsIK7k zKH{u$a&%rv zPKr!B_no0@T=`tTy!7pSMj0rbX6bIlI9YfhP%SPrNmtvW$ObrpbkW7`Tnm3z19}gNqhWfYXqoS(6^NSLfM%3LA z$%YhQ0VfS4HZxVyovy%A-S)$KPuB`$7qJz5^?>?cV21WD#S{dADUj z26f<1p{20I$vUr$mj?*Q%WA9%M6__?=oFJqz@h#aWN1r$OV1tS&Yw%hj+T|!*mj-IpM()Isc75 zj;J4~r|@PJge-@_@WLq0VY|Erg@ieKW1NUEs52K%63d^n6!$b!73UtIml{X;_T(XM zFE(!BA?8^%$b;3%e(&X?EF^G_$E4a()c19es9iN#;O7}SlR^fCY5oh#U_BaK6307; zu(u`Q`jYLiy**)?{E(D-wtVS+Rvd>35pi`fRErV1{nzN}pu!X5sj}eFOVO8)&PX=J z3nFg(H^I&S7)a#UG)b|z@e>QWQUFbP?BQVNuQ>o~AT|@aXErJ6p^Igp()eeDUvm4j zhO^xu9nzz(F0%^|i$e>Pgq!7oI}|d%i8AGMGnnm!P=;5pALYJ4P!M4{$O|D&3`w>2 zHw-xlRD{Y>3Wd@m>ktSy)U)z)7Du70+Up+$k6N=)@5~Faa8_+WJ=4qEwlMHU&nERc zuu+lEy1!;m0o&N#Sv&2=2@G$B2Wkk-<*sF-=r-LBixuJ2l8kmHv{ZC37n!e!o0yyw zCIVvpGCNED!#Kk0{x%$HNhU|bfHtq>mIvu_t=ZR>Avwg}u4dqU?F>Hk;goZTn&*De#FSCK|P`b@{#9b3kqr+WR$C zo?@>`+}#Fo;A75`=Xi? znvM>kBI(tAH~0q!<{u5pP@+fpO&k?pm_F!Ln!@i2+6L)~koZgIeu_6`YAeeFkJU+( zSSTics=r+ywxcf$O$H07NLBsb`7zwQLU#OVqr=IP!$%Z{jqfS|_Pybnr}FtGAWCFMQ{#?X{j7l1MqkQ{ zP`W=Y)`@Q2y~nGoiFzrt;?sX7x6tN z!fK|8AGNuVM30FKh#UVTEGWtFt@tVnfARdaiDS7I*@{N(!|Y)EU*na-aC}D?A^+$g z(~hg_S+>hU=rtcLJ(LiR<=9~qPT1mop4qSc6q*=nm_9w@m5;h6*tsee!`6wihc!RR z%Rgl&0iuZMo2L2)z{itlo-@k z!(Q;o9e;{rCK8(1pv>}f-%i}MB2hZe4Q@x9IA?3rf66U#nPR9^?~+|yjIZ$+-ef)U z3(E%xwZ(s4$V4q}P7Rmt+B@({v(c?EVJ@m*{t34v_9A5iDpy=;El^%wlZUE$A?q^; z_nVv|{g#v(e}cX%^xPW9A%^F#L;_jL+l|O_Q{8pxgoJb?tk&Y3AD;CgzhXJs?@(1Z zl7#4VGPyS^Lg33piHxI8j(Lxlzh^8@{q*sON&W_)LY~i~RH$lv*VN3E%eoOd+P#s^ z!GzNI^>b!OJbEu{ChTm)+wX4#2ipuKPJ~^i-we$}90Cle4H)oV(Nmee)_l zFjNRqnM2HojFXF=u!GuGY|&5+#kd)5nwXOQeu}|whOIvG_4v4EdeFOCkTEwZ|8LY? zB&xKKfRA?{F}6IRcr~p8Pe4*My+a5qv}*s0j3@!^;^b6W;_VNMPjiSvpr_+NC-_ZX zQ^hE5$$h6HXsT5CDYso~mD~^&iPPXvGa6X!QIxK>o%SdIY2IvOaqq8(mzkFzyTTc{?|0_WuUs4))|#(-C19WI zCHLL*VdA;PK3P>KH97!~2CdB35p>xbl9V^@zcZdv3SpzyJoI?2*25 z9}BKWxfh)JUPh?*U(M!9wZPlh6dmEfpjsc$|L319EQr8!G_%V}l3yra6E{Ho3FMSc zF~PBQMK0wjZ`S|-l&`89T}HV$9jmM1YaVR{hI{5vWlfstH7!1gA0x$}wicOk{fR2c zZoeU2;ZWoB=X6Zf&m7&slgGovWmPw2O=5g<6{5d09lHziq6xH1<>6i!o`dRa_O1;A z|62`SDGrwYis1C3l@Zpwft|a5B|TOI=61jlYz4gLkych8H<61Hcf`*kvC^G3IBnET zxcj`iP%mgOCBx7oveW;aWsqz6q#8JXE2?rJouvffqGX~zlSut7i|CPexQN_Rfx>N8 zMVCw}!y3N1KC%J5K9QtI@|UW8r6!8>Or*mZCa8uv-K|`FT%2q$GX0=*w6hFkrlvdtIh%6^F-70N!XYqJ=LJ}ym6yNH7zV>Q^lYPG1mFD zb-a*~tTTc(DRSwk9EHf}nqq7%BjHzC-i*SNyH-4UtmV#b0^Kh$E@^4|wds1TB#Q;& zm!e~U(hT#VOK5VKsh?iip7z&l)__I#Bjdg&=Jjob){X!Cg9lEQ+@O_@`Hy2Rg8m79 zV<3c0;EO*{AC|{@0U|@CU9a5|89dD>aYBGirU1lZb9K} zy5Vwi)ZEDQ9+y{uu^YWw*g1g_UzW@@9nW;CMxG(AZQ=uX1KD(NwE944;QYDK< zDp*d|Ky~4Y@LYpR6GUKCZyi*Tpq&mF-)(a2opqA*Q_$X^Q&UvA`noJm)IPB?7AO7L z+uFIRhS4N-xT;~?vFm#FCWVhSRX;o=jJ1C+y^yeAW*C?I^&5?u%xaxYkTda)m)}c_ z$Ky@%#nVES&RB`>`NP&T2r0F-OMC5hHCLlXufub^{r@W;m^j`G_-z|K!Y#F1&Q@0c zFZ;mhUi*@A7tGY=?$=ecxgkt(DY-JLJT``VL3Y2jKb+5s3jJAc@>zIj1Joa%+#a}1 zJaM(SoGyTc8F8O{96R4b##|cGc^b$2KB2FWImC_kHo0qN1jRk^(1U&d7&_IsFzj9_ z=+UBtyhO5@CwRu6F$a8GG=`Im$u9LG?yOceU;}BHe+%x?9e2xMRGW(}#2luDwNoXi z4zrm*`)Gm|)D45i_pdYE$d9#}SrEI#6QgXX7b6sP*$0Q5emffpa2{iQQ%%186e+oa zm;H_@8mdUHl*p~y8prp*`8*x#*SfV`ulxURO+}-UDo%dBgLm-~=Uw(j$7}@%+!O~{@61M*P!tjMY*e0UZ zhjV-wGJlk~_jmOBi2p9n*m?chKpas>+miZS=tT)5Kz?1(QV9I4Dm|Xl4+G76Zb1Wn z;6T+(Z2vUj>-~~ImMX-RV`{LRrEZwEKRDBJvf)y0bQ#rXFdp1DAhU z28@2DS38cA#s9R8$s`}4tL5nVQ$!10hFR}XE-u&GxB@DOAI`nypcsRn!}%L-Zl$PS z22Wq8=;_}SERcB*bD1U+9mtjX614c#`dqif@qfVcp+JTA;#FTUg~M-`cEiSZKP3YXdC6aSv_Dh?y^$^H)^E-Ax+2!(^GmXO^ zhD3J!9a_-Jg%tbaG>FQM7Dq~M6@Jz*n8SWJ(P7*)c2aNtcu~OSy4Lx-!V8f_0jz(W zUw*D+ZnE3tYTNYIMx?#n>S1;n^m6snrs|$*GM|jX`K-EvbK?C_)o`#ABC98)dODWN zzSm%Uc)sqG{%f?M&g&xE>D~LK>0EC;1)({X{>QVM-SHlDjd{6ZGSmy^p58O~J|t5Y zE=|g(VMT4DkWE6vnvV*63)ys<501xb47w7g(Oeg%U`LM#E{LAv==X_mVV(_1Kpm0d zEEt`S1b#Lg;rXzXPGI0hU#UeGR^J+MY2RQ>L0a_@NKq>%%b&n3CGA>^HYcFUu%VW# zzw4=gYA1HsS+Q3UNWvF1BJ)Aqh+1bLBnT-P?0uTIGLz1+mD^QSjy;FMkW91?nx6Rw z*B6SCO5$KN<3bAvhQg4;*!B`?XdA-D87mA(bMdH;<%)Zx$?+ap%*0|unfw4b7;q0^ zHO`i*pGz%7b?2L*$6SJ{)-gO_*~BAA(8Z==j0DPILj-c)SL(EQ!@Rv&DqwAF5&Xk< zebzls7q$p2d{rNBZVYnH8e9EKKJHp<6TXpW+jl*^Zjo&HUVz3*_!~@FLVQ7)HP2iD z-a?#May?_2P^&Rb!_ZxBcBya>HvwKfTmh|qyCCD@e_(wA5v!i|EU1-NFT31RxoSur zIw+e;%bxtMjd1GO0NS5g%_tHu#-ma!@WtO_gyu2i5mx`$uqz6>6#g=qZjUD=ZxZ<9 zBKbN3V^E1TCpwzD_;!`gJaJNvm5CeEWucJc&dG9F@?XDAPU}rFz&BL{-oKDo@J8JU z^h+SeAA(58nPs)9L?N4NFviEHny)11HX^ZR0)80B>FBCw$NXEJ-$%d}Nxsl1dG}Q( z&-+f~LH`*(c^+}syY91~-%h`@)9aJ0DB;96{~}L&i%GD*IC?NtX)sq{b|$s8ixGb2 z=XIYsW^~D> zY4qHUP{p{Hg*t5jSBvr`e}BDG#2HQ+z2=7f0*sk0$B)BaB55zn;{9ld8lH{Ui)DX- ze4O;mauo;!`ssJb9tnt^LI}1%2&mit5dcJNNCE+5@#6X&u0R6-9~Sl2hWm1j&r6c< zCpMT2Bg9g)#=n=sj(PlHoV{_lm?lsA#bcO1jUb1alfIoInnY#@%05Ef^MR+Nv5zYT zxiJ^8qt~D@DLN{L|G@u)X6J)%*Wj*?k{aqBw8!R0cV~_+D!~4~?Em{2VPn=Z_#Cry3Xi&oG-tHxlRO z67qN3j39zQk+ET;bO)dOZlN-MHE5GFA;WblptLbnG+pC z?lG=fMeYhoC0ezgrcXdMpj~5xg46g1X+MjsoTe>h2^U)pJmBVpSd>*Q28CKGr12$iSoHEY903-~ z$MU@Dg_X+4E)Wg*Q!dgEn}y( zmLK0Abf;HLNK@cRpQ%nu0vgFJLtli!{sMJ+{I-jTPD&Rl^Jf0Iwha$sBY50DY#nIwb$mpRpW8u*7SLkq3;tHdZklLdj;nV32 z6fK1rV58WPg@qu~R zLuk{wR_W)xdmS7~8~VFN`qbICNPrIrreBRH6NoG1HFUcjMsmWDVL=Q#3A=)AZ{>|vv-jjmv0|Vq--P8=PwJIb@t!Qx!l>FKLhe={ zknSvrhu5O2V>Nwc`I~{6dPgf|?_nL0jf-uu_jzGWZDk3R6RqKzBZMP~BoL;R$kulV z-|W1d6`RyV`LRzSVGnd?K$c%(5d31qv!my=MA$42Scm`LHUhd3r4MPlDr6V8gwTSI zc!0gi?P3lok=E0SRC#hzW6IiDGmOZT2tR_9F#JDJDr4@6e zHFm0wi24txLZcg##uMa#5-E!Rq3Dm`mQb(GWEN3WnRivGNqM@1eI^CH+KefC1%yip z7e4Rgm3fz8)vH70a-+zVg(5ZIE4yhw0ipA;gAMu@V?(ruCMunA9=5)rxdo$2t*$n7 zWrqM5m3N`VVLOe1P_^8CW_veUVnTT_aAqc`i-;v6oJu0Tk7xKabEJMOKSBn?#o!7Z z%mWL%1@+r`7J{G}t=zkm{8&bd<5qBPcC~*}Dnn=*%iZ?y8Dz?rcCvwUp(llKF@6r= z=CTV!){vl#FK<6puvc9kni0sC!p$AtFPrqddEL8V?`-8y^TA(Wtr}1J11F_? zyIxbuOcCt8WKp(A`nB&i2~SK>mvQUpb3IW?{SEIQAm7a`Ih&OJplt^IGtPu4G@HCU zJ0FWHvHsHsNzm+@nJv3fi3^!AA(6O=dCr{nxPVDOdLbgY#azT$T=>{@zWUc2UHc`l z>9e$E*)X?!=FIzp%hJK+7ml)(XY=OJI4R+Uc);8A86LI7Mn^lIYHziCILpW)hwQb3 z9;;_Q6YM!VixyiAoOx$wb?qGWATW=ix#pT7WeFPjlXz+@f&{_b}_r`28Md^N0U zva|PemRKGk3qq$ng72jCI$vL4s8VO1Hx+{TDLV5c=(PZdP(llEFg`NAbPt#_sk2PQ z3m={GLr zx=;DJs;9{-!p2FGW_d~HjzMy4OevxYJhzZ1z&*nD;e@&*Z0 z^15-Xtu?)Cno#3_OP@#BNkVFY;=DZ{5t^UnacdCsl3@Wjz}d8vy&^DO44v zEq=)#Ls}5~c z58pcYvh(x1?bI-K+|ppz6))!{P+Z}qEoEQ!abRx^h7zb})N3i`fFc+R70b(iJTXfZLA}(HG|}(I%LrMhC~1hA9W^?={=!9g|jI+=`PS2aq4c5*%MPaRD6=3BF3E@o9IM<^>Y8OmZy0?VB z%51>V47VD)f0>fbrqsw`cfcmD6vWu5H!hfD;djjG{jNl9 zfv+r!aG10P#Tzq1PKlb+(HM;Z75-%}_a;yda=+_!9P2%;DPoT&3VH=%R!&cL72}K- zmIIMbe`7ptV&~bJvUf|_^Ul9xMLf+{Kw`=Bm3t=S9*RvX1Wo9{8efYJAl zMq&nmFrQ5u_ld66;Y6IS!gO$tU{d9e!i>o*Gf;xjJ2I`FsXTz(qFT=?|0rnQU5t9?AI1DMU`bArxF=lgLGhEgG!ZRk%$uNgZhA1O)7& zNSC}p@@sY_c}5oazy$mnU&oPhd-6?j3Jo#Fr?L8lQ2Twvdj|GdOgX3x0#dlp$%j{# zqO1L<=S!LUfQ5XLnMfLHA8Y~+O+${m1GIYQJ;uoitrp7SBdYqHiCO!0?aH?56!5;t z?99+t|80DAbzr(4eMdT$HaYu_821aa;~fl!tEqZcRGsyP|D8hg^kAJ5{RgsjDF%+* z_zPblO)CLpPB`}Uc~f4xWj7A+kpUCka(%a;E@#C+20VKGlkK)g1J1vWy&H#2nR8rWw^~=}CzaHE`+HE{}=YQlK5K7TzV@r967W=oC4%!$P^nBxhTfhCY zaOaVphb5k;#U#t_j*|<7Yh-Pr!rb0y^z0P0StQ`XA{pPq@tyzaLtY?$1oogaX}a?; zW@r3=lVdlETI9+^DK&pG^x5!H1V8|UG0GSn{Ta4=6gc0`A0&t`u)=W`$yH1ASO1hS z(l^-<)+jpMz!-<}rOCt#N%#2)LOwH8PKFAG=5H#3P=o$hoxoJNl80yDFpIs&(x_T= z6{kSg3fmtqsI&Ay!w^5y7B0fGP;H20lz>iXz3X}?^CFWoc-aaa2557L>~xRl+`-H*ne~ z0Y~Dfi>Q`=AN)qQ4pSvfn&HV{rzdr$m4nXrau0k!5g9g(IB-;kxRK44C<xAxEVKuV(Xce4H+{r4M(4U|d4K?UpnPOWh(RxX%kBEI@rM zcp1(gGTyQ`I10SmMROeXt^%*@7jOatsC{BaBfHP`%8}gYR#f9VaYvsglH90eeM3Lp zdd(5Aw>-b&(;lbtlCj&^ZLKw8p4)H?{WY`e$G{nge0bCtE5L|`_)#!Bgi-K`x~5~m zwl1c00s0@$LQL|J@j_7Vv|&QTI=)m!hc*AUIA*HPb4%EJuKnib`V2-a`T=(lpQ0|Q z-N>!bcZx^M$36k3$GkIuRQ56Yh5t8n)>YO1wZw*I^zm3&B%rcNHuW1Y= zNSqO>a>S@TxMh=dBI4^PlBTQF+BDL@PTd)K^2cc7Z=ud9Z41MwlvAnKawv<+A5S?&BZB5gXpMU z?6H<&hZ<{0PF9$(kDQ-GNPs!{b@H^3C0HbB%qY+$I)n&^ld-25cBAOX?YI}w#Ea8? zdm`st`h+M6-8k)A>c9{!ct@|Z8P5DI4gg6$@i0|fYc?Pc@{?$Gf*YwT?|8#zfu)Wh zD8xsPF2L8B7+89>W?w~TK@ZZ<#EzV~GKhts(eu?izsfm&p8uW8Z6M&j1PFH0Y<$2K zxlNQ?4KShT4$!7MT5(((h$N@H!7@cwziA3>tpUpD0xEgn(hz44kZp#o$$QpnHj2U2$P7Yi0 zeRqAnzPK)B(177@5ooow`g}W>q6KWh!WNv#BZl(yAq(5trXe5Ez)11)wQz+OLsr9B zEQt7jV$9l8D>3moknH!g@Dt6P7`CfEq^Y_}&RxpY~<| zPT)O5-{Er@e6pd$1Y54F*j&s%*LT4kwcJ*Hd}@SRlssFJ8!9EtkN#AzL;XDI{qrfi zZD-z>ESYO+2h!i?6dgIT*b4-@l_EUl2wW~VXgk_Hg(Nlx)i#BwUVJD!-_SBVM1Yc` zpArnRmSB40DO}ZlYn+lIJly|1w`f8J$jeeA{d6Sze7O=Fp~V6!j!8lNBImWBpA`Dx z*&hI%d-{$(71qU;dDP67_9ck-MV7fUZrpr&#h^R{R!YCoi#{^7)%YkAEzt((m^V?| zjl{#5UwpbsQ-c*dXJT=&Ltd7RIIM;}p-l2IVRDN60?0?G`8-oY*GxW6dpNL1Uq&Yu zoh32E&QPJGD@sXg7_U$&DJ@aL(ukQ|SDehT{XO;l7yDG1cI_n>bEwPpPx?NxPUGt` zNsh;HW-WFB;Xeyz@L7(Gr3n1a@fqG(-elSvG7I1l6%`-KOl>M7rvpm%$(m4Gr=4l| z75I%fyfG96zd}KwSPj6$S!t?jKWm@csl|>tg`UnKv7^9MF*OO!QJA|%=b5B=buJ8% zr3~Npvt)D~h({W8q;_JW|2&yO9y%&pR7msaekt8+J~{O5Ak2;erVteppmk{JMVcygQ0%$M2%BI~-ZBwy&<&1tF-2XQ#Yt>Ji2hQCD^7jQ+CHV`e9{#9(yfXn8y2QVJGUi7v+1wA`6TWMe z>}5k^9y-SMQ^(NLF~b(64{c(utaIqF1^h7l9mk??4zOMuVTxLWi%v#ew7R|TXfGg` zPb3IDNNqFh8)0$aZx{u3yE@AV`O+7rJ$eWY?IHm+>VE!pD5t#1oOvY>Byr{1ymq&~ zQA0prnvUUy5`dfHXQ$~ELEO5`*?hl~LErv2^^ZqE` z%Svm?z`o1cpG)+XdYSsrlcp0}w{tu3dV!5h5hJ+thoSBV_>MTm=tv8KgnVIO)%tY# z#|{gHZU>RfV$i^SIxEmuFw$>J#Nz#hYg$8IOGgJ$!B;d+`0D8J*No@wq1KyB1Suyc z)BNkqDK4{~%s|m;@gI{LSVu>&I`+mJx0w`*`uu4g+aRk0y328|j20Y}_kChwfF|K) zax&*y+w(>rCJ(L8>C^0bnMv;DBr+Ba9aKA5koEU`U`2oGQ`{s3dPl+cb6jk&W z!=rbg@jgGLj;sDtT(#W%ox--~oait&4WN{&D@_u9PCBh0!|59F={K6=h=ZEB!h^#L zx%ttvzJjOTm362y&Z?05v|5^>hxxG~kx4Qe=Ex2$pJ_*oz(9V*46vf{M+p*beq1q&5WjJ9X5t1D6_#g(N z=l|+!RNUuhOw6>32$ue_yxL&EU|jjq>ij3`4~DVa}9+nPf6*|Y>i!WnS70Yr9x-X*zp=`WIZgM+#c9ZnNQef5CK#2mDm=6gpm5A9OQD@k4j2xFeZo#s=XSFA{M3J z3J2eh;%Kn8rrq_ORDS)-=UBDFbzZLdm(O9LE!q%M2z0Y|wv}wYxT8ep=qoCWsCHtU ze}|f)XV3WZPYXZBnQZzZ;=W8|7ttj55bZFpOdM105-z+Sbc;I%sOiF3Lvk^ZxRqq2 zYeY%%0&5{-&r39IEIDWyH_S-u57O*xX#4xr>Ob{3vLOPScFooyn%(R@i?^=_9}I9e zmSppW`3nk-B6ySK50SK~v2|6ozqE2+WMe(HGeW|z)ACH3a-~DiblD4oYl!{vOsVC% z`p*JJ-t@0j54BuaQt(ZY2l=UqG~>=h;V3j+XqR479Km_i7Z5C?CFk$GXX!iQlN;#| z?7+`SX1qOhMCW!qwrF1z6y1GoxtJzUba*?2GHD^54lqUhJ{2HYZlh&^S4#1BA#TkZ z{%VXV1PFYqDvWPpLWHlAv+tl@YL+=)Oo-bhz~oPMFDQ(oa9AoaiIS9e3`$EmgA)iP zqjQK)=cD1rvl2|-h6j3C3L8)qA{s>e<2 z1#reee~i^P*~N56n}b~g2q%Nn#q)wfCJ#5drVX+5Pw4n?;ER=0TTx2h&KVS}h+m$iWuQTh_HWT3@40XSX zly(Ar_9dHtmNGlRKm-K@t8}Z!temV=5L!nC5 zyDtPmtTM#f0bI>V5YVJd#S$~Zskih9O!B(LJe7_J>nY9xuuk!xBc2An*4DBx>Z){G zem2&nvVGPBa3?I0iBnc7Fvgy_VrfiYOAhTNi_~ds4A4PyGJztH@M~n9P(sniiMIDB zV}vC;J9!ottwn*SqPekZMki}U4M<773hC(fJzP?HQsDF^n*i~&>aaZsN4Qlg{~yN= z@|IGcN?p-na6|4_9^LdI5PEH5p5CiD6l_tBz;6c%9@pZ!XL;IW+ zWH%)r5oCat_S_fu^x|qZSK!MVH^>zXqR(EoQQQ(eg(Y*Gz^BX2s|1y14cZY|>Iu%u?6!mHZh(y)2ZytsHy*c7?mh@F;l>cZcz(wV z5ZQ5pWMret%bTB1!DIOLf|Mw|#OxoQ!UGH}f;hrM;q2Krn{smp!1iamF-&O}+UFOT z%Cx_y@#!QWbPE6&oy=wuJtT5H+_TJX`Ot8=2oM#W`GOfl1DwD6h=@$x2~uNGdlcb0q)(xM`pDUCh~~8=ro$p zIk*4<)UJ7xZusRdW;({uTrzzszdQ>B{3V?sF*E#YkwQT+)MC^EPwLmd`vD>5>*9?gD1zdS~syMp0|#04wn zAc($a?Gth9-%uwhD7RJ5%#9N4LKBRb5u2+vO@korTERWIcU#epGR z7@s~5uXbiF&_Zp;Hs7kO6lIq&0QNtNvf_sgwWk{?%NXw#{PB8X2&Daijl!&Px z$m(^i;WnJu7$Dlpp20~PNjoE5ok~x87aDXBPt}Zb}4^O)mIRU)Bw+|IT4w)N20k0BNb<+hAei? z@;st>{&?(3Cs-6Oj*MfzAM{77p;vlmqfaLz0!-%+^G zhtx^Wsk#rL{NEw>-aR)HY?hxEKTcAk9jF31RF~wPiGq)1%o{b zidx|s3j}5(YX*mt6!SQA=9&Q1$@ZvgHxf3#-yWf;2?YCf*qHM}0xQ95-n*o}54#?} zo@w~18_km(r0Z*<{|950GD+1jN5Q%fvOfu9HGghlP?~HbjDLkXdfvQ;iYvE8Dc6#3 z@A$N;TLpL3!oh%^fJG&tfqED4i?`uHMqG@`Hh-_)QYCIQCl2cni^J*o_ZB8-Ps%>@ zb;fAW30L=+({CZTl^-iU{?*g6rFXl(KXCC`1|F}{INQ3EX5TY7dit_~TlZ%_a>LlX zg3h7r>|(-p8DL}A@l}sNOJ>_4OFCNo8}QO>&2(i-8g}N)s7w9gl=?q=OW{KVu_|Xz zM7p@?17!)a>Ke=#9f#Po7z{pw7n4sbRRRdwS}~m;4kFa#gor?$W>^% zXotXco6EN71lWaTKE!Fam69DRp30q&Mh^n^Fhl}-l6&Ta7^F0A zqGf{qNDXWZvSmZ!K#<;Uu#2H%b{Nu|4+(>qZ5)lbd*Ag0{ygOqKHmTyhg#A`1F(?j zFyVZf<Rfnq5CRNybp@cV*leF}b^%dmM1*q3wJ!Wzv= zeN2{-q8tg*QOJmo=hHYLXi*^2i|(Rs)f#LUeUYvR#%Z?v_nHahlf4FF&K@q-7dtyE z2C#NzIKPG1tLwbbMaYQYG_1x+U05Wu=&@A@A(Wp^-sKc%g$?~(KIR79^0ri{7-b@8 z&09NhD&*nEdEAKPkCfRHMC=@#?AzD|;+K4y`d;>4J8r6>iNA-Dnwd<2CKaDW`)s5o zMbo&v`gT#W*Jj)&lmO8B`O47N1qcjf9skt{>@fnnR@xNd6w(mCtf2Yk;eY(IK@U~P zd6e-@v}nsN8U<$e$@5i5HE=YG89D1m%2gyLcE8)+UP==mWV7H2rJj?h0aKni2f?Rh?36tB3-ieTNx?Jr~3lSPl~Xxj-gyRGPYjXdc4 z@*HRR&mQ)02(ph9G~e#m8)o0NHE&fhT^G7>GTfGIg2`HUUgCW2z${=p-H6wr$(C zZ9D0pW81c^{dB+Yx6fL8tUb;dZ8ARvaQJ@ZNNNmSRX)9# z&Jf+7vOPXg;^t;IJQ?2)u%CGjDAA12wHtr|W3y^@!DWT}>%zMS`C8F(o#E|HEE^}4 zl<3R8o4g9Mh!UsxfRbL><3K8vD;EJXX&P_H^DaM6g;0|CO0O9UR6oGd?>10KPCPm} zt;Dk`e}nU@@E2q}iv&AaoB@P=e7-mc(SI4@{m-NGMe?J-8s>KadsTwE``+!qv*!o6#34_Cthk;6xbz!? z-nu-iSz-(WKh11_ZX%s8b=e>(oA|w7uq(Sg@D}6S#OJ*%h&ro-e1CMKIf(|U^*04c z{X&c1eFbYt%*!!yEI)Evj2y%id%rF!=u+MFZ>Fwsv|p1MNLf{0kg~1F4^AOP3R!rF z2BB!?dz=TTP11iPM{XZzNO&6WKJ}W%4Nd>1C&FT!sfBKZ37WdLj@!-N(@(sfgn}ni z`nBtQ!y2?dw95Z_Rxn&LZ!WS~HZx55q6GU~h1W1RwIL9CExVfBIrbucpw*JQO88u0 z`R}C$mxf2$$HMuY>6jE^m0@;IKv)c0Cngr>X9b76uX3!F{EF{!=U+X25#y<>VnH%l2rX4+A=Rcqaw0Nd z!K9_1xa&GK56s-G75U3+D5YQ55N9P0ph&3v#CuIu)FzVRA9>QoP$A*9Sosp9Daf|p zT(dOiJR}UxF6&VVrys#3g82y@EVEsBjkh=Y1A2kD#|X3l8iEY^`*5MP495>dUle0Q z%&YT|w`}PlO&k-j<{Dx)o%|23F8h~Rt(@F6trdt;Wf}E<-xjt&Qpph|M{lnDuQnz( zSwC<52~x7V9zjcAw7j~ zQPMT2Ax!_ie)Q%12Eq6r1Irv+5QgP1cwkdsWcRWS6|3jDG4B{d!Z?>{bp|3qgd=7dW zMW|xlSp~fC{CVe5^ijQOB>3X>`0{_; z5j_Xe=|+z0rWYUgoKjRZYk#07<%?C0y3L+;uiv6IzlQoX`PP}owiOGn!2(?zHd<%H z-?W}Lo!2*QYQ{?|XR~(O4>pegs4EjE^&}^-jV`yG*3VqPr93}CN)G?AA-I!4@xJoP z8oo|O!kDHiU#T^dw<80zeb1qP7KA@Tg=ORQd2$3xf+kHF4r7R<{=H?Q`LM4aTPIF< zGE$SzO<2^K_vKnvSpv>x+iZB*`<9yb#H;($n1G&@!-tFe6N5G_x!ZLn7}(bBCK>_a z`mbHVrP1XNJZBp@l>L4sloZ%=XH@hjGR!glXWvKEK+)Arvy9Ut$RiE#@G?pEI>tQc z@Ar36eCEcd!P`kE(zv`mE&S&*L18c!N8ZBcKaz)oW83d}nu5pf!_Uguk8(v*3oK8r|VN38!xWViW-l>M z{24>|ycYPMvajQypW8h21e6%V#Na6t0{^uI(S>T6_y4&B5!ZL??X^a*TOd07lH@-T z8{{P?odfb9l=7!`_jgoq%NHoO9H8~i<#Tmfy+?0iS#UvB6j1@T^hAMD`SS`)>FZsg zNKr#{!k{*9Q`d!yYIMlq1}aA5W620FWx1Xcs#z)2uzl`y)(K^&Wb&07NmLm@AkzkU zF2WD8HdpXsi3uAMj(~~4&M61;)#Qe6kE`+06YYnGy3gZRIsX4-{Tpu|CjQ5)|DuWN zvAsHK2^NoKdk_Pd(FC*}j*H&~$Y06$A6G1gue+bjxv4J5Ic*y2EOSq(XPj$!?OVbtF}ewOJh@R%tO{9h6EA7_?z zPz+Lw$hRYbK@3-wV4eL!I9mDJ|1=r_7q@~&zJQe^!zEa$-)+-(n)vw_w=XmCH&dTg z7BO?63mceBx=dd0>0sbq-Ziv!Y>A z%E#|T8H&CO7`_u7loAhfrzmiHe!OQ8&%JBrz%EXV`&(3acV~MM!-TVjKkPj}t8#wOz_ra@0_UAwz$LAZvzaO)Ji4%!G5Q#b?-X-dM+eBc6OXf~p zb$oP2p6P!en-66I-T&d5Z^JWr&%L3E!68m%^p~i~RTdO9?ime{0og&Ui1YmhbH6

        &c?(AAUaFYNC38B5NhzYmJ_RR zL>SGF>SN$vDeeqMfUz1WeRyOj;Ilr%cMsNSwW*xQok;wu-W~Tik;lp>_`PH^@n4S@ zXw=7}@NQjEv>_%k*v;YbU*w%TtT+7+wmo;YUEI<%0sv)jAOjZT)wo=d6=sickEvhuX7{PxVy2T$f-kR=!SU=hVj!2k5|7`y#qK1k1)5N7xjMVQ-H4!NL*;UVF=FMdD!@J-yLk|D&~XB+;jk$v9i#aqNbKKbu^*4BVwni?4S&ceH%)78Vo;3We3z>0}G(1W=Te^H+ zc3x`TUiBlCK8kjO`)Jlb4l8GuDG**g!r+l8S7}78R6^WFWuoTL;6SIIbdQ7FC0>|Aqq~|&r=2%&UIMNuFHXGipg$|j6gaGa~R9GyX%`#=8mz& z3F%O4WFF_ttHHFgIZ+N&G2gE5GZpX*q=o-WEO)j_tD^PBBG=-7;r+*Q4Z2` zd)&d#IICHLqscicjx#W19KMHf0lpyLuck>DOZN<{4le$@2=v?aU+Q|4qM*k>-V3l4 zhz_qPiX%|Uj6NG1EbPn~E(IF^otw_5K0Zsnh!>(6!|GbJjcFu}_E&iooVwdg4L;Tg zgvRB3UbgDZ2{|RieK*w){5%dEz&s_U(5s7*4#wg50$1<-3H($4{;Ym7^$!&E6_lYf z*4BfZ5_qKWaWv4dWpk430t3i^55*3c(8Ukv_bVAV7a(#z84gq0an27F(A2H*4Db75 ziQ2P=`Vd`>>uP4kvi=Bs0lN|rw~3n*-QSY4=d8uY8|)@WgqMZq>2;;Cyz(o}R#s7|?Xb*2FxuR(TNhozRkI6;i zKV-ND5n7cS)KuR3=PGsvO%nVDlMhnUVk_Qz_>=HX7A6@#RmmB@|!RG9Y_ovVfRS7{@8n5Q6 zTwP2>0ytm%d`Sl~0RE+Z(~gIW&gOJ>$Zdl~yl|qPxCQ6YifqjhC}lzq-x`*MbDnxY z6X%@`=;opCoAxl|$!i}hty9``$(#9N2ch%%%8E?D0?^4*pA@1%!39QxJE4!H8Ym%X zLnYCKCu1c1-fZ)636;P86s0(JX}%CBXxfe_!TRN{FVItBs!p&af`C@3lG(C>Axw?8 z#WI65W$*}y2`%agC-7q7YkGmWpTpuoM#UvS4d3E>2umvtH*JA*g znd19VV?1e9@2OtR1~luQ!q#hzCKGejMFjj3_P`StljZ_yvDu~RnGF;wip%36cjm0# z^i3%$wt^!^+D;#A!_lRBY6#(Mb5r`;Zu`?+MP=-h00D&kQHPY=SC1M`uU0H3G%LD5 zGE>OQDaJS_maeT}vRz>!lmduAeeszNL1||4yV~8)Lg#}Se z<^M?=o8`9llaqG0di12T@@OCNmOMisOHhF8sFzLjD)*+ro!G7}DqkUv^FO{-GJA^j z-1;()hM&|Q5p_5dI!`o*ZgQMf%R0v+M0+@GI?4tpz^o0gEyvNsk*Dx0RFWV<&)xL| zBY_1)HeDcr)3p0>>}0qQAu-S$L)SlssV^~nQ*viu62k?@6&=T(d+244z|2w`r8ua!_t-e)Vw z0G?bZOYb0Z>f&?%7sgn3_v6QRgkji#fsAD$GHN<#kiOGaI1}g}uq_l8v`nyvdr6>7 zzAktxI{={0brzX+yig3qk?vDaa+x$5{=++v{>mFZ36cWHInd`P*p{A^ooC zdtt=0+$!gdR%*J&LlpI?U|&?9K{uG3&zUA|2k$m6DK_9OcHkdFJP0edE84t3f z87S=QiEo&HDD@z~d8Zb>-~1LD=A@bc@zA4&uI~E9cx{cLRo6iLG4~&gQWWTeH-n86 zVyL~(SP9{$h1*yiH`>weD92Vi`?R+Qk}()=fkp2{r|tDGJz68!M_Ju+$*xfQd9U9d zBr%QoLTWQ@!)aQYt-KFT=a|$K_8_v+sNZ%B%*ddN2wvCQonH|+p)fJN7fF-lR{P0) z@t(tlo8X6nAVSHo-Ai)O!N(AHwShk_Jw~Is-1+4u`$FY|_;wPiYy@JPYLuGPt&W5~ zjfJv>J$(lPaEW5Fp@H<&&ShceaQl?-;qbe6ds?;WC*hX(zyxT6tWn3Icmb%&8vH7U zq}cr6KT~41)4r%BcRr4wAL_kK z``AB~{bl+YQ6l*5f088l7kw7)(xO%?bGsbb6vqn9dPj{We|Aw5d~A8<`^L@Kqr5Pm zn@?#Ua|0q_+XPG+d~syb%T21hUZyOeAf!4c1!!E_9^HK{Iq$YVa!_oij2=;TT p za|S9}Nq)oDBpg9eOtGdiorS7RQnZ!41n)*Q!@w9NhP~ znR@#=%y@>o%PzhUg6o9~p)vc5m-_ebf!I>ZLg>?7847oQqTZ zG?0FhrjBMM3Z2t*VN+InfdR6x~*giLcB1;Dx}vmOjYHgemkFigSlo>auVv|uaK z4ZBF=s$WcK0LndfG9YAI$HgN$q)I?pkdJfyVaSs|3wvr%FF_sEI z7U_7$zM&NDEY;_eKbPi<9^Bwo0CSO%Y`w#t2VKU>S5klsX@ovt4w53v(kWD_D$DRM zt`?F1qVyr`clmXF_hM1E`_XwLggM`qY(htc6-?g*WA0lVVGZS0ohams!MHbAfu z{`$^^fG3bbEC&Z{rg7wiKxngAA-T?*QY8W8dne|LLLlRn3`eTo=#zRK3|IvlRBy?M zExhgcvv~Q#OW4DE8*Rh2WC5Zw@Uq%H5G=H~W^36?biPJRjTQ(6u?k6vqkK=>(S-(4 z4;dwN@bPUFa762=jPI}t9WnXP-ZUnkOYO~8uE@Vk1%#Xwt&D}4pEX`#a}1!FIuni} zi?VNh7j%)dw#aO5p!9>(Gw0Zl@+aY?<`vlRpFmp{rNHNji^+en=|uPqnLVw>*O2C1 zK4vg}vtq6>6i!l;KGwb(?{hZ!&EVTLIhus8f^zvfYPn``2!e`KD%)=H-bZ7KV&H^te*c6xgX{-ZjtGvo3)ub z(OVVdwli9Uk_c)&G&k+mRU@B7={NaEL!pV9)_D1yhPc(}z|%b4%S$##mG_9jZ&9@D zOay(w6_^f`$4Ek`LZ@ z4F(mv)CYQqtZz@$_#9d$i_(qX%R$A?4N+$i=FN-!dJ6@M9Yy)&qdXJL_Yp$V8|KuN z`CEF0LxEmVZ_o(tQgpnw|4q!6Urdxf9QYfxa^FXdBe+47ntbRgXKw(OiquxK2h4Ub za|YEptzPQ6*z1NehKY0!{|L!CG5j#j!?BuiP)!i#Oc6OR=+3%kb_>K%fWEuxBv==# zi)@-ITPB_VM|*{*8`ajUJ9(~YHHUi*0A0^Oy(l!_VtL!s! z86?11Zl2^!xx0~bFLj>g6^$AYF+M*kcZk8iUM*4i!gQINifmNx@@$2M7YJ9bpL*c~ zUmi)7OK`&#OT8tDE9Jo1#j|r-5p+{0qn|BV{`~muMW7TbWLhT5ggNdp)p}ts)EsyK_izFY)20R9 zKIGt6G7q_h5B`$Gh}W72RGcR8Z7UxcreA3=E0ud-J)TweK%i0!lUY9ury+?3f5F#y zNH|6P2LAra1kwQ{CWPrDgxS>aU#R*~R+F>Uc&7niD#@*4Gj$6q+8119L2n=>@sx!2 za^9sA4%FE^>rRdT4XVG9UWfs7j-c7L+UF)0Zx8~Dt?R}6rbP%>4U25|s2BS~@*;iCcoDh^|`Kw8b{MH^uqeplExnlJYx}=y_=M?X$ zBunjC|2X3jEOfGVs?o5SItjjHU@@TJkk-d0`tpjkk)~S%I=i8ex zntuTKWG)a80)lwN+z+C`9ih}NOg#51(DjrRg?|M$-}&Bb@k${i4%{xgvL6c2hLO%- z|0JRR0`kp>(^p25{?AZ##QzRe3&j9J)&Ju0BS!$CYLH5b!9$-8-w@Co%bd0L%QpRm zA)e*HYmcb}Z&e>B&s)yUoM!+UU%b)*-odT}NgGQ8HsaJPa8eX~%{5F&#M@lNK#mQP zzaapqm@jbpr`BRRC=~or1N6#6DOnm{73-F!JzzIXaM9e3QF}lw!VuBo2Pl-~=e>R# z>sccy^^^?X1Rn~dQKa&BZGtFf3~-g`aGyhv%S?t+B;s4Dn9sR z;ht@+N#w&H$n3tMlyh5&YS)BE$e1ald7F@BwHZ64G~g}OhK*SF-zFcyi@UH}nCBRP z7YMX5$jNKYpOa)m3}w#57P#(F(pvAkBM>10Djf#_Kh=k*fC5}SW{?gr8{!J?ORZgw zIQF*pFJwIqmIuU-teWQMw1}K#a5S0#Dt~IUH}IHekd@Ci0p$XPdkx0a@DMbw!7oiKMJ5;n#Y-s_vH|Im+2xqsoHmA% z2`=a+xm0+MeCTn**_%bWlu;1KF-UlXF_TSG5l0ZeY^y6e2jGV>sf_fx*oSQL@Be)aNkv^Hr)ffAJ4LooF=fwda? z{{G7c`?a|yT}*{L)jULY`4Tp0>@B$)x4EMv&|b6RYs<;jUUR~kpgZBR|E4@hM*a7k zJq$6!s`JS>Zg2jY;CHV=ZtqQ^-MuGR#&d=zqm*B~HiVs`oFHOIXfuFA1qG>+RX`rJ z<4RjVM+v;-{NfR9li5|z!ul}c_}4`zh_|Bt5WVm#>?F>HKVKL+y-cYQ>d7sd?r1Z$ zfhNx#O$1<*Bz$)cto~WvI0)+G3v6;v4v8QjSRS5Q5>!ZUl2+lVZ-<{9-pRk|I%L6R zbu&?u!=2MTvkqCc=M$4qM}k2kt1JG!eutVnNQeYnkwP1^W-2E0H{U-$^;`CcW> z2$s}tU~^Vfj&{jTZ2<1q@=4Bjj(a_jF(%2=Ru;EP8;hdG!qqHW6j_exnAHb}7gU*w zLa9N3jpz!V%dSCN0cK-H+wC~8l}4pxmi>&n^(py>en)XefP(cepY`_HG^4ZCn4-Y} z%m(l3FEaT)-};1lRqL9(4*i(o9W1|h2KjtDU-(DL?}nLNXZSAl)>8mOMu z!)fsOG5LC%tmQ#eI^S7g0Xw`qZ{}@^mzzEBBCchfLAH9(6EKs^pf#9_uw&20oK8vU zNEtLy<8#+%?{6EOviOV!o&c^yjo(ci$%)>JyJ{S55om zdKm``DY6Faf~(M=9r7zG5WToBj5z90RHXT#!bYAl9A8h&lr&kl0|<0u84lX5S=%%c z98iGfh*ZKQMTMy$<+G0hYn(m5`$EFrG0x^!A4+EW1rQU?JLlkLq>a#CkV6Vhq``Xc*wn*7{<>%oq#>#&Qb6D?Q&VX z;}__;pA3_QlLRXeU{_Xp22(ql9X6%2V?W}JEjP`NXcG{VIOzO7f=;V*qsn)B5LUv| z)QXc3pV$D$OZDkpS`Cn#koOr8Dnb7AcTN$PC@r!o7zo<{8sF_@P_xk`>!TQB1P) z{*h2<5KMgu_Q-*Df~Hjelw2S^ScoDj5tV!5v_G&A+5u|6Xvr@}fa-4Pipsa*?Tv)H z2!Uv5Cd1a)aI*RMJ)+Es!k2ZK2TjK;ys0RjRk9D1V~|M#C6NKtf6L1?%aGFu1f>(l zsys(0+0w(5OLpo~t(XSCJ@ z^7?axQvd8Th%9!6K7)^EtFe_7Y7Xu4QS*TT0Nah%F^_D#UNF<*dGnLauCHu5u5=l7 z(%rvHFTQ7$F#*~X{zC1|Tq+yxpfBtl7&+P&KL&X^7@()>{P__@>Vz42poB}KS0d|bdFV9{*E3S#9ThB~=aU!+ zUZtEt%#}F3*9doLEyh!OzO5u{ulGkP2t#0qi>?0^KlGQU_+G*9oR4tE zj}Hb10i;!0?Dg$L%HA3_(7e(7)^rqkleDdWfBift7PKDK>Fsd>6JN_SBDYSUy~@}P zHy@j3DU|ExPzcj}m(I=~FEAU29affAqIOGA*8Twtv`R?5_#z@K!A@=*7)42TMTZNV zV2Sq~<6v!nX4_wcl_|9>q|Ly~j;<6caI7qH?k!=b1b?u^*eo0sq3h0VLK=QQGFQ{t zP;`SiyRfBmq>=w)S|Aox`JRR47(n)@4w@1Kfh6W*zJTygd}xk{6?Rg(0B(ESUygC? zO7hglUBE&}UTXSZ7_pKfCCuZc2-=+YC6c-7N?jN zkQGuVpafpov3gNWfBF9aKS%R>$bz(W5Vtb&wTN|e-fZe zW2!E@@+W}@7=px|m{x&oT$BqZYCGU7**Nj*5T*Z7)X48Ob7GLo;f1@5LawYC|MQpk z-`I}Q5HM}GX<3Dlw>}sorz*&HS0%f=o%L&oMMYXXFZ}!8^D_|Iovn4Bwt`k{zwLew z9mv4`sXF`_HQ#`s-;YGSdIuC9cd9zozUMbB*19IF!H$86050ZI4=t&MDNz>euFzxjkZ6qL4Yf27U zYi1e>LuMbE;Z~_zekXvSS|^^iVcc?!qxnv5J)RpaTNCJiIaP>bRu_1S%j0jcr9_Oi zfgunT5XLw?LBBVx?`gtCqA{nG!iey0Za4{~MfQpsimE)8jQl)%CAOs)d6dXjI#p2H zR9Sk$m`O?Fnc&|Xxx=X5|7sNIQAD`B=kbOkPs7^qjM>~BWGSy)ns=Ch{rQv7ABGPS zJ2b9L=B-JJw`?TZxaII{O2z()RlST%EX8oql;yYd%PT7fU?=p?T_3pJK!-6}s%g^; zX{#Yx0UKp^ECdC=W|um)xMtW_K_yu}pkVBqX=4xurkLE$*S&5u*GF*(WLC}#ZVxMT z29Zi?6}q)U47>=o{l+EBQNa(gu0GHjLZ#;Lx%?~D-y#4lA@C^Y6pgE(?{L_P3ebeG zD0zGocEZ#4a;R2HHMKWHLtITl3Xf}0TKLZIY5CnUMlb4m5)sF9Vw#{ow@5p=ZwMx0 z2qh-NtS6M1pqX|Gn_&>I5-Rh{r~=QZh@a$!g?9($&1&+2w}+$Z<|wN0tF9H7sABET zy}-B^#>=_R{$8#pb;GH=TA|J+pFS;OW9LMv+Sb4Dc+9WXb$xr3c92BAXx+nHJA{3$ z*J>%sBSVp4Kyhq@xr!m%tdh{JSpqLoi#kv6kf~}~4a~>tP9mM-!V^2IGvtf*bZI?) zpW@0OH)avFsW4)Bc}cvqqf^kheS{?ZAsXo$_~ht8&&+CCL>YEcllDKq$Ba-Ac@?(Q z(rsLmjeq}G8GxmtthxG5%)m7_(JGJRuA7r#UmBPYqxQS#0Q1v9W%}#W=?~6mu;h4U zb7lsExv;i5N%=8~vr?zu(z6v$?tV%?>fn#P&goQ*BY3v+;&r?;w*BS#N-VW;f7j0) z@mPuN6lzEmufAg212rzp2Oa4KvkU@?xKwM!Qg*+M+b;`!Lxzw(57 zVe4+$VCv@RH3LD22Q>(qeY9GArf4BVO^TP-z+i8%UE~d&{o|A$hvq)QRW!QVCftEB z!juWvdXa$Yx8(_R5-fL%(Q3JN>OvD81ze#qE|!pmq5>T=Y_Oy-wmlXldT7le&xIQKBud{k z53TrSC6$z4i>}0}9$hM2WZy#HLBK+4`P}5j4Q*;ber#P7TOaWTC(?UVygVo_E$$}a z)GMXdDGBO&?jkqznjDG8G^Gfpj{FxS75M$oY2N3r)eb5+Ltz^n z7H{U~Gyl%IBn1TALRj%0QVOJOnsJjqo)WP%XkoY1zEQ^*vE#M-_to66HH=d_G8V8@ zQC3E#`F?G{-31=Rnm-CwI9pP5$AgfxX#~Z>WyP2lGS;lo%(< zRZb0Ivje1SBGriiUsV6DfLEUQ;~q1ocY@_&2C73+s=#@)j-)dzPv@gHeuM@Iw{dQB z1vD`?Vp8TX&yh%C_@0z3UtlDZNo`J8Lq@JQL68360xkX{@E49uIVAW`>SQ;6|2rro;sr z^r0FZW?TmE)?lxyxXH&4c@rTkKuWv`5$v({YU^-ijVg{6(#{eW?B8ixRwhXBTu|Vd zm>)2mQ96wihlGFF)J! z{(9A%`)R^pwrJa3fb`(pbkD4GRjx@qdqZ|Z5r$+F>GyZ(UW5#JiL&4anG_q3_ANIH zHElU&1;{LKI8!I&?Y#G8aIE0P-LN@Eo1`_2eHW#uf$))NI3BrP3`z0++nr73khj# zvl%*n=LA}v&7Y}S$XNbqdm^DO8!X>VnR1gzX-l1OWuE7|$7J+F6>_V%@xk|a=0s}4 zpab|cK;hb1Xk%a*`vdrLNgFz_yh<0@z0u7a1bvreqo4wkvJM+Kk2xawedE6si)yxU z7{DJZ;4t%;D)q{j}6Tsqq^7FLfRGA>{cJU0r475#q6idv zGi)g_wDxH0-F6L(4gb=hp{l@~!8F%}w>k6LjI)^WBDnz_@C;(y0bkIPARFF$e|zus zb@jc5Q+DI7_P8;=%5@AX(}x-n{&S97ol$=Q=GbAdOGb&w*~7QB@2v!5kS~@tscZ%H z)0fb@gHKh-(wUZs!T&Kl`jcXEdVL$tjS?Mrt3cwt*nJ!jF2MX0P}pZ830VZWy({IC zAe4q~5z469;Bp#q-n{0ZRpI7)fP9@9z{_QSfdju<@!b+=B`3YhGFt11hg9 zW!s9zpoUoVb2VC=^AEV`nma4^XVol8D<6!jdB)&SX`0hJQ-V(L;_TiAs?b)<(jXaP zq{ysLy|oFpRuL3G@pCZp5e>EQ(J7k33b)O2_CPQs{gX)iBOmO_>koywFwB0P+oqk37raWalJ$-jFUo)$D=vLl*zB4&dbbo+O?rJqk; z_T2WwttOmfOlWkIhhGRYmZ?+~C0e0p>{w`ZqL)4D*aas(dJo`fxmEWk&_OS{QF+N0 z?~v)+R3oItV4y3uYpVO~edvX3+{mK-90<`9D^hL4E#2r|6Alqw#^Ry9{UKK8JYV^< zrE2o#*l~h^q{qd9%)%V~OOV-uVHD!hA@+qy$y~{_>w|VA$s4-w+Db>KR{ux+Pu)va z-*_Mja8-d{3QGhWk900%87$p?AvZ)b)06 zjz0M7mlZrLOLF@)tg1sXRl#aSOtM#Utu3hvl=WTL&XCat=Z3)7fXVIrABuVsx7YYWZ<%ET= zzx)WU%@ViQ!)#U0nkJocT1>$zJL21Lb#au=bl~rIh>vr@J(p7ttr>V4CJXk}~wxX=roUV#wLd+8V1NC048&w;Uk>{5W)XmEAXQdFeh5s0}_~;PABDTki z68#oN@4@Z@{Ronz=8t~UW-d1E33?&_A}evAb&0*iLo((rgLhRClIPS{o=TuiLE>03 zQY)Ah_^B7!SKj0!EWe)t;T{G_5l1d+dT8*4a%_68qU(dI6zcMRRLWF0s}WyAjqZfo z@U_{(`U6y(8k}HqIoi;3;k-wi%VDzDRYzx0zNF*JDfc#Hjk z6}o&p6YYC{E`Ogh1br=&B_9SqwiQtYMuJ^yPzADGh5|?D*QE8h_zf;;`Yt#I>2?H^snCqeQIB9?auDKd7^Y=QA{?kBUk5c%ECljD6)urxpSvb_{*vg$3;V& z78WL)=?p%z@#df*2jxLkeaL8TEpHO8Pm+%|!46!w>^EoGZ@Oau6F_Ks0OmsNJu8i5 zxOARaiK9OKXhAY_vjMmN&`r+axbXgDQ9T#8h25Q45LIIM!wFUncleMi#7pBqc_(r! zt0r(H6yJVS6=aN0C-hv{E`^AwX#hq8X$3+pn@~B0%t8_*6&*Qx{?Y42V~1}Cx7W@c zPdU{?SlUpNo(>-Er0>Cq*Rj4Rs`%C2LXr+6c$JBL=3OKxXdn|Q=Y!!)6`e?- zU85}JDMzNftDo8sZg8sq(lzc789AmIR=$oYQ8_FgGTz_O%=nEbT zTpy1^OrSldZ<0p(@h!DG2WaMQ3S#A!+_}k|gP#75Uy?jj1!J+`3nB2CRFPH)1ri7-dtlh`z*V4X&*+Vh-L=E#|!Cm5JcC^AMuhDqKWw^H7ox2w5zJ1kKls)ldGu z7tjf^vTa?abN1DLUM=BcQ;H|y<8ow5w|!o(xiTaQGPoy|*IH+d=_GG%Av^F&kE{dg zfF1YEUG?y{X`{#vQ`P)Mt@|Q&@00y~L@Y~`(@YUnIg9T3#S@4uZzhj-+iUC%_m&WG zYzvi8LKTCq$V@_h{d3NlTRe?L+&-0f@j!-cA)mQ?ko2(ev6M!?g=7np7d6_+ z?UXOm@Szc<5ZY&FyN_@8R25n69zOxwM7ss799W!XyVNne6nM`p;_IXpu}3DQA4%So z%NHPeWUks%aIiWpI@eC&VWLWMn$sGn?OLD7IiS5~uBXN0)9Pzbu0Di+o(11yHq(6bWlT${ zR9drau*jgv(j^BJ>(*0AU?B;lN|nV5*_3k|Krhhv9Pb=V^dnLg_x2GZ{XB+WA?Al1 zUz%_m25>b}dC^_kC9?fqr}pS4!{(ZEyT+Q+XpHyb=ssyb_bp#baL{Lp0lxb?WSgIZvp?tlE}*AURh zX(1_q3vr4On>c9ZL=r~=TOFRycr-?_Y*B-ZQ?G9U1)X&#W-dS(x_uX)t75op_NI05cp91=3Iyu*e0|8m-{$_i zLXy`mgBh`X({}J^ruZsQPJ{H=k>p}&^AaWP?bMa|i(BuSYEH;%_7t?!VHg+1*wKf$ z_+CwBydk->*h0pml&HHCw34l(zs`((CY1c*8(d6@3ysX2vNw%e=upPaEReJZo$7CDyV& zK9LDogJc7ap`ko0eS^MW{aiKZR?bxD@ZRZ=-Bt*F+fQcQ%(PzryDVyv-CbGzm=SOr z}ubPU#Ugt`0IJ@CBj+2dBa?_Dl6Zk(yzOA-_C4t7_fOX5d6r&GM|Tjor26x+;7RU zkB)SG=oMUSsmg~akien7;3}A8u8|wXBF2cwwoy&Jm?*7_4N=A(KiN(`MQxb86YFIV zuXU3@fuACGLy(ss&h^5GJ3d$KBq)UL71h!aDH(yZy9UnMhx^WAk%o4arP*|MqsMl~ zUzS2h-nEA}m(dSyTQ@D<&sIMzZ+vCjVin7txIkexK0hv;y=gIUfV(F>Wu|daf4LyCK9hld`LS1IP8d9 zpNT_!RWF`6M=hhV0r#Flhj|;v&*In(aQe^&xB878 zdo9k$nfu?&U4U#&6VS$|x%Q#B+xupd701TtP<57WPX$-EGFLdoBNipk;uk|eLxuap zw6qR#$TE5nD*q$;TM3-rPqW&{T)#&?gw3lElx~;*wJ5Q=AOD}{Pi6r%kYBfz@o#&b zls>gSs^(H*LV%RHk8SboQ(OGrxg24X6brrE?R0ZSv)B@sjwJ^5CuUw*HgEHl&u>lB zRxwy#zswYMKHB>5wUz6Qm+wz{vG;WJBLc3p|Kr54(=fc}LV&!tPxU*b&SN^ztX!e{-Qd;wqx)+DJ zNfxj0lK3$%J@5Da{L|OcMZL2G<^B6*S&_j&HT9V#qjxdwZC4^ i18nLabel: 'Sidebar_Sections_Order', i18nDescription: 'Sidebar_Sections_Order_Description', }); + + await this.add('Accounts_Default_User_Preferences_featuresPreview', '[]', { + type: 'string', + public: true, + }); }); await this.section('Avatar', async function () { diff --git a/apps/meteor/tests/end-to-end/api/miscellaneous.ts b/apps/meteor/tests/end-to-end/api/miscellaneous.ts index b8341f7c0994..d933f1f3c4b3 100644 --- a/apps/meteor/tests/end-to-end/api/miscellaneous.ts +++ b/apps/meteor/tests/end-to-end/api/miscellaneous.ts @@ -186,6 +186,7 @@ describe('miscellaneous', () => { 'muteFocusedConversations', 'notifyCalendarEvents', 'enableMobileRinging', + 'featuresPreview', ].filter((p) => Boolean(p)); expect(res.body).to.have.property('success', true); diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 0e99c1bdc1d8..47d2034e002e 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -85,6 +85,7 @@ "Accounts_AllowEmailChange": "Allow Email Change", "Accounts_AllowEmailNotifications": "Allow Email Notifications", "Accounts_AllowFeaturePreview": "Allow Feature Preview", + "Accounts_AllowFeaturePreview_Description": "Make feature preview available to all workspace members.", "Accounts_AllowPasswordChange": "Allow Password Change", "Accounts_AllowPasswordChangeForOAuthUsers": "Allow Password Change for OAuth Users", "Accounts_AllowRealNameChange": "Allow Name Change", @@ -1125,8 +1126,8 @@ "Common_Access": "Common Access", "Commit": "Commit", "Community": "Community", - "Contextualbar_resizable": "Contextual bar resizable", - "Contextualbar_resizable_description": "Allows you to adjust the size of the contextual bar by simply dragging, giving you instant customization and flexibility", + "Contextualbar_resizable": "Resizable contextual bar", + "Contextualbar_resizable_description": "Adjust the size of the contextual bar by clicking and dragging the edge, giving you instant customization and flexibility.", "Free_Edition": "Free edition", "Composer_not_available_phone_calls": "Messages are not available on phone calls", "Condensed": "Condensed", @@ -1949,8 +1950,8 @@ "Enable_Password_History": "Enable Password History", "Enable_Password_History_Description": "When enabled, users won't be able to update their passwords to some of their most recently used passwords.", "Enable_Svg_Favicon": "Enable SVG favicon", - "Enable_timestamp": "Enable timestamp parsing in messages", - "Enable_timestamp_description": "Enable timestamps to be parsed in messages", + "Enable_timestamp": "Timestamp in messages", + "Enable_timestamp_description": "Render Unix timestamps inside messages in your local (system) timezone.", "Enable_to_bypass_email_verification": "Enable to bypass email verification", "Enable_two-factor_authentication": "Enable two-factor authentication via TOTP", "Enable_two-factor_authentication_email": "Enable two-factor authentication via Email", @@ -2284,7 +2285,10 @@ "Favorite_Rooms": "Enable Favorite Rooms", "Favorites": "Favorites", "Feature_preview": "Feature preview", - "Feature_preview_page_description": "Welcome to the features preview page! Here, you can enable the latest cutting-edge features that are currently under development and not yet officially released.\n\nPlease note that these configurations are still in the testing phase and may not be stable or fully functional.", + "Feature_preview_page_description": "Enable the latest features that are currently under development.", + "Feature_preview_page_callout": "Feature previews are being tested and may not be stable or fully functional. Features may become premium capabilities once officially released.", + "Feature_preview_admin_page_description": "Choose what feature previews to make available to workspace members.", + "Feature_preview_admin_page_callout": "Features enabled here will be enabled to each user in their feature preview preferences.", "featured": "featured", "Featured": "Featured", "Feature_depends_on_selected_call_provider_to_be_enabled_from_administration_settings": "This feature depends on the above selected call provider to be enabled from the administration settings (Admin -> Video Conference).", @@ -4364,7 +4368,7 @@ "Queue_Time": "Queue Time", "Queue_management": "Queue Management", "Quick_reactions": "Quick reactions", - "Quick_reactions_description": "The three most used reactions get an easy access while your mouse is over the message", + "Quick_reactions_description": "Easily access your most used and most recent emoji message reactions by hovering on a message.", "quote": "quote", "Quote": "Quote", "Random": "Random", diff --git a/packages/i18n/src/locales/hi-IN.i18n.json b/packages/i18n/src/locales/hi-IN.i18n.json index 090e081e83fa..3110d6e82a67 100644 --- a/packages/i18n/src/locales/hi-IN.i18n.json +++ b/packages/i18n/src/locales/hi-IN.i18n.json @@ -2169,7 +2169,6 @@ "Favorite_Rooms": "पसंदीदा कमरे सक्षम करें", "Favorites": "पसंदीदा", "Feature_preview": "फ़ीचर पूर्वावलोकन", - "Feature_preview_page_description": "फीचर पूर्वावलोकन पृष्ठ पर आपका स्वागत है! यहां, आप नवीनतम अत्याधुनिक सुविधाओं को सक्षम कर सकते हैं जो वर्तमान में विकास के अधीन हैं और अभी तक आधिकारिक तौर पर जारी नहीं की गई हैं।\n\nकृपया ध्यान दें कि ये कॉन्फ़िगरेशन अभी भी परीक्षण चरण में हैं और स्थिर या पूरी तरह कार्यात्मक नहीं हो सकते हैं।", "featured": "प्रदर्शित", "Featured": "प्रदर्शित", "Feature_depends_on_selected_call_provider_to_be_enabled_from_administration_settings": "यह सुविधा प्रशासन सेटिंग्स (एडमिन -> वीडियो कॉन्फ्रेंस) से सक्षम होने के लिए उपरोक्त चयनित कॉल प्रदाता पर निर्भर करती है।", @@ -4128,7 +4127,6 @@ "Queue_Time": "कतार समय", "Queue_management": "कतार प्रबंधन", "Quick_reactions": "त्वरित प्रतिक्रियाएँ", - "Quick_reactions_description": "जब आपका माउस संदेश पर होता है तो सबसे अधिक उपयोग की जाने वाली तीन प्रतिक्रियाओं तक आसान पहुंच मिलती है", "quote": "उद्धरण", "Quote": "उद्धरण", "Random": "Random", @@ -4987,7 +4985,7 @@ "The_application_will_be_able_to": "<1>{{appName}} यह करने में सक्षम होगा:", "The_channel_name_is_required": "चैनल का नाम आवश्यक है", "The_emails_are_being_sent": "ईमेल भेजे जा रहे हैं.", - "The_empty_room__roomName__will_be_removed_automatically": "खाली कमरा {{roomName}} स्वचालित रूप से हटा दिया जाएगा।", + "The_empty_room__roomName__will_be_removed_automatically": "खाली कमरा {{roomName}} स्वचालित रूप से हटा दिया जाएगा।", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "छवि का आकार बदलना काम नहीं करेगा क्योंकि हम आपके सर्वर पर स्थापित ImageMagick या ग्राफ़िक्सMagick का पता नहीं लगा सकते हैं।", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "संदेश एक चर्चा है आप संदेशों को पुनर्प्राप्त नहीं कर पाएंगे!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "मोबाइल सूचनाएं सभी उपयोगकर्ताओं के लिए अक्षम कर दी गई थीं, पुश गेटवे को फिर से सक्षम करने के लिए \"एडमिन > पुश\" पर जाएं", @@ -6134,4 +6132,4 @@ "Unlimited_seats": "असीमित सीटें", "Unlimited_MACs": "असीमित एमएसी", "Unlimited_seats_MACs": "असीमित सीटें और एमएसी" -} \ No newline at end of file +} diff --git a/packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx b/packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx new file mode 100644 index 000000000000..eece30cc7280 --- /dev/null +++ b/packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx @@ -0,0 +1,21 @@ +import { Badge } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; + +import { usePreferenceFeaturePreviewList } from '../../hooks/usePreferenceFeaturePreviewList'; + +const FeaturePreviewBadge = () => { + const t = useTranslation(); + const { unseenFeatures } = usePreferenceFeaturePreviewList(); + + if (!unseenFeatures) { + return null; + } + + return ( + + {unseenFeatures} + + ); +}; + +export default FeaturePreviewBadge; diff --git a/packages/ui-client/src/components/FeaturePreview/index.ts b/packages/ui-client/src/components/FeaturePreview/index.ts new file mode 100644 index 000000000000..f6b8e5f2071e --- /dev/null +++ b/packages/ui-client/src/components/FeaturePreview/index.ts @@ -0,0 +1,2 @@ +export { FeaturePreview, FeaturePreviewOn, FeaturePreviewOff } from './FeaturePreview'; +export { default as FeaturePreviewBadge } from './FeaturePreviewBadge'; diff --git a/packages/ui-client/src/components/index.ts b/packages/ui-client/src/components/index.ts index 8642983229aa..7308c8e75431 100644 --- a/packages/ui-client/src/components/index.ts +++ b/packages/ui-client/src/components/index.ts @@ -11,7 +11,7 @@ export * as UserStatus from './UserStatus'; export * from './Header'; export * from './HeaderV2'; export * from './MultiSelectCustom/MultiSelectCustom'; -export * from './FeaturePreview/FeaturePreview'; +export * from './FeaturePreview'; export * from './RoomBanner'; export { default as UserAutoComplete } from './UserAutoComplete'; export * from './GenericMenu'; diff --git a/packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts b/packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts new file mode 100644 index 000000000000..373862379cc1 --- /dev/null +++ b/packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts @@ -0,0 +1,12 @@ +import { useSetting } from '@rocket.chat/ui-contexts'; +import { useMemo } from 'react'; + +import { parseSetting, useFeaturePreviewList } from './useFeaturePreviewList'; + +export const useDefaultSettingFeaturePreviewList = () => { + const featurePreviewSettingJSON = useSetting('Accounts_Default_User_Preferences_featuresPreview'); + + const settingFeaturePreview = useMemo(() => parseSetting(featurePreviewSettingJSON), [featurePreviewSettingJSON]); + + return useFeaturePreviewList(settingFeaturePreview ?? []); +}; diff --git a/packages/ui-client/src/hooks/useFeaturePreview.ts b/packages/ui-client/src/hooks/useFeaturePreview.ts index 4bdda9c9251a..bd46adfdefff 100644 --- a/packages/ui-client/src/hooks/useFeaturePreview.ts +++ b/packages/ui-client/src/hooks/useFeaturePreview.ts @@ -1,7 +1,8 @@ -import { type FeaturesAvailable, useFeaturePreviewList } from './useFeaturePreviewList'; +import { type FeaturesAvailable } from './useFeaturePreviewList'; +import { usePreferenceFeaturePreviewList } from './usePreferenceFeaturePreviewList'; export const useFeaturePreview = (featureName: FeaturesAvailable) => { - const { features } = useFeaturePreviewList(); + const { features } = usePreferenceFeaturePreviewList(); const currentFeature = features?.find((feature) => feature.name === featureName); diff --git a/packages/ui-client/src/hooks/useFeaturePreviewList.ts b/packages/ui-client/src/hooks/useFeaturePreviewList.ts index ff103a8d84ef..08bda4ff81ff 100644 --- a/packages/ui-client/src/hooks/useFeaturePreviewList.ts +++ b/packages/ui-client/src/hooks/useFeaturePreviewList.ts @@ -1,5 +1,4 @@ import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useUserPreference, useSetting } from '@rocket.chat/ui-contexts'; export type FeaturesAvailable = | 'quickReactions' @@ -24,6 +23,7 @@ export type FeaturePreviewProps = { }; }; +// TODO: Move the features preview array to another directory to be accessed from both BE and FE. export const defaultFeaturesPreview: FeaturePreviewProps[] = [ { name: 'quickReactions', @@ -47,6 +47,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ i18n: 'Enable_timestamp', description: 'Enable_timestamp_description', group: 'Message', + imageUrl: 'images/featurePreview/timestamp.png', value: false, enabled: true, }, @@ -55,6 +56,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ i18n: 'Contextualbar_resizable', description: 'Contextualbar_resizable_description', group: 'Navigation', + imageUrl: 'images/featurePreview/resizable-contextual-bar.png', value: false, enabled: true, }, @@ -63,6 +65,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ i18n: 'New_navigation', description: 'New_navigation_description', group: 'Navigation', + imageUrl: 'images/featurePreview/enhanced-navigation.png', value: false, enabled: true, }, @@ -82,22 +85,27 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ export const enabledDefaultFeatures = defaultFeaturesPreview.filter((feature) => feature.enabled); -export const useFeaturePreviewList = () => { - const featurePreviewEnabled = useSetting('Accounts_AllowFeaturePreview'); - const userFeaturesPreview = useUserPreference('featuresPreview'); - - if (!featurePreviewEnabled) { - return { unseenFeatures: 0, features: [] as FeaturePreviewProps[], featurePreviewEnabled }; +// TODO: Remove this logic after we have a way to store object settings. +export const parseSetting = (setting?: FeaturePreviewProps[] | string) => { + if (typeof setting === 'string') { + try { + return JSON.parse(setting) as FeaturePreviewProps[]; + } catch (_) { + return; + } } + return setting; +}; +export const useFeaturePreviewList = (featuresList: Pick[]) => { const unseenFeatures = enabledDefaultFeatures.filter( - (feature) => !userFeaturesPreview?.find((userFeature) => userFeature.name === feature.name), + (defaultFeature) => !featuresList?.find((feature) => feature.name === defaultFeature.name), ).length; - const mergedFeatures = enabledDefaultFeatures.map((feature) => { - const userFeature = userFeaturesPreview?.find((userFeature) => userFeature.name === feature.name); - return { ...feature, ...userFeature }; + const mergedFeatures = enabledDefaultFeatures.map((defaultFeature) => { + const features = featuresList?.find((feature) => feature.name === defaultFeature.name); + return { ...defaultFeature, ...features }; }); - return { unseenFeatures, features: mergedFeatures, featurePreviewEnabled }; + return { unseenFeatures, features: mergedFeatures }; }; diff --git a/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.spec.tsx similarity index 79% rename from packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx rename to packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.spec.tsx index e348cfb6a864..ac3d6f92d51a 100644 --- a/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx +++ b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.spec.tsx @@ -1,10 +1,11 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; import { renderHook } from '@testing-library/react'; -import { useFeaturePreviewList, enabledDefaultFeatures } from './useFeaturePreviewList'; +import { enabledDefaultFeatures } from './useFeaturePreviewList'; +import { usePreferenceFeaturePreviewList } from './usePreferenceFeaturePreviewList'; it('should return the number of unseen features and Accounts_AllowFeaturePreview enabled ', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', true).build(), }); @@ -18,7 +19,7 @@ it('should return the number of unseen features and Accounts_AllowFeaturePreview }); it('should return the number of unseen features and Accounts_AllowFeaturePreview disabled ', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', false).build(), }); @@ -32,7 +33,7 @@ it('should return the number of unseen features and Accounts_AllowFeaturePreview }); it('should return 0 unseen features', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) @@ -49,7 +50,7 @@ it('should return 0 unseen features', () => { }); it('should ignore removed feature previews', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) @@ -72,7 +73,7 @@ it('should ignore removed feature previews', () => { }); it('should turn off ignored feature previews', async () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) diff --git a/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts new file mode 100644 index 000000000000..d7c4c13417d2 --- /dev/null +++ b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts @@ -0,0 +1,16 @@ +import { useSetting, useUserPreference } from '@rocket.chat/ui-contexts'; +import { useMemo } from 'react'; + +import { FeaturePreviewProps, parseSetting, useFeaturePreviewList } from './useFeaturePreviewList'; + +export const usePreferenceFeaturePreviewList = () => { + const featurePreviewEnabled = useSetting('Accounts_AllowFeaturePreview'); + const userFeaturesPreviewPreference = useUserPreference('featuresPreview'); + const userFeaturesPreview = useMemo(() => parseSetting(userFeaturesPreviewPreference), [userFeaturesPreviewPreference]); + const { unseenFeatures, features } = useFeaturePreviewList(userFeaturesPreview ?? []); + + if (!featurePreviewEnabled) { + return { unseenFeatures: 0, features: [] as FeaturePreviewProps[], featurePreviewEnabled }; + } + return { unseenFeatures, features, featurePreviewEnabled }; +}; diff --git a/packages/ui-client/src/index.ts b/packages/ui-client/src/index.ts index 3e640343da5b..a96ef265aadc 100644 --- a/packages/ui-client/src/index.ts +++ b/packages/ui-client/src/index.ts @@ -1,5 +1,7 @@ export * from './components'; export * from './hooks/useFeaturePreview'; +export * from './hooks/useDefaultSettingFeaturePreviewList'; export * from './hooks/useFeaturePreviewList'; +export * from './hooks/usePreferenceFeaturePreviewList'; export * from './hooks/useDocumentTitle'; export * from './helpers'; From a4fcd99e3006f28abb0b3f06985809b447365fc4 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 24 Sep 2024 12:45:44 -0300 Subject: [PATCH 109/170] chore: move common files to core-services (#33341) --- _templates/service/new/service.ejs.t | 8 ++------ ee/apps/account-service/src/service.ts | 8 ++------ ee/apps/authorization-service/src/service.ts | 8 ++------ ee/apps/ddp-streamer/src/service.ts | 8 ++------ ee/apps/omnichannel-transcript/src/service.ts | 8 ++------ ee/apps/presence-service/src/service.ts | 8 ++------ ee/apps/queue-worker/src/service.ts | 8 ++------ ee/apps/stream-hub-service/src/service.ts | 8 ++------ packages/core-services/src/index.ts | 2 ++ .../core-services/src/lib}/mongo.ts | 14 ++------------ 10 files changed, 20 insertions(+), 60 deletions(-) rename {apps/meteor/ee/server/services => packages/core-services/src/lib}/mongo.ts (72%) diff --git a/_templates/service/new/service.ejs.t b/_templates/service/new/service.ejs.t index 77f02d2b7769..699539365259 100644 --- a/_templates/service/new/service.ejs.t +++ b/_templates/service/new/service.ejs.t @@ -1,12 +1,10 @@ --- to: ee/apps/<%= name %>/src/service.ts --- -import { api } from '@rocket.chat/core-services'; +import { api, getConnection, getTrashCollection } from '@rocket.chat/core-services'; import { broker } from '@rocket.chat/network-broker'; -import type { Document } from 'mongodb'; import polka from 'polka'; -import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; const PORT = process.env.PORT || <%= h.random() %>; @@ -14,9 +12,7 @@ const PORT = process.env.PORT || <%= h.random() %>; (async () => { const db = await getConnection(); - const trash = await getCollection(Collections.Trash); - - registerServiceModels(db, trash); + registerServiceModels(db, await getTrashCollection()); api.setBroker(broker); diff --git a/ee/apps/account-service/src/service.ts b/ee/apps/account-service/src/service.ts index 07ca30ed748f..c2f64e37bde3 100755 --- a/ee/apps/account-service/src/service.ts +++ b/ee/apps/account-service/src/service.ts @@ -1,19 +1,15 @@ -import { api } from '@rocket.chat/core-services'; +import { api, getConnection, getTrashCollection } from '@rocket.chat/core-services'; import { broker } from '@rocket.chat/network-broker'; -import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; -import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; const PORT = process.env.PORT || 3033; (async () => { const db = await getConnection(); - const trash = await getCollection(Collections.Trash); - - registerServiceModels(db, trash); + registerServiceModels(db, await getTrashCollection()); api.setBroker(broker); diff --git a/ee/apps/authorization-service/src/service.ts b/ee/apps/authorization-service/src/service.ts index 4dcd466afa60..1698ef7a115c 100755 --- a/ee/apps/authorization-service/src/service.ts +++ b/ee/apps/authorization-service/src/service.ts @@ -1,19 +1,15 @@ -import { api } from '@rocket.chat/core-services'; +import { api, getConnection, getTrashCollection } from '@rocket.chat/core-services'; import { broker } from '@rocket.chat/network-broker'; -import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; -import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; const PORT = process.env.PORT || 3034; (async () => { const db = await getConnection(); - const trash = await getCollection(Collections.Trash); - - registerServiceModels(db, trash); + registerServiceModels(db, await getTrashCollection()); api.setBroker(broker); diff --git a/ee/apps/ddp-streamer/src/service.ts b/ee/apps/ddp-streamer/src/service.ts index 07666a265dbe..58552240cadd 100755 --- a/ee/apps/ddp-streamer/src/service.ts +++ b/ee/apps/ddp-streamer/src/service.ts @@ -1,16 +1,12 @@ -import { api } from '@rocket.chat/core-services'; +import { api, getConnection, getTrashCollection } from '@rocket.chat/core-services'; import { broker } from '@rocket.chat/network-broker'; -import type { Document } from 'mongodb'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; -import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; (async () => { const db = await getConnection(); - const trash = await getCollection(Collections.Trash); - - registerServiceModels(db, trash); + registerServiceModels(db, await getTrashCollection()); api.setBroker(broker); diff --git a/ee/apps/omnichannel-transcript/src/service.ts b/ee/apps/omnichannel-transcript/src/service.ts index 66456456fb74..ad60687d5ba4 100644 --- a/ee/apps/omnichannel-transcript/src/service.ts +++ b/ee/apps/omnichannel-transcript/src/service.ts @@ -1,20 +1,16 @@ -import { api } from '@rocket.chat/core-services'; +import { api, getConnection, getTrashCollection } from '@rocket.chat/core-services'; import { Logger } from '@rocket.chat/logger'; import { broker } from '@rocket.chat/network-broker'; -import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; -import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; const PORT = process.env.PORT || 3036; (async () => { const db = await getConnection(); - const trash = await getCollection(Collections.Trash); - - registerServiceModels(db, trash); + registerServiceModels(db, await getTrashCollection()); api.setBroker(broker); diff --git a/ee/apps/presence-service/src/service.ts b/ee/apps/presence-service/src/service.ts index 0e1c97f2daa2..0c51c30dc577 100755 --- a/ee/apps/presence-service/src/service.ts +++ b/ee/apps/presence-service/src/service.ts @@ -1,19 +1,15 @@ -import { api } from '@rocket.chat/core-services'; +import { api, getConnection, getTrashCollection } from '@rocket.chat/core-services'; import { broker } from '@rocket.chat/network-broker'; -import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; -import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; const PORT = process.env.PORT || 3031; (async () => { const db = await getConnection(); - const trash = await getCollection(Collections.Trash); - - registerServiceModels(db, trash); + registerServiceModels(db, await getTrashCollection()); api.setBroker(broker); diff --git a/ee/apps/queue-worker/src/service.ts b/ee/apps/queue-worker/src/service.ts index 4bc6c9642913..c11376d56534 100644 --- a/ee/apps/queue-worker/src/service.ts +++ b/ee/apps/queue-worker/src/service.ts @@ -1,20 +1,16 @@ -import { api } from '@rocket.chat/core-services'; +import { api, getConnection, getTrashCollection } from '@rocket.chat/core-services'; import { Logger } from '@rocket.chat/logger'; import { broker } from '@rocket.chat/network-broker'; -import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; -import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; const PORT = process.env.PORT || 3038; (async () => { const db = await getConnection(); - const trash = await getCollection(Collections.Trash); - - registerServiceModels(db, trash); + registerServiceModels(db, await getTrashCollection()); api.setBroker(broker); diff --git a/ee/apps/stream-hub-service/src/service.ts b/ee/apps/stream-hub-service/src/service.ts index eade703321d2..5e035548dc38 100755 --- a/ee/apps/stream-hub-service/src/service.ts +++ b/ee/apps/stream-hub-service/src/service.ts @@ -1,11 +1,9 @@ -import { api } from '@rocket.chat/core-services'; +import { api, getConnection, getTrashCollection } from '@rocket.chat/core-services'; import { Logger } from '@rocket.chat/logger'; import { broker } from '@rocket.chat/network-broker'; -import type { Document } from 'mongodb'; import polka from 'polka'; import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; -import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; import { DatabaseWatcher } from '../../../../apps/meteor/server/database/DatabaseWatcher'; import { StreamHub } from './StreamHub'; @@ -14,9 +12,7 @@ const PORT = process.env.PORT || 3035; (async () => { const db = await getConnection(); - const trash = await getCollection(Collections.Trash); - - registerServiceModels(db, trash); + registerServiceModels(db, await getTrashCollection()); api.setBroker(broker); diff --git a/packages/core-services/src/index.ts b/packages/core-services/src/index.ts index 8eea19ea7405..85722c98839f 100644 --- a/packages/core-services/src/index.ts +++ b/packages/core-services/src/index.ts @@ -75,6 +75,8 @@ export { AnalyticsOverviewDataResult, } from './types/IOmnichannelAnalyticsService'; +export { getConnection, getTrashCollection } from './lib/mongo'; + export { AutoUpdateRecord, FindVoipRoomsParams, diff --git a/apps/meteor/ee/server/services/mongo.ts b/packages/core-services/src/lib/mongo.ts similarity index 72% rename from apps/meteor/ee/server/services/mongo.ts rename to packages/core-services/src/lib/mongo.ts index 27e9e931c039..fab1fd108d99 100644 --- a/apps/meteor/ee/server/services/mongo.ts +++ b/packages/core-services/src/lib/mongo.ts @@ -5,16 +5,6 @@ const { MONGO_URL = 'mongodb://localhost:27017/rocketchat' } = process.env; const name = /^mongodb:\/\/.*?(?::[0-9]+)?\/([^?]*)/.exec(MONGO_URL)?.[1]; -export enum Collections { - Subscriptions = 'rocketchat_subscription', - UserSession = 'usersSessions', - User = 'users', - Trash = 'rocketchat__trash', - Messages = 'rocketchat_message', - Rooms = 'rocketchat_room', - Settings = 'rocketchat_settings', -} - function connectDb(options?: MongoClientOptions): Promise { const client = new MongoClient(MONGO_URL, options); @@ -44,9 +34,9 @@ export const getConnection = ((): ((options?: MongoClientOptions) => Promise }; })(); -export async function getCollection(name: Collections): Promise> { +export async function getTrashCollection(): Promise> { if (!db) { db = await getConnection(); } - return db.collection(name); + return db.collection('rocketchat__trash'); } From d94a159126a757d156496f8ab2ce95f09ea45ff1 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 24 Sep 2024 12:50:10 -0300 Subject: [PATCH 110/170] regression: `Sidepanel` color highlight (#33342) --- apps/meteor/package.json | 2 +- apps/uikit-playground/package.json | 2 +- ee/packages/ui-theming/package.json | 2 +- packages/fuselage-ui-kit/package.json | 2 +- packages/gazzodown/package.json | 2 +- packages/ui-avatar/package.json | 2 +- packages/ui-client/package.json | 2 +- packages/ui-composer/package.json | 2 +- packages/ui-video-conf/package.json | 2 +- yarn.lock | 50 +++++++++++++-------------- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/apps/meteor/package.json b/apps/meteor/package.json index a09dcb657466..a30ce30a7b6f 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -241,7 +241,7 @@ "@rocket.chat/favicon": "workspace:^", "@rocket.chat/forked-matrix-appservice-bridge": "^4.0.2", "@rocket.chat/forked-matrix-bot-sdk": "^0.6.0-beta.3", - "@rocket.chat/fuselage": "^0.59.0", + "@rocket.chat/fuselage": "^0.59.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/fuselage-toastbar": "^0.33.0", diff --git a/apps/uikit-playground/package.json b/apps/uikit-playground/package.json index 48c099b8d9d1..c5e7628001c6 100644 --- a/apps/uikit-playground/package.json +++ b/apps/uikit-playground/package.json @@ -17,7 +17,7 @@ "@lezer/highlight": "^1.1.6", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.59.0", + "@rocket.chat/fuselage": "^0.59.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/fuselage-toastbar": "^0.33.0", diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json index 0548f235c3fd..29fe229ca532 100644 --- a/ee/packages/ui-theming/package.json +++ b/ee/packages/ui-theming/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.59.0", + "@rocket.chat/fuselage": "^0.59.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/ui-contexts": "workspace:~", diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 8fb0ca254d68..573d65dc215e 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -66,7 +66,7 @@ "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.59.0", + "@rocket.chat/fuselage": "^0.59.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/icons": "~0.38.0", diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 47bf2782226e..a5883bbe3c0f 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -28,7 +28,7 @@ "@babel/core": "~7.22.20", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.59.0", + "@rocket.chat/fuselage": "^0.59.1", "@rocket.chat/fuselage-tokens": "^0.33.1", "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/message-parser": "workspace:^", diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index a32a7a8be6bf..70f0efe2cff9 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@babel/core": "~7.22.20", - "@rocket.chat/fuselage": "^0.59.0", + "@rocket.chat/fuselage": "^0.59.1", "@rocket.chat/ui-contexts": "workspace:^", "@types/react": "~17.0.80", "@types/react-dom": "~17.0.25", diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 82705ba026cb..40bccd8ca628 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -21,7 +21,7 @@ "@babel/core": "~7.22.20", "@react-aria/toolbar": "^3.0.0-beta.1", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.59.0", + "@rocket.chat/fuselage": "^0.59.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index 363299698bfa..c43f3485880e 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -19,7 +19,7 @@ "@babel/core": "~7.22.20", "@react-aria/toolbar": "^3.0.0-beta.1", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.59.0", + "@rocket.chat/fuselage": "^0.59.1", "@rocket.chat/icons": "~0.38.0", "@storybook/addon-actions": "~6.5.16", "@storybook/addon-docs": "~6.5.16", diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 0f1f3e50eab8..74c3ec43bcbb 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@rocket.chat/css-in-js": "~0.31.25", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.59.0", + "@rocket.chat/fuselage": "^0.59.1", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/jest-presets": "workspace:~", diff --git a/yarn.lock b/yarn.lock index c0fb2733310e..20c005cca203 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8910,7 +8910,7 @@ __metadata: "@rocket.chat/apps-engine": 1.45.0-alpha.868 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.59.0 + "@rocket.chat/fuselage": ^0.59.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/gazzodown": "workspace:^" @@ -8959,19 +8959,19 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": "*" - "@rocket.chat/ui-contexts": "*" + "@rocket.chat/ui-avatar": 7.0.0-rc.0 + "@rocket.chat/ui-contexts": 11.0.0-rc.0 "@rocket.chat/ui-kit": "*" - "@rocket.chat/ui-video-conf": "*" + "@rocket.chat/ui-video-conf": 11.0.0-rc.0 "@tanstack/react-query": "*" react: "*" react-dom: "*" languageName: unknown linkType: soft -"@rocket.chat/fuselage@npm:^0.59.0": - version: 0.59.0 - resolution: "@rocket.chat/fuselage@npm:0.59.0" +"@rocket.chat/fuselage@npm:^0.59.1": + version: 0.59.1 + resolution: "@rocket.chat/fuselage@npm:0.59.1" dependencies: "@rocket.chat/css-in-js": ^0.31.25 "@rocket.chat/css-supports": ^0.31.25 @@ -8989,7 +8989,7 @@ __metadata: react: ^17.0.2 react-dom: ^17.0.2 react-virtuoso: 1.2.4 - checksum: 259dce5381a3c3e0d7c7f3dc7ab51346cb65a9f4906a5ca5d6a976627d05e01e7f8a3a940604d0ad1b2b4ed89c250a871ef3fb253f6bbb69d35bc931e193898d + checksum: 6ecceaefe8b2c6b9fe0ba3b6e19360f5d46af9697e7c97af16cce6c9eea2cb79255f38ccffdbc4766b4104c079281b4980fe7c924cd62fe5d2d341581fdf4f62 languageName: node linkType: hard @@ -9000,7 +9000,7 @@ __metadata: "@babel/core": ~7.22.20 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.59.0 + "@rocket.chat/fuselage": ^0.59.1 "@rocket.chat/fuselage-tokens": ^0.33.1 "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/message-parser": "workspace:^" @@ -9047,10 +9047,10 @@ __metadata: "@rocket.chat/css-in-js": "*" "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-tokens": "*" - "@rocket.chat/message-parser": 0.31.29 + "@rocket.chat/message-parser": 0.31.30-rc.0 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": "*" - "@rocket.chat/ui-contexts": "*" + "@rocket.chat/ui-client": 11.0.0-rc.0 + "@rocket.chat/ui-contexts": 11.0.0-rc.0 katex: "*" react: "*" languageName: unknown @@ -9372,7 +9372,7 @@ __metadata: "@rocket.chat/favicon": "workspace:^" "@rocket.chat/forked-matrix-appservice-bridge": ^4.0.2 "@rocket.chat/forked-matrix-bot-sdk": ^0.6.0-beta.3 - "@rocket.chat/fuselage": ^0.59.0 + "@rocket.chat/fuselage": ^0.59.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/fuselage-toastbar": ^0.33.0 @@ -10244,7 +10244,7 @@ __metadata: resolution: "@rocket.chat/ui-avatar@workspace:packages/ui-avatar" dependencies: "@babel/core": ~7.22.20 - "@rocket.chat/fuselage": ^0.59.0 + "@rocket.chat/fuselage": ^0.59.1 "@rocket.chat/ui-contexts": "workspace:^" "@types/react": ~17.0.80 "@types/react-dom": ~17.0.25 @@ -10257,7 +10257,7 @@ __metadata: typescript: ~5.5.4 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": "*" + "@rocket.chat/ui-contexts": 11.0.0-rc.0 react: ~17.0.2 languageName: unknown linkType: soft @@ -10269,7 +10269,7 @@ __metadata: "@babel/core": ~7.22.20 "@react-aria/toolbar": ^3.0.0-beta.1 "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.59.0 + "@rocket.chat/fuselage": ^0.59.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/jest-presets": "workspace:~" @@ -10308,8 +10308,8 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-avatar": "*" - "@rocket.chat/ui-contexts": "*" + "@rocket.chat/ui-avatar": 7.0.0-rc.0 + "@rocket.chat/ui-contexts": 11.0.0-rc.0 react: "*" react-i18next: "*" languageName: unknown @@ -10322,7 +10322,7 @@ __metadata: "@babel/core": ~7.22.20 "@react-aria/toolbar": ^3.0.0-beta.1 "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.59.0 + "@rocket.chat/fuselage": ^0.59.1 "@rocket.chat/icons": ~0.38.0 "@storybook/addon-actions": ~6.5.16 "@storybook/addon-docs": ~6.5.16 @@ -10416,7 +10416,7 @@ __metadata: resolution: "@rocket.chat/ui-theming@workspace:ee/packages/ui-theming" dependencies: "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.59.0 + "@rocket.chat/fuselage": ^0.59.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/ui-contexts": "workspace:~" @@ -10446,7 +10446,7 @@ __metadata: "@rocket.chat/css-in-js": ~0.31.25 "@rocket.chat/emitter": ~0.31.25 "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.59.0 + "@rocket.chat/fuselage": ^0.59.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ~0.38.0 "@rocket.chat/jest-presets": "workspace:~" @@ -10478,8 +10478,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": "*" - "@rocket.chat/ui-contexts": "*" + "@rocket.chat/ui-avatar": 7.0.0-rc.0 + "@rocket.chat/ui-contexts": 11.0.0-rc.0 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10495,7 +10495,7 @@ __metadata: "@lezer/highlight": ^1.1.6 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.59.0 + "@rocket.chat/fuselage": ^0.59.1 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/fuselage-toastbar": ^0.33.0 @@ -10567,7 +10567,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 - "@rocket.chat/ui-contexts": "*" + "@rocket.chat/ui-contexts": 11.0.0-rc.0 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 2f9eea03d2122e963bc89559e772bf00a54ad200 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Tue, 24 Sep 2024 09:54:31 -0300 Subject: [PATCH 111/170] feat: Adds new admin feature preview setting management (#33212) Co-authored-by: Guilherme Gazzo --- .changeset/quick-rings-wave.md | 7 + .../UserMenu/hooks/useAccountItems.tsx | 4 +- .../hooks/useFeaturePreviewEnableQuery.ts | 28 ++++ .../sidebar/header/hooks/useAccountItems.tsx | 4 +- .../AccountFeaturePreviewBadge.tsx | 21 --- .../AccountFeaturePreviewPage.tsx | 44 ++---- .../client/views/account/sidebarItems.tsx | 5 +- .../AdminFeaturePreviewPage.tsx | 127 ++++++++++++++++++ .../AdminFeaturePreviewRoute.tsx | 26 ++++ apps/meteor/client/views/admin/routes.tsx | 9 ++ .../meteor/client/views/admin/sidebarItems.ts | 8 ++ .../featurePreview/enhanced-navigation.png | Bin 0 -> 2372 bytes .../resizable-contextual-bar.png | Bin 0 -> 4776 bytes .../images/featurePreview/timestamp.png | Bin 0 -> 51432 bytes apps/meteor/server/settings/accounts.ts | 5 + .../tests/end-to-end/api/miscellaneous.ts | 1 + packages/i18n/src/locales/en.i18n.json | 16 ++- packages/i18n/src/locales/hi-IN.i18n.json | 6 +- .../FeaturePreview/FeaturePreviewBadge.tsx | 21 +++ .../src/components/FeaturePreview/index.ts | 2 + packages/ui-client/src/components/index.ts | 2 +- .../useDefaultSettingFeaturePreviewList.ts | 12 ++ .../ui-client/src/hooks/useFeaturePreview.ts | 5 +- .../src/hooks/useFeaturePreviewList.ts | 32 +++-- ... usePreferenceFeaturePreviewList.spec.tsx} | 13 +- .../hooks/usePreferenceFeaturePreviewList.ts | 16 +++ packages/ui-client/src/index.ts | 2 + 27 files changed, 324 insertions(+), 92 deletions(-) create mode 100644 .changeset/quick-rings-wave.md create mode 100644 apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts delete mode 100644 apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx create mode 100644 apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx create mode 100644 apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx create mode 100644 apps/meteor/public/images/featurePreview/enhanced-navigation.png create mode 100644 apps/meteor/public/images/featurePreview/resizable-contextual-bar.png create mode 100644 apps/meteor/public/images/featurePreview/timestamp.png create mode 100644 packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx create mode 100644 packages/ui-client/src/components/FeaturePreview/index.ts create mode 100644 packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts rename packages/ui-client/src/hooks/{useFeaturePreviewList.spec.tsx => usePreferenceFeaturePreviewList.spec.tsx} (79%) create mode 100644 packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts diff --git a/.changeset/quick-rings-wave.md b/.changeset/quick-rings-wave.md new file mode 100644 index 000000000000..0ea22897ff45 --- /dev/null +++ b/.changeset/quick-rings-wave.md @@ -0,0 +1,7 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/i18n": minor +"@rocket.chat/ui-client": minor +--- + +Added new Admin Feature Preview management view, this will allow the workspace admins to both enable feature previewing in the workspace as well as define which feature previews are enabled by default for the users in the workspace. diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx index 82c39c5c1b10..e54e2b72d675 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useAccountItems.tsx @@ -1,7 +1,7 @@ import { Badge } from '@rocket.chat/fuselage'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; -import { defaultFeaturesPreview, useFeaturePreviewList } from '@rocket.chat/ui-client'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; +import { defaultFeaturesPreview, usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; @@ -9,7 +9,7 @@ export const useAccountItems = (): GenericMenuItemProps[] => { const t = useTranslation(); const router = useRouter(); - const { unseenFeatures, featurePreviewEnabled } = useFeaturePreviewList(); + const { unseenFeatures, featurePreviewEnabled } = usePreferenceFeaturePreviewList(); const handleMyAccount = useEffectEvent(() => { router.navigate('/account'); diff --git a/apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts b/apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts new file mode 100644 index 000000000000..fd88f0237d29 --- /dev/null +++ b/apps/meteor/client/hooks/useFeaturePreviewEnableQuery.ts @@ -0,0 +1,28 @@ +import type { FeaturePreviewProps } from '@rocket.chat/ui-client'; +import { useMemo } from 'react'; + +const handleFeaturePreviewEnableQuery = (item: FeaturePreviewProps, _: any, features: FeaturePreviewProps[]) => { + if (item.enableQuery) { + const expected = item.enableQuery.value; + const received = features.find((el) => el.name === item.enableQuery?.name)?.value; + if (expected !== received) { + item.disabled = true; + item.value = false; + } else { + item.disabled = false; + } + } + return item; +}; + +const groupFeaturePreview = (features: FeaturePreviewProps[]) => + Object.entries( + features.reduce((result, currentValue) => { + (result[currentValue.group] = result[currentValue.group] || []).push(currentValue); + return result; + }, {} as Record), + ); + +export const useFeaturePreviewEnableQuery = (features: FeaturePreviewProps[]) => { + return useMemo(() => groupFeaturePreview(features.map(handleFeaturePreviewEnableQuery)), [features]); +}; diff --git a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx index 2be6b2b1dea2..51ab7a198a67 100644 --- a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx @@ -1,7 +1,7 @@ import { Badge } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; -import { defaultFeaturesPreview, useFeaturePreviewList } from '@rocket.chat/ui-client'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; +import { defaultFeaturesPreview, usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React from 'react'; @@ -9,7 +9,7 @@ export const useAccountItems = (): GenericMenuItemProps[] => { const t = useTranslation(); const router = useRouter(); - const { unseenFeatures, featurePreviewEnabled } = useFeaturePreviewList(); + const { unseenFeatures, featurePreviewEnabled } = usePreferenceFeaturePreviewList(); const handleMyAccount = useMutableCallback(() => { router.navigate('/account'); diff --git a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx deleted file mode 100644 index c109ca1aefb5..000000000000 --- a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewBadge.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Badge } from '@rocket.chat/fuselage'; -import { useFeaturePreviewList } from '@rocket.chat/ui-client'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; - -const AccountFeaturePreviewBadge = () => { - const { t } = useTranslation(); - const { unseenFeatures } = useFeaturePreviewList(); - - if (!unseenFeatures) { - return null; - } - - return ( - - {unseenFeatures} - - ); -}; - -export default AccountFeaturePreviewBadge; diff --git a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx index dd9ab6a90959..358d2394003b 100644 --- a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx +++ b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.tsx @@ -1,4 +1,3 @@ -import { css } from '@rocket.chat/css-in-js'; import { ButtonGroup, Button, @@ -13,9 +12,10 @@ import { FieldLabel, FieldRow, FieldHint, + Callout, + Margins, } from '@rocket.chat/fuselage'; -import type { FeaturePreviewProps } from '@rocket.chat/ui-client'; -import { useFeaturePreviewList } from '@rocket.chat/ui-client'; +import { usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useToastMessageDispatch, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; import type { ChangeEvent } from 'react'; @@ -23,26 +23,12 @@ import React, { useEffect, Fragment } from 'react'; import { useForm } from 'react-hook-form'; import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../../components/Page'; +import { useFeaturePreviewEnableQuery } from '../../../hooks/useFeaturePreviewEnableQuery'; -const handleEnableQuery = (features: FeaturePreviewProps[]) => { - return features.map((item) => { - if (item.enableQuery) { - const expected = item.enableQuery.value; - const received = features.find((el) => el.name === item.enableQuery?.name)?.value; - if (expected !== received) { - item.disabled = true; - item.value = false; - } else { - item.disabled = false; - } - } - return item; - }); -}; const AccountFeaturePreviewPage = () => { const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const { features, unseenFeatures } = useFeaturePreviewList(); + const { features, unseenFeatures } = usePreferenceFeaturePreviewList(); const setUserPreferences = useEndpoint('POST', '/v1/users.setPreferences'); @@ -85,12 +71,7 @@ const AccountFeaturePreviewPage = () => { setValue('featuresPreview', updated, { shouldDirty: true }); }; - const grouppedFeaturesPreview = Object.entries( - handleEnableQuery(featuresPreview).reduce((result, currentValue) => { - (result[currentValue.group] = result[currentValue.group] || []).push(currentValue); - return result; - }, {} as Record), - ); + const grouppedFeaturesPreview = useFeaturePreviewEnableQuery(featuresPreview); return ( @@ -105,14 +86,11 @@ const AccountFeaturePreviewPage = () => { )} {featuresPreview.length > 0 && ( <> - - {t('Feature_preview_page_description')} + + + {t('Feature_preview_page_description')} + {t('Feature_preview_page_callout')} + {grouppedFeaturesPreview?.map(([group, features], index) => ( diff --git a/apps/meteor/client/views/account/sidebarItems.tsx b/apps/meteor/client/views/account/sidebarItems.tsx index ca0376be329d..fa2ab8bd5e40 100644 --- a/apps/meteor/client/views/account/sidebarItems.tsx +++ b/apps/meteor/client/views/account/sidebarItems.tsx @@ -1,10 +1,9 @@ -import { defaultFeaturesPreview } from '@rocket.chat/ui-client'; +import { defaultFeaturesPreview, FeaturePreviewBadge } from '@rocket.chat/ui-client'; import React from 'react'; import { hasPermission, hasAtLeastOnePermission } from '../../../app/authorization/client'; import { settings } from '../../../app/settings/client'; import { createSidebarItems } from '../../lib/createSidebarItems'; -import AccountFeaturePreviewBadge from './featurePreview/AccountFeaturePreviewBadge'; export const { registerSidebarItem: registerAccountSidebarItem, @@ -54,7 +53,7 @@ export const { href: '/account/feature-preview', i18nLabel: 'Feature_preview', icon: 'flask', - badge: () => , + badge: () => , permissionGranted: () => settings.get('Accounts_AllowFeaturePreview') && defaultFeaturesPreview?.length > 0, }, { diff --git a/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx new file mode 100644 index 000000000000..615fd20cf5a6 --- /dev/null +++ b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx @@ -0,0 +1,127 @@ +import { + ButtonGroup, + Button, + Box, + ToggleSwitch, + Accordion, + Field, + FieldGroup, + FieldLabel, + FieldRow, + FieldHint, + Callout, + Margins, +} from '@rocket.chat/fuselage'; +import { useDefaultSettingFeaturePreviewList } from '@rocket.chat/ui-client'; +import type { TranslationKey } from '@rocket.chat/ui-contexts'; +import { useToastMessageDispatch, useTranslation, useSettingsDispatch } from '@rocket.chat/ui-contexts'; +import type { ChangeEvent } from 'react'; +import React, { Fragment } from 'react'; +import { useForm } from 'react-hook-form'; + +import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../../components/Page'; +import { useFeaturePreviewEnableQuery } from '../../../hooks/useFeaturePreviewEnableQuery'; +import { useEditableSetting } from '../EditableSettingsContext'; +import Setting from '../settings/Setting'; +import SettingsGroupPageSkeleton from '../settings/SettingsGroupPage/SettingsGroupPageSkeleton'; + +const AdminFeaturePreviewPage = () => { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + const allowFeaturePreviewSetting = useEditableSetting('Accounts_AllowFeaturePreview'); + const { features } = useDefaultSettingFeaturePreviewList(); + + const { + watch, + formState: { isDirty }, + setValue, + handleSubmit, + reset, + } = useForm({ + defaultValues: { featuresPreview: features }, + }); + const { featuresPreview } = watch(); + const dispatch = useSettingsDispatch(); + + const handleSave = async () => { + try { + const featuresToBeSaved = featuresPreview.map((feature) => ({ name: feature.name, value: feature.value })); + + await dispatch([ + { _id: allowFeaturePreviewSetting!._id, value: allowFeaturePreviewSetting!.value }, + { _id: 'Accounts_Default_User_Preferences_featuresPreview', value: JSON.stringify(featuresToBeSaved) }, + ]); + dispatchToastMessage({ type: 'success', message: t('Preferences_saved') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + reset({ featuresPreview }); + } + }; + + const handleFeatures = (e: ChangeEvent) => { + const updated = featuresPreview.map((item) => (item.name === e.target.name ? { ...item, value: e.target.checked } : item)); + setValue('featuresPreview', updated, { shouldDirty: true }); + }; + + const grouppedFeaturesPreview = useFeaturePreviewEnableQuery(featuresPreview); + + if (!allowFeaturePreviewSetting) { + // TODO: Implement FeaturePreviewSkeleton component + return ; + } + + return ( + + + + + + + {t('Feature_preview_admin_page_description')} + {t('Feature_preview_page_callout')} + {t('Feature_preview_admin_page_callout')} + + + + + {grouppedFeaturesPreview?.map(([group, features], index) => ( + + + {features.map((feature) => ( + + + + {t(feature.i18n)} + + + {feature.description && {t(feature.description)}} + + {feature.imageUrl && } + + ))} + + + ))} + + + + + + + + + + + ); +}; + +export default AdminFeaturePreviewPage; diff --git a/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx new file mode 100644 index 000000000000..a7d6bd77d136 --- /dev/null +++ b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewRoute.tsx @@ -0,0 +1,26 @@ +import { usePermission } from '@rocket.chat/ui-contexts'; +import type { ReactElement } from 'react'; +import React, { memo } from 'react'; + +import SettingsProvider from '../../../providers/SettingsProvider'; +import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage'; +import EditableSettingsProvider from '../settings/EditableSettingsProvider'; +import AdminFeaturePreviewPage from './AdminFeaturePreviewPage'; + +const AdminFeaturePreviewRoute = (): ReactElement => { + const canViewFeaturesPreview = usePermission('manage-cloud'); + + if (!canViewFeaturesPreview) { + return ; + } + + return ( + + + + + + ); +}; + +export default memo(AdminFeaturePreviewRoute); diff --git a/apps/meteor/client/views/admin/routes.tsx b/apps/meteor/client/views/admin/routes.tsx index f70df1625871..d244d5e2f19b 100644 --- a/apps/meteor/client/views/admin/routes.tsx +++ b/apps/meteor/client/views/admin/routes.tsx @@ -104,6 +104,10 @@ declare module '@rocket.chat/ui-contexts' { pathname: `/admin/subscription`; pattern: '/admin/subscription'; }; + 'admin-feature-preview': { + pathname: '/admin/feature-preview'; + pattern: '/admin/feature-preview'; + }; } } @@ -237,3 +241,8 @@ registerAdminRoute('/subscription', { name: 'subscription', component: lazy(() => import('./subscription/SubscriptionRoute')), }); + +registerAdminRoute('/feature-preview', { + name: 'admin-feature-preview', + component: lazy(() => import('./featurePreview/AdminFeaturePreviewRoute')), +}); diff --git a/apps/meteor/client/views/admin/sidebarItems.ts b/apps/meteor/client/views/admin/sidebarItems.ts index 013206d9e9a8..fc7d307396d4 100644 --- a/apps/meteor/client/views/admin/sidebarItems.ts +++ b/apps/meteor/client/views/admin/sidebarItems.ts @@ -1,3 +1,5 @@ +import { defaultFeaturesPreview } from '@rocket.chat/ui-client'; + import { hasPermission, hasAtLeastOnePermission, hasAllPermission } from '../../../app/authorization/client'; import { createSidebarItems } from '../../lib/createSidebarItems'; @@ -129,6 +131,12 @@ export const { icon: 'emoji', permissionGranted: (): boolean => hasPermission('manage-emoji'), }, + { + href: '/admin/feature-preview', + i18nLabel: 'Feature_preview', + icon: 'flask', + permissionGranted: () => defaultFeaturesPreview?.length > 0, + }, { href: '/admin/settings', i18nLabel: 'Settings', diff --git a/apps/meteor/public/images/featurePreview/enhanced-navigation.png b/apps/meteor/public/images/featurePreview/enhanced-navigation.png new file mode 100644 index 0000000000000000000000000000000000000000..4240326ba985d0a054ae5d9c8521b24c8d93e6f7 GIT binary patch literal 2372 zcmeHIYgCg*8lKz;k(*0VynsLp8%mX01@Ra$34#GB2w8)n2Lz6kXazzALMRv_YP;xG zVrfx?0*kHdhC)CtVh|D##7hAYg%TP_P1$fufB*?0CfSL{AKkOvo<04szxKyBGw<`h z^UgExH}gzEL^#D}&89T~0Gp8DKq>$zF&wv8TEKSeq4Rv$;nISm(*aoTVg3*yRQGuZ zBGRdp08rcKGzASbgB(T%puW)RWda5O%aM>k@?kbYDJ7;mXg7)%7}|_U^u0g_?-vIh z3PLLno>;U^yRy;Ip#U%U`gz?3Q9dbXM|jd~=gzm4M_kLikKsE!!V_rWmyy}L8oj)= zS2fb?Im$rG8QwM!!;_UE8Rx|HP0%OX2>m!4{!$M9@ zmzycKXS|vvx3jAFOuN;#LOx%@xz-bPQB~L4+B$H!?W8hJu;wTX4KMQ=yEwA+byHJQ z4Srntp0Hr<_>yuo%x4&B_O`IRa^*|1XD(Z^^k)!1hMgXbR43&u9)Lcv`iBcipXe%2 zq_vq)1Omaa`(22J@|`C&yL#jc-3GtCI}p2cuqKsjiPzA?P2zh4jxQVm;07eyMCq?+ zYV8fOwUa-ksVNIq0FcPLSd^mM+Od*DToGaEjy4EpBb~T5rBg*r>d@@<%gYepB7JF0 zqq_ZhTTbt4e99^Fl9eP{muC7SQ?As-T7ZUt1HXW7`egSV>XAs%dT2+~9d#BA(P*)j z(D0-Wc6F=Xq;Ez*19MWIbzS0osT7X6ozKk>&N3dh)U{&Re&fo8P%s&w0N~{VcrIKq z2x~}d4RQmV;DFu^gWmrCgjZEc@Ze_b(=Aoh-_d=XJZ8+v)lKA~z%BN~S86rpYMt?0u zFkC3)tSau`mnY25=B{g)dM3owSbf=Vw0-aZz2T~fTHkJ@F6pcLmqLRS&;Cv>BWR!I z+RPN!dq?ck6I|axSa+4|B7lNzG$S`NkbWu8%wj3c6P@vb)pL!5@#dmB^TW{?vN zBGfH=G3iH<==4p-aBGihHuu9{(zqJ-xB51NXv62_%8>>T@awGan@0K^3i((iN+xo%#ouHt&I7j7;gA~ zaM|kYft59-NVWnweEfy~obuR!X;>4?FtKhWk9LQc+ATc4!u|H0t|p=C4#)UkIs1b* zU~l>r;^|xj-Rs_fd+|eK`kzi4=TVAO6y`vwsAMd7!IrRlB4EwT%Irr}B_*-~AjVn(;{-)H)yq<^yYV&jM#%$9>QVh%U z%UJHItG`bwI}ZY}o0&klMYUn~qrAe2#ymoOtW#gr9Dz%HofNmdj`t8&#p7n_pOvuZ z=F?L2tj|bH_{0E*sl4L|c!c+jV` zeXy-WWIHdBNTLXs_UIBMDy?(d=pS%;{K~$(^7C(zfUTgQC0m#>rkYzG!&0srmo+zP z%uIJAf4!wl*sSe43silWOG&I~w3z|7=J<^(E=H1Jo*@0}lR+k4a4{Z+7t=?Z<-^16 z#HH**nNR$)vabV9KteLt5UV>qWh13{~`%a65CIDvwi8xxILa6 z!t*MO@WlMq>6uJgtPOPTCQBxzspEI!dI! CCsuy| literal 0 HcmV?d00001 diff --git a/apps/meteor/public/images/featurePreview/resizable-contextual-bar.png b/apps/meteor/public/images/featurePreview/resizable-contextual-bar.png new file mode 100644 index 0000000000000000000000000000000000000000..c36c7e44a29d8c27c9c035a77026f1cd7e7dabd0 GIT binary patch literal 4776 zcmb_gc|6o>+y4y{3PqAFw469i)`&`jifq|xQrRVB8`*};U@Ub)ksQe`Y7ApZSu&Ox z6)GY7))=y78T%}Z8PBitzUT9K&->SNp7Z=MGr#-3uj^jE_jP^0*KgviER2MAN$&yx zK-k3C;4%R4lELS<0({`NlI6W(@Mq^8;~Rkhu>a`K55(m1FUw#jB=EA)d7!N0z%1B+ zdYm&q2LKgGf?F;-0AMfN#NZqv6hfo;Jv`tM&cE!zND54gZ$Tjr8UJp7FxeF9e>=~- zNczd;?|U6ZGO+R3j65s?Iw<~pHX$#1*wnzw?C>E+k>1!?Q)OT2Rh}c~J?-;xh*DD@ z5&VuPfv6;!uDa`!Y;|D_5s9QkRjaLGpz021e>yNWI*E7UP9U*uPKlu$5l ze~mBdx$8HNP<@t@lk;O=yF-uBG)gm}vQ`FTX2=5oSi1PVK?_BPq3}?*Ii*IA>5n%v zbWfn2Z0%VeSS;40*OG6^x`g#gc6vG+0n4xqj%>2%a|E&SDoPm@8=~J!AF?cEymsTg zg9!IX{1QP(Ia9Y692SZ~j-v+Fzbsry_Do~5Q;7QVx)|1Hgr?kFWAI^!+ImZe`h7{@ z<7Wd?nvqU+hh0K`X#Te9Qv~+NQEfZlaS3p1E?Qj;@Lu62F^-=7@DAebv#>32$7(zZ z#2P$QKDTo&6i`vDH*Gffd5$i%t_F_vl8F?y%}h3Z8H@yM*BiosI8lh4P_(iF1@}}? zq{PzNEj#Cf+}E7=M~A1;!yU-VR(Iqja9E9a^KglbjG>o(CfIVWY-qIJ*IfOF9qsco zsP|zA0FZBI-ri@#KFBojJyDX#L`1fpMw(8}=y(;Qb50 ztG4g(e21#ii+lH)f6o-y6co%37_uw9=%rOG{I07yaBXcWTt!j*qfypbuNvD_ng%1S zswfOjww>h>)~7YAPcMAKJRN5mtgR)u*&%|zQM^a8U~`j4t7%8x1g0+hG$#bW$p^tB zc&WljyR{;5B?77{FJK2sZ+Y5Xbn=6bQF;65*X%HMlHJoVhw z6)82L1yy>U@X&1#ma6@IPERFLq98z_CBT>0j}WxM`2u5KK=^tyR#3-#w17MA|1nno zKD<)L2GDvPHBG2q=DbfuxLTun%p7zwTGyA<=9 zB!nyebHtGOAm~b6YDV#ihj{|_k6cGWtTxFs7vUX!*wNWgREa0gb-;1oeZ2iKt*DX@2Z)*70VGVg08F*ZA zN+mNp(=s7Jmf!Q?i^1xoFC8yoT1#hWss%)Q8AJ5+1%MCxP`1?Sl)meFbG2i$N3ZYy zP7t`h^XCM3EB)QYgZ=YwNe|}&eD~2#Z~og?)Df-6Nztk0Y_8`~07mCBDH(F1W8Bph#ys^|#42?=rT@YlU~u*~iG*si#l?3kX@Ir@UX9UT-FG>MBPYH$M)1rcwf_ z;mn;)0AK>};Xee7Ye)YOzvg2$uN+Y*A_Uwy0g-gp58g$BpH~COpPJh^Ieh5GDu!JXulYcLtS%E|89R1ose!2gV6*o1XuQdW zlBMFtWFVo>D8T~`o--ZUMT_o#V6D@lVOpcW-O*QU4kh*j>HHph>nY=I%_>z6m10y3;)SB_t2!g=fg5r4Cg)Ha6UgS$0${lJb;CW!A zg>Wj}CXM5UNb@eZ-C6$(Dwua((c)p%-L<=(4RojcV>}zLLeNMpX-^jyb^q5kgp9R8 z|5yEsawWp3DYK97@r$ZlS^QH*i7G@g@1|&U=R6-6Q@Iu)-~5ei{hY!ly=SXOkY)q+ zf#ytRq>^wQ9?;HgM+!I^Z(Vvb^c8*p=&(|UYmArxy)AKR=fXBSnmXi@vNg75awqhP zhlVzKXIZMp4Hip_339;X2g#odd21l^fk{FHI)dJ({@-}3!bAPT9gtb)?o%F}3kpFC8HXdb}#1X%B> zF8A`Zyq^jRmXwaIf6)NM15*goeIKRSRuO*H41K}}%=(Yl5%zPq_$5T^RKA>#6Brdj zGJi+T{=#AZL^QDv#SNuRKnClLp%H9{Q|O=&>bJxrNJly^x-S3!{hjDXYI|P|k6Y?S zp6tn+tNzo=<$t^ut!Hqk<0oZg(CbqCq(`pQm-sQ`w<>Lh@WIC7mvAZfQYdgsdAIHe zC8iT4t^9vh&FA@N^8Qcp0A&Ce%E(DKQN7gpVkSoip(`&hZ#LscdD7C_vX_h(1vCA` z8b@9?l}o2`k8sBLEpZ-u%$3<0f=-)Hf|_=ynp~@2U0tM!?{wY=-Umov%auzyRORFM z`S)-`O|bEEF3`eK%C7Hjs-#~WP_u2_{mPkQ^j9-7+gT{R)g(`%-3mOFw{z=ly`fbi z{qB1@DLG=Qiu5~h|HhxGV_4Ive3!ePP1Af(5y*$uTgOZhoGg=c87$9xg%P3|$U*M? z=X>5YZ0ZN|G!cgD(awmicwO9Dv`^nl1 zzjYT-L+eYT8PSo5+5)@fSFxM;O2cVM#iEOcKIf?8G3O<3kV^s3C1SZEnQ`{BY};A8}$L{)cZWe-He=7IuFnmhY#4 zY4E58i;gn|BRS3+r;6+SHcPc%%tvs7XD`vC?_eAskXhqi@US|;p8Cu(-kNgy~rVG>ghS%FC0N}9f?~Ks%GAz6J`Z%cVO}B zG04y@>b8#k=;z!%1hn-NM-L`XT9eg&nMqxp*7RR7oT3$9b4u=@sq`?pYiu|62LtEe z%mc7~s>k96X5&=9)5DSQm4rx_zJbV9Ro!gHS%&KD+~VuXk+#m1%{A39Yo-Bt%80P3 zq2VTDzf#=Rmdh&?bCCx)b*_Bg4-wI3l2pChar~jmn+7izL<}=qt?9DEhX7`ApQulH zMEj?4#;~_z$l3Lll0lC%>Vrf3=gSpgq(a-sPF?M*i6e<#oG7stWG;STlQSA38!4w~ z3fwm=Na;p^D=55k@_R@4!LT=E(c(nD&8r-6O_;~)0c9x82zM9b4Q1@Qgjqk8p)K@{ zcK3AGBaS(kU`DqS7yE$=&M+7`WhXH9jFNO9`v*QtIaJs+;+mMNJC&Z8+14tW6_(oX z(yMp>G?90}aC_5kKK5E+LFE1gZd^6s<@360Hi!Y%5J8nXe&u1I?-_5za#YY8N2io~ z)d6Pb9A<3nGbM^mLOZxeCnBdj&>VU~+1Mc>wzZnqD$ug>jHkb)X}j!B;NxhcUt~>v z(%iJEn2uq{z?DZ-4o!wy@AWID@3@mSA8wR2bf#TEmU@&Y3{wM7g6EWRrwA4qQ>PUk z#mD8H|03d$wnSxHxWE;p>Ncycy(|wRkQ)4Z8pLFPlU0T4+8T_bVCjIpvpmQe=!?D- z6hgZFIu&I%SkgPKEF8dj#lON z(7`duN{&Q@~nOMl(JXj*jar!?fu3+B&+@XnbY{$`_o+Q$CoF`g?Fl|#K^V#e7dx4>c9L#(ge z9RZ?he#Djbs<~Ae%4@Vry)%dBj=fmz4EWB5FSq<4?*_=p%jYiGL@lWxq96zDI2uw( z%zGJhR(P=ZMBc=HN^Sx13>@y@XoFWtaipVNh#B;d?L7F8 z6w2Jvt+Ti35do9N>Jqh!ewVXbv?v3~a~PY^VI#70y~7uhFuj{T2(>1Z}n9=S~tg zag~^B{YLWWt@Rd~Tn4Oex2nVkP$KB7x(Xx1wlOMix@6f)@|yvh(puJ?>s^t zrF5E9*fYD3k)B@buYR(O7BN=6*r^bo%Eu2@Y2+IsQ8j4oA*F7yzy!hV^*~owCtKxp a2K(3rHj$^VY%~U(889)lFep3k9Q`kU29J{f literal 0 HcmV?d00001 diff --git a/apps/meteor/public/images/featurePreview/timestamp.png b/apps/meteor/public/images/featurePreview/timestamp.png new file mode 100644 index 0000000000000000000000000000000000000000..7573f97db55b73e2d880af67e6705e3c4a2040c7 GIT binary patch literal 51432 zcmY&I;+-*YJcs>o%A*9CD*w zN8@p~9UFmUL=UF0QoDG?@49d!Nib-d(z9o%!x8dHFgHBma z;FAdYG|=i3(lb%mv0XS{G%RgGwlC0G(?ag$K}WC zMDG=9@0G`~6^a=6B`L4#ab&t}ChPwl85V{Xo1yhIBXYCzjdYj2D|& zuvLN}&X!r{32CJ|wcr$e*wx;B!(V`SW>hv21aq9N4$?uqmnkjcYSjfz?siuRy+Z-~pnMmF}bi{2MnX53H^ZZyt5^F7K<_zh~a^U!QWNzKK zK}YL~$PGB~pi0{MzjH{cjOwx%@~*^UhN-HbJ|_n?Ix;oaKP8r29dE%<+@SLW^Zl(h z+d*pei8t4OWo%FK17xmNIf|S*QshJf>Hp$%7^V<%Ka;6d`2pT_dfrg3Vxn1mgMJ5W zX*1DSFVEVnq%^}JFU~*DHbk$c(3)a#x2jp#$M0RYQgx+nq%$UO;9v|efVYONtva2Y zI`2}f>~@}5r7pVFG9so~qsNkrvPQG^sm!ILFp|O?phUFvXMZRYe5m(DzzLlFQkx*jT-z*@iWRQ=9_n9hVD1T1ysPgD z5M8p~nFKC5`Zeg`S`a6O*oIM)%&6e_D0%hV&lVrlF<0-nwmB#OUjz@Z4HrP)sl=DD z8%`HcePzsrDJ)bZkY(pSL^ES;IUG+TCe(8)qY}{mWnsU_6HGKLVTLGiG zjKipn)x;knxiZ<;9@Een3e%*r?wbs_G7b4~XyItAHbVVQHomW(5`kqcJk6jU)fS@ewU%1>cOg-kuj`+mWwGRphz-T2wWQZ7@e_``dv43CCikc-McrC+&y$a+lEr8U9Ux9Czq+H z53mSTAL&86%N(lGcVr%2-g#QtB$*ymVU0cv$vxEok(<9F){WgrOkV5%)giKhTEr*W zbQ=Sey7DQNv-=O9!V;0mZz&P!k<78P=s5c9%8EkP$iP6^fX?dJ%+|yI#0wgR2t5D^ zpn=D|!=9qDL})Rwr|Y+-Ha6kONsSfl6fTu{fRAfZ@x8>kXuQsdAC__O_;OjAKa^hS z3lOJ$VvbEO274{KPt!<;7UnuFBqqr5%VtO5Psc){ek^E#Z+?7aIAe9w{K8~gDF%io zt`h4(C%D1;4mb^YDr%5PJ7a=yg+Y(`XkD?Ok=7-?*U&Weuk`1!sC_?~mpRE##htP@ z1Slqgu6q%XHg8{Z)YLN;J1u?8-d8iPbbjPWmv;2ciPO zxFyW9Oi$o~J0SgNVTv|gFQefNj0Z?-DO27l$R;8A0kdrhZ@jodFOaTY4oW{p{%?-2 zf@`aC(9I`$7jHLAx-4SDH*ygtU|wrL8sHv^U2hM`FQ`6O?_0zXVoKsE*4e>NZM941 zkRn^Dz-LavhV5rX{;J5)YSRE_ta(eB%n9azFZgMBIvO3@ z{M^WK5)$W1MH^?GXd2(5mCQQY5InD;=>^9>$4(aGPn(XCieF%7w=0Y_sC^$+&H)E3 z${-m;)xOf)yT3)aSw8&Jxa(qt&~7=Rcet~v8u?%^+IY*5lZ?9hqT!QXGJv36oK4@W zM(q!}b68A&cxA@O+1XT1|6{5DGu`8LR@GZvX~91;run{BOQd{c84~7FZNC;iLk|ix zh}ZVFm2JWI>0W>z0~B*fKu@GQi(5srs&l1H0jb?G&8&_;eK@l4nMN)fFDzt6P6lV! z5tAZeS;e_ZiV}Zt?sci`=v==>@ZIF;6?{#k9-(w{V<8vp2eTs1@iAdny+|3W;-d6B z?<?x{F2A zIJ^M|GSi32N7sTA2$umDqYa9|cdoB-C2k+mkE-*V9CHlTA8euVG_k&BRjN|V!A^2@ zE1LdO$LEaVM5hxAC&T-PwFjGqEF@{@b~8!g*Ov&Uo=s0kT)ngr83&J|{d(J3B2PPH zAA$?B|Ez94pG=Jm(}(YdEbOY%0{E))GsdDU3doeTgt6*n7~*jQv)_)nmBU1B4w9uI zT7MXZn~$Md4;*!!HNR2GQIVc2YLqX0FD2o}D5J~v+!*12zwe(z(TT*_I%vijSVp-OQg9LS;jD%%EZ+0bmm{;}Bl%cT^@> zpWKXV)`-76>|p~<&RdIh(K~b!R0u8P_Q1`seP%P+F~>WrH>cI->A_16y1PwJFDZ*x zS#Bn@N?#M6r?F;D%nPO3eph!Smk1{3zg@$M9S5=a*Bz%6_kiP}32H*dF7TVjLJXNI zkur61BpmOS*+qx-L;tg=lH@-dke9%TetR5FFFtO({it)K8!{uK#lha1dtR%*?=M&B zqM%(=%LW+BP6~Ss`Kv2&Au5Ud&0JJRVkmZmY>i(#L*VL?Ks?n#0&d%1UqElT6S3Ar z>vBRU@Vkra-|>@K14gw|St@P~CdRFcK?%`3f!#J<^zkwgQoCx>CHD2nq{aOuljT(O z+1n`Ly$g(%t51hci*BnBz&eGn7p@E%-Xrt6VeF9Z_?Jr9OXBHbLnn@{*&CeaYR!fL z6L510i>HyA=@Cop5@NWzp3V=MCMm)ewyHeFd5ih2AApw{Pv|K+yoSg7FyJRa+vV@Z>R@S)NT>5(Jj)3CY>m0^%Arg0rNep4 zGwg~g3P38`Bq-;@%`Tk$dCy^Po0taJasZvCrLWz^ns zu06Rd``TQ^!q+G%*di*6O^s_3!>H+`6o@+V(T1zS6!f@M-~Y|_8rIfiX1uJCJ0a$k zy&h6!J%26arxIJ#>yHlU-pRqlMl-vKnwf7fE!(pTH9g)SsHe!L_xF4TF?t5y$S&iw z?+9^z;II}rnGmXD#=J}lMl4B<#Td?X6=WyWwqMiveY79x|A?Czy`;0xg!lg+#!*FG zh(VtudQHSpGXvPg^O=-E#F^)Rd!=?^XICvv`C=Ar+&|f_5zcP^w6j+_t^8T>*+nLP zv=<%2?unR7!BG>HDTj#0z_G6i>u%iH&VgV8q4yXYW%mcgD4MUY24Zo`;Z4C}3#MQQ zxllC`LBdkLD{Efp#NbrS#-f9d33bGV3foUG8FIz?@*SG&e93gtNen`pDdZBd$T3~5AtiobAp5{)w%hEy==^wm9RMnYujj0@Yd%l=HndNUrYwh;>>D= zUBOgz2PJt#MK^~Md^m9m5eznPycMx2an`zAMt=I-?*^W^DYUEHEvVB6! zD#Hki0Kx8R0JXoxtf|uHcxz{s4V2x(3%ST|oX&TXFiwkP-zJ9nwLw6zQFa%m zTyr``obU!1u_$Ghs`aBo(p2OvXh-cl#CHKmco%ZewKP8j{i6yd(A&CJl)h>8A=XD(ii z?2{i7DCz0_1=z&y=b*zOv|v0YeK%OGWI&(Ais&Y_C~~++=6E9{(%;`-n`NA7ZL=4n7Ggws6sPGLpIfNGHsr$qz<*~3 zE)Vk^dVd~8DJ|iO(&WH1Lfkf028aE)J!(Gc;kR^V>%2-6=?uNoulJxR`64JBdEQM_ z7FIEA2G#t8HtiidT{~<8rSG);c%h+!AE{J#ZHx&flKpbMg+MjUPXf(^V?+r2(kF2@ z1;#<2Gcj8RJE+AvmF`Y=`MT0IdgzlkmC4%ECaXnxo)zPYz0$baT1;LomGVpr2nMW# z=!VAjNMigGOZSk=s)!nn%^z|Pu#$!LeuqW5DiPTi`6ID6!;H-HIjJ!LK8E6vJAAT% z7ot!+_AY61akY$~HQqrpx^l>D0oXr7NB=#r$z&Jb<|H#d#a}vlB16sK8_`4z6z@ND zTSXqEt1=L>H;6Bu$eOe+SHH+kB0$_wXv0tE1Y|P()kXbT7SgGh3#j_au;pXAX!NV3 zt!{kO&q+-psi2y>kaF_SU{vjwRsh`TFA#vDfaH=BTMvBomB%&rNPdrphc&LXU`ORk zMWZvnVVaF%3bTMSKh>vXJ^FgFqG)EhkI2Ruef)MG>E|z^pp3B-HkM%J8stV4!WMY2 z5s{b_W3e*kY8#^bw2K;MtpL7$rI-C$7k#oe$W^=RHaXVc*ou&baUwBhS_I6j z7sE$i8taeCgSCPeR)5+P)p@gbW-urVXVeS8GHKLbEx{El@6oK8b1@C__}RN?bZar~ z2V)Wq-V&R}-BO|Y{U4&t2q(UnYxW7f`-q`{5#XBlM47fS;SrjX`&vV z3YBQ>wYkmHeh6UwtYE010L!@N{Rux!6kppU&l)Ar0HBSl?dVS00%ViI&(em9{ zSwhFUwi3|~ajlR}pdU%r%E3_PuYG!t!bu0$yY$;Qt5sP{%^^Ad2Y{i#NF#lWk)b~! z{$|f0pA~7STNRi>A@k!sAX@q&blJ_ePEHc%VCPCFlg3n)slty&5a==*n_Y4fAwQoU z!c!m?!Jgz;6)%eiVEwwAyjL`G$Sak{*g|cuVw}Ne8f=6%1R&dM#45jmM+XF7bv)h> zSrJ_qDy4F_>RFgL12L6DU91egMrx}|`|Q4tcwl@uDzg14WpW+t9ty@!u~6!tBz*}S z0CLi(4(RT#sj4jb`cU^v=s#phFb7uB`rHLxgV{_W&0}D>5w6uRUpmsau&O`{@U$pM zQVr-xi%&JmyI>&=&eK;~F1J$pv73lS7JS!S#PyZ9h(&jRlDe}myOxheo67$i7b$2?QJEz?h}Bdg2e3xo;)8wOY;Osb{r-+K7x&Djgaj?Ucc% zvbcmKL(qW9UpDA|Bi}hHY}Myo0I)?tS$)v%q@o9F+|A6$$;r6r3vn#W2)l!JrV?h} z6g@M58-WG4Ju`kUZ0iF{OF437Lq|Ltv2i|=J7UI>PRF6J;DmLdC8%rds+L zU%3ci=KhA*ruZp3IA}fNn9@6P=kUgLjnQ|iO0PjqB0GYXsxTUM{zM}e6GOropdMF~)igZ1iDtABYP1@mJa}W&LAwA6{OH%fc+)~F~tp0(pS#z|P ztlX5s{w89^xL#_?ehL?Owus(QkHQn*vtOU%y@by+7h;W)G+F!n;|k5~`TJzF|1opq zxqJ-aQ&&8OdRR(`*T~1s*RPHFjqPk3m^Xr5k`k&z&s+6xyEp$c6>Wyw!*SGpMdh|O ztFkF3)OLMoBBOuEWY*bKh2%lwK@fZOcTJ4>Z!~sxhE%_z`7hLoMhcyKr2F!;>9o-{ zZBq@LY4J=#*{pTVFnL2yN)s6*XG}=|G__CPE^J3-tg{yrs$K0zVU@P5AX;)bQu21G zR5&DYInGK^wI$M%jGqPRC2J|EeJPul=MzLtPew#hdOas=fN{zd?j1<&%BiRu)N~Q! zO5z-3Kjso|N_IwP_!$@`jI<%e?mva1zp13_4hY4QCq3zCR3Too2X9Yhv3zg1CI%cW)*IOWt*rzm z<5;7F-5cV)FYs!F*p~8orb@MFA58Xvl$;`m&O!2?Q?%Ue^Ol`5#B4U3JnD%GDIisH zRL;5|PR2ZUYkP1S(y0p0;a-_?a9VtL`kpFcN>h9Z-+}scd&IohG5BRb?hrIasg0dc?@$eV;s|?mQaGE7b!QPua{x~9Nc#lSREPP7hk=H`qW8q7g7;EZ z>R;y@<$SCW8zx@-JeC;f*WMH!U!ng;>fzWnDWy1k_jvlkCs^vV2ZkOI{rIQI=lNa1 z-ZnmNa$dZ74K;^p_JxbOMnP5&;xe-wI@T0n&CfEgb|ol=?)n*4;3g#e+Js}mSVT`2 zBeg6iBjwH&gFcPozHpmn?~T@#<~lmo+34(~$uv4~TnlM(YZI`BzZ;l_ZVVH5muebd z*qQ`IkI*!VaVd)f%0&Sb(WfQFhL<5t%3}`3zmb*8*ZxtiT#)$!8$KP;H^)!N>+U+d zB9BkC9oFrs*Yybl%^3+AxbhVvVF7>`P4isC{R5!BR{vF0WoHSNS%^`I`obFNZqqb6 zo)wsJGt<#a>ou~#3h+NDLQaq98onruqN|G81d&w=griB6RJ zVf`C@o6c*#X;FR4^??Sz zvyd(|$Wp%NC1`UijICam`33A{?WG{i7&l{_ju!RF`&6f36SCEGz15tU!%@#xUN+(M z7n8^9^-n(8QcDm~qb?s_4oyLk3|)uQnUw|Rn8VdN`lD;?3QQLD|K@+Iq`5G9$*Zh^ z6fV)HzGfL8hwojYNuS;!Mm1yjjejL@%-F7f{Vget&TN^&lZ)BV;3n_ATdDU+{KQ`H zx9_{Y>tXSpzMF*xgju=DC{d2BJFGYHMp+Lx+Fl$Si1YZNrbKiD&r)yT z!XzD<>QOyn%)rA zJaP^r^AAE8)+wu#K#2vooZ2apHD+@L5!8Bp$!%sm=@k|G$0u&<2ONKop#Gu;xa*VLZ5rrG&U&Vr0FeG|3#hs?Qu9bA$JWj?|@3`N`Rh ztAo~}ebOzOW^jU?H?1v|#nw;vTNKq0MshySFPN0aV)i_Sin>wT`@)c9IRP9i{}Fwp zg!`y#6hO*B$_)yMh8z^t{Cl^Yx(;KP=%K&vc#VP*;FKQ}L$guupnYmvSQER`(u@8f%i&7aq(7W0|VaXe3vf=>5|$^T|Yln zyQ;lV8z_Iy$p@e7fmp!nr}^yl%zv?ZB*oJM;30wnA0a~{O_m670JDUgap7?mMR81^ zzUU^Fg_~@bkj-RoX?A)$X1~G-AFKQsNjj6`b7Z3GM*A3BJ@`{g<_$dcXv|Tz?e0XR z=g*)6uZUN*V`X9k(C=0ss`Bl})+RZOT$&KUx|sT(K}!|MHXDTFy=Z(<64rMmswJKEW+ zyfThK`$0yr|Ba*1KK4t99gd}b>3nupKiPr16vA;ps<(B8u|7?v$<&m+26iTcCuQB( zJqnGaS9!$IL_};l>%>*77{!BPA1*5i)|ES4b1|F;h8=RttfXz`yaJbwMI%g>p*l(8 z2n2pp7-lEpvfS+u^R&ko29;TwwfQ!ifxX7rX~<^t=I&p3=y&gpBdfAaW57jU;w~y(b!?9iUiN$EJ8#sA1|#gy`0%)+<-^U&aWR z_wBy!+RfjZf~+O%6hQ->-a@F#lApm?@NzG#bgrrIw)(J$+a*vxlv?QS&epV@v1(Fo zF)~Hoy@5Pi{xDk62jb=@xX#Wz&j0~J7Ft(m8t7c=s>_TJJDfw6|2ak zc7-SU>%=gLO*@5UgjvaVB~_B3Y2$&1SdlhbU41EN#!Z@ew$b~B`4wE>Fm9yN;B%F{ zX#zZ+Y(C17JS*oZ8UARuIw8aYdts69|7}~Wx3;`wJGKWQQt|FfdGbVXieho;T(cxqVqeYl6$+9&!@^CgAyeAl)ZI9e78J{%jh!; z{QR2v33QF_CemN8G!4yMK{O@^N*z*;Dy4h5Isk3rG(AzpZ)+Fx@PoW`!e-W5!G}8> zE7t^m#Ef`!Sz%4x!z+o^@xv$rnOO88I4d{Td7vdHfbk?}9<5izEq69rzH#VLVkcV$ z(R%^F4W%AePHa1EI>vY{1u04@xp#4ndUet~ac1@+8RJ{Sa-Oo;KB>Zg5h8-puK|!J zX4fmD$h;U|T<=pMztgTJS&R2$S!2lAU_{cv({rTFbt zPk7-Kqc%$xm28iVO+9!owjJrJeXSUp8UNt(bOl0A-kW2 zzW|LifSI~i{e5k6aBbTPHHZ*CDr?tZ=fQrk4FOdbzOIjev1xJ-gLo!i0yD`072$~) z2J7!~!swOeHX7VwfKh6yG94e8mmH5(D45dJ{i1eG_PGlSf&{+J&b)ygmJe)o7 zvhpmRDTZ$CMcvl;!4}Y6$2j1JmJqf_XmmPlWO5fh_sywriD`($z zL2?=my7a8f5J#7BR7klmdjwHR$_xby5~a!WReT`7XuC7NQb_x< z$AayK5zezCb1a$vT$0hRk+;XcE7n{)-Sb&ey~er15BeT&i)WsXxqqR@HhO$JARaZM7)-RUjn*);p|=gzVAc{RP4GXCLLMoDn63EVwXlL??&|MxcQ@(j&{2LH74~rGERcUJZ!ZzyPnp474~+Qg}{_c`@F3-_URcNt$06f z3N9oX-qZHRlhOSCE}(Dn?tQW-=l3{?^dNLFV>y$1PyKoM%YbhH?c=T@?5EylFW8JQ z9)>y6g$F&BHgdv;!FmT930owFaXC2N5_(!_W6fyeOjh2}N)}(ilKDIfj_P6FeJ=sp z*@P_(p5~xR>L6tpEj(c-aII5VMV&xj6RLZIMs0ImB{fszgnlngq_G|!Rkd{7R%O>p zEh86t`MqfjrpkV>h6|y&aEs$=i_>HeXwb>-s;gAv>pu~v(i1xVaqQ_6N66|>`0LAg zb2^UTYS>X4mX*;_FVge3vixgXVmvhX0%&fv4Wugpn9)zzC6zebwAje-l*f3Jpx z6PVohg~JXYdcgA!pvjWNP2%=Y5BslRt1bkj3dgf}9R0wu0-l7_Xb% z2Bc71lN=QjX+8N91u?`;97SYwV0uf^2fsL zQlXJc?%5g2jt1Lu*4aMeUS0ksfQfSFZ;M^$$&tW9_SgK4ds^#ObM;{|S^ zW6(AaOn*@qPhW?kL^eVGz5*TiOe2S!R3&1wSYoc$Sx^C(k~;At(fO35kl^q_XL7R9 zmv_Vmx5tpvL4{}N4MvexmLBeyHhZ=!711!rC1)Hpln{cb+uhIh+vyIsQ$*6gTh^wa z-%4)nV_cZW+A2LJ&TTTwMGl$Y_n}M2kY?ZQa|TeLPb9{;tnw&&7bJCJ_&IGNy=P_} zGGGbM*}E~mcyJK1P=Yi(>qQ0;b}xS2yNLrbCt%?IrM9~zoFBVLfXw}H^ML=KrGu^LQ-)y*>!~Ulc z>>Oo3FCF0HqvRx#^m75%2SJ6jj>o3Uu*m$t{=nBixeN=6l7A3A(SDOC7vPlM9Ck1_u6z7IW*Q#F;q+T@(}k^pk?NwWv+;tnTg^h?|v~#Q_oKicsp#g zh2?yhK6oX*e9ovItuo`wvFBfJyCI1-o#I(Fn-dOYm!U13gC%=uy9uJJD}OOw3xcca zL`3ganwuALB%5-IXpg=9zqLqDn#RSgyO2NM!o2X?NgffY@eMn~WBD5X6tX#D?_`1g zsm=_657JifgWe|mF~MfBjgNHsS-*=fHuU_@$&F6egU3cc(&X;~yL_dDHW>PDttV2L zLyt#{a};Ys{scpdpb-3Z=b2po<$e4y1vwvC;2OHIhT>wjamv5VjE1eY*4tlUsST;2 z@4HNs;1jsQ;`uT)3&?f%>dJ{%=eZbTE*D&4R`+woPJXyD_Jsu8V`VGQaM0>4oQ8z7 zr)hCS-xGDP{#sFMES4EXe<5O2=%U&Gp_IpZ&cLIyVp4jozz&uI2oRd>MTA~6R4)>U z4AYmVbNZyvm9|pWFCFbALm!RzOU0foGK4rxI@+#u6M`uVDREqs=_l1OjCzW=ciPpR z72;x$^Y9($b5qXS>v84lZ=PEFr+Cq>u%Y)5kkR=ag$ED}z=eldzVH1kmyUSAe}-;>73!RK>#(vw^TnGt{up#yAYLpC z5G3+`XN}GB==CXC%~-uhKmOO`guCnPwoq>^lo(Rr7z?l)4WD?>TKZ(X=* zWJNW%G~F_dyWK8~ET*cu6G%HUd|P5)J`Wv^$MJ@`D}^*OHIQh2H3+khF0%=*RwQlX z%_r7hU9kO3>VZfmJ&x{{C6`H;o`e{d2k)JnYKyyUutKT<9f&p@!2UddfqI^VZe2vN z*90>nkzHA&J;zB2YBR0sgF3)LbHO{tUSm2HtY(T!J9x!|TK^|Q$bf+*7`V5wBc5un z%b(IhBDfU#{{XhRVd4Su#0PE{umHYE)X5(+?=y37ZG*|Jcr@!q_U`&H#!D z9RBneOd_`G!<^?YB8WA8O)|8(QCcW%>h&dQfw;}&150R^KWj`dB=}WP6_>0VZB$fj zAz1&BAeM5olUN4ca8IfE=xaxBRw;-Jo5Hq-iU`J0ak#=PSEGJRUYr#V-hWbxMhd}Z zIkOdm+Nq+*5xd(YZTgkQVsHbB>AQnm^#yBsG3&idtZb_(3B(&y|K=_oI~qh)EDPMW znXY^C&Gs&vY%mqE$|OB=cKw#2nnhJzK4|J^Ac;Q`cFZ2FDQzhb$OekBYWbBAZ635J zod`))6-qnJab^y~#iryp<+qk1(B$(}1eYo*7&uLZ?FmDg;9E-8P2F)8yzEb&LeS&r zlD57WZBm%gR*TBfD^)l&5@M%CNJz?_x=&1+w3`Z9FEwgW;O|k5R1;Q(#u#&Y;e8I* z{Z&hFR#w{ea7)QONqbI;lmSFMlq9|V9@U#tZ}D(a#G6Qr^nK9U$G@X7%vNl zNr0kL_A+WocE;6nWQM|J7U#d?Vzc?vt0}W&)Y^Zg!N;1+U^ZFeTM=yC6xpB8o-zk| z!|UE(=H3e%8T9Es?F--1$p*JM#?<8O;~;-k@oACsYp#wD5DKQMEicBn@jifa4WI- zwU7l_3`&JlWkl?U@n7d^A(vbQ;WK9wFvSOB8A)52|0DqbU%Py>Bg^cx^f#LOKoF;2_8HF?4^Z>ctpwF! zN-4~*=KIaOaIrLo08!3Bf|pl9-B=qVXiLR%$$X9ICNNL5X{42Ywn$E`XuSk#^5=@{ zA$=DHNpUKYroyAi@pd+<4ukn4M)HdtDvIRw?!tNCtRPT&pvT7Soi+zm+S;`J@`5Ep ze?VgwP#uvMA07{qZsW1>Os7%>xAEjOe5fIVd$G3p0|)W5x#6YUWa7UwGkV_c>#1xo zgxd@TtQL+KqLWYNzn#dfTrPWKRf|VFcx2>f-uhvHbvjYcp+bPMf z!C}>j^2luQdagF1pr6OWx#XbW$Ftmr8W#K?#TmY&%F=6HUo-yD0;y&t26cXy&pL-n z(Da#IQ1opGVe>zjjDL4*tSR_n0peKu0O<)5&aQA?2p( zJwpjSH))F>aliPk29wU&e%?hT>NI-kyJ1&8kgW)fT$#i6OZNr!x4^Eu?1nK;;+DS1 z_7qVb>mAvm4=i#?63ln@S^lT-Jwz|nxIaBTLE%>D9fuCp$DA;^7*)E48hO&S>sKRb z1iyXzw_@Z&RMCe_F_NVr@E|R0M0B5;7fC3J*YUZs$&|p^pp2`Pya@+~7OQhsD`Qr4 z1=N6S`PjilY4z9V43ebPl3R2T*C=e+9EoRYY_Fv`aP1^LO7(;H&Vh7{7d-zR2 zoG=Z&_Avz(v%iMWkhIII%8*<2^hKczya?4u;nNHZ)Y#EVlWH_Ix00ayQDoK@`S6oS z>8yk4%4^|vm2MWA!}xEA9>(G;?%6l4j96-=$umT?hvbc~sR;Uj24QKlR^n1;94VkuLin{Ik>rSJIZm+-^xXiy7keu$oat0)b7>n3ZtsA;#qoMycHJ{^^5EKtvu z%3I?mQ;0M@ldrGOiZ-*I^6_IMOU?s_)j#6_DauW}cD8BD)z?FdY?Ve4Lhyz9JI=RF^NEs8+lUxeceY zTGkPYY zeTub6Ul(7fG{_%X{b2(>+^_`dChAdc?DiVW3gJ_q$~*1z)@RC(Wj9lD7+Yp*=VOT{ z$e1l28;%8Ls21>$@VLDuqcmt`GX1<@*~^m0qMxS1vpdCyHmF927pR3~w&!U7&?x`qzESAKJZ=~|9uQ(h-TigRr5nZ8Yl^-3p+NFj*v4H?e; zzV?*Xh;b`F#pA?buCx|&kXy-&>N3t6H$5DZym8CVsr>uNQ+ay%^J1d1q8U}z^R-d9 z1}xBl$2^+KXRZL`8idYPZBkfMpS(~1_ zT~uhoZpZ7w6?^-?4ctJDg}}JL#4pXudorV zFQj+-ySW1(RQWzzOnLE@rxX66g9@6>d~5XL-|3i7pyf)DufNfM!tj=GTd)V0a79V! z!ihYWt~8*4AC* zfv#sLu_Zx8KuU@lv8Nlii#$$)ez7pJC_;=?u0ZHXby~#G69UxncU>o z`Jn^NWo^Q!@ui9P8AMp81#j?n0(8CY4duryn8O<1g0=8g_F&qT_6<58@LP>f#(`Cw zVee4B2stMIR5j|S4Lx%014^L)(JSxA^3xRKM5sSdCkWI=Ff@eU?LR@eoSO?;fq(n9 z9Q)34Kdmqxwen&|j*U=eDz#V)K#dXQKgRml%j^zEu#$TpU3*<_dMAM_SQD$e)$sTx zX5agN7{Zakn zkq)yfW(M3cY%%~-8f7BXxN>{Y^>XF>t%cj%dqFY^}*QfKBahQfbacEK}ZN$sWpEu zSs$k8F{bNB99@o_yo)od=ZiU_Z$wZEgv_r^L5fQzdUSL&Y0u!vN?>GTz1XlnCaE8t zqH7Fq9d6;b`I792<&Sydu&ej`#TIcrq>kpEyz>Zv+iZ9V z3=HJGQ1U(Ye-rJEDvXt^k3r47s=^#Igf;4{lU&5j9XfH@YuqNB3qR&wOWwk)GlWz= z6+uACO?)yg$BZBeft7j4h73GDMSt46V^`p4O-PQQdph`_BBoRc9WZUlwJLFX{ zlqOVHs^GB}3)QWzeqzdFRqU55|3x}p|2#|V{Ftp*YZ#Q+G{*6ykmvU)nqr+@JvFyX z6Z7-&UU7dB&#@(^mX$Hsh{+VX?o6j=P3qa{_2siN%P{hYP%M@q9d~W|_nI-Lrjj~1 zXQuAtl32N!oOlcwm*L8>F*A!hEpi-}b?=UUpf_MMgCEO~yS52b{U&`A1y`E<3iG9% z-~YN0n8s)r~uS@eASju|Ag413&-dkoZ|nio8Zj5gi-*pubh3g1q;0^Mrq& z54W@*wMdJ+EH!?a;xfA20~^TPkWE!P_m#08Ery-2+Rtl3k!E6nnOLXI)pvKGCBwvu zSXs8;Mh2|pnKB}mveEv@GFRBAEK>!4&vq}jK=jbn zv}4;+$m5P~lvz>4M>P4t7Ve)^{gVwUf{pLU>)_avOh-QKm+W_Ra=!n=*IRJa)ivw3 zXmBSu1ef6M8X&ksaDvOi-CcvbYjC$ka1ZY8?(VSAyWUUsz5BLy&R>{wwiwIzMeTe((wM205Ctm7J;tK<_0!%AQh(IJif*d~2e(#HE z=yk5|5L0(5Hq5YbeLiS{wE8+o=a&=GbSaXyZ#IKUZk6SweG+@w@)*>LRBR7*5LTxh`9fbF0V zEbH?X{Gm(N$wwXz1>YLZn>u^hC2=KM&J z2GZrCPOC&T8nna+U$;>Fi~4>P z&A8!{kRH$&a3ZTBEpD4GgO#y9^+>y*Ji3p1i1X(IH_yPUrI5Y?jb~MUx3tBLbNR{b z&iFVdFl(c}dDNduLEgL9)`M^@N!~>TQUA25&^ePX(si{HnFFs10SSXPR3>Pj3NB(Q z^26@qd~4ak5Z_21e-wszNkFxidL1jt`=2($)s^PEg7jM_tS|# z)QeX8na9`bocn5G5ifBM35zpJ9q)kX3za6alrO)(d^k@W=;`P-6F5F>zK+DUZeD&Y ze;<>C#x!*IC$NOQ8C=xvB~X~6C3k%r$mu>)oo$_VoNmF6LzJ)hz6)8Gk*c}*?zes% zOUA75&^&mkas{3=Wlh4Kx^jvT|5P-z^dciItF^N(pP=*qR$Y?o!8CPcHDuYE3m*3r z*d*|@GUme6EW%GE$h@F9ZTa?##cXA{OuRM2JAH5-3Nr%4LY? zM?Zzan@s77hq`^de;F%>d>$^6^~r^@IZ9#F(KblK(($|hAxCUvnf|LmpM`8Y>*{8= z?215}Fce2RDr3uFludQdn7q&-dxvh+wO<`}G6v3KkK2EKmcbtqyNiZhQ;mPnMDs)} zWcPPrP%!@Fyum(soXOTMfpN&Aat~%?ZE(+zz_phi#jCW^9u;SnkiGVGNrDe@_n>S0 zbDP1K?5q$pvvK{vCbWOLyI33s&S*bSr)&d%eyOxEMNRY>Uem|#+}lzsIK7k zKH{u$a&%rv zPKr!B_no0@T=`tTy!7pSMj0rbX6bIlI9YfhP%SPrNmtvW$ObrpbkW7`Tnm3z19}gNqhWfYXqoS(6^NSLfM%3LA z$%YhQ0VfS4HZxVyovy%A-S)$KPuB`$7qJz5^?>?cV21WD#S{dADUj z26f<1p{20I$vUr$mj?*Q%WA9%M6__?=oFJqz@h#aWN1r$OV1tS&Yw%hj+T|!*mj-IpM()Isc75 zj;J4~r|@PJge-@_@WLq0VY|Erg@ieKW1NUEs52K%63d^n6!$b!73UtIml{X;_T(XM zFE(!BA?8^%$b;3%e(&X?EF^G_$E4a()c19es9iN#;O7}SlR^fCY5oh#U_BaK6307; zu(u`Q`jYLiy**)?{E(D-wtVS+Rvd>35pi`fRErV1{nzN}pu!X5sj}eFOVO8)&PX=J z3nFg(H^I&S7)a#UG)b|z@e>QWQUFbP?BQVNuQ>o~AT|@aXErJ6p^Igp()eeDUvm4j zhO^xu9nzz(F0%^|i$e>Pgq!7oI}|d%i8AGMGnnm!P=;5pALYJ4P!M4{$O|D&3`w>2 zHw-xlRD{Y>3Wd@m>ktSy)U)z)7Du70+Up+$k6N=)@5~Faa8_+WJ=4qEwlMHU&nERc zuu+lEy1!;m0o&N#Sv&2=2@G$B2Wkk-<*sF-=r-LBixuJ2l8kmHv{ZC37n!e!o0yyw zCIVvpGCNED!#Kk0{x%$HNhU|bfHtq>mIvu_t=ZR>Avwg}u4dqU?F>Hk;goZTn&*De#FSCK|P`b@{#9b3kqr+WR$C zo?@>`+}#Fo;A75`=Xi? znvM>kBI(tAH~0q!<{u5pP@+fpO&k?pm_F!Ln!@i2+6L)~koZgIeu_6`YAeeFkJU+( zSSTics=r+ywxcf$O$H07NLBsb`7zwQLU#OVqr=IP!$%Z{jqfS|_Pybnr}FtGAWCFMQ{#?X{j7l1MqkQ{ zP`W=Y)`@Q2y~nGoiFzrt;?sX7x6tN z!fK|8AGNuVM30FKh#UVTEGWtFt@tVnfARdaiDS7I*@{N(!|Y)EU*na-aC}D?A^+$g z(~hg_S+>hU=rtcLJ(LiR<=9~qPT1mop4qSc6q*=nm_9w@m5;h6*tsee!`6wihc!RR z%Rgl&0iuZMo2L2)z{itlo-@k z!(Q;o9e;{rCK8(1pv>}f-%i}MB2hZe4Q@x9IA?3rf66U#nPR9^?~+|yjIZ$+-ef)U z3(E%xwZ(s4$V4q}P7Rmt+B@({v(c?EVJ@m*{t34v_9A5iDpy=;El^%wlZUE$A?q^; z_nVv|{g#v(e}cX%^xPW9A%^F#L;_jL+l|O_Q{8pxgoJb?tk&Y3AD;CgzhXJs?@(1Z zl7#4VGPyS^Lg33piHxI8j(Lxlzh^8@{q*sON&W_)LY~i~RH$lv*VN3E%eoOd+P#s^ z!GzNI^>b!OJbEu{ChTm)+wX4#2ipuKPJ~^i-we$}90Cle4H)oV(Nmee)_l zFjNRqnM2HojFXF=u!GuGY|&5+#kd)5nwXOQeu}|whOIvG_4v4EdeFOCkTEwZ|8LY? zB&xKKfRA?{F}6IRcr~p8Pe4*My+a5qv}*s0j3@!^;^b6W;_VNMPjiSvpr_+NC-_ZX zQ^hE5$$h6HXsT5CDYso~mD~^&iPPXvGa6X!QIxK>o%SdIY2IvOaqq8(mzkFzyTTc{?|0_WuUs4))|#(-C19WI zCHLL*VdA;PK3P>KH97!~2CdB35p>xbl9V^@zcZdv3SpzyJoI?2*25 z9}BKWxfh)JUPh?*U(M!9wZPlh6dmEfpjsc$|L319EQr8!G_%V}l3yra6E{Ho3FMSc zF~PBQMK0wjZ`S|-l&`89T}HV$9jmM1YaVR{hI{5vWlfstH7!1gA0x$}wicOk{fR2c zZoeU2;ZWoB=X6Zf&m7&slgGovWmPw2O=5g<6{5d09lHziq6xH1<>6i!o`dRa_O1;A z|62`SDGrwYis1C3l@Zpwft|a5B|TOI=61jlYz4gLkych8H<61Hcf`*kvC^G3IBnET zxcj`iP%mgOCBx7oveW;aWsqz6q#8JXE2?rJouvffqGX~zlSut7i|CPexQN_Rfx>N8 zMVCw}!y3N1KC%J5K9QtI@|UW8r6!8>Or*mZCa8uv-K|`FT%2q$GX0=*w6hFkrlvdtIh%6^F-70N!XYqJ=LJ}ym6yNH7zV>Q^lYPG1mFD zb-a*~tTTc(DRSwk9EHf}nqq7%BjHzC-i*SNyH-4UtmV#b0^Kh$E@^4|wds1TB#Q;& zm!e~U(hT#VOK5VKsh?iip7z&l)__I#Bjdg&=Jjob){X!Cg9lEQ+@O_@`Hy2Rg8m79 zV<3c0;EO*{AC|{@0U|@CU9a5|89dD>aYBGirU1lZb9K} zy5Vwi)ZEDQ9+y{uu^YWw*g1g_UzW@@9nW;CMxG(AZQ=uX1KD(NwE944;QYDK< zDp*d|Ky~4Y@LYpR6GUKCZyi*Tpq&mF-)(a2opqA*Q_$X^Q&UvA`noJm)IPB?7AO7L z+uFIRhS4N-xT;~?vFm#FCWVhSRX;o=jJ1C+y^yeAW*C?I^&5?u%xaxYkTda)m)}c_ z$Ky@%#nVES&RB`>`NP&T2r0F-OMC5hHCLlXufub^{r@W;m^j`G_-z|K!Y#F1&Q@0c zFZ;mhUi*@A7tGY=?$=ecxgkt(DY-JLJT``VL3Y2jKb+5s3jJAc@>zIj1Joa%+#a}1 zJaM(SoGyTc8F8O{96R4b##|cGc^b$2KB2FWImC_kHo0qN1jRk^(1U&d7&_IsFzj9_ z=+UBtyhO5@CwRu6F$a8GG=`Im$u9LG?yOceU;}BHe+%x?9e2xMRGW(}#2luDwNoXi z4zrm*`)Gm|)D45i_pdYE$d9#}SrEI#6QgXX7b6sP*$0Q5emffpa2{iQQ%%186e+oa zm;H_@8mdUHl*p~y8prp*`8*x#*SfV`ulxURO+}-UDo%dBgLm-~=Uw(j$7}@%+!O~{@61M*P!tjMY*e0UZ zhjV-wGJlk~_jmOBi2p9n*m?chKpas>+miZS=tT)5Kz?1(QV9I4Dm|Xl4+G76Zb1Wn z;6T+(Z2vUj>-~~ImMX-RV`{LRrEZwEKRDBJvf)y0bQ#rXFdp1DAhU z28@2DS38cA#s9R8$s`}4tL5nVQ$!10hFR}XE-u&GxB@DOAI`nypcsRn!}%L-Zl$PS z22Wq8=;_}SERcB*bD1U+9mtjX614c#`dqif@qfVcp+JTA;#FTUg~M-`cEiSZKP3YXdC6aSv_Dh?y^$^H)^E-Ax+2!(^GmXO^ zhD3J!9a_-Jg%tbaG>FQM7Dq~M6@Jz*n8SWJ(P7*)c2aNtcu~OSy4Lx-!V8f_0jz(W zUw*D+ZnE3tYTNYIMx?#n>S1;n^m6snrs|$*GM|jX`K-EvbK?C_)o`#ABC98)dODWN zzSm%Uc)sqG{%f?M&g&xE>D~LK>0EC;1)({X{>QVM-SHlDjd{6ZGSmy^p58O~J|t5Y zE=|g(VMT4DkWE6vnvV*63)ys<501xb47w7g(Oeg%U`LM#E{LAv==X_mVV(_1Kpm0d zEEt`S1b#Lg;rXzXPGI0hU#UeGR^J+MY2RQ>L0a_@NKq>%%b&n3CGA>^HYcFUu%VW# zzw4=gYA1HsS+Q3UNWvF1BJ)Aqh+1bLBnT-P?0uTIGLz1+mD^QSjy;FMkW91?nx6Rw z*B6SCO5$KN<3bAvhQg4;*!B`?XdA-D87mA(bMdH;<%)Zx$?+ap%*0|unfw4b7;q0^ zHO`i*pGz%7b?2L*$6SJ{)-gO_*~BAA(8Z==j0DPILj-c)SL(EQ!@Rv&DqwAF5&Xk< zebzls7q$p2d{rNBZVYnH8e9EKKJHp<6TXpW+jl*^Zjo&HUVz3*_!~@FLVQ7)HP2iD z-a?#May?_2P^&Rb!_ZxBcBya>HvwKfTmh|qyCCD@e_(wA5v!i|EU1-NFT31RxoSur zIw+e;%bxtMjd1GO0NS5g%_tHu#-ma!@WtO_gyu2i5mx`$uqz6>6#g=qZjUD=ZxZ<9 zBKbN3V^E1TCpwzD_;!`gJaJNvm5CeEWucJc&dG9F@?XDAPU}rFz&BL{-oKDo@J8JU z^h+SeAA(58nPs)9L?N4NFviEHny)11HX^ZR0)80B>FBCw$NXEJ-$%d}Nxsl1dG}Q( z&-+f~LH`*(c^+}syY91~-%h`@)9aJ0DB;96{~}L&i%GD*IC?NtX)sq{b|$s8ixGb2 z=XIYsW^~D> zY4qHUP{p{Hg*t5jSBvr`e}BDG#2HQ+z2=7f0*sk0$B)BaB55zn;{9ld8lH{Ui)DX- ze4O;mauo;!`ssJb9tnt^LI}1%2&mit5dcJNNCE+5@#6X&u0R6-9~Sl2hWm1j&r6c< zCpMT2Bg9g)#=n=sj(PlHoV{_lm?lsA#bcO1jUb1alfIoInnY#@%05Ef^MR+Nv5zYT zxiJ^8qt~D@DLN{L|G@u)X6J)%*Wj*?k{aqBw8!R0cV~_+D!~4~?Em{2VPn=Z_#Cry3Xi&oG-tHxlRO z67qN3j39zQk+ET;bO)dOZlN-MHE5GFA;WblptLbnG+pC z?lG=fMeYhoC0ezgrcXdMpj~5xg46g1X+MjsoTe>h2^U)pJmBVpSd>*Q28CKGr12$iSoHEY903-~ z$MU@Dg_X+4E)Wg*Q!dgEn}y( zmLK0Abf;HLNK@cRpQ%nu0vgFJLtli!{sMJ+{I-jTPD&Rl^Jf0Iwha$sBY50DY#nIwb$mpRpW8u*7SLkq3;tHdZklLdj;nV32 z6fK1rV58WPg@qu~R zLuk{wR_W)xdmS7~8~VFN`qbICNPrIrreBRH6NoG1HFUcjMsmWDVL=Q#3A=)AZ{>|vv-jjmv0|Vq--P8=PwJIb@t!Qx!l>FKLhe={ zknSvrhu5O2V>Nwc`I~{6dPgf|?_nL0jf-uu_jzGWZDk3R6RqKzBZMP~BoL;R$kulV z-|W1d6`RyV`LRzSVGnd?K$c%(5d31qv!my=MA$42Scm`LHUhd3r4MPlDr6V8gwTSI zc!0gi?P3lok=E0SRC#hzW6IiDGmOZT2tR_9F#JDJDr4@6e zHFm0wi24txLZcg##uMa#5-E!Rq3Dm`mQb(GWEN3WnRivGNqM@1eI^CH+KefC1%yip z7e4Rgm3fz8)vH70a-+zVg(5ZIE4yhw0ipA;gAMu@V?(ruCMunA9=5)rxdo$2t*$n7 zWrqM5m3N`VVLOe1P_^8CW_veUVnTT_aAqc`i-;v6oJu0Tk7xKabEJMOKSBn?#o!7Z z%mWL%1@+r`7J{G}t=zkm{8&bd<5qBPcC~*}Dnn=*%iZ?y8Dz?rcCvwUp(llKF@6r= z=CTV!){vl#FK<6puvc9kni0sC!p$AtFPrqddEL8V?`-8y^TA(Wtr}1J11F_? zyIxbuOcCt8WKp(A`nB&i2~SK>mvQUpb3IW?{SEIQAm7a`Ih&OJplt^IGtPu4G@HCU zJ0FWHvHsHsNzm+@nJv3fi3^!AA(6O=dCr{nxPVDOdLbgY#azT$T=>{@zWUc2UHc`l z>9e$E*)X?!=FIzp%hJK+7ml)(XY=OJI4R+Uc);8A86LI7Mn^lIYHziCILpW)hwQb3 z9;;_Q6YM!VixyiAoOx$wb?qGWATW=ix#pT7WeFPjlXz+@f&{_b}_r`28Md^N0U zva|PemRKGk3qq$ng72jCI$vL4s8VO1Hx+{TDLV5c=(PZdP(llEFg`NAbPt#_sk2PQ z3m={GLr zx=;DJs;9{-!p2FGW_d~HjzMy4OevxYJhzZ1z&*nD;e@&*Z0 z^15-Xtu?)Cno#3_OP@#BNkVFY;=DZ{5t^UnacdCsl3@Wjz}d8vy&^DO44v zEq=)#Ls}5~c z58pcYvh(x1?bI-K+|ppz6))!{P+Z}qEoEQ!abRx^h7zb})N3i`fFc+R70b(iJTXfZLA}(HG|}(I%LrMhC~1hA9W^?={=!9g|jI+=`PS2aq4c5*%MPaRD6=3BF3E@o9IM<^>Y8OmZy0?VB z%51>V47VD)f0>fbrqsw`cfcmD6vWu5H!hfD;djjG{jNl9 zfv+r!aG10P#Tzq1PKlb+(HM;Z75-%}_a;yda=+_!9P2%;DPoT&3VH=%R!&cL72}K- zmIIMbe`7ptV&~bJvUf|_^Ul9xMLf+{Kw`=Bm3t=S9*RvX1Wo9{8efYJAl zMq&nmFrQ5u_ld66;Y6IS!gO$tU{d9e!i>o*Gf;xjJ2I`FsXTz(qFT=?|0rnQU5t9?AI1DMU`bArxF=lgLGhEgG!ZRk%$uNgZhA1O)7& zNSC}p@@sY_c}5oazy$mnU&oPhd-6?j3Jo#Fr?L8lQ2Twvdj|GdOgX3x0#dlp$%j{# zqO1L<=S!LUfQ5XLnMfLHA8Y~+O+${m1GIYQJ;uoitrp7SBdYqHiCO!0?aH?56!5;t z?99+t|80DAbzr(4eMdT$HaYu_821aa;~fl!tEqZcRGsyP|D8hg^kAJ5{RgsjDF%+* z_zPblO)CLpPB`}Uc~f4xWj7A+kpUCka(%a;E@#C+20VKGlkK)g1J1vWy&H#2nR8rWw^~=}CzaHE`+HE{}=YQlK5K7TzV@r967W=oC4%!$P^nBxhTfhCY zaOaVphb5k;#U#t_j*|<7Yh-Pr!rb0y^z0P0StQ`XA{pPq@tyzaLtY?$1oogaX}a?; zW@r3=lVdlETI9+^DK&pG^x5!H1V8|UG0GSn{Ta4=6gc0`A0&t`u)=W`$yH1ASO1hS z(l^-<)+jpMz!-<}rOCt#N%#2)LOwH8PKFAG=5H#3P=o$hoxoJNl80yDFpIs&(x_T= z6{kSg3fmtqsI&Ay!w^5y7B0fGP;H20lz>iXz3X}?^CFWoc-aaa2557L>~xRl+`-H*ne~ z0Y~Dfi>Q`=AN)qQ4pSvfn&HV{rzdr$m4nXrau0k!5g9g(IB-;kxRK44C<xAxEVKuV(Xce4H+{r4M(4U|d4K?UpnPOWh(RxX%kBEI@rM zcp1(gGTyQ`I10SmMROeXt^%*@7jOatsC{BaBfHP`%8}gYR#f9VaYvsglH90eeM3Lp zdd(5Aw>-b&(;lbtlCj&^ZLKw8p4)H?{WY`e$G{nge0bCtE5L|`_)#!Bgi-K`x~5~m zwl1c00s0@$LQL|J@j_7Vv|&QTI=)m!hc*AUIA*HPb4%EJuKnib`V2-a`T=(lpQ0|Q z-N>!bcZx^M$36k3$GkIuRQ56Yh5t8n)>YO1wZw*I^zm3&B%rcNHuW1Y= zNSqO>a>S@TxMh=dBI4^PlBTQF+BDL@PTd)K^2cc7Z=ud9Z41MwlvAnKawv<+A5S?&BZB5gXpMU z?6H<&hZ<{0PF9$(kDQ-GNPs!{b@H^3C0HbB%qY+$I)n&^ld-25cBAOX?YI}w#Ea8? zdm`st`h+M6-8k)A>c9{!ct@|Z8P5DI4gg6$@i0|fYc?Pc@{?$Gf*YwT?|8#zfu)Wh zD8xsPF2L8B7+89>W?w~TK@ZZ<#EzV~GKhts(eu?izsfm&p8uW8Z6M&j1PFH0Y<$2K zxlNQ?4KShT4$!7MT5(((h$N@H!7@cwziA3>tpUpD0xEgn(hz44kZp#o$$QpnHj2U2$P7Yi0 zeRqAnzPK)B(177@5ooow`g}W>q6KWh!WNv#BZl(yAq(5trXe5Ez)11)wQz+OLsr9B zEQt7jV$9l8D>3moknH!g@Dt6P7`CfEq^Y_}&RxpY~<| zPT)O5-{Er@e6pd$1Y54F*j&s%*LT4kwcJ*Hd}@SRlssFJ8!9EtkN#AzL;XDI{qrfi zZD-z>ESYO+2h!i?6dgIT*b4-@l_EUl2wW~VXgk_Hg(Nlx)i#BwUVJD!-_SBVM1Yc` zpArnRmSB40DO}ZlYn+lIJly|1w`f8J$jeeA{d6Sze7O=Fp~V6!j!8lNBImWBpA`Dx z*&hI%d-{$(71qU;dDP67_9ck-MV7fUZrpr&#h^R{R!YCoi#{^7)%YkAEzt((m^V?| zjl{#5UwpbsQ-c*dXJT=&Ltd7RIIM;}p-l2IVRDN60?0?G`8-oY*GxW6dpNL1Uq&Yu zoh32E&QPJGD@sXg7_U$&DJ@aL(ukQ|SDehT{XO;l7yDG1cI_n>bEwPpPx?NxPUGt` zNsh;HW-WFB;Xeyz@L7(Gr3n1a@fqG(-elSvG7I1l6%`-KOl>M7rvpm%$(m4Gr=4l| z75I%fyfG96zd}KwSPj6$S!t?jKWm@csl|>tg`UnKv7^9MF*OO!QJA|%=b5B=buJ8% zr3~Npvt)D~h({W8q;_JW|2&yO9y%&pR7msaekt8+J~{O5Ak2;erVteppmk{JMVcygQ0%$M2%BI~-ZBwy&<&1tF-2XQ#Yt>Ji2hQCD^7jQ+CHV`e9{#9(yfXn8y2QVJGUi7v+1wA`6TWMe z>}5k^9y-SMQ^(NLF~b(64{c(utaIqF1^h7l9mk??4zOMuVTxLWi%v#ew7R|TXfGg` zPb3IDNNqFh8)0$aZx{u3yE@AV`O+7rJ$eWY?IHm+>VE!pD5t#1oOvY>Byr{1ymq&~ zQA0prnvUUy5`dfHXQ$~ELEO5`*?hl~LErv2^^ZqE` z%Svm?z`o1cpG)+XdYSsrlcp0}w{tu3dV!5h5hJ+thoSBV_>MTm=tv8KgnVIO)%tY# z#|{gHZU>RfV$i^SIxEmuFw$>J#Nz#hYg$8IOGgJ$!B;d+`0D8J*No@wq1KyB1Suyc z)BNkqDK4{~%s|m;@gI{LSVu>&I`+mJx0w`*`uu4g+aRk0y328|j20Y}_kChwfF|K) zax&*y+w(>rCJ(L8>C^0bnMv;DBr+Ba9aKA5koEU`U`2oGQ`{s3dPl+cb6jk&W z!=rbg@jgGLj;sDtT(#W%ox--~oait&4WN{&D@_u9PCBh0!|59F={K6=h=ZEB!h^#L zx%ttvzJjOTm362y&Z?05v|5^>hxxG~kx4Qe=Ex2$pJ_*oz(9V*46vf{M+p*beq1q&5WjJ9X5t1D6_#g(N z=l|+!RNUuhOw6>32$ue_yxL&EU|jjq>ij3`4~DVa}9+nPf6*|Y>i!WnS70Yr9x-X*zp=`WIZgM+#c9ZnNQef5CK#2mDm=6gpm5A9OQD@k4j2xFeZo#s=XSFA{M3J z3J2eh;%Kn8rrq_ORDS)-=UBDFbzZLdm(O9LE!q%M2z0Y|wv}wYxT8ep=qoCWsCHtU ze}|f)XV3WZPYXZBnQZzZ;=W8|7ttj55bZFpOdM105-z+Sbc;I%sOiF3Lvk^ZxRqq2 zYeY%%0&5{-&r39IEIDWyH_S-u57O*xX#4xr>Ob{3vLOPScFooyn%(R@i?^=_9}I9e zmSppW`3nk-B6ySK50SK~v2|6ozqE2+WMe(HGeW|z)ACH3a-~DiblD4oYl!{vOsVC% z`p*JJ-t@0j54BuaQt(ZY2l=UqG~>=h;V3j+XqR479Km_i7Z5C?CFk$GXX!iQlN;#| z?7+`SX1qOhMCW!qwrF1z6y1GoxtJzUba*?2GHD^54lqUhJ{2HYZlh&^S4#1BA#TkZ z{%VXV1PFYqDvWPpLWHlAv+tl@YL+=)Oo-bhz~oPMFDQ(oa9AoaiIS9e3`$EmgA)iP zqjQK)=cD1rvl2|-h6j3C3L8)qA{s>e<2 z1#reee~i^P*~N56n}b~g2q%Nn#q)wfCJ#5drVX+5Pw4n?;ER=0TTx2h&KVS}h+m$iWuQTh_HWT3@40XSX zly(Ar_9dHtmNGlRKm-K@t8}Z!temV=5L!nC5 zyDtPmtTM#f0bI>V5YVJd#S$~Zskih9O!B(LJe7_J>nY9xuuk!xBc2An*4DBx>Z){G zem2&nvVGPBa3?I0iBnc7Fvgy_VrfiYOAhTNi_~ds4A4PyGJztH@M~n9P(sniiMIDB zV}vC;J9!ottwn*SqPekZMki}U4M<773hC(fJzP?HQsDF^n*i~&>aaZsN4Qlg{~yN= z@|IGcN?p-na6|4_9^LdI5PEH5p5CiD6l_tBz;6c%9@pZ!XL;IW+ zWH%)r5oCat_S_fu^x|qZSK!MVH^>zXqR(EoQQQ(eg(Y*Gz^BX2s|1y14cZY|>Iu%u?6!mHZh(y)2ZytsHy*c7?mh@F;l>cZcz(wV z5ZQ5pWMret%bTB1!DIOLf|Mw|#OxoQ!UGH}f;hrM;q2Krn{smp!1iamF-&O}+UFOT z%Cx_y@#!QWbPE6&oy=wuJtT5H+_TJX`Ot8=2oM#W`GOfl1DwD6h=@$x2~uNGdlcb0q)(xM`pDUCh~~8=ro$p zIk*4<)UJ7xZusRdW;({uTrzzszdQ>B{3V?sF*E#YkwQT+)MC^EPwLmd`vD>5>*9?gD1zdS~syMp0|#04wn zAc($a?Gth9-%uwhD7RJ5%#9N4LKBRb5u2+vO@korTERWIcU#epGR z7@s~5uXbiF&_Zp;Hs7kO6lIq&0QNtNvf_sgwWk{?%NXw#{PB8X2&Daijl!&Px z$m(^i;WnJu7$Dlpp20~PNjoE5ok~x87aDXBPt}Zb}4^O)mIRU)Bw+|IT4w)N20k0BNb<+hAei? z@;st>{&?(3Cs-6Oj*MfzAM{77p;vlmqfaLz0!-%+^G zhtx^Wsk#rL{NEw>-aR)HY?hxEKTcAk9jF31RF~wPiGq)1%o{b zidx|s3j}5(YX*mt6!SQA=9&Q1$@ZvgHxf3#-yWf;2?YCf*qHM}0xQ95-n*o}54#?} zo@w~18_km(r0Z*<{|950GD+1jN5Q%fvOfu9HGghlP?~HbjDLkXdfvQ;iYvE8Dc6#3 z@A$N;TLpL3!oh%^fJG&tfqED4i?`uHMqG@`Hh-_)QYCIQCl2cni^J*o_ZB8-Ps%>@ zb;fAW30L=+({CZTl^-iU{?*g6rFXl(KXCC`1|F}{INQ3EX5TY7dit_~TlZ%_a>LlX zg3h7r>|(-p8DL}A@l}sNOJ>_4OFCNo8}QO>&2(i-8g}N)s7w9gl=?q=OW{KVu_|Xz zM7p@?17!)a>Ke=#9f#Po7z{pw7n4sbRRRdwS}~m;4kFa#gor?$W>^% zXotXco6EN71lWaTKE!Fam69DRp30q&Mh^n^Fhl}-l6&Ta7^F0A zqGf{qNDXWZvSmZ!K#<;Uu#2H%b{Nu|4+(>qZ5)lbd*Ag0{ygOqKHmTyhg#A`1F(?j zFyVZf<Rfnq5CRNybp@cV*leF}b^%dmM1*q3wJ!Wzv= zeN2{-q8tg*QOJmo=hHYLXi*^2i|(Rs)f#LUeUYvR#%Z?v_nHahlf4FF&K@q-7dtyE z2C#NzIKPG1tLwbbMaYQYG_1x+U05Wu=&@A@A(Wp^-sKc%g$?~(KIR79^0ri{7-b@8 z&09NhD&*nEdEAKPkCfRHMC=@#?AzD|;+K4y`d;>4J8r6>iNA-Dnwd<2CKaDW`)s5o zMbo&v`gT#W*Jj)&lmO8B`O47N1qcjf9skt{>@fnnR@xNd6w(mCtf2Yk;eY(IK@U~P zd6e-@v}nsN8U<$e$@5i5HE=YG89D1m%2gyLcE8)+UP==mWV7H2rJj?h0aKni2f?Rh?36tB3-ieTNx?Jr~3lSPl~Xxj-gyRGPYjXdc4 z@*HRR&mQ)02(ph9G~e#m8)o0NHE&fhT^G7>GTfGIg2`HUUgCW2z${=p-H6wr$(C zZ9D0pW81c^{dB+Yx6fL8tUb;dZ8ARvaQJ@ZNNNmSRX)9# z&Jf+7vOPXg;^t;IJQ?2)u%CGjDAA12wHtr|W3y^@!DWT}>%zMS`C8F(o#E|HEE^}4 zl<3R8o4g9Mh!UsxfRbL><3K8vD;EJXX&P_H^DaM6g;0|CO0O9UR6oGd?>10KPCPm} zt;Dk`e}nU@@E2q}iv&AaoB@P=e7-mc(SI4@{m-NGMe?J-8s>KadsTwE``+!qv*!o6#34_Cthk;6xbz!? z-nu-iSz-(WKh11_ZX%s8b=e>(oA|w7uq(Sg@D}6S#OJ*%h&ro-e1CMKIf(|U^*04c z{X&c1eFbYt%*!!yEI)Evj2y%id%rF!=u+MFZ>Fwsv|p1MNLf{0kg~1F4^AOP3R!rF z2BB!?dz=TTP11iPM{XZzNO&6WKJ}W%4Nd>1C&FT!sfBKZ37WdLj@!-N(@(sfgn}ni z`nBtQ!y2?dw95Z_Rxn&LZ!WS~HZx55q6GU~h1W1RwIL9CExVfBIrbucpw*JQO88u0 z`R}C$mxf2$$HMuY>6jE^m0@;IKv)c0Cngr>X9b76uX3!F{EF{!=U+X25#y<>VnH%l2rX4+A=Rcqaw0Nd z!K9_1xa&GK56s-G75U3+D5YQ55N9P0ph&3v#CuIu)FzVRA9>QoP$A*9Sosp9Daf|p zT(dOiJR}UxF6&VVrys#3g82y@EVEsBjkh=Y1A2kD#|X3l8iEY^`*5MP495>dUle0Q z%&YT|w`}PlO&k-j<{Dx)o%|23F8h~Rt(@F6trdt;Wf}E<-xjt&Qpph|M{lnDuQnz( zSwC<52~x7V9zjcAw7j~ zQPMT2Ax!_ie)Q%12Eq6r1Irv+5QgP1cwkdsWcRWS6|3jDG4B{d!Z?>{bp|3qgd=7dW zMW|xlSp~fC{CVe5^ijQOB>3X>`0{_; z5j_Xe=|+z0rWYUgoKjRZYk#07<%?C0y3L+;uiv6IzlQoX`PP}owiOGn!2(?zHd<%H z-?W}Lo!2*QYQ{?|XR~(O4>pegs4EjE^&}^-jV`yG*3VqPr93}CN)G?AA-I!4@xJoP z8oo|O!kDHiU#T^dw<80zeb1qP7KA@Tg=ORQd2$3xf+kHF4r7R<{=H?Q`LM4aTPIF< zGE$SzO<2^K_vKnvSpv>x+iZB*`<9yb#H;($n1G&@!-tFe6N5G_x!ZLn7}(bBCK>_a z`mbHVrP1XNJZBp@l>L4sloZ%=XH@hjGR!glXWvKEK+)Arvy9Ut$RiE#@G?pEI>tQc z@Ar36eCEcd!P`kE(zv`mE&S&*L18c!N8ZBcKaz)oW83d}nu5pf!_Uguk8(v*3oK8r|VN38!xWViW-l>M z{24>|ycYPMvajQypW8h21e6%V#Na6t0{^uI(S>T6_y4&B5!ZL??X^a*TOd07lH@-T z8{{P?odfb9l=7!`_jgoq%NHoO9H8~i<#Tmfy+?0iS#UvB6j1@T^hAMD`SS`)>FZsg zNKr#{!k{*9Q`d!yYIMlq1}aA5W620FWx1Xcs#z)2uzl`y)(K^&Wb&07NmLm@AkzkU zF2WD8HdpXsi3uAMj(~~4&M61;)#Qe6kE`+06YYnGy3gZRIsX4-{Tpu|CjQ5)|DuWN zvAsHK2^NoKdk_Pd(FC*}j*H&~$Y06$A6G1gue+bjxv4J5Ic*y2EOSq(XPj$!?OVbtF}ewOJh@R%tO{9h6EA7_?z zPz+Lw$hRYbK@3-wV4eL!I9mDJ|1=r_7q@~&zJQe^!zEa$-)+-(n)vw_w=XmCH&dTg z7BO?63mceBx=dd0>0sbq-Ziv!Y>A z%E#|T8H&CO7`_u7loAhfrzmiHe!OQ8&%JBrz%EXV`&(3acV~MM!-TVjKkPj}t8#wOz_ra@0_UAwz$LAZvzaO)Ji4%!G5Q#b?-X-dM+eBc6OXf~p zb$oP2p6P!en-66I-T&d5Z^JWr&%L3E!68m%^p~i~RTdO9?ime{0og&Ui1YmhbH6

        &c?(AAUaFYNC38B5NhzYmJ_RR zL>SGF>SN$vDeeqMfUz1WeRyOj;Ilr%cMsNSwW*xQok;wu-W~Tik;lp>_`PH^@n4S@ zXw=7}@NQjEv>_%k*v;YbU*w%TtT+7+wmo;YUEI<%0sv)jAOjZT)wo=d6=sickEvhuX7{PxVy2T$f-kR=!SU=hVj!2k5|7`y#qK1k1)5N7xjMVQ-H4!NL*;UVF=FMdD!@J-yLk|D&~XB+;jk$v9i#aqNbKKbu^*4BVwni?4S&ceH%)78Vo;3We3z>0}G(1W=Te^H+ zc3x`TUiBlCK8kjO`)Jlb4l8GuDG**g!r+l8S7}78R6^WFWuoTL;6SIIbdQ7FC0>|Aqq~|&r=2%&UIMNuFHXGipg$|j6gaGa~R9GyX%`#=8mz& z3F%O4WFF_ttHHFgIZ+N&G2gE5GZpX*q=o-WEO)j_tD^PBBG=-7;r+*Q4Z2` zd)&d#IICHLqscicjx#W19KMHf0lpyLuck>DOZN<{4le$@2=v?aU+Q|4qM*k>-V3l4 zhz_qPiX%|Uj6NG1EbPn~E(IF^otw_5K0Zsnh!>(6!|GbJjcFu}_E&iooVwdg4L;Tg zgvRB3UbgDZ2{|RieK*w){5%dEz&s_U(5s7*4#wg50$1<-3H($4{;Ym7^$!&E6_lYf z*4BfZ5_qKWaWv4dWpk430t3i^55*3c(8Ukv_bVAV7a(#z84gq0an27F(A2H*4Db75 ziQ2P=`Vd`>>uP4kvi=Bs0lN|rw~3n*-QSY4=d8uY8|)@WgqMZq>2;;Cyz(o}R#s7|?Xb*2FxuR(TNhozRkI6;i zKV-ND5n7cS)KuR3=PGsvO%nVDlMhnUVk_Qz_>=HX7A6@#RmmB@|!RG9Y_ovVfRS7{@8n5Q6 zTwP2>0ytm%d`Sl~0RE+Z(~gIW&gOJ>$Zdl~yl|qPxCQ6YifqjhC}lzq-x`*MbDnxY z6X%@`=;opCoAxl|$!i}hty9``$(#9N2ch%%%8E?D0?^4*pA@1%!39QxJE4!H8Ym%X zLnYCKCu1c1-fZ)636;P86s0(JX}%CBXxfe_!TRN{FVItBs!p&af`C@3lG(C>Axw?8 z#WI65W$*}y2`%agC-7q7YkGmWpTpuoM#UvS4d3E>2umvtH*JA*g znd19VV?1e9@2OtR1~luQ!q#hzCKGejMFjj3_P`StljZ_yvDu~RnGF;wip%36cjm0# z^i3%$wt^!^+D;#A!_lRBY6#(Mb5r`;Zu`?+MP=-h00D&kQHPY=SC1M`uU0H3G%LD5 zGE>OQDaJS_maeT}vRz>!lmduAeeszNL1||4yV~8)Lg#}Se z<^M?=o8`9llaqG0di12T@@OCNmOMisOHhF8sFzLjD)*+ro!G7}DqkUv^FO{-GJA^j z-1;()hM&|Q5p_5dI!`o*ZgQMf%R0v+M0+@GI?4tpz^o0gEyvNsk*Dx0RFWV<&)xL| zBY_1)HeDcr)3p0>>}0qQAu-S$L)SlssV^~nQ*viu62k?@6&=T(d+244z|2w`r8ua!_t-e)Vw z0G?bZOYb0Z>f&?%7sgn3_v6QRgkji#fsAD$GHN<#kiOGaI1}g}uq_l8v`nyvdr6>7 zzAktxI{={0brzX+yig3qk?vDaa+x$5{=++v{>mFZ36cWHInd`P*p{A^ooC zdtt=0+$!gdR%*J&LlpI?U|&?9K{uG3&zUA|2k$m6DK_9OcHkdFJP0edE84t3f z87S=QiEo&HDD@z~d8Zb>-~1LD=A@bc@zA4&uI~E9cx{cLRo6iLG4~&gQWWTeH-n86 zVyL~(SP9{$h1*yiH`>weD92Vi`?R+Qk}()=fkp2{r|tDGJz68!M_Ju+$*xfQd9U9d zBr%QoLTWQ@!)aQYt-KFT=a|$K_8_v+sNZ%B%*ddN2wvCQonH|+p)fJN7fF-lR{P0) z@t(tlo8X6nAVSHo-Ai)O!N(AHwShk_Jw~Is-1+4u`$FY|_;wPiYy@JPYLuGPt&W5~ zjfJv>J$(lPaEW5Fp@H<&&ShceaQl?-;qbe6ds?;WC*hX(zyxT6tWn3Icmb%&8vH7U zq}cr6KT~41)4r%BcRr4wAL_kK z``AB~{bl+YQ6l*5f088l7kw7)(xO%?bGsbb6vqn9dPj{We|Aw5d~A8<`^L@Kqr5Pm zn@?#Ua|0q_+XPG+d~syb%T21hUZyOeAf!4c1!!E_9^HK{Iq$YVa!_oij2=;TT p za|S9}Nq)oDBpg9eOtGdiorS7RQnZ!41n)*Q!@w9NhP~ znR@#=%y@>o%PzhUg6o9~p)vc5m-_ebf!I>ZLg>?7847oQqTZ zG?0FhrjBMM3Z2t*VN+InfdR6x~*giLcB1;Dx}vmOjYHgemkFigSlo>auVv|uaK z4ZBF=s$WcK0LndfG9YAI$HgN$q)I?pkdJfyVaSs|3wvr%FF_sEI z7U_7$zM&NDEY;_eKbPi<9^Bwo0CSO%Y`w#t2VKU>S5klsX@ovt4w53v(kWD_D$DRM zt`?F1qVyr`clmXF_hM1E`_XwLggM`qY(htc6-?g*WA0lVVGZS0ohams!MHbAfu z{`$^^fG3bbEC&Z{rg7wiKxngAA-T?*QY8W8dne|LLLlRn3`eTo=#zRK3|IvlRBy?M zExhgcvv~Q#OW4DE8*Rh2WC5Zw@Uq%H5G=H~W^36?biPJRjTQ(6u?k6vqkK=>(S-(4 z4;dwN@bPUFa762=jPI}t9WnXP-ZUnkOYO~8uE@Vk1%#Xwt&D}4pEX`#a}1!FIuni} zi?VNh7j%)dw#aO5p!9>(Gw0Zl@+aY?<`vlRpFmp{rNHNji^+en=|uPqnLVw>*O2C1 zK4vg}vtq6>6i!l;KGwb(?{hZ!&EVTLIhus8f^zvfYPn``2!e`KD%)=H-bZ7KV&H^te*c6xgX{-ZjtGvo3)ub z(OVVdwli9Uk_c)&G&k+mRU@B7={NaEL!pV9)_D1yhPc(}z|%b4%S$##mG_9jZ&9@D zOay(w6_^f`$4Ek`LZ@ z4F(mv)CYQqtZz@$_#9d$i_(qX%R$A?4N+$i=FN-!dJ6@M9Yy)&qdXJL_Yp$V8|KuN z`CEF0LxEmVZ_o(tQgpnw|4q!6Urdxf9QYfxa^FXdBe+47ntbRgXKw(OiquxK2h4Ub za|YEptzPQ6*z1NehKY0!{|L!CG5j#j!?BuiP)!i#Oc6OR=+3%kb_>K%fWEuxBv==# zi)@-ITPB_VM|*{*8`ajUJ9(~YHHUi*0A0^Oy(l!_VtL!s! z86?11Zl2^!xx0~bFLj>g6^$AYF+M*kcZk8iUM*4i!gQINifmNx@@$2M7YJ9bpL*c~ zUmi)7OK`&#OT8tDE9Jo1#j|r-5p+{0qn|BV{`~muMW7TbWLhT5ggNdp)p}ts)EsyK_izFY)20R9 zKIGt6G7q_h5B`$Gh}W72RGcR8Z7UxcreA3=E0ud-J)TweK%i0!lUY9ury+?3f5F#y zNH|6P2LAra1kwQ{CWPrDgxS>aU#R*~R+F>Uc&7niD#@*4Gj$6q+8119L2n=>@sx!2 za^9sA4%FE^>rRdT4XVG9UWfs7j-c7L+UF)0Zx8~Dt?R}6rbP%>4U25|s2BS~@*;iCcoDh^|`Kw8b{MH^uqeplExnlJYx}=y_=M?X$ zBunjC|2X3jEOfGVs?o5SItjjHU@@TJkk-d0`tpjkk)~S%I=i8ex zntuTKWG)a80)lwN+z+C`9ih}NOg#51(DjrRg?|M$-}&Bb@k${i4%{xgvL6c2hLO%- z|0JRR0`kp>(^p25{?AZ##QzRe3&j9J)&Ju0BS!$CYLH5b!9$-8-w@Co%bd0L%QpRm zA)e*HYmcb}Z&e>B&s)yUoM!+UU%b)*-odT}NgGQ8HsaJPa8eX~%{5F&#M@lNK#mQP zzaapqm@jbpr`BRRC=~or1N6#6DOnm{73-F!JzzIXaM9e3QF}lw!VuBo2Pl-~=e>R# z>sccy^^^?X1Rn~dQKa&BZGtFf3~-g`aGyhv%S?t+B;s4Dn9sR z;ht@+N#w&H$n3tMlyh5&YS)BE$e1ald7F@BwHZ64G~g}OhK*SF-zFcyi@UH}nCBRP z7YMX5$jNKYpOa)m3}w#57P#(F(pvAkBM>10Djf#_Kh=k*fC5}SW{?gr8{!J?ORZgw zIQF*pFJwIqmIuU-teWQMw1}K#a5S0#Dt~IUH}IHekd@Ci0p$XPdkx0a@DMbw!7oiKMJ5;n#Y-s_vH|Im+2xqsoHmA% z2`=a+xm0+MeCTn**_%bWlu;1KF-UlXF_TSG5l0ZeY^y6e2jGV>sf_fx*oSQL@Be)aNkv^Hr)ffAJ4LooF=fwda? z{{G7c`?a|yT}*{L)jULY`4Tp0>@B$)x4EMv&|b6RYs<;jUUR~kpgZBR|E4@hM*a7k zJq$6!s`JS>Zg2jY;CHV=ZtqQ^-MuGR#&d=zqm*B~HiVs`oFHOIXfuFA1qG>+RX`rJ z<4RjVM+v;-{NfR9li5|z!ul}c_}4`zh_|Bt5WVm#>?F>HKVKL+y-cYQ>d7sd?r1Z$ zfhNx#O$1<*Bz$)cto~WvI0)+G3v6;v4v8QjSRS5Q5>!ZUl2+lVZ-<{9-pRk|I%L6R zbu&?u!=2MTvkqCc=M$4qM}k2kt1JG!eutVnNQeYnkwP1^W-2E0H{U-$^;`CcW> z2$s}tU~^Vfj&{jTZ2<1q@=4Bjj(a_jF(%2=Ru;EP8;hdG!qqHW6j_exnAHb}7gU*w zLa9N3jpz!V%dSCN0cK-H+wC~8l}4pxmi>&n^(py>en)XefP(cepY`_HG^4ZCn4-Y} z%m(l3FEaT)-};1lRqL9(4*i(o9W1|h2KjtDU-(DL?}nLNXZSAl)>8mOMu z!)fsOG5LC%tmQ#eI^S7g0Xw`qZ{}@^mzzEBBCchfLAH9(6EKs^pf#9_uw&20oK8vU zNEtLy<8#+%?{6EOviOV!o&c^yjo(ci$%)>JyJ{S55om zdKm``DY6Faf~(M=9r7zG5WToBj5z90RHXT#!bYAl9A8h&lr&kl0|<0u84lX5S=%%c z98iGfh*ZKQMTMy$<+G0hYn(m5`$EFrG0x^!A4+EW1rQU?JLlkLq>a#CkV6Vhq``Xc*wn*7{<>%oq#>#&Qb6D?Q&VX z;}__;pA3_QlLRXeU{_Xp22(ql9X6%2V?W}JEjP`NXcG{VIOzO7f=;V*qsn)B5LUv| z)QXc3pV$D$OZDkpS`Cn#koOr8Dnb7AcTN$PC@r!o7zo<{8sF_@P_xk`>!TQB1P) z{*h2<5KMgu_Q-*Df~Hjelw2S^ScoDj5tV!5v_G&A+5u|6Xvr@}fa-4Pipsa*?Tv)H z2!Uv5Cd1a)aI*RMJ)+Es!k2ZK2TjK;ys0RjRk9D1V~|M#C6NKtf6L1?%aGFu1f>(l zsys(0+0w(5OLpo~t(XSCJ@ z^7?axQvd8Th%9!6K7)^EtFe_7Y7Xu4QS*TT0Nah%F^_D#UNF<*dGnLauCHu5u5=l7 z(%rvHFTQ7$F#*~X{zC1|Tq+yxpfBtl7&+P&KL&X^7@()>{P__@>Vz42poB}KS0d|bdFV9{*E3S#9ThB~=aU!+ zUZtEt%#}F3*9doLEyh!OzO5u{ulGkP2t#0qi>?0^KlGQU_+G*9oR4tE zj}Hb10i;!0?Dg$L%HA3_(7e(7)^rqkleDdWfBift7PKDK>Fsd>6JN_SBDYSUy~@}P zHy@j3DU|ExPzcj}m(I=~FEAU29affAqIOGA*8Twtv`R?5_#z@K!A@=*7)42TMTZNV zV2Sq~<6v!nX4_wcl_|9>q|Ly~j;<6caI7qH?k!=b1b?u^*eo0sq3h0VLK=QQGFQ{t zP;`SiyRfBmq>=w)S|Aox`JRR47(n)@4w@1Kfh6W*zJTygd}xk{6?Rg(0B(ESUygC? zO7hglUBE&}UTXSZ7_pKfCCuZc2-=+YC6c-7N?jN zkQGuVpafpov3gNWfBF9aKS%R>$bz(W5Vtb&wTN|e-fZe zW2!E@@+W}@7=px|m{x&oT$BqZYCGU7**Nj*5T*Z7)X48Ob7GLo;f1@5LawYC|MQpk z-`I}Q5HM}GX<3Dlw>}sorz*&HS0%f=o%L&oMMYXXFZ}!8^D_|Iovn4Bwt`k{zwLew z9mv4`sXF`_HQ#`s-;YGSdIuC9cd9zozUMbB*19IF!H$86050ZI4=t&MDNz>euFzxjkZ6qL4Yf27U zYi1e>LuMbE;Z~_zekXvSS|^^iVcc?!qxnv5J)RpaTNCJiIaP>bRu_1S%j0jcr9_Oi zfgunT5XLw?LBBVx?`gtCqA{nG!iey0Za4{~MfQpsimE)8jQl)%CAOs)d6dXjI#p2H zR9Sk$m`O?Fnc&|Xxx=X5|7sNIQAD`B=kbOkPs7^qjM>~BWGSy)ns=Ch{rQv7ABGPS zJ2b9L=B-JJw`?TZxaII{O2z()RlST%EX8oql;yYd%PT7fU?=p?T_3pJK!-6}s%g^; zX{#Yx0UKp^ECdC=W|um)xMtW_K_yu}pkVBqX=4xurkLE$*S&5u*GF*(WLC}#ZVxMT z29Zi?6}q)U47>=o{l+EBQNa(gu0GHjLZ#;Lx%?~D-y#4lA@C^Y6pgE(?{L_P3ebeG zD0zGocEZ#4a;R2HHMKWHLtITl3Xf}0TKLZIY5CnUMlb4m5)sF9Vw#{ow@5p=ZwMx0 z2qh-NtS6M1pqX|Gn_&>I5-Rh{r~=QZh@a$!g?9($&1&+2w}+$Z<|wN0tF9H7sABET zy}-B^#>=_R{$8#pb;GH=TA|J+pFS;OW9LMv+Sb4Dc+9WXb$xr3c92BAXx+nHJA{3$ z*J>%sBSVp4Kyhq@xr!m%tdh{JSpqLoi#kv6kf~}~4a~>tP9mM-!V^2IGvtf*bZI?) zpW@0OH)avFsW4)Bc}cvqqf^kheS{?ZAsXo$_~ht8&&+CCL>YEcllDKq$Ba-Ac@?(Q z(rsLmjeq}G8GxmtthxG5%)m7_(JGJRuA7r#UmBPYqxQS#0Q1v9W%}#W=?~6mu;h4U zb7lsExv;i5N%=8~vr?zu(z6v$?tV%?>fn#P&goQ*BY3v+;&r?;w*BS#N-VW;f7j0) z@mPuN6lzEmufAg212rzp2Oa4KvkU@?xKwM!Qg*+M+b;`!Lxzw(57 zVe4+$VCv@RH3LD22Q>(qeY9GArf4BVO^TP-z+i8%UE~d&{o|A$hvq)QRW!QVCftEB z!juWvdXa$Yx8(_R5-fL%(Q3JN>OvD81ze#qE|!pmq5>T=Y_Oy-wmlXldT7le&xIQKBud{k z53TrSC6$z4i>}0}9$hM2WZy#HLBK+4`P}5j4Q*;ber#P7TOaWTC(?UVygVo_E$$}a z)GMXdDGBO&?jkqznjDG8G^Gfpj{FxS75M$oY2N3r)eb5+Ltz^n z7H{U~Gyl%IBn1TALRj%0QVOJOnsJjqo)WP%XkoY1zEQ^*vE#M-_to66HH=d_G8V8@ zQC3E#`F?G{-31=Rnm-CwI9pP5$AgfxX#~Z>WyP2lGS;lo%(< zRZb0Ivje1SBGriiUsV6DfLEUQ;~q1ocY@_&2C73+s=#@)j-)dzPv@gHeuM@Iw{dQB z1vD`?Vp8TX&yh%C_@0z3UtlDZNo`J8Lq@JQL68360xkX{@E49uIVAW`>SQ;6|2rro;sr z^r0FZW?TmE)?lxyxXH&4c@rTkKuWv`5$v({YU^-ijVg{6(#{eW?B8ixRwhXBTu|Vd zm>)2mQ96wihlGFF)J! z{(9A%`)R^pwrJa3fb`(pbkD4GRjx@qdqZ|Z5r$+F>GyZ(UW5#JiL&4anG_q3_ANIH zHElU&1;{LKI8!I&?Y#G8aIE0P-LN@Eo1`_2eHW#uf$))NI3BrP3`z0++nr73khj# zvl%*n=LA}v&7Y}S$XNbqdm^DO8!X>VnR1gzX-l1OWuE7|$7J+F6>_V%@xk|a=0s}4 zpab|cK;hb1Xk%a*`vdrLNgFz_yh<0@z0u7a1bvreqo4wkvJM+Kk2xawedE6si)yxU z7{DJZ;4t%;D)q{j}6Tsqq^7FLfRGA>{cJU0r475#q6idv zGi)g_wDxH0-F6L(4gb=hp{l@~!8F%}w>k6LjI)^WBDnz_@C;(y0bkIPARFF$e|zus zb@jc5Q+DI7_P8;=%5@AX(}x-n{&S97ol$=Q=GbAdOGb&w*~7QB@2v!5kS~@tscZ%H z)0fb@gHKh-(wUZs!T&Kl`jcXEdVL$tjS?Mrt3cwt*nJ!jF2MX0P}pZ830VZWy({IC zAe4q~5z469;Bp#q-n{0ZRpI7)fP9@9z{_QSfdju<@!b+=B`3YhGFt11hg9 zW!s9zpoUoVb2VC=^AEV`nma4^XVol8D<6!jdB)&SX`0hJQ-V(L;_TiAs?b)<(jXaP zq{ysLy|oFpRuL3G@pCZp5e>EQ(J7k33b)O2_CPQs{gX)iBOmO_>koywFwB0P+oqk37raWalJ$-jFUo)$D=vLl*zB4&dbbo+O?rJqk; z_T2WwttOmfOlWkIhhGRYmZ?+~C0e0p>{w`ZqL)4D*aas(dJo`fxmEWk&_OS{QF+N0 z?~v)+R3oItV4y3uYpVO~edvX3+{mK-90<`9D^hL4E#2r|6Alqw#^Ry9{UKK8JYV^< zrE2o#*l~h^q{qd9%)%V~OOV-uVHD!hA@+qy$y~{_>w|VA$s4-w+Db>KR{ux+Pu)va z-*_Mja8-d{3QGhWk900%87$p?AvZ)b)06 zjz0M7mlZrLOLF@)tg1sXRl#aSOtM#Utu3hvl=WTL&XCat=Z3)7fXVIrABuVsx7YYWZ<%ET= zzx)WU%@ViQ!)#U0nkJocT1>$zJL21Lb#au=bl~rIh>vr@J(p7ttr>V4CJXk}~wxX=roUV#wLd+8V1NC048&w;Uk>{5W)XmEAXQdFeh5s0}_~;PABDTki z68#oN@4@Z@{Ronz=8t~UW-d1E33?&_A}evAb&0*iLo((rgLhRClIPS{o=TuiLE>03 zQY)Ah_^B7!SKj0!EWe)t;T{G_5l1d+dT8*4a%_68qU(dI6zcMRRLWF0s}WyAjqZfo z@U_{(`U6y(8k}HqIoi;3;k-wi%VDzDRYzx0zNF*JDfc#Hjk z6}o&p6YYC{E`Ogh1br=&B_9SqwiQtYMuJ^yPzADGh5|?D*QE8h_zf;;`Yt#I>2?H^snCqeQIB9?auDKd7^Y=QA{?kBUk5c%ECljD6)urxpSvb_{*vg$3;V& z78WL)=?p%z@#df*2jxLkeaL8TEpHO8Pm+%|!46!w>^EoGZ@Oau6F_Ks0OmsNJu8i5 zxOARaiK9OKXhAY_vjMmN&`r+axbXgDQ9T#8h25Q45LIIM!wFUncleMi#7pBqc_(r! zt0r(H6yJVS6=aN0C-hv{E`^AwX#hq8X$3+pn@~B0%t8_*6&*Qx{?Y42V~1}Cx7W@c zPdU{?SlUpNo(>-Er0>Cq*Rj4Rs`%C2LXr+6c$JBL=3OKxXdn|Q=Y!!)6`e?- zU85}JDMzNftDo8sZg8sq(lzc789AmIR=$oYQ8_FgGTz_O%=nEbT zTpy1^OrSldZ<0p(@h!DG2WaMQ3S#A!+_}k|gP#75Uy?jj1!J+`3nB2CRFPH)1ri7-dtlh`z*V4X&*+Vh-L=E#|!Cm5JcC^AMuhDqKWw^H7ox2w5zJ1kKls)ldGu z7tjf^vTa?abN1DLUM=BcQ;H|y<8ow5w|!o(xiTaQGPoy|*IH+d=_GG%Av^F&kE{dg zfF1YEUG?y{X`{#vQ`P)Mt@|Q&@00y~L@Y~`(@YUnIg9T3#S@4uZzhj-+iUC%_m&WG zYzvi8LKTCq$V@_h{d3NlTRe?L+&-0f@j!-cA)mQ?ko2(ev6M!?g=7np7d6_+ z?UXOm@Szc<5ZY&FyN_@8R25n69zOxwM7ss799W!XyVNne6nM`p;_IXpu}3DQA4%So z%NHPeWUks%aIiWpI@eC&VWLWMn$sGn?OLD7IiS5~uBXN0)9Pzbu0Di+o(11yHq(6bWlT${ zR9drau*jgv(j^BJ>(*0AU?B;lN|nV5*_3k|Krhhv9Pb=V^dnLg_x2GZ{XB+WA?Al1 zUz%_m25>b}dC^_kC9?fqr}pS4!{(ZEyT+Q+XpHyb=ssyb_bp#baL{Lp0lxb?WSgIZvp?tlE}*AURh zX(1_q3vr4On>c9ZL=r~=TOFRycr-?_Y*B-ZQ?G9U1)X&#W-dS(x_uX)t75op_NI05cp91=3Iyu*e0|8m-{$_i zLXy`mgBh`X({}J^ruZsQPJ{H=k>p}&^AaWP?bMa|i(BuSYEH;%_7t?!VHg+1*wKf$ z_+CwBydk->*h0pml&HHCw34l(zs`((CY1c*8(d6@3ysX2vNw%e=upPaEReJZo$7CDyV& zK9LDogJc7ap`ko0eS^MW{aiKZR?bxD@ZRZ=-Bt*F+fQcQ%(PzryDVyv-CbGzm=SOr z}ubPU#Ugt`0IJ@CBj+2dBa?_Dl6Zk(yzOA-_C4t7_fOX5d6r&GM|Tjor26x+;7RU zkB)SG=oMUSsmg~akien7;3}A8u8|wXBF2cwwoy&Jm?*7_4N=A(KiN(`MQxb86YFIV zuXU3@fuACGLy(ss&h^5GJ3d$KBq)UL71h!aDH(yZy9UnMhx^WAk%o4arP*|MqsMl~ zUzS2h-nEA}m(dSyTQ@D<&sIMzZ+vCjVin7txIkexK0hv;y=gIUfV(F>Wu|daf4LyCK9hld`LS1IP8d9 zpNT_!RWF`6M=hhV0r#Flhj|;v&*In(aQe^&xB878 zdo9k$nfu?&U4U#&6VS$|x%Q#B+xupd701TtP<57WPX$-EGFLdoBNipk;uk|eLxuap zw6qR#$TE5nD*q$;TM3-rPqW&{T)#&?gw3lElx~;*wJ5Q=AOD}{Pi6r%kYBfz@o#&b zls>gSs^(H*LV%RHk8SboQ(OGrxg24X6brrE?R0ZSv)B@sjwJ^5CuUw*HgEHl&u>lB zRxwy#zswYMKHB>5wUz6Qm+wz{vG;WJBLc3p|Kr54(=fc}LV&!tPxU*b&SN^ztX!e{-Qd;wqx)+DJ zNfxj0lK3$%J@5Da{L|OcMZL2G<^B6*S&_j&HT9V#qjxdwZC4^ i18nLabel: 'Sidebar_Sections_Order', i18nDescription: 'Sidebar_Sections_Order_Description', }); + + await this.add('Accounts_Default_User_Preferences_featuresPreview', '[]', { + type: 'string', + public: true, + }); }); await this.section('Avatar', async function () { diff --git a/apps/meteor/tests/end-to-end/api/miscellaneous.ts b/apps/meteor/tests/end-to-end/api/miscellaneous.ts index b8341f7c0994..d933f1f3c4b3 100644 --- a/apps/meteor/tests/end-to-end/api/miscellaneous.ts +++ b/apps/meteor/tests/end-to-end/api/miscellaneous.ts @@ -186,6 +186,7 @@ describe('miscellaneous', () => { 'muteFocusedConversations', 'notifyCalendarEvents', 'enableMobileRinging', + 'featuresPreview', ].filter((p) => Boolean(p)); expect(res.body).to.have.property('success', true); diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 8ce6bea2e117..27978d72e7dd 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -85,6 +85,7 @@ "Accounts_AllowEmailChange": "Allow Email Change", "Accounts_AllowEmailNotifications": "Allow Email Notifications", "Accounts_AllowFeaturePreview": "Allow Feature Preview", + "Accounts_AllowFeaturePreview_Description": "Make feature preview available to all workspace members.", "Accounts_AllowPasswordChange": "Allow Password Change", "Accounts_AllowPasswordChangeForOAuthUsers": "Allow Password Change for OAuth Users", "Accounts_AllowRealNameChange": "Allow Name Change", @@ -1125,8 +1126,8 @@ "Common_Access": "Common Access", "Commit": "Commit", "Community": "Community", - "Contextualbar_resizable": "Contextual bar resizable", - "Contextualbar_resizable_description": "Allows you to adjust the size of the contextual bar by simply dragging, giving you instant customization and flexibility", + "Contextualbar_resizable": "Resizable contextual bar", + "Contextualbar_resizable_description": "Adjust the size of the contextual bar by clicking and dragging the edge, giving you instant customization and flexibility.", "Free_Edition": "Free edition", "Composer_not_available_phone_calls": "Messages are not available on phone calls", "Condensed": "Condensed", @@ -1949,8 +1950,8 @@ "Enable_Password_History": "Enable Password History", "Enable_Password_History_Description": "When enabled, users won't be able to update their passwords to some of their most recently used passwords.", "Enable_Svg_Favicon": "Enable SVG favicon", - "Enable_timestamp": "Enable timestamp parsing in messages", - "Enable_timestamp_description": "Enable timestamps to be parsed in messages", + "Enable_timestamp": "Timestamp in messages", + "Enable_timestamp_description": "Render Unix timestamps inside messages in your local (system) timezone.", "Enable_to_bypass_email_verification": "Enable to bypass email verification", "Enable_two-factor_authentication": "Enable two-factor authentication via TOTP", "Enable_two-factor_authentication_email": "Enable two-factor authentication via Email", @@ -2284,7 +2285,10 @@ "Favorite_Rooms": "Enable Favorite Rooms", "Favorites": "Favorites", "Feature_preview": "Feature preview", - "Feature_preview_page_description": "Welcome to the features preview page! Here, you can enable the latest cutting-edge features that are currently under development and not yet officially released.\n\nPlease note that these configurations are still in the testing phase and may not be stable or fully functional.", + "Feature_preview_page_description": "Enable the latest features that are currently under development.", + "Feature_preview_page_callout": "Feature previews are being tested and may not be stable or fully functional. Features may become premium capabilities once officially released.", + "Feature_preview_admin_page_description": "Choose what feature previews to make available to workspace members.", + "Feature_preview_admin_page_callout": "Features enabled here will be enabled to each user in their feature preview preferences.", "featured": "featured", "Featured": "Featured", "Feature_depends_on_selected_call_provider_to_be_enabled_from_administration_settings": "This feature depends on the above selected call provider to be enabled from the administration settings (Admin -> Video Conference).", @@ -4363,7 +4367,7 @@ "Queue_Time": "Queue Time", "Queue_management": "Queue Management", "Quick_reactions": "Quick reactions", - "Quick_reactions_description": "The three most used reactions get an easy access while your mouse is over the message", + "Quick_reactions_description": "Easily access your most used and most recent emoji message reactions by hovering on a message.", "quote": "quote", "Quote": "Quote", "Random": "Random", diff --git a/packages/i18n/src/locales/hi-IN.i18n.json b/packages/i18n/src/locales/hi-IN.i18n.json index 090e081e83fa..3110d6e82a67 100644 --- a/packages/i18n/src/locales/hi-IN.i18n.json +++ b/packages/i18n/src/locales/hi-IN.i18n.json @@ -2169,7 +2169,6 @@ "Favorite_Rooms": "पसंदीदा कमरे सक्षम करें", "Favorites": "पसंदीदा", "Feature_preview": "फ़ीचर पूर्वावलोकन", - "Feature_preview_page_description": "फीचर पूर्वावलोकन पृष्ठ पर आपका स्वागत है! यहां, आप नवीनतम अत्याधुनिक सुविधाओं को सक्षम कर सकते हैं जो वर्तमान में विकास के अधीन हैं और अभी तक आधिकारिक तौर पर जारी नहीं की गई हैं।\n\nकृपया ध्यान दें कि ये कॉन्फ़िगरेशन अभी भी परीक्षण चरण में हैं और स्थिर या पूरी तरह कार्यात्मक नहीं हो सकते हैं।", "featured": "प्रदर्शित", "Featured": "प्रदर्शित", "Feature_depends_on_selected_call_provider_to_be_enabled_from_administration_settings": "यह सुविधा प्रशासन सेटिंग्स (एडमिन -> वीडियो कॉन्फ्रेंस) से सक्षम होने के लिए उपरोक्त चयनित कॉल प्रदाता पर निर्भर करती है।", @@ -4128,7 +4127,6 @@ "Queue_Time": "कतार समय", "Queue_management": "कतार प्रबंधन", "Quick_reactions": "त्वरित प्रतिक्रियाएँ", - "Quick_reactions_description": "जब आपका माउस संदेश पर होता है तो सबसे अधिक उपयोग की जाने वाली तीन प्रतिक्रियाओं तक आसान पहुंच मिलती है", "quote": "उद्धरण", "Quote": "उद्धरण", "Random": "Random", @@ -4987,7 +4985,7 @@ "The_application_will_be_able_to": "<1>{{appName}} यह करने में सक्षम होगा:", "The_channel_name_is_required": "चैनल का नाम आवश्यक है", "The_emails_are_being_sent": "ईमेल भेजे जा रहे हैं.", - "The_empty_room__roomName__will_be_removed_automatically": "खाली कमरा {{roomName}} स्वचालित रूप से हटा दिया जाएगा।", + "The_empty_room__roomName__will_be_removed_automatically": "खाली कमरा {{roomName}} स्वचालित रूप से हटा दिया जाएगा।", "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "छवि का आकार बदलना काम नहीं करेगा क्योंकि हम आपके सर्वर पर स्थापित ImageMagick या ग्राफ़िक्सMagick का पता नहीं लगा सकते हैं।", "The_message_is_a_discussion_you_will_not_be_able_to_recover": "संदेश एक चर्चा है आप संदेशों को पुनर्प्राप्त नहीं कर पाएंगे!", "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "मोबाइल सूचनाएं सभी उपयोगकर्ताओं के लिए अक्षम कर दी गई थीं, पुश गेटवे को फिर से सक्षम करने के लिए \"एडमिन > पुश\" पर जाएं", @@ -6134,4 +6132,4 @@ "Unlimited_seats": "असीमित सीटें", "Unlimited_MACs": "असीमित एमएसी", "Unlimited_seats_MACs": "असीमित सीटें और एमएसी" -} \ No newline at end of file +} diff --git a/packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx b/packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx new file mode 100644 index 000000000000..eece30cc7280 --- /dev/null +++ b/packages/ui-client/src/components/FeaturePreview/FeaturePreviewBadge.tsx @@ -0,0 +1,21 @@ +import { Badge } from '@rocket.chat/fuselage'; +import { useTranslation } from '@rocket.chat/ui-contexts'; + +import { usePreferenceFeaturePreviewList } from '../../hooks/usePreferenceFeaturePreviewList'; + +const FeaturePreviewBadge = () => { + const t = useTranslation(); + const { unseenFeatures } = usePreferenceFeaturePreviewList(); + + if (!unseenFeatures) { + return null; + } + + return ( + + {unseenFeatures} + + ); +}; + +export default FeaturePreviewBadge; diff --git a/packages/ui-client/src/components/FeaturePreview/index.ts b/packages/ui-client/src/components/FeaturePreview/index.ts new file mode 100644 index 000000000000..f6b8e5f2071e --- /dev/null +++ b/packages/ui-client/src/components/FeaturePreview/index.ts @@ -0,0 +1,2 @@ +export { FeaturePreview, FeaturePreviewOn, FeaturePreviewOff } from './FeaturePreview'; +export { default as FeaturePreviewBadge } from './FeaturePreviewBadge'; diff --git a/packages/ui-client/src/components/index.ts b/packages/ui-client/src/components/index.ts index 8642983229aa..7308c8e75431 100644 --- a/packages/ui-client/src/components/index.ts +++ b/packages/ui-client/src/components/index.ts @@ -11,7 +11,7 @@ export * as UserStatus from './UserStatus'; export * from './Header'; export * from './HeaderV2'; export * from './MultiSelectCustom/MultiSelectCustom'; -export * from './FeaturePreview/FeaturePreview'; +export * from './FeaturePreview'; export * from './RoomBanner'; export { default as UserAutoComplete } from './UserAutoComplete'; export * from './GenericMenu'; diff --git a/packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts b/packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts new file mode 100644 index 000000000000..373862379cc1 --- /dev/null +++ b/packages/ui-client/src/hooks/useDefaultSettingFeaturePreviewList.ts @@ -0,0 +1,12 @@ +import { useSetting } from '@rocket.chat/ui-contexts'; +import { useMemo } from 'react'; + +import { parseSetting, useFeaturePreviewList } from './useFeaturePreviewList'; + +export const useDefaultSettingFeaturePreviewList = () => { + const featurePreviewSettingJSON = useSetting('Accounts_Default_User_Preferences_featuresPreview'); + + const settingFeaturePreview = useMemo(() => parseSetting(featurePreviewSettingJSON), [featurePreviewSettingJSON]); + + return useFeaturePreviewList(settingFeaturePreview ?? []); +}; diff --git a/packages/ui-client/src/hooks/useFeaturePreview.ts b/packages/ui-client/src/hooks/useFeaturePreview.ts index 4bdda9c9251a..bd46adfdefff 100644 --- a/packages/ui-client/src/hooks/useFeaturePreview.ts +++ b/packages/ui-client/src/hooks/useFeaturePreview.ts @@ -1,7 +1,8 @@ -import { type FeaturesAvailable, useFeaturePreviewList } from './useFeaturePreviewList'; +import { type FeaturesAvailable } from './useFeaturePreviewList'; +import { usePreferenceFeaturePreviewList } from './usePreferenceFeaturePreviewList'; export const useFeaturePreview = (featureName: FeaturesAvailable) => { - const { features } = useFeaturePreviewList(); + const { features } = usePreferenceFeaturePreviewList(); const currentFeature = features?.find((feature) => feature.name === featureName); diff --git a/packages/ui-client/src/hooks/useFeaturePreviewList.ts b/packages/ui-client/src/hooks/useFeaturePreviewList.ts index ff103a8d84ef..08bda4ff81ff 100644 --- a/packages/ui-client/src/hooks/useFeaturePreviewList.ts +++ b/packages/ui-client/src/hooks/useFeaturePreviewList.ts @@ -1,5 +1,4 @@ import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useUserPreference, useSetting } from '@rocket.chat/ui-contexts'; export type FeaturesAvailable = | 'quickReactions' @@ -24,6 +23,7 @@ export type FeaturePreviewProps = { }; }; +// TODO: Move the features preview array to another directory to be accessed from both BE and FE. export const defaultFeaturesPreview: FeaturePreviewProps[] = [ { name: 'quickReactions', @@ -47,6 +47,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ i18n: 'Enable_timestamp', description: 'Enable_timestamp_description', group: 'Message', + imageUrl: 'images/featurePreview/timestamp.png', value: false, enabled: true, }, @@ -55,6 +56,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ i18n: 'Contextualbar_resizable', description: 'Contextualbar_resizable_description', group: 'Navigation', + imageUrl: 'images/featurePreview/resizable-contextual-bar.png', value: false, enabled: true, }, @@ -63,6 +65,7 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ i18n: 'New_navigation', description: 'New_navigation_description', group: 'Navigation', + imageUrl: 'images/featurePreview/enhanced-navigation.png', value: false, enabled: true, }, @@ -82,22 +85,27 @@ export const defaultFeaturesPreview: FeaturePreviewProps[] = [ export const enabledDefaultFeatures = defaultFeaturesPreview.filter((feature) => feature.enabled); -export const useFeaturePreviewList = () => { - const featurePreviewEnabled = useSetting('Accounts_AllowFeaturePreview'); - const userFeaturesPreview = useUserPreference('featuresPreview'); - - if (!featurePreviewEnabled) { - return { unseenFeatures: 0, features: [] as FeaturePreviewProps[], featurePreviewEnabled }; +// TODO: Remove this logic after we have a way to store object settings. +export const parseSetting = (setting?: FeaturePreviewProps[] | string) => { + if (typeof setting === 'string') { + try { + return JSON.parse(setting) as FeaturePreviewProps[]; + } catch (_) { + return; + } } + return setting; +}; +export const useFeaturePreviewList = (featuresList: Pick[]) => { const unseenFeatures = enabledDefaultFeatures.filter( - (feature) => !userFeaturesPreview?.find((userFeature) => userFeature.name === feature.name), + (defaultFeature) => !featuresList?.find((feature) => feature.name === defaultFeature.name), ).length; - const mergedFeatures = enabledDefaultFeatures.map((feature) => { - const userFeature = userFeaturesPreview?.find((userFeature) => userFeature.name === feature.name); - return { ...feature, ...userFeature }; + const mergedFeatures = enabledDefaultFeatures.map((defaultFeature) => { + const features = featuresList?.find((feature) => feature.name === defaultFeature.name); + return { ...defaultFeature, ...features }; }); - return { unseenFeatures, features: mergedFeatures, featurePreviewEnabled }; + return { unseenFeatures, features: mergedFeatures }; }; diff --git a/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.spec.tsx similarity index 79% rename from packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx rename to packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.spec.tsx index e348cfb6a864..ac3d6f92d51a 100644 --- a/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx +++ b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.spec.tsx @@ -1,10 +1,11 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; import { renderHook } from '@testing-library/react'; -import { useFeaturePreviewList, enabledDefaultFeatures } from './useFeaturePreviewList'; +import { enabledDefaultFeatures } from './useFeaturePreviewList'; +import { usePreferenceFeaturePreviewList } from './usePreferenceFeaturePreviewList'; it('should return the number of unseen features and Accounts_AllowFeaturePreview enabled ', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', true).build(), }); @@ -18,7 +19,7 @@ it('should return the number of unseen features and Accounts_AllowFeaturePreview }); it('should return the number of unseen features and Accounts_AllowFeaturePreview disabled ', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', false).build(), }); @@ -32,7 +33,7 @@ it('should return the number of unseen features and Accounts_AllowFeaturePreview }); it('should return 0 unseen features', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) @@ -49,7 +50,7 @@ it('should return 0 unseen features', () => { }); it('should ignore removed feature previews', () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) @@ -72,7 +73,7 @@ it('should ignore removed feature previews', () => { }); it('should turn off ignored feature previews', async () => { - const { result } = renderHook(() => useFeaturePreviewList(), { + const { result } = renderHook(() => usePreferenceFeaturePreviewList(), { legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) diff --git a/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts new file mode 100644 index 000000000000..d7c4c13417d2 --- /dev/null +++ b/packages/ui-client/src/hooks/usePreferenceFeaturePreviewList.ts @@ -0,0 +1,16 @@ +import { useSetting, useUserPreference } from '@rocket.chat/ui-contexts'; +import { useMemo } from 'react'; + +import { FeaturePreviewProps, parseSetting, useFeaturePreviewList } from './useFeaturePreviewList'; + +export const usePreferenceFeaturePreviewList = () => { + const featurePreviewEnabled = useSetting('Accounts_AllowFeaturePreview'); + const userFeaturesPreviewPreference = useUserPreference('featuresPreview'); + const userFeaturesPreview = useMemo(() => parseSetting(userFeaturesPreviewPreference), [userFeaturesPreviewPreference]); + const { unseenFeatures, features } = useFeaturePreviewList(userFeaturesPreview ?? []); + + if (!featurePreviewEnabled) { + return { unseenFeatures: 0, features: [] as FeaturePreviewProps[], featurePreviewEnabled }; + } + return { unseenFeatures, features, featurePreviewEnabled }; +}; diff --git a/packages/ui-client/src/index.ts b/packages/ui-client/src/index.ts index 3e640343da5b..a96ef265aadc 100644 --- a/packages/ui-client/src/index.ts +++ b/packages/ui-client/src/index.ts @@ -1,5 +1,7 @@ export * from './components'; export * from './hooks/useFeaturePreview'; +export * from './hooks/useDefaultSettingFeaturePreviewList'; export * from './hooks/useFeaturePreviewList'; +export * from './hooks/usePreferenceFeaturePreviewList'; export * from './hooks/useDocumentTitle'; export * from './helpers'; From 519ed86b392219851c28b101b1219c22caf23c9e Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 24 Sep 2024 12:03:20 -0600 Subject: [PATCH 112/170] fix: Avoid destructuring `connectionData` when value is undefined (#33339) --- .changeset/brave-brooms-invent.md | 5 ++++ .../app/livechat/server/lib/LivechatTyped.ts | 8 ++++-- .../end-to-end/api/livechat/09-visitors.ts | 28 +++++++++++++++++-- 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 .changeset/brave-brooms-invent.md diff --git a/.changeset/brave-brooms-invent.md b/.changeset/brave-brooms-invent.md new file mode 100644 index 000000000000..35d32b485944 --- /dev/null +++ b/.changeset/brave-brooms-invent.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes a problem that caused visitor creation to fail when GDPR setting was enabled and visitor was created via Apps Engine or the deprecated `livechat:registerGuest` method. diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts index ade6726336ec..6c2d655f4c95 100644 --- a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts +++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts @@ -589,6 +589,10 @@ class LivechatClass { } } + isValidObject(obj: unknown): obj is Record { + return typeof obj === 'object' && obj !== null; + } + async registerGuest({ id, token, @@ -654,10 +658,10 @@ class LivechatClass { visitorDataToUpdate.status = status; visitorDataToUpdate.ts = new Date(); - if (settings.get('Livechat_Allow_collect_and_store_HTTP_header_informations')) { + if (settings.get('Livechat_Allow_collect_and_store_HTTP_header_informations') && Livechat.isValidObject(connectionData)) { Livechat.logger.debug(`Saving connection data for visitor ${token}`); const { httpHeaders, clientAddress } = connectionData; - if (httpHeaders) { + if (Livechat.isValidObject(httpHeaders)) { visitorDataToUpdate.userAgent = httpHeaders['user-agent']; visitorDataToUpdate.ip = httpHeaders['x-real-ip'] || httpHeaders['x-forwarded-for'] || clientAddress; visitorDataToUpdate.host = httpHeaders?.host; diff --git a/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts b/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts index f02d9d1d1e95..31134412b8ec 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts @@ -1,11 +1,11 @@ import { faker } from '@faker-js/faker'; import type { ILivechatVisitor } from '@rocket.chat/core-typings'; import { expect } from 'chai'; -import { before, describe, it } from 'mocha'; +import { before, describe, it, after } from 'mocha'; import moment from 'moment'; import { type Response } from 'supertest'; -import { getCredentials, api, request, credentials } from '../../../data/api-data'; +import { getCredentials, api, request, credentials, methodCallAnon } from '../../../data/api-data'; import { createCustomField, deleteCustomField } from '../../../data/livechat/custom-fields'; import { makeAgentAvailable, @@ -217,6 +217,30 @@ describe('LIVECHAT - visitors', () => { expect(body.visitor).to.have.property('livechatData'); expect(body.visitor.livechatData).to.have.property(customFieldName, 'Not a real address :)'); }); + + describe('special cases', () => { + before(async () => { + await updateSetting('Livechat_Allow_collect_and_store_HTTP_header_informations', true); + }); + after(async () => { + await updateSetting('Livechat_Allow_collect_and_store_HTTP_header_informations', false); + }); + + // Note: this had to use the meteor method because the endpoint used `req.headers` which we cannot send as empty + // method doesn't pass them to the func allowing us to create a test for it + it('should allow to create a visitor without passing connectionData when GDPR setting is enabled', async () => { + const token = `${new Date().getTime()}-test`; + const response = await request + .post(methodCallAnon('livechat:registerGuest')) + .send({ message: `{"msg":"method","id":"23","method":"livechat:registerGuest","params":[{ "token": "${token}"}]}` }); + + expect(response.body).to.have.property('success', true); + const r = JSON.parse(response.body.message); + + expect(r.result).to.have.property('visitor'); + expect(r.result.visitor).to.have.property('token', token); + }); + }); }); describe('livechat/visitors.info', () => { From 2327ff58b2b06f127ac2d9fbc5b37ceb7202f752 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 24 Sep 2024 21:16:36 +0000 Subject: [PATCH 113/170] Release 6.13.0-rc.1 [no ci] --- .changeset/bump-patch-1727212585363.md | 5 +++ .changeset/pre.json | 3 ++ apps/meteor/CHANGELOG.md | 39 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 14 +++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- apps/uikit-playground/CHANGELOG.md | 13 +++++++ apps/uikit-playground/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 14 +++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 14 +++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 15 +++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 15 +++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 14 +++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 14 +++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 ++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/license/CHANGELOG.md | 10 +++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 15 +++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 10 +++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 12 ++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/api-client/CHANGELOG.md | 11 ++++++ packages/api-client/package.json | 2 +- packages/apps/CHANGELOG.md | 11 ++++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 12 ++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 3 ++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 11 ++++++ packages/cron/package.json | 2 +- packages/ddp-client/CHANGELOG.md | 12 ++++++ packages/ddp-client/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 14 +++++++ packages/fuselage-ui-kit/package.json | 8 ++-- packages/gazzodown/CHANGELOG.md | 12 ++++++ packages/gazzodown/package.json | 6 +-- packages/i18n/CHANGELOG.md | 6 +++ packages/i18n/package.json | 2 +- packages/instance-status/CHANGELOG.md | 10 +++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 10 +++++ packages/livechat/package.json | 2 +- packages/mock-providers/CHANGELOG.md | 9 +++++ packages/mock-providers/package.json | 2 +- packages/model-typings/CHANGELOG.md | 10 +++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 10 +++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 10 +++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 +++++ packages/ui-avatar/package.json | 4 +- packages/ui-client/CHANGELOG.md | 15 +++++++ packages/ui-client/package.json | 6 +-- packages/ui-contexts/CHANGELOG.md | 13 +++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 11 ++++++ packages/ui-video-conf/package.json | 6 +-- packages/web-ui-registration/CHANGELOG.md | 9 +++++ packages/web-ui-registration/package.json | 4 +- 72 files changed, 474 insertions(+), 47 deletions(-) create mode 100644 .changeset/bump-patch-1727212585363.md diff --git a/.changeset/bump-patch-1727212585363.md b/.changeset/bump-patch-1727212585363.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1727212585363.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/pre.json b/.changeset/pre.json index 6976ce2b60aa..7c415a6b0dde 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -63,7 +63,9 @@ "@rocket.chat/web-ui-registration": "10.0.0" }, "changesets": [ + "brave-brooms-invent", "brown-singers-appear", + "bump-patch-1727212585363", "cyan-ladybugs-thank", "dirty-stingrays-beg", "five-coats-rhyme", @@ -80,6 +82,7 @@ "mighty-drinks-hide", "nasty-tools-enjoy", "pink-swans-teach", + "quick-rings-wave", "quiet-cherries-punch", "rich-toes-bow", "rotten-rabbits-brush", diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index ee5d553d85a5..c31645ca4ea4 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,44 @@ # @rocket.chat/meteor +## 6.13.0-rc.1 + +### Minor Changes + +- ([#33212](https://github.com/RocketChat/Rocket.Chat/pull/33212)) Added new Admin Feature Preview management view, this will allow the workspace admins to both enable feature previewing in the workspace as well as define which feature previews are enabled by default for the users in the workspace. + +### Patch Changes + +- ([#33339](https://github.com/RocketChat/Rocket.Chat/pull/33339)) Fixes a problem that caused visitor creation to fail when GDPR setting was enabled and visitor was created via Apps Engine or the deprecated `livechat:registerGuest` method. + +- Bump @rocket.chat/meteor version. + +-

        Updated dependencies [2f9eea03d2]: + + - @rocket.chat/i18n@0.8.0-rc.1 + - @rocket.chat/ui-client@11.0.0-rc.1 + - @rocket.chat/ui-contexts@11.0.0-rc.1 + - @rocket.chat/web-ui-registration@11.0.0-rc.1 + - @rocket.chat/gazzodown@11.0.0-rc.1 + - @rocket.chat/fuselage-ui-kit@11.0.0-rc.1 + - @rocket.chat/ui-theming@0.3.0-rc.0 + - @rocket.chat/ui-avatar@7.0.0-rc.1 + - @rocket.chat/ui-video-conf@11.0.0-rc.1 + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 + - @rocket.chat/license@0.2.8-rc.1 + - @rocket.chat/omnichannel-services@0.3.5-rc.1 + - @rocket.chat/pdf-worker@0.2.5-rc.1 + - @rocket.chat/presence@0.2.8-rc.1 + - @rocket.chat/api-client@0.2.8-rc.1 + - @rocket.chat/apps@0.1.8-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/cron@0.1.8-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.3.0-rc.1 + - @rocket.chat/instance-status@0.1.8-rc.1 +
        + ## 6.13.0-rc.0 ### Minor Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index fc41ef05cacd..cfec7fa33824 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.13.0-rc.0" + "version": "6.13.0-rc.1" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index fb0072738db2..59da7bfded9c 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.3.5-rc.1 + +### Patch Changes + +-
        Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
        + ## 1.3.5-rc.0 ### Patch Changes @@ -13,6 +26,7 @@ - @rocket.chat/message-parser@0.31.30-rc.0 - @rocket.chat/models@0.3.0-rc.0
  • + ## 1.3.4 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 2cab26ca2d38..540a283be188 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.5-rc.0", + "version": "1.3.5-rc.1", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index a30ce30a7b6f..a36621eac547 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.13.0-rc.0", + "version": "6.13.0-rc.1", "private": true, "author": { "name": "Rocket.Chat", diff --git a/apps/uikit-playground/CHANGELOG.md b/apps/uikit-playground/CHANGELOG.md index d1528ca7502d..d2793509ff54 100644 --- a/apps/uikit-playground/CHANGELOG.md +++ b/apps/uikit-playground/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/uikit-playground +## 0.5.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.1 + - @rocket.chat/fuselage-ui-kit@11.0.0-rc.1 + - @rocket.chat/ui-avatar@7.0.0-rc.1 + - @rocket.chat/core-typings@6.13.0-rc.1 +
    + ## 0.5.0-rc.0 ### Minor Changes @@ -15,6 +27,7 @@ - @rocket.chat/ui-avatar@7.0.0-rc.0 - @rocket.chat/ui-contexts@11.0.0-rc.0
    + ## 0.4.1 ### Patch Changes diff --git a/apps/uikit-playground/package.json b/apps/uikit-playground/package.json index c5e7628001c6..82ebd11ee8dc 100644 --- a/apps/uikit-playground/package.json +++ b/apps/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.5.0-rc.0", + "version": "0.5.0-rc.1", "type": "module", "scripts": { "dev": "vite", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 929082c7bb9a..4c86f21b24c4 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.4.8-rc.0 ### Patch Changes @@ -12,6 +25,7 @@ - @rocket.chat/core-services@0.7.0-rc.0 - @rocket.chat/models@0.3.0-rc.0
    + ## 0.4.7 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index f2c7dd0a8761..36ea1d9294c6 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.8-rc.0", + "version": "0.4.8-rc.1", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index 5be055a875d0..c587761cdb38 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.4.8-rc.0 ### Patch Changes @@ -12,6 +25,7 @@ - @rocket.chat/core-services@0.7.0-rc.0 - @rocket.chat/models@0.3.0-rc.0
    + ## 0.4.7 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index eaa51c88691c..255b76d2db2e 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.8-rc.0", + "version": "0.4.8-rc.1", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 4b61203020bf..975b9af1abf2 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/ddp-streamer +## 0.3.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 + - @rocket.chat/instance-status@0.1.8-rc.1 +
    + ## 0.3.8-rc.0 ### Patch Changes @@ -13,6 +27,7 @@ - @rocket.chat/models@0.3.0-rc.0 - @rocket.chat/instance-status@0.1.7-rc.0
    + ## 0.3.7 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 16dcc7b6f507..7fd25289ca55 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.8-rc.0", + "version": "0.3.8-rc.1", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index b934e4037e8a..613d6ef3f377 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/omnichannel-services@0.3.5-rc.1 + - @rocket.chat/pdf-worker@0.2.5-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.4.8-rc.0 ### Patch Changes @@ -13,6 +27,7 @@ - @rocket.chat/omnichannel-services@0.3.4-rc.0 - @rocket.chat/pdf-worker@0.2.4-rc.0
    + ## 0.4.7 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 2f83816f4650..b0f97ce6d562 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.8-rc.0", + "version": "0.4.8-rc.1", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 78b716888236..795b6a2df283 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/presence@0.2.8-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.4.8-rc.0 ### Patch Changes @@ -12,6 +25,7 @@ - @rocket.chat/models@0.3.0-rc.0 - @rocket.chat/presence@0.2.7-rc.0
    + ## 0.4.7 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 7c21dbbdcbec..d1eb50267c52 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.8-rc.0", + "version": "0.4.8-rc.1", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 9ac7c4bed05f..cca63889589c 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/omnichannel-services@0.3.5-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.4.8-rc.0 ### Patch Changes @@ -12,6 +25,7 @@ - @rocket.chat/models@0.3.0-rc.0 - @rocket.chat/omnichannel-services@0.3.4-rc.0
    + ## 0.4.7 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index b800469a8274..634d49159ea8 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.8-rc.0", + "version": "0.4.8-rc.1", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 550a6a251252..05843d5502b1 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.4.8-rc.0 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 1ffac9a8775c..dca9ad443b3d 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.8-rc.0", + "version": "0.4.8-rc.1", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 05c4edfb5e77..92b07995bb4b 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 +
    + ## 0.2.8-rc.0 ### Patch Changes @@ -8,6 +17,7 @@ - @rocket.chat/core-typings@6.13.0-rc.0
    + ## 0.2.7 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 24b5676b8fc0..30a89b4334bd 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.8-rc.0", + "version": "0.2.8-rc.1", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 3cfb53628c15..339277317d7f 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.5-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 + - @rocket.chat/pdf-worker@0.2.5-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.3.5-rc.0 ### Patch Changes @@ -13,6 +27,7 @@ - @rocket.chat/models@0.3.0-rc.0 - @rocket.chat/pdf-worker@0.2.4-rc.0
    + ## 0.3.4 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 227ac2927974..98f507325586 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.5-rc.0", + "version": "0.3.5-rc.1", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index 785607cc6856..60f03a15a1de 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.5-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 +
    + ## 0.2.5-rc.0 ### Patch Changes @@ -8,6 +17,7 @@ - @rocket.chat/core-typings@6.13.0-rc.0
    + ## 0.2.4 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index dbc1f4483d23..570b3baab2e2 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.5-rc.0", + "version": "0.2.5-rc.1", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index 428dcbca5933..7b8bc5b28116 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/core-services@0.7.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.2.8-rc.0 ### Patch Changes @@ -10,6 +21,7 @@ - @rocket.chat/core-services@0.7.0-rc.0 - @rocket.chat/models@0.3.0-rc.0
    + ## 0.2.7 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index a0a9d059dead..912b4bf453fd 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.8-rc.0", + "version": "0.2.8-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index 2f89cab55d2a..1a87fa6034bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.13.0-rc.0", + "version": "6.13.0-rc.1", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md index 8158e1f876d5..18b99f365728 100644 --- a/packages/api-client/CHANGELOG.md +++ b/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 +
    + ## 0.2.8-rc.0 ### Patch Changes @@ -9,6 +19,7 @@ - @rocket.chat/rest-typings@6.13.0-rc.0 - @rocket.chat/core-typings@6.13.0-rc.0
    + ## 0.2.7 ### Patch Changes diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 10492ffedab4..b87cdb6600d9 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.8-rc.0", + "version": "0.2.8-rc.1", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.13", diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 10681302f29e..fcf1229c306a 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/model-typings@0.8.0-rc.1 +
    + ## 0.1.8-rc.0 ### Patch Changes @@ -9,6 +19,7 @@ - @rocket.chat/model-typings@0.8.0-rc.0 - @rocket.chat/core-typings@6.13.0-rc.0
    + ## 0.1.7 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 7dc954e5c3db..af88aff27664 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.8-rc.0", + "version": "0.1.8-rc.1", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index b1c5158d51a4..aafc8e1f0c6c 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.7.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.7.0-rc.0 ### Minor Changes @@ -19,6 +30,7 @@ - @rocket.chat/message-parser@0.31.30-rc.0 - @rocket.chat/models@0.3.0-rc.0
    + ## 0.6.1 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 7326f3cd3617..2ee07033e732 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.7.0-rc.0", + "version": "0.7.0-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index 4d686538954f..e7171dedd7b6 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.13.0-rc.1 + ## 6.13.0-rc.0 ### Minor Changes @@ -16,6 +18,7 @@ - @rocket.chat/message-parser@0.31.30-rc.0
    + ## 6.12.1 ### Patch Changes diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 2c5cb3f64a2d..6fcd5a43d20d 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.13.0-rc.0", + "version": "6.13.0-rc.1", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 27aa9beb2b65..297acb29b0cf 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.1.8-rc.0 ### Patch Changes @@ -9,6 +19,7 @@ - @rocket.chat/core-typings@6.13.0-rc.0 - @rocket.chat/models@0.3.0-rc.0
    + ## 0.1.7 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index 798e07348d3b..f9ac01ce7740 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.8-rc.0", + "version": "0.1.8-rc.1", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/ddp-client/CHANGELOG.md b/packages/ddp-client/CHANGELOG.md index ac4b3f76b11c..5e81a05f3804 100644 --- a/packages/ddp-client/CHANGELOG.md +++ b/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ddp-client +## 0.3.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 + - @rocket.chat/api-client@0.2.8-rc.1 +
    + ## 0.3.8-rc.0 ### Patch Changes @@ -10,6 +21,7 @@ - @rocket.chat/core-typings@6.13.0-rc.0 - @rocket.chat/api-client@0.2.7-rc.0
    + ## 0.3.7 ### Patch Changes diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index 949fe4eebd65..c2dc8b95a4b9 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.8-rc.0", + "version": "0.3.8-rc.1", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.13", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 895ffaf94ab4..14c2fea3c3c1 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 11.0.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.1 + - @rocket.chat/gazzodown@11.0.0-rc.1 + - @rocket.chat/ui-avatar@7.0.0-rc.1 + - @rocket.chat/ui-video-conf@11.0.0-rc.1 + - @rocket.chat/core-typings@6.13.0-rc.1 +
    + ## 11.0.0-rc.0 ### Minor Changes @@ -20,6 +33,7 @@ - @rocket.chat/ui-avatar@7.0.0-rc.0 - @rocket.chat/ui-contexts@11.0.0-rc.0
    + ## 10.0.1 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 573d65dc215e..975051db933f 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "11.0.0-rc.0", + "version": "11.0.0-rc.1", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "7.0.0-rc.0", - "@rocket.chat/ui-contexts": "11.0.0-rc.0", + "@rocket.chat/ui-avatar": "7.0.0-rc.1", + "@rocket.chat/ui-contexts": "11.0.0-rc.1", "@rocket.chat/ui-kit": "*", - "@rocket.chat/ui-video-conf": "11.0.0-rc.0", + "@rocket.chat/ui-video-conf": "11.0.0-rc.1", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 9c4e6777a8a8..5ce5e8e7afed 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 11.0.0-rc.1 + +### Patch Changes + +-
    Updated dependencies [2f9eea03d2]: + + - @rocket.chat/ui-client@11.0.0-rc.1 + - @rocket.chat/ui-contexts@11.0.0-rc.1 + - @rocket.chat/core-typings@6.13.0-rc.1 +
    + ## 11.0.0-rc.0 ### Minor Changes @@ -15,6 +26,7 @@ - @rocket.chat/message-parser@0.31.30-rc.0 - @rocket.chat/ui-contexts@11.0.0-rc.0
    + ## 10.0.1 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index b9a5023ce13c..cf4a9209d649 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "11.0.0-rc.0", + "version": "11.0.0-rc.1", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", @@ -74,8 +74,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.31-rc.0", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "11.0.0-rc.0", - "@rocket.chat/ui-contexts": "11.0.0-rc.0", + "@rocket.chat/ui-client": "11.0.0-rc.1", + "@rocket.chat/ui-contexts": "11.0.0-rc.1", "katex": "*", "react": "*" }, diff --git a/packages/i18n/CHANGELOG.md b/packages/i18n/CHANGELOG.md index 27bb4b471c66..3fa9140d4e99 100644 --- a/packages/i18n/CHANGELOG.md +++ b/packages/i18n/CHANGELOG.md @@ -1,5 +1,11 @@ # @rocket.chat/i18n +## 0.8.0-rc.1 + +### Minor Changes + +- ([#33212](https://github.com/RocketChat/Rocket.Chat/pull/33212)) Added new Admin Feature Preview management view, this will allow the workspace admins to both enable feature previewing in the workspace as well as define which feature previews are enabled by default for the users in the workspace. + ## 0.8.0-rc.0 ### Minor Changes diff --git a/packages/i18n/package.json b/packages/i18n/package.json index fe98e3b1f7fc..b93b9e9926cc 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/i18n", - "version": "0.8.0-rc.0", + "version": "0.8.0-rc.1", "private": true, "type": "module", "main": "./dist/index.js", diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index a2df17f053d2..dacdd5e1d383 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.8-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/models@0.3.0-rc.1 +
    + ## 0.1.8-rc.0 ### Patch Changes @@ -8,6 +17,7 @@ - @rocket.chat/models@0.3.0-rc.0
    + ## 0.1.7 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index a99c78a1ea78..79f0a19faf15 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.8-rc.0", + "version": "0.1.8-rc.1", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index 480e9f27b435..b5e6fc40dff6 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.20.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/gazzodown@11.0.0-rc.1 +
    + ## 1.20.0-rc.0 ### Minor Changes @@ -14,6 +23,7 @@ - @rocket.chat/gazzodown@11.0.0-rc.0 - @rocket.chat/message-parser@0.31.30-rc.0 + ## 1.19.4 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index ab4a2a9b3a11..5663d8746eea 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.20.0-rc.0", + "version": "1.20.0-rc.1", "files": [ "/build" ], diff --git a/packages/mock-providers/CHANGELOG.md b/packages/mock-providers/CHANGELOG.md index 5bd539fda340..a18b8b2e51fc 100644 --- a/packages/mock-providers/CHANGELOG.md +++ b/packages/mock-providers/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/mock-providers +## 0.1.3-rc.1 + +### Patch Changes + +-
    Updated dependencies [2f9eea03d2]: + + - @rocket.chat/i18n@0.8.0-rc.1 +
    + ## 0.1.3-rc.0 ### Patch Changes diff --git a/packages/mock-providers/package.json b/packages/mock-providers/package.json index 1a7051e87ff2..3cd4aef7325d 100644 --- a/packages/mock-providers/package.json +++ b/packages/mock-providers/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/mock-providers", - "version": "0.1.3-rc.0", + "version": "0.1.3-rc.1", "private": true, "dependencies": { "@rocket.chat/emitter": "~0.31.25", diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index ecec03565e40..54c1a0769d1e 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.8.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 +
    + ## 0.8.0-rc.0 ### Minor Changes @@ -18,6 +27,7 @@ - @rocket.chat/core-typings@6.13.0-rc.0 + ## 0.7.1 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index 10a2fd9b643c..2c535eb950ad 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.8.0-rc.0", + "version": "0.8.0-rc.1", "private": true, "devDependencies": { "@types/node-rsa": "^1.1.4", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 5491066cea23..a332d48b4443 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.3.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/model-typings@0.8.0-rc.1 +
    + ## 0.3.0-rc.0 ### Minor Changes @@ -12,6 +21,7 @@ - @rocket.chat/model-typings@0.8.0-rc.0 + ## 0.2.4 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index 35064171d9a6..aee39a8e841c 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.3.0-rc.0", + "version": "0.3.0-rc.1", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 8d999a8e7f5f..8dff96c33b7e 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.13.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.1 +
    + ## 6.13.0-rc.0 ### Minor Changes @@ -23,6 +32,7 @@ - @rocket.chat/core-typings@6.13.0-rc.0 - @rocket.chat/message-parser@0.31.30-rc.0 + ## 6.12.1 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 33aad6d64823..6d435a93ccfc 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.13.0-rc.0", + "version": "6.13.0-rc.1", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.13", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index 8192d99f770b..b5fc9c4b46d3 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 7.0.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.1 +
    + ## 7.0.0-rc.0 ### Minor Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 70f0efe2cff9..5c319c8837a5 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "7.0.0-rc.0", + "version": "7.0.0-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -30,7 +30,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "11.0.0-rc.0", + "@rocket.chat/ui-contexts": "11.0.0-rc.1", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 9be8c33c299d..0d5f01b17910 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/ui-client +## 11.0.0-rc.1 + +### Minor Changes + +- ([#33212](https://github.com/RocketChat/Rocket.Chat/pull/33212)) Added new Admin Feature Preview management view, this will allow the workspace admins to both enable feature previewing in the workspace as well as define which feature previews are enabled by default for the users in the workspace. + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.1 + - @rocket.chat/ui-avatar@7.0.0-rc.1 +
    + ## 11.0.0-rc.0 ### Minor Changes @@ -17,6 +31,7 @@ - @rocket.chat/ui-avatar@7.0.0-rc.0 - @rocket.chat/ui-contexts@11.0.0-rc.0 + ## 10.0.1 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 40bccd8ca628..3b551cf83681 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "11.0.0-rc.0", + "version": "11.0.0-rc.1", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", @@ -61,8 +61,8 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-avatar": "7.0.0-rc.0", - "@rocket.chat/ui-contexts": "11.0.0-rc.0", + "@rocket.chat/ui-avatar": "7.0.0-rc.1", + "@rocket.chat/ui-contexts": "11.0.0-rc.1", "react": "*", "react-i18next": "*" }, diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index 9dcb89eda51d..4e29a0d34993 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/ui-contexts +## 11.0.0-rc.1 + +### Patch Changes + +-
    Updated dependencies [2f9eea03d2]: + + - @rocket.chat/i18n@0.8.0-rc.1 + - @rocket.chat/core-typings@6.13.0-rc.1 + - @rocket.chat/rest-typings@6.13.0-rc.1 + - @rocket.chat/ddp-client@0.3.8-rc.1 +
    + ## 11.0.0-rc.0 ### Patch Changes @@ -11,6 +23,7 @@ - @rocket.chat/core-typings@6.13.0-rc.0 - @rocket.chat/ddp-client@0.3.7-rc.0 + ## 10.0.1 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 37f83e96a2aa..c3b0d5465da2 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "11.0.0-rc.0", + "version": "11.0.0-rc.1", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index e058c3c4d257..450c89d74361 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 11.0.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.1 + - @rocket.chat/ui-avatar@7.0.0-rc.1 +
    + ## 11.0.0-rc.0 ### Minor Changes @@ -13,6 +23,7 @@ - @rocket.chat/ui-avatar@7.0.0-rc.0 - @rocket.chat/ui-contexts@11.0.0-rc.0 + ## 10.0.1 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 74c3ec43bcbb..fa14113988a2 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "11.0.0-rc.0", + "version": "11.0.0-rc.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -39,8 +39,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "7.0.0-rc.0", - "@rocket.chat/ui-contexts": "11.0.0-rc.0", + "@rocket.chat/ui-avatar": "7.0.0-rc.1", + "@rocket.chat/ui-contexts": "11.0.0-rc.1", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index c53cb5a2623b..01be06de3c00 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 11.0.0-rc.1 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.1 +
    + ## 11.0.0-rc.0 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 23fd80c89842..c039b3fc6c94 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "11.0.0-rc.0", + "version": "11.0.0-rc.1", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -47,7 +47,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "11.0.0-rc.0", + "@rocket.chat/ui-contexts": "11.0.0-rc.1", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From 7dc9c4154f672c26f046e8936f4cb02e86814355 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 25 Sep 2024 13:14:54 -0300 Subject: [PATCH 114/170] chore: replace Meteor._localStorage -> Accounts.storageLocation (#33356) --- apps/meteor/app/e2e/client/rocketchat.e2e.ts | 27 ++++++++++--------- apps/meteor/app/ui-master/server/scripts.ts | 1 + .../client/messageBox/createComposerAPI.ts | 8 +++--- apps/meteor/app/ui-utils/server/Message.ts | 4 +-- .../app/utils/client/lib/RestApiClient.ts | 6 +++-- .../client/meteorOverrides/login/saml.ts | 2 +- .../providers/UserProvider/UserProvider.tsx | 6 ++--- apps/meteor/client/startup/accounts.ts | 16 +---------- .../components/AuthorizationFormPage.tsx | 3 +-- .../externals/meteor/accounts-base.d.ts | 1 + 10 files changed, 31 insertions(+), 43 deletions(-) diff --git a/apps/meteor/app/e2e/client/rocketchat.e2e.ts b/apps/meteor/app/e2e/client/rocketchat.e2e.ts index bbd6f208f35a..50224cb89dbb 100644 --- a/apps/meteor/app/e2e/client/rocketchat.e2e.ts +++ b/apps/meteor/app/e2e/client/rocketchat.e2e.ts @@ -6,6 +6,7 @@ import { isE2EEMessage } from '@rocket.chat/core-typings'; import { Emitter } from '@rocket.chat/emitter'; import EJSON from 'ejson'; import _ from 'lodash'; +import { Accounts } from 'meteor/accounts-base'; import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; @@ -308,8 +309,8 @@ class E2E extends Emitter { getKeysFromLocalStorage(): KeyPair { return { - public_key: Meteor._localStorage.getItem('public_key'), - private_key: Meteor._localStorage.getItem('private_key'), + public_key: Accounts.storageLocation.getItem('public_key'), + private_key: Accounts.storageLocation.getItem('private_key'), }; } @@ -332,7 +333,7 @@ class E2E extends Emitter { imperativeModal.close(); }, onConfirm: () => { - Meteor._localStorage.removeItem('e2e.randomPassword'); + Accounts.storageLocation.removeItem('e2e.randomPassword'); this.setState(E2EEState.READY); dispatchToastMessage({ type: 'success', message: t('End_To_End_Encryption_Enabled') }); this.closeAlert(); @@ -394,7 +395,7 @@ class E2E extends Emitter { await this.persistKeys(this.getKeysFromLocalStorage(), await this.createRandomPassword()); } - const randomPassword = Meteor._localStorage.getItem('e2e.randomPassword'); + const randomPassword = Accounts.storageLocation.getItem('e2e.randomPassword'); if (randomPassword) { this.setState(E2EEState.SAVE_PASSWORD); this.openAlert({ @@ -412,8 +413,8 @@ class E2E extends Emitter { this.log('-> Stop Client'); this.closeAlert(); - Meteor._localStorage.removeItem('public_key'); - Meteor._localStorage.removeItem('private_key'); + Accounts.storageLocation.removeItem('public_key'); + Accounts.storageLocation.removeItem('private_key'); this.instancesByRoomId = {}; this.privateKey = undefined; this.started = false; @@ -425,8 +426,8 @@ class E2E extends Emitter { async changePassword(newPassword: string): Promise { await this.persistKeys(this.getKeysFromLocalStorage(), newPassword, { force: true }); - if (Meteor._localStorage.getItem('e2e.randomPassword')) { - Meteor._localStorage.setItem('e2e.randomPassword', newPassword); + if (Accounts.storageLocation.getItem('e2e.randomPassword')) { + Accounts.storageLocation.setItem('e2e.randomPassword', newPassword); } } @@ -447,12 +448,12 @@ class E2E extends Emitter { } async loadKeys({ public_key, private_key }: { public_key: string; private_key: string }): Promise { - Meteor._localStorage.setItem('public_key', public_key); + Accounts.storageLocation.setItem('public_key', public_key); try { this.privateKey = await importRSAKey(EJSON.parse(private_key), ['decrypt']); - Meteor._localStorage.setItem('private_key', private_key); + Accounts.storageLocation.setItem('private_key', private_key); } catch (error) { this.setState(E2EEState.ERROR); return this.error('Error importing private key: ', error); @@ -474,7 +475,7 @@ class E2E extends Emitter { try { const publicKey = await exportJWKKey(key.publicKey); - Meteor._localStorage.setItem('public_key', JSON.stringify(publicKey)); + Accounts.storageLocation.setItem('public_key', JSON.stringify(publicKey)); } catch (error) { this.setState(E2EEState.ERROR); return this.error('Error exporting public key: ', error); @@ -483,7 +484,7 @@ class E2E extends Emitter { try { const privateKey = await exportJWKKey(key.privateKey); - Meteor._localStorage.setItem('private_key', JSON.stringify(privateKey)); + Accounts.storageLocation.setItem('private_key', JSON.stringify(privateKey)); } catch (error) { this.setState(E2EEState.ERROR); return this.error('Error exporting private key: ', error); @@ -498,7 +499,7 @@ class E2E extends Emitter { async createRandomPassword(): Promise { const randomPassword = await generateMnemonicPhrase(5); - Meteor._localStorage.setItem('e2e.randomPassword', randomPassword); + Accounts.storageLocation.setItem('e2e.randomPassword', randomPassword); return randomPassword; } diff --git a/apps/meteor/app/ui-master/server/scripts.ts b/apps/meteor/app/ui-master/server/scripts.ts index 9edadb021d32..3e84a6e39c90 100644 --- a/apps/meteor/app/ui-master/server/scripts.ts +++ b/apps/meteor/app/ui-master/server/scripts.ts @@ -45,6 +45,7 @@ window.addEventListener('load', function() { }); window.localStorage.clear(); Meteor._localStorage = window.sessionStorage; + Accounts.config({ clientStorage: 'session' }); } }); ` diff --git a/apps/meteor/app/ui-message/client/messageBox/createComposerAPI.ts b/apps/meteor/app/ui-message/client/messageBox/createComposerAPI.ts index a926f8540d27..741f7959fa90 100644 --- a/apps/meteor/app/ui-message/client/messageBox/createComposerAPI.ts +++ b/apps/meteor/app/ui-message/client/messageBox/createComposerAPI.ts @@ -1,6 +1,6 @@ import type { IMessage } from '@rocket.chat/core-typings'; import { Emitter } from '@rocket.chat/emitter'; -import { Meteor } from 'meteor/meteor'; +import { Accounts } from 'meteor/accounts-base'; import type { ComposerAPI } from '../../../../client/lib/chats/ChatAPI'; import { withDebouncing } from '../../../../lib/utils/highOrderFunctions'; @@ -31,11 +31,11 @@ export const createComposerAPI = (input: HTMLTextAreaElement, storageID: string) const persist = withDebouncing({ wait: 300 })(() => { if (input.value) { - Meteor._localStorage.setItem(storageID, input.value); + Accounts.storageLocation.setItem(storageID, input.value); return; } - Meteor._localStorage.removeItem(storageID); + Accounts.storageLocation.removeItem(storageID); }); const notifyQuotedMessagesUpdate = (): void => { @@ -262,7 +262,7 @@ export const createComposerAPI = (input: HTMLTextAreaElement, storageID: string) const insertNewLine = (): void => insertText('\n'); - setText(Meteor._localStorage.getItem(storageID) ?? '', { + setText(Accounts.storageLocation.getItem(storageID) ?? '', { skipFocus: true, }); diff --git a/apps/meteor/app/ui-utils/server/Message.ts b/apps/meteor/app/ui-utils/server/Message.ts index 06ae59238b42..21d8886c70bc 100644 --- a/apps/meteor/app/ui-utils/server/Message.ts +++ b/apps/meteor/app/ui-utils/server/Message.ts @@ -1,6 +1,6 @@ import type { IMessage } from '@rocket.chat/core-typings'; import { escapeHTML } from '@rocket.chat/string-helpers'; -import { Meteor } from 'meteor/meteor'; +import { Accounts } from 'meteor/accounts-base'; import { trim } from '../../../lib/utils/stringUtils'; import { i18n } from '../../../server/lib/i18n'; @@ -17,7 +17,7 @@ export const Message = { } if (messageType.message) { if (!language) { - language = Meteor._localStorage.getItem('userLanguage') || 'en'; + language = Accounts.storageLocation.getItem('userLanguage') || 'en'; } const data = (typeof messageType.data === 'function' && messageType.data(msg)) || {}; return i18n.t(messageType.message, { ...data, lng: language }); diff --git a/apps/meteor/app/utils/client/lib/RestApiClient.ts b/apps/meteor/app/utils/client/lib/RestApiClient.ts index c5e12250b441..53c95ee3e4fa 100644 --- a/apps/meteor/app/utils/client/lib/RestApiClient.ts +++ b/apps/meteor/app/utils/client/lib/RestApiClient.ts @@ -1,6 +1,5 @@ import { RestClient } from '@rocket.chat/api-client'; import { Accounts } from 'meteor/accounts-base'; -import { Meteor } from 'meteor/meteor'; import { invokeTwoFactorModal } from '../../../../client/lib/2fa/process2faReturn'; import { baseURI } from '../../../../client/lib/baseURI'; @@ -12,7 +11,10 @@ class RestApiClient extends RestClient { 'X-Auth-Token': string; } | undefined { - const [uid, token] = [Meteor._localStorage.getItem(Accounts.USER_ID_KEY), Meteor._localStorage.getItem(Accounts.LOGIN_TOKEN_KEY)]; + const [uid, token] = [ + Accounts.storageLocation.getItem(Accounts.USER_ID_KEY), + Accounts.storageLocation.getItem(Accounts.LOGIN_TOKEN_KEY), + ]; if (!uid || !token) { return; diff --git a/apps/meteor/client/meteorOverrides/login/saml.ts b/apps/meteor/client/meteorOverrides/login/saml.ts index 14dfcc694e5c..f2199af5c0c7 100644 --- a/apps/meteor/client/meteorOverrides/login/saml.ts +++ b/apps/meteor/client/meteorOverrides/login/saml.ts @@ -72,7 +72,7 @@ Meteor.logout = async function (...args) { // Remove the userId from the client to prevent calls to the server while the logout is processed. // If the logout fails, the userId will be reloaded on the resume call - Meteor._localStorage.removeItem(Accounts.USER_ID_KEY); + Accounts.storageLocation.removeItem(Accounts.USER_ID_KEY); // A nasty bounce: 'result' has the SAML LogoutRequest but we need a proper 302 to redirected from the server. window.location.replace(Meteor.absoluteUrl(`_saml/sloRedirect/${provider}/?redirect=${encodeURIComponent(result)}`)); diff --git a/apps/meteor/client/providers/UserProvider/UserProvider.tsx b/apps/meteor/client/providers/UserProvider/UserProvider.tsx index 27bba21eae95..53761fbef4e7 100644 --- a/apps/meteor/client/providers/UserProvider/UserProvider.tsx +++ b/apps/meteor/client/providers/UserProvider/UserProvider.tsx @@ -19,8 +19,6 @@ import { useDeleteUser } from './hooks/useDeleteUser'; import { useEmailVerificationWarning } from './hooks/useEmailVerificationWarning'; import { useUpdateAvatar } from './hooks/useUpdateAvatar'; -const getUserId = (): string | null => Meteor.userId(); - const getUser = (): IUser | null => Meteor.user() as IUser | null; const logout = (): Promise => @@ -42,9 +40,9 @@ type UserProviderProps = { }; const UserProvider = ({ children }: UserProviderProps): ReactElement => { - const userId = useReactiveValue(getUserId); - const previousUserId = useRef(userId); const user = useReactiveValue(getUser); + const userId = user?._id ?? null; + const previousUserId = useRef(userId); const [userLanguage, setUserLanguage] = useLocalStorage('userLanguage', ''); const [preferedLanguage, setPreferedLanguage] = useLocalStorage('preferedLanguage', ''); diff --git a/apps/meteor/client/startup/accounts.ts b/apps/meteor/client/startup/accounts.ts index 88008a606656..50c033dc0596 100644 --- a/apps/meteor/client/startup/accounts.ts +++ b/apps/meteor/client/startup/accounts.ts @@ -2,7 +2,7 @@ import { Accounts } from 'meteor/accounts-base'; import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; -import { settings } from '../../app/settings/client'; +// import { settings } from '../../app/settings/client'; import { mainReady } from '../../app/ui-utils/client'; import { sdk } from '../../app/utils/client/lib/SDKClient'; import { t } from '../../app/utils/lib/i18n'; @@ -25,17 +25,3 @@ Accounts.onEmailVerificationLink((token: string) => { }); }); }); - -Meteor.startup(() => { - Tracker.autorun((computation) => { - const forgetUserSessionOnWindowClose = settings.get('Accounts_ForgetUserSessionOnWindowClose'); - - if (forgetUserSessionOnWindowClose === undefined) { - return; - } - - computation.stop(); - - Accounts.config({ clientStorage: forgetUserSessionOnWindowClose ? 'session' : 'local' }); - }); -}); diff --git a/apps/meteor/client/views/oauth/components/AuthorizationFormPage.tsx b/apps/meteor/client/views/oauth/components/AuthorizationFormPage.tsx index 14f251042abc..623214352372 100644 --- a/apps/meteor/client/views/oauth/components/AuthorizationFormPage.tsx +++ b/apps/meteor/client/views/oauth/components/AuthorizationFormPage.tsx @@ -4,7 +4,6 @@ import { useUniqueId } from '@rocket.chat/fuselage-hooks'; import { Form } from '@rocket.chat/layout'; import { useLogout, useRoute } from '@rocket.chat/ui-contexts'; import { Accounts } from 'meteor/accounts-base'; -import { Meteor } from 'meteor/meteor'; import React, { useEffect, useMemo, useRef } from 'react'; import { Trans, useTranslation } from 'react-i18next'; @@ -19,7 +18,7 @@ type AuthorizationFormPageProps = { }; const AuthorizationFormPage = ({ oauthApp, redirectUri, user }: AuthorizationFormPageProps) => { - const token = useMemo(() => Meteor._localStorage.getItem(Accounts.LOGIN_TOKEN_KEY) ?? undefined, []); + const token = useMemo(() => Accounts.storageLocation.getItem(Accounts.LOGIN_TOKEN_KEY) ?? undefined, []); const formLabelId = useUniqueId(); diff --git a/apps/meteor/definition/externals/meteor/accounts-base.d.ts b/apps/meteor/definition/externals/meteor/accounts-base.d.ts index 31b70f7b7154..0d30eed0430d 100644 --- a/apps/meteor/definition/externals/meteor/accounts-base.d.ts +++ b/apps/meteor/definition/externals/meteor/accounts-base.d.ts @@ -1,5 +1,6 @@ declare module 'meteor/accounts-base' { namespace Accounts { + const storageLocation: Window['localStorage']; function createUser( options: { username?: string; From b4c3e5cfee9f5a778b26c374b8b89a5a1ae79a26 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 25 Sep 2024 19:43:42 -0300 Subject: [PATCH 115/170] Bump rocket.chat to 6.14.0-develop (#33366) --- apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/package.json | 2 +- package.json | 2 +- packages/core-typings/package.json | 2 +- packages/rest-typings/package.json | 2 +- yarn.lock | 22 +++++++++++----------- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index cfec7fa33824..de3eb50fa5d1 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.13.0-rc.1" + "version": "6.14.0-develop" } diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 766770427e0a..3767939a7e3c 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.13.0-rc.1", + "version": "6.14.0-develop", "private": true, "author": { "name": "Rocket.Chat", diff --git a/package.json b/package.json index 1a87fa6034bf..f06deed440ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.13.0-rc.1", + "version": "6.14.0-develop", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 6fcd5a43d20d..0db23760066b 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.13.0-rc.1", + "version": "6.14.0-develop", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 6d435a93ccfc..30a448980c9b 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.13.0-rc.1", + "version": "6.14.0-develop", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.13", diff --git a/yarn.lock b/yarn.lock index 161420f46399..f6c5de3e9a44 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8962,10 +8962,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 7.0.0-rc.0 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-avatar": 7.0.0-rc.1 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 "@rocket.chat/ui-kit": "*" - "@rocket.chat/ui-video-conf": 11.0.0-rc.0 + "@rocket.chat/ui-video-conf": 11.0.0-rc.1 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9052,8 +9052,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.31-rc.0 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 11.0.0-rc.0 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-client": 11.0.0-rc.1 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 katex: "*" react: "*" languageName: unknown @@ -10286,7 +10286,7 @@ __metadata: typescript: ~5.5.4 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 react: ~17.0.2 languageName: unknown linkType: soft @@ -10337,8 +10337,8 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-avatar": 7.0.0-rc.0 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-avatar": 7.0.0-rc.1 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 react: "*" react-i18next: "*" languageName: unknown @@ -10507,8 +10507,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 7.0.0-rc.0 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-avatar": 7.0.0-rc.1 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10596,7 +10596,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 725997009f5ad86227c216473c1b41fad6c7374e Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Thu, 26 Sep 2024 11:53:04 -0300 Subject: [PATCH 116/170] Bump Apps-Engine version (#33368) --- apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/ddp-streamer/package.json | 2 +- ee/packages/presence/package.json | 2 +- packages/apps/package.json | 2 +- packages/core-services/package.json | 2 +- packages/core-typings/package.json | 2 +- packages/fuselage-ui-kit/package.json | 2 +- packages/rest-typings/package.json | 2 +- yarn.lock | 48 ++++++++++----------- 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 540a283be188..4aa98902c3e3 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -18,7 +18,7 @@ "author": "Rocket.Chat", "license": "MIT", "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "1.46.0", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", diff --git a/apps/meteor/package.json b/apps/meteor/package.json index a36621eac547..a1c74052c933 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -230,7 +230,7 @@ "@rocket.chat/agenda": "workspace:^", "@rocket.chat/api-client": "workspace:^", "@rocket.chat/apps": "workspace:^", - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "1.46.0", "@rocket.chat/base64": "workspace:^", "@rocket.chat/cas-validate": "workspace:^", "@rocket.chat/core-services": "workspace:^", diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 7fd25289ca55..fca0c2122b21 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -15,7 +15,7 @@ ], "author": "Rocket.Chat", "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "1.46.0", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 912b4bf453fd..aaa5596836a9 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@babel/preset-env": "~7.22.20", "@babel/preset-typescript": "~7.22.15", - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "1.46.0", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@types/node": "^14.18.63", diff --git a/packages/apps/package.json b/packages/apps/package.json index af88aff27664..8a758aa4fb6e 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -18,7 +18,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "1.46.0", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/model-typings": "workspace:^" } diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 2ee07033e732..f4e8369314c4 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -32,7 +32,7 @@ "extends": "../../package.json" }, "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "1.46.0", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/message-parser": "workspace:^", diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 6fcd5a43d20d..47543b7b6637 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -22,7 +22,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "1.46.0", "@rocket.chat/icons": "~0.38.0", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/ui-kit": "workspace:~", diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 975051db933f..4fcf3a852bf9 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -63,7 +63,7 @@ "@babel/preset-env": "~7.22.20", "@babel/preset-react": "~7.22.15", "@babel/preset-typescript": "~7.22.15", - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "1.46.0", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/fuselage": "^0.59.1", diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 6d435a93ccfc..529e073d0bd7 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -23,7 +23,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "1.46.0", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/ui-kit": "workspace:~", diff --git a/yarn.lock b/yarn.lock index bd9d3f7ea36d..2b1e2b970d43 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8512,9 +8512,9 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/apps-engine@npm:1.45.0-alpha.868": - version: 1.45.0-alpha.868 - resolution: "@rocket.chat/apps-engine@npm:1.45.0-alpha.868" +"@rocket.chat/apps-engine@npm:1.46.0": + version: 1.46.0 + resolution: "@rocket.chat/apps-engine@npm:1.46.0" dependencies: "@msgpack/msgpack": 3.0.0-beta2 adm-zip: ^0.5.9 @@ -8530,7 +8530,7 @@ __metadata: uuid: ~8.3.2 peerDependencies: "@rocket.chat/ui-kit": "*" - checksum: 3ac41e3de76be67e856e4bca888f113360628e510f9d4c66d70ed71d84f25bda6ca6659ead6c7a87d21c117c47bfa090b4508cce66e8630d2e935d3ed3158835 + checksum: 0b4f0c6d00c666a78c488e5940639523e5d22500cbe2d687adc4b532b221be0e4bb9c4f011730077d8f8a06e252ea8e1d78c90d56f2517a5cf5d36d4376bed1e languageName: node linkType: hard @@ -8538,7 +8538,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/apps@workspace:packages/apps" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.868 + "@rocket.chat/apps-engine": 1.46.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/model-typings": "workspace:^" eslint: ~8.45.0 @@ -8611,7 +8611,7 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": 1.45.0-alpha.868 + "@rocket.chat/apps-engine": 1.46.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/icons": ~0.38.0 @@ -8636,7 +8636,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/core-typings@workspace:packages/core-typings" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.868 + "@rocket.chat/apps-engine": 1.46.0 "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/icons": ~0.38.0 "@rocket.chat/message-parser": "workspace:^" @@ -8709,7 +8709,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/ddp-streamer@workspace:ee/apps/ddp-streamer" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.868 + "@rocket.chat/apps-engine": 1.46.0 "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/ddp-client": "workspace:~" @@ -8907,7 +8907,7 @@ __metadata: "@babel/preset-env": ~7.22.20 "@babel/preset-react": ~7.22.15 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": 1.45.0-alpha.868 + "@rocket.chat/apps-engine": 1.46.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/fuselage": ^0.59.1 @@ -8959,10 +8959,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 7.0.0-rc.0 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-avatar": 7.0.0-rc.1 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 "@rocket.chat/ui-kit": "*" - "@rocket.chat/ui-video-conf": 11.0.0-rc.0 + "@rocket.chat/ui-video-conf": 11.0.0-rc.1 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9049,8 +9049,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.31-rc.0 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 11.0.0-rc.0 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-client": 11.0.0-rc.1 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 katex: "*" react: "*" languageName: unknown @@ -9360,7 +9360,7 @@ __metadata: "@rocket.chat/agenda": "workspace:^" "@rocket.chat/api-client": "workspace:^" "@rocket.chat/apps": "workspace:^" - "@rocket.chat/apps-engine": 1.45.0-alpha.868 + "@rocket.chat/apps-engine": 1.46.0 "@rocket.chat/base64": "workspace:^" "@rocket.chat/cas-validate": "workspace:^" "@rocket.chat/core-services": "workspace:^" @@ -9983,7 +9983,7 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": 1.45.0-alpha.868 + "@rocket.chat/apps-engine": 1.46.0 "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" @@ -10097,7 +10097,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/rest-typings@workspace:packages/rest-typings" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.868 + "@rocket.chat/apps-engine": 1.46.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:~" "@rocket.chat/message-parser": "workspace:^" @@ -10257,7 +10257,7 @@ __metadata: typescript: ~5.5.4 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 react: ~17.0.2 languageName: unknown linkType: soft @@ -10308,8 +10308,8 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-avatar": 7.0.0-rc.0 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-avatar": 7.0.0-rc.1 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 react: "*" react-i18next: "*" languageName: unknown @@ -10478,8 +10478,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 7.0.0-rc.0 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-avatar": 7.0.0-rc.1 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10567,7 +10567,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2 - "@rocket.chat/ui-contexts": 11.0.0-rc.0 + "@rocket.chat/ui-contexts": 11.0.0-rc.1 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" @@ -37200,7 +37200,7 @@ __metadata: version: 0.0.0-use.local resolution: "rocketchat-services@workspace:apps/meteor/ee/server/services" dependencies: - "@rocket.chat/apps-engine": 1.45.0-alpha.868 + "@rocket.chat/apps-engine": 1.46.0 "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/emitter": ~0.31.25 From 6bee2a11a5ca3ed282311d0dd7f97d9c0a9392a0 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:54:59 -0700 Subject: [PATCH 117/170] ci: use node20 for release action (#33343) --- packages/release-action/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/release-action/action.yml b/packages/release-action/action.yml index 2fc8fe35d565..23d7382aab6d 100644 --- a/packages/release-action/action.yml +++ b/packages/release-action/action.yml @@ -10,7 +10,7 @@ inputs: required: false runs: - using: "node16" + using: "node20" main: "dist/index.js" branding: From fc26d85b287e9f3c7b8b8f714316cfb72470048e Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 26 Sep 2024 18:47:39 -0300 Subject: [PATCH 118/170] regression: `Sidepanel` sort requires refresh after room update (#33370) --- .../views/room/Sidepanel/hooks/useTeamslistChildren.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts index 5791a6e5d547..772c29509608 100644 --- a/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts +++ b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts @@ -1,6 +1,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import type { Mongo } from 'meteor/mongo'; import { useEffect, useMemo } from 'react'; import { ChatRoom } from '../../../../../app/models/client'; @@ -12,7 +13,7 @@ const sortRoomByLastMessage = (a: IRoom, b: IRoom) => { if (!b.lm) { return -1; } - return new Date(b.lm).toUTCString().localeCompare(new Date(a.lm).toUTCString()); + return b.lm.getTime() - a.lm.getTime(); }; export const useTeamsListChildrenUpdate = ( @@ -23,7 +24,7 @@ export const useTeamsListChildrenUpdate = ( const queryClient = useQueryClient(); const query = useMemo(() => { - const query: Parameters[0] = { + const query: Mongo.Selector = { $or: [ { _id: parentRid, From 14f7fd11e445ae50f4d5d99f0f97b100ef0dfd55 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 26 Sep 2024 18:47:39 -0300 Subject: [PATCH 119/170] regression: `Sidepanel` sort requires refresh after room update (#33370) --- .../views/room/Sidepanel/hooks/useTeamslistChildren.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts index 5791a6e5d547..772c29509608 100644 --- a/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts +++ b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts @@ -1,6 +1,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import type { Mongo } from 'meteor/mongo'; import { useEffect, useMemo } from 'react'; import { ChatRoom } from '../../../../../app/models/client'; @@ -12,7 +13,7 @@ const sortRoomByLastMessage = (a: IRoom, b: IRoom) => { if (!b.lm) { return -1; } - return new Date(b.lm).toUTCString().localeCompare(new Date(a.lm).toUTCString()); + return b.lm.getTime() - a.lm.getTime(); }; export const useTeamsListChildrenUpdate = ( @@ -23,7 +24,7 @@ export const useTeamsListChildrenUpdate = ( const queryClient = useQueryClient(); const query = useMemo(() => { - const query: Parameters[0] = { + const query: Mongo.Selector = { $or: [ { _id: parentRid, From 9d26a73120639d961773d9e21fa844662e9f5a5f Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Thu, 26 Sep 2024 23:09:03 +0000 Subject: [PATCH 120/170] Release 6.13.0-rc.2 [no ci] --- .changeset/bump-patch-1727392133102.md | 5 +++ .changeset/pre.json | 1 + apps/meteor/CHANGELOG.md | 32 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 ++++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- apps/uikit-playground/CHANGELOG.md | 12 +++++++ apps/uikit-playground/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 ++++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 ++++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 14 ++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 ++++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 ++++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 ++++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 +++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 ++++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 ++++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 ++++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 +++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/api-client/CHANGELOG.md | 10 ++++++ packages/api-client/package.json | 2 +- packages/apps/CHANGELOG.md | 10 ++++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 +++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 ++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 ++++++ packages/cron/package.json | 2 +- packages/ddp-client/CHANGELOG.md | 11 +++++++ packages/ddp-client/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 ++++++++ packages/fuselage-ui-kit/package.json | 8 ++--- packages/gazzodown/CHANGELOG.md | 11 +++++++ packages/gazzodown/package.json | 6 ++-- packages/instance-status/CHANGELOG.md | 9 ++++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 ++++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 ++++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 ++++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 ++++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 ++++++ packages/ui-avatar/package.json | 4 +-- packages/ui-client/CHANGELOG.md | 10 ++++++ packages/ui-client/package.json | 6 ++-- packages/ui-contexts/CHANGELOG.md | 11 +++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 ++++++ packages/ui-video-conf/package.json | 6 ++-- packages/web-ui-registration/CHANGELOG.md | 9 ++++++ packages/web-ui-registration/package.json | 4 +-- 68 files changed, 415 insertions(+), 45 deletions(-) create mode 100644 .changeset/bump-patch-1727392133102.md diff --git a/.changeset/bump-patch-1727392133102.md b/.changeset/bump-patch-1727392133102.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1727392133102.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/pre.json b/.changeset/pre.json index 7c415a6b0dde..467d26f1e0fd 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -66,6 +66,7 @@ "brave-brooms-invent", "brown-singers-appear", "bump-patch-1727212585363", + "bump-patch-1727392133102", "cyan-ladybugs-thank", "dirty-stingrays-beg", "five-coats-rhyme", diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index c31645ca4ea4..891e1aacc10d 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,37 @@ # @rocket.chat/meteor +## 6.13.0-rc.2 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 + - @rocket.chat/license@0.2.8-rc.2 + - @rocket.chat/omnichannel-services@0.3.5-rc.2 + - @rocket.chat/pdf-worker@0.2.5-rc.2 + - @rocket.chat/presence@0.2.8-rc.2 + - @rocket.chat/api-client@0.2.8-rc.2 + - @rocket.chat/apps@0.1.8-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/cron@0.1.8-rc.2 + - @rocket.chat/fuselage-ui-kit@11.0.0-rc.2 + - @rocket.chat/gazzodown@11.0.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/ui-contexts@11.0.0-rc.2 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.3.0-rc.2 + - @rocket.chat/ui-theming@0.3.0-rc.0 + - @rocket.chat/ui-avatar@7.0.0-rc.2 + - @rocket.chat/ui-client@11.0.0-rc.2 + - @rocket.chat/ui-video-conf@11.0.0-rc.2 + - @rocket.chat/web-ui-registration@11.0.0-rc.2 + - @rocket.chat/instance-status@0.1.8-rc.2 +
    + ## 6.13.0-rc.1 ### Minor Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index cfec7fa33824..cdb965e398f1 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.13.0-rc.1" + "version": "6.13.0-rc.2" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 59da7bfded9c..533aa4bed06a 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.3.5-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 1.3.5-rc.1 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 4aa98902c3e3..3824180239ba 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.5-rc.1", + "version": "1.3.5-rc.2", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index a1c74052c933..ad9f35d1e940 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.13.0-rc.1", + "version": "6.13.0-rc.2", "private": true, "author": { "name": "Rocket.Chat", diff --git a/apps/uikit-playground/CHANGELOG.md b/apps/uikit-playground/CHANGELOG.md index d2793509ff54..8355445a504c 100644 --- a/apps/uikit-playground/CHANGELOG.md +++ b/apps/uikit-playground/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/uikit-playground +## 0.5.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/fuselage-ui-kit@11.0.0-rc.2 + - @rocket.chat/ui-contexts@11.0.0-rc.2 + - @rocket.chat/ui-avatar@7.0.0-rc.2 +
    + ## 0.5.0-rc.1 ### Patch Changes diff --git a/apps/uikit-playground/package.json b/apps/uikit-playground/package.json index 82ebd11ee8dc..31978e953958 100644 --- a/apps/uikit-playground/package.json +++ b/apps/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.5.0-rc.1", + "version": "0.5.0-rc.2", "type": "module", "scripts": { "dev": "vite", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 4c86f21b24c4..3f7aacf72531 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.4.8-rc.1 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 36ea1d9294c6..995f14803292 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.8-rc.1", + "version": "0.4.8-rc.2", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index c587761cdb38..596be6356d49 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.4.8-rc.1 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 255b76d2db2e..1b824e01726c 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.8-rc.1", + "version": "0.4.8-rc.2", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 975b9af1abf2..50a3a8329ef0 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/ddp-streamer +## 0.3.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 + - @rocket.chat/instance-status@0.1.8-rc.2 +
    + ## 0.3.8-rc.1 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index fca0c2122b21..5feec2abc901 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.8-rc.1", + "version": "0.3.8-rc.2", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 613d6ef3f377..6b87f074638c 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/omnichannel-services@0.3.5-rc.2 + - @rocket.chat/pdf-worker@0.2.5-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.4.8-rc.1 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index b0f97ce6d562..53ba16262a44 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.8-rc.1", + "version": "0.4.8-rc.2", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 795b6a2df283..b73a591e04c3 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/presence@0.2.8-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.4.8-rc.1 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index d1eb50267c52..88c87a1785ba 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.8-rc.1", + "version": "0.4.8-rc.2", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index cca63889589c..bd77d36d5fb1 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/omnichannel-services@0.3.5-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.4.8-rc.1 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 634d49159ea8..f9522c510479 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.8-rc.1", + "version": "0.4.8-rc.2", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 05843d5502b1..8d119d985f98 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.4.8-rc.1 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index dca9ad443b3d..9fb58738737a 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.8-rc.1", + "version": "0.4.8-rc.2", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 92b07995bb4b..5325c6fdab8c 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 +
    + ## 0.2.8-rc.1 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 30a89b4334bd..976461397924 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.8-rc.1", + "version": "0.2.8-rc.2", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 339277317d7f..04c1ed37d1f7 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.5-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 + - @rocket.chat/pdf-worker@0.2.5-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.3.5-rc.1 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 98f507325586..7d784b9ca847 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.5-rc.1", + "version": "0.3.5-rc.2", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index 60f03a15a1de..666ab0405664 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.5-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 +
    + ## 0.2.5-rc.1 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 570b3baab2e2..ef5fe9e25641 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.5-rc.1", + "version": "0.2.5-rc.2", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index 7b8bc5b28116..8478835b20c8 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/core-services@0.7.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.2.8-rc.1 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index aaa5596836a9..a658148d537f 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.8-rc.1", + "version": "0.2.8-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index 1a87fa6034bf..6da849fc768d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.13.0-rc.1", + "version": "6.13.0-rc.2", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md index 18b99f365728..879fad65c766 100644 --- a/packages/api-client/CHANGELOG.md +++ b/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 +
    + ## 0.2.8-rc.1 ### Patch Changes diff --git a/packages/api-client/package.json b/packages/api-client/package.json index b87cdb6600d9..972e51d4d804 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.8-rc.1", + "version": "0.2.8-rc.2", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.13", diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index fcf1229c306a..78678d25bbfc 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/model-typings@0.8.0-rc.2 +
    + ## 0.1.8-rc.1 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 8a758aa4fb6e..4262f5447404 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.8-rc.1", + "version": "0.1.8-rc.2", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index aafc8e1f0c6c..853a8fc13260 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.7.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.7.0-rc.1 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index f4e8369314c4..effb18278253 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.7.0-rc.1", + "version": "0.7.0-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index e7171dedd7b6..d8dd0a43ceb0 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.13.0-rc.2 + ## 6.13.0-rc.1 ## 6.13.0-rc.0 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 47543b7b6637..88748914eb47 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.13.0-rc.1", + "version": "6.13.0-rc.2", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 297acb29b0cf..a783830d3db8 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.1.8-rc.1 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index f9ac01ce7740..f23f1f9b04ae 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.8-rc.1", + "version": "0.1.8-rc.2", "private": true, "devDependencies": { "eslint": "~8.45.0", diff --git a/packages/ddp-client/CHANGELOG.md b/packages/ddp-client/CHANGELOG.md index 5e81a05f3804..20b386444de1 100644 --- a/packages/ddp-client/CHANGELOG.md +++ b/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ddp-client +## 0.3.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 + - @rocket.chat/api-client@0.2.8-rc.2 +
    + ## 0.3.8-rc.1 ### Patch Changes diff --git a/packages/ddp-client/package.json b/packages/ddp-client/package.json index c2dc8b95a4b9..54b10ecc53c9 100644 --- a/packages/ddp-client/package.json +++ b/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.8-rc.1", + "version": "0.3.8-rc.2", "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.13", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 14c2fea3c3c1..c5c801fd123b 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 11.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/gazzodown@11.0.0-rc.2 + - @rocket.chat/ui-contexts@11.0.0-rc.2 + - @rocket.chat/ui-avatar@7.0.0-rc.2 + - @rocket.chat/ui-video-conf@11.0.0-rc.2 +
    + ## 11.0.0-rc.1 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 4fcf3a852bf9..93e937c566a8 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "11.0.0-rc.1", + "version": "11.0.0-rc.2", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "7.0.0-rc.1", - "@rocket.chat/ui-contexts": "11.0.0-rc.1", + "@rocket.chat/ui-avatar": "7.0.0-rc.2", + "@rocket.chat/ui-contexts": "11.0.0-rc.2", "@rocket.chat/ui-kit": "*", - "@rocket.chat/ui-video-conf": "11.0.0-rc.1", + "@rocket.chat/ui-video-conf": "11.0.0-rc.2", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 5ce5e8e7afed..0b4fb2012547 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 11.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/ui-contexts@11.0.0-rc.2 + - @rocket.chat/ui-client@11.0.0-rc.2 +
    + ## 11.0.0-rc.1 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index cf4a9209d649..a905e90e2a4c 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "11.0.0-rc.1", + "version": "11.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", @@ -74,8 +74,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.31-rc.0", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "11.0.0-rc.1", - "@rocket.chat/ui-contexts": "11.0.0-rc.1", + "@rocket.chat/ui-client": "11.0.0-rc.2", + "@rocket.chat/ui-contexts": "11.0.0-rc.2", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index dacdd5e1d383..592d2b18879b 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.8-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/models@0.3.0-rc.2 +
    + ## 0.1.8-rc.1 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 79f0a19faf15..edcad17e2ff8 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.8-rc.1", + "version": "0.1.8-rc.2", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index b5e6fc40dff6..4c20e6d34d2f 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.20.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/gazzodown@11.0.0-rc.2 +
    + ## 1.20.0-rc.1 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 5663d8746eea..c3fb62ebc539 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.20.0-rc.1", + "version": "1.20.0-rc.2", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 54c1a0769d1e..51f30ad091e7 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.8.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 +
    + ## 0.8.0-rc.1 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index 2c535eb950ad..a3344bf44577 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.8.0-rc.1", + "version": "0.8.0-rc.2", "private": true, "devDependencies": { "@types/node-rsa": "^1.1.4", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index a332d48b4443..effdec77a73e 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.3.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/model-typings@0.8.0-rc.2 +
    + ## 0.3.0-rc.1 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index aee39a8e841c..578e1f52d9b5 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.3.0-rc.1", + "version": "0.3.0-rc.2", "private": true, "devDependencies": { "@rocket.chat/jest-presets": "workspace:~", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 8dff96c33b7e..4fc0ce1a524d 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.13.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 +
    + ## 6.13.0-rc.1 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 529e073d0bd7..d9259c966591 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.13.0-rc.1", + "version": "6.13.0-rc.2", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.13", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index b5fc9c4b46d3..06d8d346596a 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 7.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.2 +
    + ## 7.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 5c319c8837a5..2504481c999f 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "7.0.0-rc.1", + "version": "7.0.0-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -30,7 +30,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "11.0.0-rc.1", + "@rocket.chat/ui-contexts": "11.0.0-rc.2", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 0d5f01b17910..77ee80a47966 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-client +## 11.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.2 + - @rocket.chat/ui-avatar@7.0.0-rc.2 +
    + ## 11.0.0-rc.1 ### Minor Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 3b551cf83681..dc49888789de 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "11.0.0-rc.1", + "version": "11.0.0-rc.2", "private": true, "main": "./dist/index.js", "typings": "./dist/index.d.ts", @@ -61,8 +61,8 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-avatar": "7.0.0-rc.1", - "@rocket.chat/ui-contexts": "11.0.0-rc.1", + "@rocket.chat/ui-avatar": "7.0.0-rc.2", + "@rocket.chat/ui-contexts": "11.0.0-rc.2", "react": "*", "react-i18next": "*" }, diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index 4e29a0d34993..d77eb16272a0 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 11.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/core-typings@6.13.0-rc.2 + - @rocket.chat/rest-typings@6.13.0-rc.2 + - @rocket.chat/ddp-client@0.3.8-rc.2 +
    + ## 11.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index c3b0d5465da2..eaf609940c86 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "11.0.0-rc.1", + "version": "11.0.0-rc.2", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 450c89d74361..edef43cd60e4 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 11.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.2 + - @rocket.chat/ui-avatar@7.0.0-rc.2 +
    + ## 11.0.0-rc.1 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index fa14113988a2..1ec416147b4f 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "11.0.0-rc.1", + "version": "11.0.0-rc.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -39,8 +39,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "7.0.0-rc.1", - "@rocket.chat/ui-contexts": "11.0.0-rc.1", + "@rocket.chat/ui-avatar": "7.0.0-rc.2", + "@rocket.chat/ui-contexts": "11.0.0-rc.2", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 01be06de3c00..5d342fe4754c 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 11.0.0-rc.2 + +### Patch Changes + +-
    Updated dependencies []: + + - @rocket.chat/ui-contexts@11.0.0-rc.2 +
    + ## 11.0.0-rc.1 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index c039b3fc6c94..6cacf9fea0bf 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "11.0.0-rc.1", + "version": "11.0.0-rc.2", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -47,7 +47,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2", - "@rocket.chat/ui-contexts": "11.0.0-rc.1", + "@rocket.chat/ui-contexts": "11.0.0-rc.2", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From fa226e4fcc3f1e4f785dd45f0e615e13b7775100 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 27 Sep 2024 01:49:52 -0300 Subject: [PATCH 121/170] chore: add ui-composer to storybook (#33383) --- .gitignore | 1 + packages/ui-composer/package.json | 102 +++++++++++++++--------------- 2 files changed, 53 insertions(+), 50 deletions(-) diff --git a/.gitignore b/.gitignore index dbad2c29a22c..03e74631957b 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ yarn-error.log* .env.test.local .env.production.local +storybook-static # turbo .turbo diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index c43f3485880e..562865bfd2d1 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -1,52 +1,54 @@ { - "name": "@rocket.chat/ui-composer", - "version": "0.3.0-rc.0", - "private": true, - "main": "./dist/index.js", - "typings": "./dist/index.d.ts", - "files": [ - "/dist" - ], - "scripts": { - "lint": "eslint --ext .js,.jsx,.ts,.tsx .", - "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "build": "rm -rf dist && tsc -p tsconfig.build.json", - "typecheck": "tsc --noEmit", - "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput", - "storybook": "start-storybook -p 6006" - }, - "devDependencies": { - "@babel/core": "~7.22.20", - "@react-aria/toolbar": "^3.0.0-beta.1", - "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.59.1", - "@rocket.chat/icons": "~0.38.0", - "@storybook/addon-actions": "~6.5.16", - "@storybook/addon-docs": "~6.5.16", - "@storybook/addon-essentials": "~6.5.16", - "@storybook/builder-webpack4": "~6.5.16", - "@storybook/manager-webpack4": "~6.5.16", - "@storybook/react": "~6.5.16", - "@storybook/testing-library": "~0.0.13", - "@types/react": "~17.0.80", - "@types/react-dom": "~17.0.25", - "eslint": "~8.45.0", - "eslint-plugin-react": "~7.32.2", - "eslint-plugin-react-hooks": "~4.6.2", - "eslint-plugin-storybook": "~0.6.15", - "react": "~17.0.2", - "react-docgen-typescript-plugin": "~1.0.8", - "react-dom": "~17.0.2", - "typescript": "~5.5.4" - }, - "peerDependencies": { - "@react-aria/toolbar": "*", - "@rocket.chat/fuselage": "*", - "@rocket.chat/icons": "*", - "react": "^17.0.2", - "react-dom": "^17.0.2" - }, - "volta": { - "extends": "../../package.json" - } + "name": "@rocket.chat/ui-composer", + "version": "0.3.0-rc.0", + "private": true, + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "files": [ + "/dist" + ], + "scripts": { + "lint": "eslint --ext .js,.jsx,.ts,.tsx .", + "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", + "build": "rm -rf dist && tsc -p tsconfig.build.json", + "typecheck": "tsc --noEmit", + "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput", + "storybook": "start-storybook -p 6006", + "build-preview": "build-storybook", + ".:build-preview-move": "mkdir -p ../../.preview/ && cp -r ./storybook-static ../../.preview/ui-composer" + }, + "devDependencies": { + "@babel/core": "~7.22.20", + "@react-aria/toolbar": "^3.0.0-beta.1", + "@rocket.chat/eslint-config": "workspace:^", + "@rocket.chat/fuselage": "^0.59.1", + "@rocket.chat/icons": "~0.38.0", + "@storybook/addon-actions": "~6.5.16", + "@storybook/addon-docs": "~6.5.16", + "@storybook/addon-essentials": "~6.5.16", + "@storybook/builder-webpack4": "~6.5.16", + "@storybook/manager-webpack4": "~6.5.16", + "@storybook/react": "~6.5.16", + "@storybook/testing-library": "~0.0.13", + "@types/react": "~17.0.80", + "@types/react-dom": "~17.0.25", + "eslint": "~8.45.0", + "eslint-plugin-react": "~7.32.2", + "eslint-plugin-react-hooks": "~4.6.2", + "eslint-plugin-storybook": "~0.6.15", + "react": "~17.0.2", + "react-docgen-typescript-plugin": "~1.0.8", + "react-dom": "~17.0.2", + "typescript": "~5.5.4" + }, + "peerDependencies": { + "@react-aria/toolbar": "*", + "@rocket.chat/fuselage": "*", + "@rocket.chat/icons": "*", + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "volta": { + "extends": "../../package.json" + } } From 34087b04728c52038cfd3dc7c5412c1fa35d58e3 Mon Sep 17 00:00:00 2001 From: "Julio A." <52619625+julio-cfa@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:46:04 +0200 Subject: [PATCH 122/170] ci: remove Jira-GitHub security integration (#33384) --- .../vulnerabilities-jira-integration.yml | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 .github/workflows/vulnerabilities-jira-integration.yml diff --git a/.github/workflows/vulnerabilities-jira-integration.yml b/.github/workflows/vulnerabilities-jira-integration.yml deleted file mode 100644 index 2daeb533937d..000000000000 --- a/.github/workflows/vulnerabilities-jira-integration.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Github vulnerabilities and jira board integration - -on: - schedule: - - cron: '0 1 * * *' - -jobs: - IntegrateSecurityVulnerabilities: - runs-on: ubuntu-latest - steps: - - name: "Github vulnerabilities and jira board integration" - uses: RocketChat/github-vulnerabilities-jira-integration@v0.3 - env: - JIRA_URL: https://rocketchat.atlassian.net/ - JIRA_TOKEN: ${{ secrets.JIRA_TOKEN }} - GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }} - JIRA_EMAIL: security-team-accounts@rocket.chat - JIRA_PROJECT_ID: GJIT - UID_CUSTOMFIELD_ID: customfield_10059 - JIRA_COMPLETE_PHASE_ID: 31 - JIRA_START_PHASE_ID: 11 - From 5965a1dbfe568f3379f53202a888932e6ffd3e52 Mon Sep 17 00:00:00 2001 From: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:47:09 -0300 Subject: [PATCH 123/170] chore: Single Contact ID: improved typings and removed some duplicated code (#33324) --- .../app/livechat/server/api/v1/contact.ts | 14 +-- .../app/livechat/server/lib/Contacts.ts | 87 ++++++++----------- .../app/livechat/server/lib/LivechatTyped.ts | 4 +- .../server/models/raw/LivechatCustomField.ts | 6 +- 4 files changed, 50 insertions(+), 61 deletions(-) diff --git a/apps/meteor/app/livechat/server/api/v1/contact.ts b/apps/meteor/app/livechat/server/api/v1/contact.ts index f3fec80b23fe..ec0559d5f191 100644 --- a/apps/meteor/app/livechat/server/api/v1/contact.ts +++ b/apps/meteor/app/livechat/server/api/v1/contact.ts @@ -9,7 +9,7 @@ import { Match, check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; import { API } from '../../../../api/server'; -import { Contacts, createContact, updateContact } from '../../lib/Contacts'; +import { Contacts, createContact, updateContact, isSingleContactEnabled } from '../../lib/Contacts'; API.v1.addRoute( 'omnichannel/contact', @@ -96,8 +96,8 @@ API.v1.addRoute( { authRequired: true, permissionsRequired: ['create-livechat-contact'], validateParams: isPOSTOmnichannelContactsProps }, { async post() { - if (process.env.TEST_MODE?.toUpperCase() !== 'TRUE') { - throw new Meteor.Error('error-not-allowed', 'This endpoint is only allowed in test mode'); + if (!isSingleContactEnabled()) { + return API.v1.unauthorized(); } const contactId = await createContact({ ...this.bodyParams, unknown: false }); @@ -111,8 +111,8 @@ API.v1.addRoute( { authRequired: true, permissionsRequired: ['update-livechat-contact'], validateParams: isPOSTUpdateOmnichannelContactsProps }, { async post() { - if (process.env.TEST_MODE?.toUpperCase() !== 'TRUE') { - throw new Meteor.Error('error-not-allowed', 'This endpoint is only allowed in test mode'); + if (!isSingleContactEnabled()) { + return API.v1.unauthorized(); } const contact = await updateContact({ ...this.bodyParams }); @@ -127,8 +127,8 @@ API.v1.addRoute( { authRequired: true, permissionsRequired: ['view-livechat-contact'], validateParams: isGETOmnichannelContactsProps }, { async get() { - if (process.env.TEST_MODE?.toUpperCase() !== 'TRUE') { - throw new Meteor.Error('error-not-allowed', 'This endpoint is only allowed in test mode'); + if (!isSingleContactEnabled()) { + return API.v1.unauthorized(); } const contact = await LivechatContacts.findOneById(this.queryParams.contactId); diff --git a/apps/meteor/app/livechat/server/lib/Contacts.ts b/apps/meteor/app/livechat/server/lib/Contacts.ts index f6f812ce8af8..e9be40aa942b 100644 --- a/apps/meteor/app/livechat/server/lib/Contacts.ts +++ b/apps/meteor/app/livechat/server/lib/Contacts.ts @@ -1,4 +1,5 @@ import type { + AtLeast, ILivechatContact, ILivechatContactChannel, ILivechatCustomField, @@ -113,41 +114,8 @@ export const Contacts = { } } - const allowedCF = LivechatCustomField.findByScope>( - 'visitor', - { - projection: { _id: 1, label: 1, regexp: 1, required: 1 }, - }, - false, - ); - - const livechatData: Record = {}; - - for await (const cf of allowedCF) { - if (!customFields.hasOwnProperty(cf._id)) { - if (cf.required) { - throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label })); - } - continue; - } - const cfValue: string = trim(customFields[cf._id]); - - if (!cfValue || typeof cfValue !== 'string') { - if (cf.required) { - throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label })); - } - continue; - } - - if (cf.regexp) { - const regex = new RegExp(cf.regexp); - if (!regex.test(cfValue)) { - throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label })); - } - } - - livechatData[cf._id] = cfValue; - } + const allowedCF = await getAllowedCustomFields(); + const livechatData: Record = validateCustomFields(allowedCF, customFields, { ignoreAdditionalFields: true }); const fieldsToRemove = { // if field is explicitely set to empty string, remove @@ -202,15 +170,20 @@ export const Contacts = { }, }; +export function isSingleContactEnabled(): boolean { + // The Single Contact feature is not yet available in production, but can already be partially used in test environments. + return process.env.TEST_MODE?.toUpperCase() === 'TRUE'; +} + export async function createContact(params: CreateContactParams): Promise { - const { name, emails, phones, customFields = {}, contactManager, channels, unknown } = params; + const { name, emails, phones, customFields: receivedCustomFields = {}, contactManager, channels, unknown } = params; if (contactManager) { await validateContactManager(contactManager); } const allowedCustomFields = await getAllowedCustomFields(); - validateCustomFields(allowedCustomFields, customFields); + const customFields = validateCustomFields(allowedCustomFields, receivedCustomFields); const { insertedId } = await LivechatContacts.insertOne({ name, @@ -226,7 +199,7 @@ export async function createContact(params: CreateContactParams): Promise { - const { contactId, name, emails, phones, customFields, contactManager, channels } = params; + const { contactId, name, emails, phones, customFields: receivedCustomFields, contactManager, channels } = params; const contact = await LivechatContacts.findOneById>(contactId, { projection: { _id: 1 } }); @@ -238,17 +211,21 @@ export async function updateContact(params: UpdateContactParams): Promise { +async function getAllowedCustomFields(): Promise[]> { return LivechatCustomField.findByScope( 'visitor', { @@ -258,7 +235,13 @@ async function getAllowedCustomFields(): Promise { ).toArray(); } -export function validateCustomFields(allowedCustomFields: ILivechatCustomField[], customFields: Record) { +export function validateCustomFields( + allowedCustomFields: AtLeast[], + customFields: Record, + options?: { ignoreAdditionalFields?: boolean }, +): Record { + const validValues: Record = {}; + for (const cf of allowedCustomFields) { if (!customFields.hasOwnProperty(cf._id)) { if (cf.required) { @@ -281,14 +264,20 @@ export function validateCustomFields(allowedCustomFields: ILivechatCustomField[] throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label })); } } + + validValues[cf._id] = cfValue; } - const allowedCustomFieldIds = new Set(allowedCustomFields.map((cf) => cf._id)); - for (const key in customFields) { - if (!allowedCustomFieldIds.has(key)) { - throw new Error(i18n.t('error-custom-field-not-allowed', { key })); + if (!options?.ignoreAdditionalFields) { + const allowedCustomFieldIds = new Set(allowedCustomFields.map((cf) => cf._id)); + for (const key in customFields) { + if (!allowedCustomFieldIds.has(key)) { + throw new Error(i18n.t('error-custom-field-not-allowed', { key })); + } } } + + return validValues; } export async function validateContactManager(contactManagerUserId: string) { diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts index 6c2d655f4c95..44ee46f04418 100644 --- a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts +++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts @@ -71,7 +71,7 @@ import * as Mailer from '../../../mailer/server/api'; import { metrics } from '../../../metrics/server'; import { settings } from '../../../settings/server'; import { businessHourManager } from '../business-hour'; -import { createContact } from './Contacts'; +import { createContact, isSingleContactEnabled } from './Contacts'; import { parseAgentCustomFields, updateDepartmentAgents, validateEmail, normalizeTransferredByData } from './Helper'; import { QueueManager } from './QueueManager'; import { RoutingManager } from './RoutingManager'; @@ -669,7 +669,7 @@ class LivechatClass { } } - if (process.env.TEST_MODE?.toUpperCase() === 'TRUE') { + if (isSingleContactEnabled()) { const contactId = await createContact({ name: name ?? (visitorDataToUpdate.username as string), emails: email ? [email] : [], diff --git a/apps/meteor/server/models/raw/LivechatCustomField.ts b/apps/meteor/server/models/raw/LivechatCustomField.ts index 71228f55069d..38a93f6439b4 100644 --- a/apps/meteor/server/models/raw/LivechatCustomField.ts +++ b/apps/meteor/server/models/raw/LivechatCustomField.ts @@ -13,12 +13,12 @@ export class LivechatCustomFieldRaw extends BaseRaw implem return [{ key: { scope: 1 } }]; } - findByScope( + findByScope( scope: ILivechatCustomField['scope'], options?: FindOptions, includeHidden = true, - ): FindCursor { - return this.find({ scope, ...(includeHidden === true ? {} : { visibility: { $ne: 'hidden' } }) }, options); + ): FindCursor { + return this.find({ scope, ...(includeHidden === true ? {} : { visibility: { $ne: 'hidden' } }) }, options); } findMatchingCustomFields( From 92e366ee285a2f6adec4bafa45c3bc21994cf1e3 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Fri, 27 Sep 2024 14:45:31 -0300 Subject: [PATCH 124/170] fix: race condition when forwarding livechat by splitting subscription removal (#33381) --- .changeset/dry-taxis-cry.md | 5 +++++ apps/meteor/server/models/raw/BaseRaw.ts | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 .changeset/dry-taxis-cry.md diff --git a/.changeset/dry-taxis-cry.md b/.changeset/dry-taxis-cry.md new file mode 100644 index 000000000000..ae8244087d9e --- /dev/null +++ b/.changeset/dry-taxis-cry.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes a race condition that causes livechat conversations to get stuck in the agent's sidebar panel after being forwarded. diff --git a/apps/meteor/server/models/raw/BaseRaw.ts b/apps/meteor/server/models/raw/BaseRaw.ts index d822038b177e..3e763017bbd3 100644 --- a/apps/meteor/server/models/raw/BaseRaw.ts +++ b/apps/meteor/server/models/raw/BaseRaw.ts @@ -318,33 +318,33 @@ export abstract class BaseRaw< async findOneAndDelete(filter: Filter, options?: FindOneAndDeleteOptions): Promise> { if (!this.trash) { - if (options) { - return this.col.findOneAndDelete(filter, options); - } - return this.col.findOneAndDelete(filter); + return this.col.findOneAndDelete(filter, options || {}); } - const result = await this.col.findOneAndDelete(filter); - - const { value: doc } = result; + const doc = await this.col.findOne(filter); if (!doc) { - return result; + return { ok: 1, value: null }; } const { _id, ...record } = doc; - const trash: TDeleted = { ...record, _deletedAt: new Date(), __collection__: this.name, } as unknown as TDeleted; - // since the operation is not atomic, we need to make sure that the record is not already deleted/inserted await this.trash?.updateOne({ _id } as Filter, { $set: trash } as UpdateFilter, { upsert: true, }); - return result; + try { + await this.col.deleteOne({ _id } as Filter); + } catch (e) { + await this.trash?.deleteOne({ _id } as Filter); + throw e; + } + + return { ok: 1, value: doc }; } async deleteMany(filter: Filter, options?: DeleteOptions & { onTrash?: (record: ResultFields) => void }): Promise { From 88b9dc9c9d4d53f47c7872c6c215c56dd3509e00 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Fri, 27 Sep 2024 14:45:31 -0300 Subject: [PATCH 125/170] fix: race condition when forwarding livechat by splitting subscription removal (#33381) --- .changeset/dry-taxis-cry.md | 5 +++++ apps/meteor/server/models/raw/BaseRaw.ts | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 .changeset/dry-taxis-cry.md diff --git a/.changeset/dry-taxis-cry.md b/.changeset/dry-taxis-cry.md new file mode 100644 index 000000000000..ae8244087d9e --- /dev/null +++ b/.changeset/dry-taxis-cry.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes a race condition that causes livechat conversations to get stuck in the agent's sidebar panel after being forwarded. diff --git a/apps/meteor/server/models/raw/BaseRaw.ts b/apps/meteor/server/models/raw/BaseRaw.ts index d822038b177e..3e763017bbd3 100644 --- a/apps/meteor/server/models/raw/BaseRaw.ts +++ b/apps/meteor/server/models/raw/BaseRaw.ts @@ -318,33 +318,33 @@ export abstract class BaseRaw< async findOneAndDelete(filter: Filter, options?: FindOneAndDeleteOptions): Promise> { if (!this.trash) { - if (options) { - return this.col.findOneAndDelete(filter, options); - } - return this.col.findOneAndDelete(filter); + return this.col.findOneAndDelete(filter, options || {}); } - const result = await this.col.findOneAndDelete(filter); - - const { value: doc } = result; + const doc = await this.col.findOne(filter); if (!doc) { - return result; + return { ok: 1, value: null }; } const { _id, ...record } = doc; - const trash: TDeleted = { ...record, _deletedAt: new Date(), __collection__: this.name, } as unknown as TDeleted; - // since the operation is not atomic, we need to make sure that the record is not already deleted/inserted await this.trash?.updateOne({ _id } as Filter, { $set: trash } as UpdateFilter, { upsert: true, }); - return result; + try { + await this.col.deleteOne({ _id } as Filter); + } catch (e) { + await this.trash?.deleteOne({ _id } as Filter); + throw e; + } + + return { ok: 1, value: doc }; } async deleteMany(filter: Filter, options?: DeleteOptions & { onTrash?: (record: ResultFields) => void }): Promise { From b17b3befdf860eeb532d9dfd78903ab15a709b2f Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Fri, 27 Sep 2024 14:11:21 -0600 Subject: [PATCH 126/170] fix: Avoid notifying `watch.settings` on uncaught errors (#33376) --- .../server/lib/RocketChat.ErrorHandler.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.ts b/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.ts index 264443a1378b..984561fe13cd 100644 --- a/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.ts +++ b/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.ts @@ -3,14 +3,13 @@ import { Meteor } from 'meteor/meteor'; import { throttledCounter } from '../../../../lib/utils/throttledCounter'; import { sendMessage } from '../../../lib/server/functions/sendMessage'; -import { notifyOnSettingChanged } from '../../../lib/server/lib/notifyListener'; import { settings } from '../../../settings/server'; const incException = throttledCounter((counter) => { Settings.incrementValueById('Uncaught_Exceptions_Count', counter, { returnDocument: 'after' }) .then(({ value }) => { if (value) { - void notifyOnSettingChanged(value); + settings.set(value); } }) .catch(console.error); @@ -118,5 +117,12 @@ process.on('unhandledRejection', (error) => { process.on('uncaughtException', async (error) => { incException(); + + console.error('=== UnCaughtException ==='); + console.error(error); + console.error('-------------------------'); + console.error('Errors like this can cause oplog processing errors.'); + console.error('==========================='); + void errorHandler.trackError(error.message, error.stack); }); From a430faf72bb160355bf7cb92549e27d341e35d7c Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 27 Sep 2024 18:52:13 -0300 Subject: [PATCH 127/170] chore: add gazzodown preview (#33279) --- .gitignore | 2 ++ packages/gazzodown/.storybook/main.js | 8 ++++++++ packages/gazzodown/package.json | 2 ++ 3 files changed, 12 insertions(+) diff --git a/.gitignore b/.gitignore index 03e74631957b..8ca2d018f92e 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,5 @@ storybook-static data/ registration.yaml + +storybook-static diff --git a/packages/gazzodown/.storybook/main.js b/packages/gazzodown/.storybook/main.js index de5a951bbded..f12b58cf856f 100644 --- a/packages/gazzodown/.storybook/main.js +++ b/packages/gazzodown/.storybook/main.js @@ -15,6 +15,14 @@ module.exports = { include: /node_modules/, loader: 'babel-loader', }); + config.module.rules.push({ + test: /\.m?js$/, + include: /node_modules/, + type: 'javascript/auto', + use: { + loader: require.resolve('babel-loader'), + }, + }); return config; }, }; diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index cf4a9209d649..ca64df5ec913 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -10,6 +10,8 @@ "scripts": { "build": "rm -rf dist && tsc -p tsconfig.build.json", "build-storybook": "build-storybook", + "build-preview": "build-storybook --quiet", + ".:build-preview-move": "mkdir -p ../../.preview && cp -r ./storybook-static ../../.preview/gazzodown", "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", From 214d1b348681bb43f6c1b859b31efe5773bb2cce Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 27 Sep 2024 19:11:27 -0300 Subject: [PATCH 128/170] chore(Sidepanel): uses only local channels and discussions (#33387) --- .../views/room/Sidepanel/RoomSidepanel.tsx | 4 +- .../SidepanelItem/RoomSidepanelItem.tsx | 4 +- .../Sidepanel/hooks/useTeamslistChildren.ts | 79 ++++--------------- 3 files changed, 20 insertions(+), 67 deletions(-) diff --git a/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx b/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx index 27c45e2774e8..6ee16a850202 100644 --- a/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx +++ b/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx @@ -51,8 +51,8 @@ const RoomSidepanelWithData = ({ parentRid, openedRoom }: { parentRid: string; o ( diff --git a/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx b/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx index dceb69e1aba3..8bb4d84eaebe 100644 --- a/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx +++ b/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx @@ -1,4 +1,4 @@ -import type { IRoom, ISubscription, Serialized } from '@rocket.chat/core-typings'; +import type { IRoom, ISubscription } from '@rocket.chat/core-typings'; import { useUserSubscription } from '@rocket.chat/ui-contexts'; import React, { memo } from 'react'; @@ -8,7 +8,7 @@ import { useItemData } from '../hooks/useItemData'; export type RoomSidepanelItemProps = { openedRoom?: string; - room: Serialized; + room: IRoom; parentRid: string; viewMode?: 'extended' | 'medium' | 'condensed'; }; diff --git a/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts index 772c29509608..de7645ae2a30 100644 --- a/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts +++ b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts @@ -1,107 +1,60 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { useEndpoint } from '@rocket.chat/ui-contexts'; -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import type { Mongo } from 'meteor/mongo'; import { useEffect, useMemo } from 'react'; import { ChatRoom } from '../../../../../app/models/client'; -const sortRoomByLastMessage = (a: IRoom, b: IRoom) => { - if (!a.lm) { - return 1; - } - if (!b.lm) { - return -1; - } - return b.lm.getTime() - a.lm.getTime(); -}; - export const useTeamsListChildrenUpdate = ( parentRid: string, teamId?: string | null, sidepanelItems?: 'channels' | 'discussions' | null, ) => { - const queryClient = useQueryClient(); - const query = useMemo(() => { const query: Mongo.Selector = { $or: [ { _id: parentRid, }, - { - prid: parentRid, - }, ], }; - if (teamId && query.$or) { + if ((!sidepanelItems || sidepanelItems === 'discussions') && query.$or) { + query.$or.push({ + prid: parentRid, + }); + } + + if ((!sidepanelItems || sidepanelItems === 'channels') && teamId && query.$or) { query.$or.push({ teamId, }); } return query; - }, [parentRid, teamId]); + }, [parentRid, teamId, sidepanelItems]); - const teamList = useEndpoint('GET', '/v1/teams.listChildren'); - - const listRoomsAndDiscussions = useEndpoint('GET', '/v1/teams.listChildren'); const result = useQuery({ queryKey: ['sidepanel', 'list', parentRid, sidepanelItems], queryFn: () => - listRoomsAndDiscussions({ - roomId: parentRid, - sort: JSON.stringify({ lm: -1 }), - type: sidepanelItems || undefined, - }), + ChatRoom.find(query, { + sort: { lm: -1 }, + }).fetch(), enabled: sidepanelItems !== null && teamId !== null, refetchInterval: 5 * 60 * 1000, keepPreviousData: true, }); - const { mutate: update } = useMutation({ - mutationFn: async (params?: { action: 'add' | 'remove' | 'update'; data: IRoom }) => { - queryClient.setQueryData(['sidepanel', 'list', parentRid, sidepanelItems], (data: Awaited> | void) => { - if (!data) { - return; - } - - if (params?.action === 'add') { - data.data = [JSON.parse(JSON.stringify(params.data)), ...data.data].sort(sortRoomByLastMessage); - } - - if (params?.action === 'remove') { - data.data = data.data.filter((item) => item._id !== params.data?._id); - } - - if (params?.action === 'update') { - data.data = data.data - .map((item) => (item._id === params.data?._id ? JSON.parse(JSON.stringify(params.data)) : item)) - .sort(sortRoomByLastMessage); - } - - return { ...data }; - }); - }, - }); - useEffect(() => { const liveQueryHandle = ChatRoom.find(query).observe({ - added: (item) => { - queueMicrotask(() => update({ action: 'add', data: item })); - }, - changed: (item) => { - queueMicrotask(() => update({ action: 'update', data: item })); - }, - removed: (item) => { - queueMicrotask(() => update({ action: 'remove', data: item })); - }, + added: () => queueMicrotask(() => result.refetch({ exact: false })), + changed: () => queueMicrotask(() => result.refetch({ exact: false })), + removed: () => queueMicrotask(() => result.refetch({ exact: false })), }); return () => { liveQueryHandle.stop(); }; - }, [update, query]); + }, [query, result]); return result; }; From 9f21b58c1e5ea33efa024a16b6ba085509e755da Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 27 Sep 2024 19:11:27 -0300 Subject: [PATCH 129/170] chore(Sidepanel): uses only local channels and discussions (#33387) --- .../views/room/Sidepanel/RoomSidepanel.tsx | 4 +- .../SidepanelItem/RoomSidepanelItem.tsx | 4 +- .../Sidepanel/hooks/useTeamslistChildren.ts | 79 ++++--------------- 3 files changed, 20 insertions(+), 67 deletions(-) diff --git a/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx b/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx index 27c45e2774e8..6ee16a850202 100644 --- a/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx +++ b/apps/meteor/client/views/room/Sidepanel/RoomSidepanel.tsx @@ -51,8 +51,8 @@ const RoomSidepanelWithData = ({ parentRid, openedRoom }: { parentRid: string; o ( diff --git a/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx b/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx index dceb69e1aba3..8bb4d84eaebe 100644 --- a/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx +++ b/apps/meteor/client/views/room/Sidepanel/SidepanelItem/RoomSidepanelItem.tsx @@ -1,4 +1,4 @@ -import type { IRoom, ISubscription, Serialized } from '@rocket.chat/core-typings'; +import type { IRoom, ISubscription } from '@rocket.chat/core-typings'; import { useUserSubscription } from '@rocket.chat/ui-contexts'; import React, { memo } from 'react'; @@ -8,7 +8,7 @@ import { useItemData } from '../hooks/useItemData'; export type RoomSidepanelItemProps = { openedRoom?: string; - room: Serialized; + room: IRoom; parentRid: string; viewMode?: 'extended' | 'medium' | 'condensed'; }; diff --git a/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts index 772c29509608..de7645ae2a30 100644 --- a/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts +++ b/apps/meteor/client/views/room/Sidepanel/hooks/useTeamslistChildren.ts @@ -1,107 +1,60 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { useEndpoint } from '@rocket.chat/ui-contexts'; -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import type { Mongo } from 'meteor/mongo'; import { useEffect, useMemo } from 'react'; import { ChatRoom } from '../../../../../app/models/client'; -const sortRoomByLastMessage = (a: IRoom, b: IRoom) => { - if (!a.lm) { - return 1; - } - if (!b.lm) { - return -1; - } - return b.lm.getTime() - a.lm.getTime(); -}; - export const useTeamsListChildrenUpdate = ( parentRid: string, teamId?: string | null, sidepanelItems?: 'channels' | 'discussions' | null, ) => { - const queryClient = useQueryClient(); - const query = useMemo(() => { const query: Mongo.Selector = { $or: [ { _id: parentRid, }, - { - prid: parentRid, - }, ], }; - if (teamId && query.$or) { + if ((!sidepanelItems || sidepanelItems === 'discussions') && query.$or) { + query.$or.push({ + prid: parentRid, + }); + } + + if ((!sidepanelItems || sidepanelItems === 'channels') && teamId && query.$or) { query.$or.push({ teamId, }); } return query; - }, [parentRid, teamId]); + }, [parentRid, teamId, sidepanelItems]); - const teamList = useEndpoint('GET', '/v1/teams.listChildren'); - - const listRoomsAndDiscussions = useEndpoint('GET', '/v1/teams.listChildren'); const result = useQuery({ queryKey: ['sidepanel', 'list', parentRid, sidepanelItems], queryFn: () => - listRoomsAndDiscussions({ - roomId: parentRid, - sort: JSON.stringify({ lm: -1 }), - type: sidepanelItems || undefined, - }), + ChatRoom.find(query, { + sort: { lm: -1 }, + }).fetch(), enabled: sidepanelItems !== null && teamId !== null, refetchInterval: 5 * 60 * 1000, keepPreviousData: true, }); - const { mutate: update } = useMutation({ - mutationFn: async (params?: { action: 'add' | 'remove' | 'update'; data: IRoom }) => { - queryClient.setQueryData(['sidepanel', 'list', parentRid, sidepanelItems], (data: Awaited> | void) => { - if (!data) { - return; - } - - if (params?.action === 'add') { - data.data = [JSON.parse(JSON.stringify(params.data)), ...data.data].sort(sortRoomByLastMessage); - } - - if (params?.action === 'remove') { - data.data = data.data.filter((item) => item._id !== params.data?._id); - } - - if (params?.action === 'update') { - data.data = data.data - .map((item) => (item._id === params.data?._id ? JSON.parse(JSON.stringify(params.data)) : item)) - .sort(sortRoomByLastMessage); - } - - return { ...data }; - }); - }, - }); - useEffect(() => { const liveQueryHandle = ChatRoom.find(query).observe({ - added: (item) => { - queueMicrotask(() => update({ action: 'add', data: item })); - }, - changed: (item) => { - queueMicrotask(() => update({ action: 'update', data: item })); - }, - removed: (item) => { - queueMicrotask(() => update({ action: 'remove', data: item })); - }, + added: () => queueMicrotask(() => result.refetch({ exact: false })), + changed: () => queueMicrotask(() => result.refetch({ exact: false })), + removed: () => queueMicrotask(() => result.refetch({ exact: false })), }); return () => { liveQueryHandle.stop(); }; - }, [update, query]); + }, [query, result]); return result; }; From bc1e6eec3be194a017624f73449c5974d0e296a1 Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Fri, 27 Sep 2024 19:36:57 -0300 Subject: [PATCH 130/170] chore: Move Apps-Engine to monorepo (#32951) --- .github/CODEOWNERS | 1 + .github/actions/build-docker-image/action.yml | 5 +- .github/actions/build-docker/action.yml | 7 + .github/actions/meteor-build/action.yml | 5 + .github/actions/setup-node/action.yml | 25 +- .github/workflows/ci-code-check.yml | 4 + .../workflows/ci-deploy-gh-pages-preview.yml | 1 + .github/workflows/ci-deploy-gh-pages.yml | 1 + .github/workflows/ci-test-e2e.yml | 4 + .github/workflows/ci-test-unit.yml | 4 + .github/workflows/ci.yml | 19 + .github/workflows/new-release.yml | 1 + .github/workflows/pr-update-description.yml | 1 + .github/workflows/publish-release.yml | 1 + .github/workflows/release-candidate.yml | 1 + .tool-versions | 1 + README.md | 1 + apps/meteor/.docker/Dockerfile | 11 +- apps/meteor/.docker/Dockerfile.alpine | 27 +- apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- docker-compose-ci.yml | 4 + ee/apps/account-service/Dockerfile | 4 + ee/apps/authorization-service/Dockerfile | 4 + ee/apps/ddp-streamer/Dockerfile | 4 + ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/Dockerfile | 4 + ee/apps/presence-service/Dockerfile | 4 + ee/apps/queue-worker/Dockerfile | 4 + ee/apps/stream-hub-service/Dockerfile | 4 + ee/packages/presence/package.json | 2 +- packages/apps-engine/.eslintignore | 8 + packages/apps-engine/.eslintrc.json | 58 + packages/apps-engine/.gitignore | 61 + packages/apps-engine/.prettierrc | 7 + packages/apps-engine/README.md | 125 ++ packages/apps-engine/deno-runtime/.gitignore | 1 + .../deno-runtime/AppObjectRegistry.ts | 26 + .../apps-engine/deno-runtime/acorn-walk.d.ts | 170 ++ packages/apps-engine/deno-runtime/acorn.d.ts | 857 ++++++++++ packages/apps-engine/deno-runtime/deno.jsonc | 16 + packages/apps-engine/deno-runtime/deno.lock | 107 ++ .../deno-runtime/handlers/api-handler.ts | 46 + .../deno-runtime/handlers/app/construct.ts | 126 ++ .../handlers/app/handleGetStatus.ts | 15 + .../handlers/app/handleInitialize.ts | 19 + .../handlers/app/handleOnDisable.ts | 19 + .../handlers/app/handleOnEnable.ts | 16 + .../handlers/app/handleOnInstall.ts | 30 + .../handlers/app/handleOnPreSettingUpdate.ts | 22 + .../handlers/app/handleOnSettingUpdated.ts | 24 + .../handlers/app/handleOnUninstall.ts | 30 + .../handlers/app/handleOnUpdate.ts | 30 + .../handlers/app/handleSetStatus.ts | 29 + .../deno-runtime/handlers/app/handler.ts | 112 ++ .../deno-runtime/handlers/listener/handler.ts | 150 ++ .../handlers/scheduler-handler.ts | 51 + .../handlers/slashcommand-handler.ts | 122 ++ .../handlers/tests/api-handler.test.ts | 79 + .../handlers/tests/listener-handler.test.ts | 234 +++ .../handlers/tests/scheduler-handler.test.ts | 46 + .../tests/slashcommand-handler.test.ts | 152 ++ .../handlers/tests/uikit-handler.test.ts | 99 ++ .../tests/videoconference-handler.test.ts | 122 ++ .../deno-runtime/handlers/uikit/handler.ts | 82 + .../handlers/videoconference-handler.ts | 49 + .../lib/accessors/builders/BlockBuilder.ts | 216 +++ .../accessors/builders/DiscussionBuilder.ts | 59 + .../builders/LivechatMessageBuilder.ts | 204 +++ .../lib/accessors/builders/MessageBuilder.ts | 232 +++ .../lib/accessors/builders/RoomBuilder.ts | 163 ++ .../lib/accessors/builders/UserBuilder.ts | 81 + .../builders/VideoConferenceBuilder.ts | 94 ++ .../lib/accessors/extenders/HttpExtender.ts | 62 + .../accessors/extenders/MessageExtender.ts | 66 + .../lib/accessors/extenders/RoomExtender.ts | 61 + .../extenders/VideoConferenceExtend.ts | 69 + .../deno-runtime/lib/accessors/http.ts | 92 ++ .../deno-runtime/lib/accessors/mod.ts | 302 ++++ .../lib/accessors/modify/ModifyCreator.ts | 344 ++++ .../lib/accessors/modify/ModifyExtender.ts | 93 ++ .../lib/accessors/modify/ModifyUpdater.ts | 153 ++ .../deno-runtime/lib/accessors/notifier.ts | 75 + .../lib/accessors/tests/AppAccessors.test.ts | 122 ++ .../lib/accessors/tests/ModifyCreator.test.ts | 106 ++ .../accessors/tests/ModifyExtender.test.ts | 120 ++ .../lib/accessors/tests/ModifyUpdater.test.ts | 128 ++ .../apps-engine/deno-runtime/lib/ast/mod.ts | 64 + .../deno-runtime/lib/ast/operations.ts | 239 +++ .../lib/ast/tests/data/ast_blocks.ts | 436 +++++ .../lib/ast/tests/operations.test.ts | 245 +++ .../apps-engine/deno-runtime/lib/codec.ts | 43 + .../apps-engine/deno-runtime/lib/logger.ts | 142 ++ .../apps-engine/deno-runtime/lib/messenger.ts | 199 +++ .../apps-engine/deno-runtime/lib/require.ts | 14 + packages/apps-engine/deno-runtime/lib/room.ts | 104 ++ .../deno-runtime/lib/roomFactory.ts | 27 + .../lib/sanitizeDeprecatedUsage.ts | 20 + .../deno-runtime/lib/tests/logger.test.ts | 111 ++ .../deno-runtime/lib/tests/messenger.test.ts | 96 ++ packages/apps-engine/deno-runtime/main.ts | 129 ++ packages/apps-engine/package.json | 132 ++ packages/apps-engine/scripts/bundle.js | 35 + packages/apps-engine/scripts/deno-cache.js | 25 + .../src/client/AppClientManager.ts | 28 + .../src/client/AppServerCommunicator.ts | 16 + .../src/client/AppsEngineUIClient.ts | 70 + .../src/client/AppsEngineUIHost.ts | 78 + .../apps-engine/src/client/constants/index.ts | 6 + .../client/definition/AppsEngineUIMethods.ts | 7 + .../definition/IAppsEngineUIResponse.ts | 19 + .../definition/IExternalComponentRoomInfo.ts | 16 + .../definition/IExternalComponentUserInfo.ts | 14 + .../src/client/definition/index.ts | 4 + packages/apps-engine/src/client/index.ts | 4 + .../apps-engine/src/client/utils/index.ts | 18 + packages/apps-engine/src/definition/App.ts | 236 +++ .../apps-engine/src/definition/AppStatus.ts | 65 + packages/apps-engine/src/definition/IApp.ts | 90 + packages/apps-engine/src/definition/LICENSE | 21 + .../src/definition/accessors/IApiExtend.ts | 16 + .../src/definition/accessors/IAppAccessors.ts | 11 + .../accessors/IAppInstallationContext.ts | 5 + .../accessors/IAppUninstallationContext.ts | 5 + .../definition/accessors/IAppUpdateContext.ts | 6 + .../accessors/ICloudWorkspaceRead.ts | 24 + .../accessors/IConfigurationExtend.ts | 36 + .../accessors/IConfigurationModify.ts | 18 + .../accessors/IDiscussionBuilder.ts | 25 + .../src/definition/accessors/IEmailCreator.ts | 10 + .../definition/accessors/IEnvironmentRead.ts | 27 + .../definition/accessors/IEnvironmentWrite.ts | 10 + .../accessors/IEnvironmentalVariableRead.ts | 11 + .../accessors/IExternalComponentsExtend.ts | 17 + .../src/definition/accessors/IHttp.ts | 202 +++ .../definition/accessors/ILivechatCreator.ts | 43 + .../accessors/ILivechatMessageBuilder.ts | 219 +++ .../src/definition/accessors/ILivechatRead.ts | 38 + .../definition/accessors/ILivechatUpdater.ts | 33 + .../src/definition/accessors/ILogEntry.ts | 22 + .../src/definition/accessors/ILogger.ts | 29 + .../definition/accessors/IMessageBuilder.ts | 236 +++ .../definition/accessors/IMessageExtender.ts | 36 + .../src/definition/accessors/IMessageRead.ts | 15 + .../definition/accessors/IMessageUpdater.ts | 21 + .../definition/accessors/IModerationModify.ts | 27 + .../src/definition/accessors/IModify.ts | 45 + .../definition/accessors/IModifyCreator.ts | 100 ++ .../definition/accessors/IModifyDeleter.ts | 12 + .../definition/accessors/IModifyExtender.ts | 40 + .../definition/accessors/IModifyUpdater.ts | 52 + .../src/definition/accessors/INotifier.ts | 63 + .../src/definition/accessors/IOAuthApp.ts | 13 + .../definition/accessors/IOAuthAppsModify.ts | 23 + .../definition/accessors/IOAuthAppsReader.ts | 16 + .../src/definition/accessors/IPersistence.ts | 97 ++ .../definition/accessors/IPersistenceRead.ts | 40 + .../src/definition/accessors/IRead.ts | 52 + .../src/definition/accessors/IRoleRead.ts | 27 + .../src/definition/accessors/IRoomBuilder.ts | 186 +++ .../src/definition/accessors/IRoomExtender.ts | 40 + .../src/definition/accessors/IRoomRead.ts | 93 ++ .../definition/accessors/ISchedulerExtend.ts | 11 + .../definition/accessors/ISchedulerModify.ts | 31 + .../accessors/IServerSettingRead.ts | 43 + .../accessors/IServerSettingUpdater.ts | 6 + .../accessors/IServerSettingsModify.ts | 40 + .../src/definition/accessors/ISettingRead.ts | 23 + .../definition/accessors/ISettingUpdater.ts | 5 + .../definition/accessors/ISettingsExtend.ts | 17 + .../accessors/ISlashCommandsExtend.ts | 16 + .../accessors/ISlashCommandsModify.ts | 30 + .../src/definition/accessors/IThreadRead.ts | 9 + .../src/definition/accessors/IUIController.ts | 31 + .../src/definition/accessors/IUIExtend.ts | 5 + .../definition/accessors/IUploadCreator.ts | 12 + .../src/definition/accessors/IUploadRead.ts | 7 + .../src/definition/accessors/IUserBuilder.ts | 60 + .../src/definition/accessors/IUserRead.ts | 22 + .../src/definition/accessors/IUserUpdater.ts | 18 + .../accessors/IVideoConfProvidersExtend.ts | 15 + .../accessors/IVideoConferenceBuilder.ts | 34 + .../accessors/IVideoConferenceExtend.ts | 21 + .../accessors/IVideoConferenceRead.ts | 15 + .../src/definition/accessors/index.ts | 58 + .../src/definition/api/ApiEndpoint.ts | 40 + .../apps-engine/src/definition/api/IApi.ts | 58 + .../src/definition/api/IApiEndpoint.ts | 47 + .../src/definition/api/IApiEndpointInfo.ts | 6 + .../definition/api/IApiEndpointMetadata.ts | 10 + .../src/definition/api/IApiExample.ts | 19 + .../src/definition/api/IRequest.ts | 16 + .../src/definition/api/IResponse.ts | 13 + .../apps-engine/src/definition/api/index.ts | 8 + .../src/definition/app-schema.json | 75 + .../src/definition/assets/IAsset.ts | 6 + .../src/definition/assets/IAssetProvider.ts | 5 + .../src/definition/assets/index.ts | 4 + .../src/definition/cloud/IWorkspaceToken.ts | 4 + .../src/definition/email/IEmail.ts | 9 + .../src/definition/email/IEmailDescriptor.ts | 11 + .../src/definition/email/IPreEmailSent.ts | 25 + .../definition/email/IPreEmailSentContext.ts | 6 + .../apps-engine/src/definition/email/index.ts | 4 + .../src/definition/example-app.json | 13 + .../exceptions/AppsEngineException.ts | 32 + .../EssentialAppDisabledException.ts | 16 + .../FileUploadNotAllowedException.ts | 12 + .../InvalidSettingValueException.ts | 8 + .../exceptions/UserNotAllowedException.ts | 14 + .../src/definition/exceptions/index.ts | 5 + .../externalComponent/IExternalComponent.ts | 51 + .../IExternalComponentOptions.ts | 10 + .../IExternalComponentState.ts | 16 + .../IPostExternalComponentClosed.ts | 16 + .../IPostExternalComponentOpened.ts | 16 + .../src/definition/externalComponent/index.ts | 5 + .../src/definition/livechat/IDepartment.ts | 17 + .../livechat/ILivechatEventContext.ts | 7 + .../definition/livechat/ILivechatMessage.ts | 7 + .../src/definition/livechat/ILivechatRoom.ts | 55 + .../livechat/ILivechatRoomClosedHandler.ts | 19 + .../livechat/ILivechatTransferData.ts | 8 + .../livechat/ILivechatTransferEventContext.ts | 15 + .../livechat/IPostLivechatAgentAssigned.ts | 25 + .../livechat/IPostLivechatAgentUnassigned.ts | 25 + .../livechat/IPostLivechatGuestSaved.ts | 19 + .../livechat/IPostLivechatRoomClosed.ts | 19 + .../livechat/IPostLivechatRoomSaved.ts | 19 + .../livechat/IPostLivechatRoomStarted.ts | 19 + .../livechat/IPostLivechatRoomTransferred.ts | 13 + .../src/definition/livechat/IVisitor.ts | 16 + .../src/definition/livechat/IVisitorEmail.ts | 3 + .../src/definition/livechat/IVisitorPhone.ts | 3 + .../src/definition/livechat/index.ts | 38 + .../src/definition/messages/IMessage.ts | 34 + .../src/definition/messages/IMessageAction.ts | 17 + .../definition/messages/IMessageAttachment.ts | 43 + .../messages/IMessageAttachmentAuthor.ts | 11 + .../messages/IMessageAttachmentField.ts | 11 + .../messages/IMessageAttachmentTitle.ts | 8 + .../messages/IMessageDeleteContext.ts | 17 + .../src/definition/messages/IMessageFile.ts | 5 + .../messages/IMessageFollowContext.ts | 21 + .../definition/messages/IMessagePinContext.ts | 21 + .../src/definition/messages/IMessageRaw.ts | 40 + .../definition/messages/IMessageReaction.ts | 13 + .../messages/IMessageReactionContext.ts | 25 + .../messages/IMessageReportContext.ts | 21 + .../messages/IMessageStarContext.ts | 21 + .../messages/IPostMessageDeleted.ts | 37 + .../messages/IPostMessageFollowed.ts | 18 + .../definition/messages/IPostMessagePinned.ts | 18 + .../messages/IPostMessageReacted.ts | 19 + .../messages/IPostMessageReported.ts | 18 + .../definition/messages/IPostMessageSent.ts | 27 + .../messages/IPostMessageSentToBot.ts | 15 + .../messages/IPostMessageStarred.ts | 18 + .../messages/IPostMessageUpdated.ts | 27 + .../messages/IPreMessageDeletePrevent.ts | 28 + .../messages/IPreMessageSentExtend.ts | 29 + .../messages/IPreMessageSentModify.ts | 29 + .../messages/IPreMessageSentPrevent.ts | 28 + .../messages/IPreMessageUpdatedExtend.ts | 29 + .../messages/IPreMessageUpdatedModify.ts | 29 + .../messages/IPreMessageUpdatedPrevent.ts | 28 + .../messages/MessageActionButtonsAlignment.ts | 4 + .../definition/messages/MessageActionType.ts | 3 + .../messages/MessageProcessingType.ts | 4 + .../src/definition/messages/index.ts | 71 + .../src/definition/metadata/AppInterface.ts | 60 + .../src/definition/metadata/AppMethod.ts | 102 ++ .../src/definition/metadata/IAppAuthorInfo.ts | 5 + .../src/definition/metadata/IAppInfo.ts | 20 + .../metadata/RocketChatAssociations.ts | 22 + .../src/definition/metadata/index.ts | 8 + .../src/definition/oauth2/IOAuth2.ts | 136 ++ .../src/definition/oauth2/OAuth2.ts | 15 + .../src/definition/permissions/IPermission.ts | 12 + .../persistence/IPersistenceItem.ts | 7 + .../src/definition/persistence/index.ts | 1 + .../apps-engine/src/definition/roles/IRole.ts | 8 + .../apps-engine/src/definition/roles/index.ts | 5 + .../src/definition/rooms/IPostRoomCreate.ts | 27 + .../src/definition/rooms/IPostRoomDeleted.ts | 27 + .../definition/rooms/IPostRoomUserJoined.ts | 19 + .../definition/rooms/IPostRoomUserLeave.ts | 19 + .../definition/rooms/IPreRoomCreateExtend.ts | 28 + .../definition/rooms/IPreRoomCreateModify.ts | 28 + .../definition/rooms/IPreRoomCreatePrevent.ts | 26 + .../definition/rooms/IPreRoomDeletePrevent.ts | 26 + .../definition/rooms/IPreRoomUserJoined.ts | 18 + .../src/definition/rooms/IPreRoomUserLeave.ts | 18 + .../apps-engine/src/definition/rooms/IRoom.ts | 26 + .../rooms/IRoomUserJoinedContext.ts | 23 + .../definition/rooms/IRoomUserLeaveContext.ts | 23 + .../src/definition/rooms/RoomType.ts | 6 + .../apps-engine/src/definition/rooms/index.ts | 17 + .../definition/scheduler/IOnetimeSchedule.ts | 13 + .../src/definition/scheduler/IProcessor.ts | 45 + .../scheduler/IRecurringSchedule.ts | 17 + .../src/definition/scheduler/index.ts | 3 + .../src/definition/settings/ISetting.ts | 47 + .../settings/ISettingUpdateContext.ts | 6 + .../src/definition/settings/SettingType.ts | 14 + .../src/definition/settings/index.ts | 4 + .../definition/slashcommands/ISlashCommand.ts | 41 + .../slashcommands/ISlashCommandPreview.ts | 28 + .../slashcommands/SlashCommandContext.ts | 33 + .../src/definition/slashcommands/index.ts | 5 + .../ui/IUIActionButtonDescriptor.ts | 41 + .../definition/ui/UIActionButtonContext.ts | 7 + .../apps-engine/src/definition/ui/index.ts | 2 + .../definition/uikit/IUIKitActionHandler.ts | 77 + .../uikit/IUIKitIncomingInteraction.ts | 28 + .../IUIKitIncomingInteractionActionButton.ts | 78 + .../definition/uikit/IUIKitInteractionType.ts | 41 + .../src/definition/uikit/IUIKitSurface.ts | 22 + .../src/definition/uikit/IUIKitView.ts | 7 + .../UIKitIncomingInteractionContainer.ts | 18 + .../uikit/UIKitIncomingInteractionTypes.ts | 60 + .../uikit/UIKitInteractionContext.ts | 69 + .../uikit/UIKitInteractionPayloadFormatter.ts | 68 + .../uikit/UIKitInteractionResponder.ts | 75 + .../definition/uikit/blocks/BlockBuilder.ts | 196 +++ .../src/definition/uikit/blocks/Blocks.ts | 108 ++ .../src/definition/uikit/blocks/Elements.ts | 115 ++ .../src/definition/uikit/blocks/Objects.ts | 33 + .../src/definition/uikit/blocks/index.ts | 4 + .../apps-engine/src/definition/uikit/index.ts | 7 + .../livechat/IUIKitLivechatActionHandler.ts | 23 + .../IUIKitLivechatIncomingInteraction.ts | 17 + .../UIKitLivechatIncomingInteractionType.ts | 22 + .../UIKitLivechatInteractionContext.ts | 33 + .../src/definition/uikit/livechat/index.ts | 4 + .../definition/uploads/IFileUploadContext.ts | 6 + .../src/definition/uploads/IPreFileUpload.ts | 20 + .../src/definition/uploads/IUpload.ts | 25 + .../definition/uploads/IUploadDescriptor.ts | 24 + .../src/definition/uploads/IUploadDetails.ts | 26 + .../src/definition/uploads/StoreType.ts | 7 + .../src/definition/uploads/index.ts | 6 + .../src/definition/users/IBotUser.ts | 6 + .../src/definition/users/IPostUserCreated.ts | 15 + .../src/definition/users/IPostUserDeleted.ts | 15 + .../src/definition/users/IPostUserLoggedIn.ts | 15 + .../definition/users/IPostUserLoggedOut.ts | 15 + .../users/IPostUserStatusChanged.ts | 17 + .../src/definition/users/IPostUserUpdated.ts | 15 + .../apps-engine/src/definition/users/IUser.ts | 25 + .../src/definition/users/IUserContext.ts | 19 + .../definition/users/IUserCreationOptions.ts | 7 + .../src/definition/users/IUserEmail.ts | 4 + .../src/definition/users/IUserLookup.ts | 5 + .../src/definition/users/IUserSettings.ts | 5 + .../definition/users/IUserStatusContext.ts | 23 + .../src/definition/users/IUserUpdateContex.ts | 24 + .../definition/users/IUserUpdateContext.ts | 24 + .../definition/users/UserStatusConnection.ts | 9 + .../src/definition/users/UserType.ts | 10 + .../apps-engine/src/definition/users/index.ts | 33 + .../videoConfProviders/IVideoConfProvider.ts | 63 + .../IVideoConferenceOptions.ts | 4 + .../videoConfProviders/VideoConfData.ts | 7 + .../definition/videoConfProviders/index.ts | 5 + .../videoConferences/AppVideoConference.ts | 6 + .../videoConferences/IVideoConference.ts | 56 + .../videoConferences/IVideoConferenceUser.ts | 5 + .../src/definition/videoConferences/index.ts | 5 + packages/apps-engine/src/lib/utils.ts | 1 + packages/apps-engine/src/server/AppManager.ts | 1150 +++++++++++++ .../apps-engine/src/server/IGetAppsFilter.ts | 6 + packages/apps-engine/src/server/ProxiedApp.ts | 154 ++ .../src/server/accessors/ApiExtend.ts | 11 + .../src/server/accessors/AppAccessors.ts | 36 + .../server/accessors/CloudWorkspaceRead.ts | 11 + .../server/accessors/ConfigurationExtend.ts | 24 + .../server/accessors/ConfigurationModify.ts | 9 + .../src/server/accessors/DiscussionBuilder.ts | 47 + .../src/server/accessors/EmailCreator.ts | 11 + .../src/server/accessors/EnvironmentRead.ts | 21 + .../src/server/accessors/EnvironmentWrite.ts | 13 + .../accessors/EnvironmentalVariableRead.ts | 18 + .../accessors/ExternalComponentsExtend.ts | 11 + .../apps-engine/src/server/accessors/Http.ts | 77 + .../src/server/accessors/HttpExtend.ts | 58 + .../src/server/accessors/LivechatCreator.ts | 29 + .../accessors/LivechatMessageBuilder.ts | 191 +++ .../src/server/accessors/LivechatRead.ts | 73 + .../src/server/accessors/LivechatUpdater.ts | 23 + .../src/server/accessors/MessageBuilder.ts | 224 +++ .../src/server/accessors/MessageExtender.ts | 50 + .../src/server/accessors/MessageRead.ts | 33 + .../src/server/accessors/ModerationModify.ts | 20 + .../src/server/accessors/Modify.ts | 89 + .../src/server/accessors/ModifyCreator.ts | 260 +++ .../src/server/accessors/ModifyDeleter.ts | 35 + .../src/server/accessors/ModifyExtender.ts | 46 + .../src/server/accessors/ModifyUpdater.ts | 106 ++ .../src/server/accessors/Notifier.ts | 49 + .../src/server/accessors/OAuthAppsModify.ts | 19 + .../src/server/accessors/OAuthAppsReader.ts | 15 + .../src/server/accessors/Persistence.ts | 43 + .../src/server/accessors/PersistenceRead.ts | 19 + .../src/server/accessors/Reader.ts | 87 + .../src/server/accessors/RoleRead.ts | 15 + .../src/server/accessors/RoomBuilder.ts | 155 ++ .../src/server/accessors/RoomExtender.ts | 56 + .../src/server/accessors/RoomRead.ts | 73 + .../src/server/accessors/SchedulerExtend.ts | 11 + .../src/server/accessors/SchedulerModify.ts | 27 + .../src/server/accessors/ServerSettingRead.ts | 34 + .../server/accessors/ServerSettingUpdater.ts | 15 + .../server/accessors/ServerSettingsModify.ts | 23 + .../src/server/accessors/SettingRead.ts | 25 + .../src/server/accessors/SettingUpdater.ts | 22 + .../src/server/accessors/SettingsExtend.ts | 26 + .../server/accessors/SlashCommandsExtend.ts | 11 + .../server/accessors/SlashCommandsModify.ts | 19 + .../src/server/accessors/ThreadRead.ts | 11 + .../src/server/accessors/UIController.ts | 106 ++ .../src/server/accessors/UIExtend.ts | 11 + .../src/server/accessors/UploadCreator.ts | 25 + .../src/server/accessors/UploadRead.ts | 21 + .../src/server/accessors/UserBuilder.ts | 74 + .../src/server/accessors/UserRead.ts | 23 + .../src/server/accessors/UserUpdater.ts | 28 + .../accessors/VideoConfProviderExtend.ts | 11 + .../accessors/VideoConferenceBuilder.ts | 83 + .../server/accessors/VideoConferenceExtend.ts | 64 + .../server/accessors/VideoConferenceRead.ts | 11 + .../apps-engine/src/server/accessors/index.ts | 95 ++ .../src/server/bridges/ApiBridge.ts | 49 + .../src/server/bridges/AppActivationBridge.ts | 35 + .../src/server/bridges/AppBridges.ts | 101 ++ .../server/bridges/AppDetailChangesBridge.ts | 16 + .../src/server/bridges/BaseBridge.ts | 6 + .../server/bridges/CloudWorkspaceBridge.ts | 30 + .../src/server/bridges/CommandBridge.ts | 117 ++ .../src/server/bridges/EmailBridge.ts | 30 + .../bridges/EnvironmentalVariableBridge.ts | 45 + .../src/server/bridges/HttpBridge.ts | 37 + .../src/server/bridges/IInternalBridge.ts | 7 + .../bridges/IInternalFederationBridge.ts | 15 + .../bridges/IInternalPersistenceBridge.ts | 9 + .../bridges/IInternalSchedulerBridge.ts | 8 + .../src/server/bridges/IInternalUserBridge.ts | 8 + .../src/server/bridges/IListenerBridge.ts | 10 + .../src/server/bridges/InternalBridge.ts | 22 + .../src/server/bridges/ListenerBridge.ts | 18 + .../src/server/bridges/LivechatBridge.ts | 259 +++ .../src/server/bridges/MessageBridge.ts | 116 ++ .../src/server/bridges/ModerationBridge.ts | 47 + .../src/server/bridges/OAuthAppsBridge.ts | 85 + .../src/server/bridges/PersistenceBridge.ts | 161 ++ .../src/server/bridges/RoleBridge.ts | 38 + .../src/server/bridges/RoomBridge.ts | 179 ++ .../src/server/bridges/SchedulerBridge.ts | 62 + .../src/server/bridges/ServerSettingBridge.ts | 93 ++ .../src/server/bridges/ThreadBridge.ts | 35 + .../src/server/bridges/UiInteractionBridge.ts | 31 + .../src/server/bridges/UploadBridge.ts | 62 + .../src/server/bridges/UserBridge.ts | 149 ++ .../server/bridges/VideoConferenceBridge.ts | 94 ++ .../apps-engine/src/server/bridges/index.ts | 52 + .../src/server/compiler/AppCompiler.ts | 30 + .../compiler/AppFabricationFulfillment.ts | 74 + .../src/server/compiler/AppImplements.ts | 27 + .../src/server/compiler/AppPackageParser.ts | 161 ++ .../server/compiler/IParseAppPackageResult.ts | 9 + .../apps-engine/src/server/compiler/index.ts | 7 + .../src/server/compiler/modules/index.ts | 55 + .../src/server/compiler/modules/networking.ts | 36 + .../errors/CommandAlreadyExistsError.ts | 9 + .../CommandHasAlreadyBeenTouchedError.ts | 9 + .../src/server/errors/CompilerError.ts | 9 + .../server/errors/InvalidInstallationError.ts | 5 + .../src/server/errors/InvalidLicenseError.ts | 7 + .../server/errors/MustContainFunctionError.ts | 9 + .../src/server/errors/MustExtendAppError.ts | 5 + .../errors/NotEnoughMethodArgumentsError.ts | 9 + .../server/errors/PathAlreadyExistsError.ts | 9 + .../server/errors/PermissionDeniedError.ts | 25 + .../server/errors/RequiredApiVersionError.ts | 21 + .../VideoConfProviderAlreadyExistsError.ts | 9 + .../VideoConfProviderNotRegisteredError.ts | 9 + .../apps-engine/src/server/errors/index.ts | 25 + .../src/server/logging/AppConsole.ts | 121 ++ .../src/server/logging/ILoggerStorageEntry.ts | 14 + .../apps-engine/src/server/logging/index.ts | 4 + .../src/server/managers/AppAccessorManager.ts | 228 +++ .../apps-engine/src/server/managers/AppApi.ts | 95 ++ .../src/server/managers/AppApiManager.ts | 165 ++ .../managers/AppExternalComponentManager.ts | 142 ++ .../src/server/managers/AppLicenseManager.ts | 91 + .../src/server/managers/AppListenerManager.ts | 1220 ++++++++++++++ .../server/managers/AppPermissionManager.ts | 40 + .../src/server/managers/AppRuntimeManager.ts | 57 + .../server/managers/AppSchedulerManager.ts | 98 ++ .../src/server/managers/AppSettingsManager.ts | 55 + .../server/managers/AppSignatureManager.ts | 85 + .../src/server/managers/AppSlashCommand.ts | 77 + .../server/managers/AppSlashCommandManager.ts | 470 ++++++ .../server/managers/AppVideoConfProvider.ts | 105 ++ .../managers/AppVideoConfProviderManager.ts | 207 +++ .../server/managers/UIActionButtonManager.ts | 72 + .../apps-engine/src/server/managers/index.ts | 21 + .../server/marketplace/IAppLicenseMetadata.ts | 5 + .../server/marketplace/IMarketplaceInfo.ts | 24 + .../marketplace/IMarketplacePricingPlan.ts | 11 + .../marketplace/IMarketplacePricingTier.ts | 6 + .../IMarketplaceSimpleBundleInfo.ts | 4 + .../IMarketplaceSubscriptionInfo.ts | 15 + .../marketplace/MarketplacePricingStrategy.ts | 5 + .../marketplace/MarketplacePurchaseType.ts | 4 + .../MarketplaceSubscriptionStatus.ts | 10 + .../MarketplaceSubscriptionType.ts | 4 + .../src/server/marketplace/index.ts | 8 + .../license/AppLicenseValidationResult.ts | 56 + .../src/server/marketplace/license/Crypto.ts | 26 + .../src/server/marketplace/license/index.ts | 4 + .../src/server/messages/Message.ts | 106 ++ .../apps-engine/src/server/misc/UIHelper.ts | 32 + .../apps-engine/src/server/misc/Utilities.ts | 36 + .../src/server/oauth2/OAuth2Client.ts | 322 ++++ .../src/server/permissions/AppPermissions.ts | 152 ++ packages/apps-engine/src/server/rooms/Room.ts | 104 ++ .../server/runtime/AppsEngineEmptyRuntime.ts | 21 + .../server/runtime/AppsEngineNodeRuntime.ts | 71 + .../src/server/runtime/AppsEngineRuntime.ts | 29 + .../runtime/deno/AppsEngineDenoRuntime.ts | 568 +++++++ .../server/runtime/deno/LivenessManager.ts | 184 +++ .../server/runtime/deno/ProcessMessenger.ts | 48 + .../src/server/runtime/deno/bundler.ts | 90 + .../src/server/runtime/deno/codec.ts | 29 + .../src/server/storage/AppLogStorage.ts | 24 + .../src/server/storage/AppMetadataStorage.ts | 19 + .../src/server/storage/AppSourceStorage.ts | 40 + .../src/server/storage/IAppStorageItem.ts | 31 + .../apps-engine/src/server/storage/index.ts | 4 + packages/apps-engine/tests/runner.ts | 20 + .../tests/server/AppManager.spec.ts | 122 ++ .../server/accessors/AppAccessors.spec.ts | 134 ++ .../accessors/ConfigurationExtend.spec.ts | 76 + .../accessors/ConfigurationModify.spec.ts | 28 + .../server/accessors/EnvironmentRead.spec.ts | 29 + .../server/accessors/EnvironmentWrite.spec.ts | 25 + .../EnvironmentalVariableRead.spec.ts | 33 + .../tests/server/accessors/Http.spec.ts | 128 ++ .../tests/server/accessors/HttpExtend.spec.ts | 83 + .../server/accessors/MessageBuilder.spec.ts | 125 ++ .../server/accessors/MessageExtender.spec.ts | 35 + .../server/accessors/MessageRead.spec.ts | 58 + .../tests/server/accessors/Modify.spec.ts | 44 + .../server/accessors/ModifyCreator.spec.ts | 129 ++ .../server/accessors/ModifyExtender.spec.ts | 74 + .../server/accessors/ModifyUpdater.spec.ts | 139 ++ .../tests/server/accessors/Notifier.spec.ts | 37 + .../server/accessors/Persistence.spec.ts | 82 + .../server/accessors/PersistenceRead.spec.ts | 31 + .../tests/server/accessors/Reader.spec.ts | 112 ++ .../server/accessors/RoomBuilder.spec.ts | 90 + .../server/accessors/RoomExtender.spec.ts | 38 + .../tests/server/accessors/RoomRead.spec.ts | 83 + .../accessors/ServerSettingRead.spec.ts | 43 + .../accessors/ServerSettingsModify.spec.ts | 60 + .../server/accessors/SettingRead.spec.ts | 40 + .../server/accessors/SettingsExtend.spec.ts | 54 + .../accessors/SlashCommandsExtend.spec.ts | 47 + .../accessors/SlashCommandsModify.spec.ts | 47 + .../server/accessors/UserBuilder.spec.ts | 58 + .../tests/server/accessors/UserRead.spec.ts | 49 + .../accessors/VideoConfProviderExtend.spec.ts | 38 + .../accessors/VideoConferenceBuilder.spec.ts | 108 ++ .../accessors/VideoConferenceExtend.spec.ts | 81 + .../accessors/VideoConferenceRead.spec.ts | 34 + .../tests/server/compiler/AppCompiler.spec.ts | 24 + .../AppFabricationFulfillment.spec.ts | 48 + .../server/compiler/AppImplements.spec.ts | 19 + .../errors/CommandAlreadyExistsError.spec.ts | 13 + .../CommandHasAlreadyBeenTouchedError.spec.ts | 13 + .../tests/server/errors/CompilerError.spec.ts | 13 + .../errors/MustContainFunctionError.spec.ts | 13 + .../server/errors/MustExtendAppError.spec.ts | 13 + .../NotEnoughMethodArgumentsError.spec.ts | 13 + .../errors/RequiredApiVersionError.spec.ts | 26 + .../tests/server/logging/AppConsole.spec.ts | 79 + .../managers/AppAccessorManager.spec.ts | 166 ++ .../tests/server/managers/AppApi.spec.ts | 28 + .../server/managers/AppApiManager.spec.ts | 233 +++ .../AppExternalComponentManager.spec.ts | 154 ++ .../managers/AppListenerManager.spec.ts | 44 + .../managers/AppSettingsManager.spec.ts | 148 ++ .../server/managers/AppSlashCommand.spec.ts | 29 + .../managers/AppSlashCommandManager.spec.ts | 469 ++++++ .../managers/AppVideoConfProvider.spec.ts | 25 + .../AppVideoConfProviderManager.spec.ts | 435 +++++ .../tests/server/misc/Utilities.spec.ts | 69 + .../DenoRuntimeSubprocessController.spec.ts | 222 +++ .../apps-engine/tests/test-data/README.md | 2 + .../test-data/apps/hello-world-test_0.0.1.zip | Bin 0 -> 10309 bytes .../test-data/apps/testing-app_0.0.8.zip | Bin 0 -> 37318 bytes .../test-data/bridges/OAuthAppsBridge.ts | 28 + .../test-data/bridges/activationBridge.ts | 25 + .../tests/test-data/bridges/apiBridge.ts | 37 + .../tests/test-data/bridges/appBridges.ts | 228 +++ .../test-data/bridges/appDetailChanges.ts | 6 + .../tests/test-data/bridges/cloudBridge.ts | 15 + .../tests/test-data/bridges/commandBridge.ts | 38 + .../tests/test-data/bridges/emailBridge.ts | 8 + .../bridges/environmentalVariableBridge.ts | 15 + .../tests/test-data/bridges/httpBridge.ts | 15 + .../tests/test-data/bridges/internalBridge.ts | 16 + .../bridges/internalFederationBridge.ts | 11 + .../tests/test-data/bridges/livechatBridge.ts | 96 ++ .../tests/test-data/bridges/messageBridge.ts | 43 + .../test-data/bridges/moderationBridge.ts | 17 + .../tests/test-data/bridges/persisBridge.ts | 40 + .../tests/test-data/bridges/roleBridge.ts | 12 + .../tests/test-data/bridges/roomBridge.ts | 67 + .../test-data/bridges/schedulerBridge.ts | 24 + .../test-data/bridges/serverSettingBridge.ts | 41 + .../tests/test-data/bridges/threadBridge.ts | 8 + .../test-data/bridges/uiIntegrationBridge.ts | 9 + .../tests/test-data/bridges/uploadBridge.ts | 17 + .../tests/test-data/bridges/userBridge.ts | 44 + .../bridges/videoConferenceBridge.ts | 25 + .../test-data/misc/fake-library-file.d.ts | 5 + .../test-data/storage/TestSourceStorage.ts | 20 + .../tests/test-data/storage/logStorage.ts | 25 + .../tests/test-data/storage/storage.ts | 93 ++ .../apps-engine/tests/test-data/utilities.ts | 492 ++++++ packages/apps-engine/tsconfig-lint.json | 7 + packages/apps-engine/tsconfig.json | 21 + packages/apps-engine/turbo.json | 9 + packages/apps-engine/typedoc.json | 9 + packages/apps/package.json | 2 +- packages/core-services/package.json | 2 +- packages/core-typings/package.json | 2 +- packages/fuselage-ui-kit/package.json | 2 +- packages/jwt/package.json | 3 + packages/rest-typings/package.json | 2 +- yarn.lock | 1461 +++++++++++++++-- 643 files changed, 35661 insertions(+), 132 deletions(-) create mode 100644 .tool-versions create mode 100644 packages/apps-engine/.eslintignore create mode 100644 packages/apps-engine/.eslintrc.json create mode 100644 packages/apps-engine/.gitignore create mode 100644 packages/apps-engine/.prettierrc create mode 100644 packages/apps-engine/README.md create mode 100644 packages/apps-engine/deno-runtime/.gitignore create mode 100644 packages/apps-engine/deno-runtime/AppObjectRegistry.ts create mode 100644 packages/apps-engine/deno-runtime/acorn-walk.d.ts create mode 100644 packages/apps-engine/deno-runtime/acorn.d.ts create mode 100644 packages/apps-engine/deno-runtime/deno.jsonc create mode 100644 packages/apps-engine/deno-runtime/deno.lock create mode 100644 packages/apps-engine/deno-runtime/handlers/api-handler.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/construct.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleGetStatus.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleInitialize.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleOnDisable.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleOnEnable.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleOnInstall.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleOnPreSettingUpdate.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleOnSettingUpdated.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleOnUninstall.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleOnUpdate.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handleSetStatus.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/app/handler.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/listener/handler.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/scheduler-handler.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/slashcommand-handler.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/tests/api-handler.test.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/tests/listener-handler.test.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/tests/scheduler-handler.test.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/tests/slashcommand-handler.test.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/tests/uikit-handler.test.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/tests/videoconference-handler.test.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/uikit/handler.ts create mode 100644 packages/apps-engine/deno-runtime/handlers/videoconference-handler.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/builders/BlockBuilder.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/builders/DiscussionBuilder.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/builders/LivechatMessageBuilder.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/builders/MessageBuilder.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/builders/RoomBuilder.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/builders/UserBuilder.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/builders/VideoConferenceBuilder.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/extenders/HttpExtender.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/extenders/MessageExtender.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/extenders/RoomExtender.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/extenders/VideoConferenceExtend.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/http.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/mod.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyCreator.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyExtender.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyUpdater.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/notifier.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/tests/AppAccessors.test.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyCreator.test.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyExtender.test.ts create mode 100644 packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyUpdater.test.ts create mode 100644 packages/apps-engine/deno-runtime/lib/ast/mod.ts create mode 100644 packages/apps-engine/deno-runtime/lib/ast/operations.ts create mode 100644 packages/apps-engine/deno-runtime/lib/ast/tests/data/ast_blocks.ts create mode 100644 packages/apps-engine/deno-runtime/lib/ast/tests/operations.test.ts create mode 100644 packages/apps-engine/deno-runtime/lib/codec.ts create mode 100644 packages/apps-engine/deno-runtime/lib/logger.ts create mode 100644 packages/apps-engine/deno-runtime/lib/messenger.ts create mode 100644 packages/apps-engine/deno-runtime/lib/require.ts create mode 100644 packages/apps-engine/deno-runtime/lib/room.ts create mode 100644 packages/apps-engine/deno-runtime/lib/roomFactory.ts create mode 100644 packages/apps-engine/deno-runtime/lib/sanitizeDeprecatedUsage.ts create mode 100644 packages/apps-engine/deno-runtime/lib/tests/logger.test.ts create mode 100644 packages/apps-engine/deno-runtime/lib/tests/messenger.test.ts create mode 100644 packages/apps-engine/deno-runtime/main.ts create mode 100644 packages/apps-engine/package.json create mode 100644 packages/apps-engine/scripts/bundle.js create mode 100644 packages/apps-engine/scripts/deno-cache.js create mode 100644 packages/apps-engine/src/client/AppClientManager.ts create mode 100644 packages/apps-engine/src/client/AppServerCommunicator.ts create mode 100644 packages/apps-engine/src/client/AppsEngineUIClient.ts create mode 100644 packages/apps-engine/src/client/AppsEngineUIHost.ts create mode 100644 packages/apps-engine/src/client/constants/index.ts create mode 100644 packages/apps-engine/src/client/definition/AppsEngineUIMethods.ts create mode 100644 packages/apps-engine/src/client/definition/IAppsEngineUIResponse.ts create mode 100644 packages/apps-engine/src/client/definition/IExternalComponentRoomInfo.ts create mode 100644 packages/apps-engine/src/client/definition/IExternalComponentUserInfo.ts create mode 100644 packages/apps-engine/src/client/definition/index.ts create mode 100644 packages/apps-engine/src/client/index.ts create mode 100644 packages/apps-engine/src/client/utils/index.ts create mode 100644 packages/apps-engine/src/definition/App.ts create mode 100644 packages/apps-engine/src/definition/AppStatus.ts create mode 100644 packages/apps-engine/src/definition/IApp.ts create mode 100644 packages/apps-engine/src/definition/LICENSE create mode 100644 packages/apps-engine/src/definition/accessors/IApiExtend.ts create mode 100644 packages/apps-engine/src/definition/accessors/IAppAccessors.ts create mode 100644 packages/apps-engine/src/definition/accessors/IAppInstallationContext.ts create mode 100644 packages/apps-engine/src/definition/accessors/IAppUninstallationContext.ts create mode 100644 packages/apps-engine/src/definition/accessors/IAppUpdateContext.ts create mode 100644 packages/apps-engine/src/definition/accessors/ICloudWorkspaceRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IConfigurationExtend.ts create mode 100644 packages/apps-engine/src/definition/accessors/IConfigurationModify.ts create mode 100644 packages/apps-engine/src/definition/accessors/IDiscussionBuilder.ts create mode 100644 packages/apps-engine/src/definition/accessors/IEmailCreator.ts create mode 100644 packages/apps-engine/src/definition/accessors/IEnvironmentRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IEnvironmentWrite.ts create mode 100644 packages/apps-engine/src/definition/accessors/IEnvironmentalVariableRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IExternalComponentsExtend.ts create mode 100644 packages/apps-engine/src/definition/accessors/IHttp.ts create mode 100644 packages/apps-engine/src/definition/accessors/ILivechatCreator.ts create mode 100644 packages/apps-engine/src/definition/accessors/ILivechatMessageBuilder.ts create mode 100644 packages/apps-engine/src/definition/accessors/ILivechatRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/ILivechatUpdater.ts create mode 100644 packages/apps-engine/src/definition/accessors/ILogEntry.ts create mode 100644 packages/apps-engine/src/definition/accessors/ILogger.ts create mode 100644 packages/apps-engine/src/definition/accessors/IMessageBuilder.ts create mode 100644 packages/apps-engine/src/definition/accessors/IMessageExtender.ts create mode 100644 packages/apps-engine/src/definition/accessors/IMessageRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IMessageUpdater.ts create mode 100644 packages/apps-engine/src/definition/accessors/IModerationModify.ts create mode 100644 packages/apps-engine/src/definition/accessors/IModify.ts create mode 100644 packages/apps-engine/src/definition/accessors/IModifyCreator.ts create mode 100644 packages/apps-engine/src/definition/accessors/IModifyDeleter.ts create mode 100644 packages/apps-engine/src/definition/accessors/IModifyExtender.ts create mode 100644 packages/apps-engine/src/definition/accessors/IModifyUpdater.ts create mode 100644 packages/apps-engine/src/definition/accessors/INotifier.ts create mode 100644 packages/apps-engine/src/definition/accessors/IOAuthApp.ts create mode 100644 packages/apps-engine/src/definition/accessors/IOAuthAppsModify.ts create mode 100644 packages/apps-engine/src/definition/accessors/IOAuthAppsReader.ts create mode 100644 packages/apps-engine/src/definition/accessors/IPersistence.ts create mode 100644 packages/apps-engine/src/definition/accessors/IPersistenceRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IRoleRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IRoomBuilder.ts create mode 100644 packages/apps-engine/src/definition/accessors/IRoomExtender.ts create mode 100644 packages/apps-engine/src/definition/accessors/IRoomRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/ISchedulerExtend.ts create mode 100644 packages/apps-engine/src/definition/accessors/ISchedulerModify.ts create mode 100644 packages/apps-engine/src/definition/accessors/IServerSettingRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IServerSettingUpdater.ts create mode 100644 packages/apps-engine/src/definition/accessors/IServerSettingsModify.ts create mode 100644 packages/apps-engine/src/definition/accessors/ISettingRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/ISettingUpdater.ts create mode 100644 packages/apps-engine/src/definition/accessors/ISettingsExtend.ts create mode 100644 packages/apps-engine/src/definition/accessors/ISlashCommandsExtend.ts create mode 100644 packages/apps-engine/src/definition/accessors/ISlashCommandsModify.ts create mode 100644 packages/apps-engine/src/definition/accessors/IThreadRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IUIController.ts create mode 100644 packages/apps-engine/src/definition/accessors/IUIExtend.ts create mode 100644 packages/apps-engine/src/definition/accessors/IUploadCreator.ts create mode 100644 packages/apps-engine/src/definition/accessors/IUploadRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IUserBuilder.ts create mode 100644 packages/apps-engine/src/definition/accessors/IUserRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/IUserUpdater.ts create mode 100644 packages/apps-engine/src/definition/accessors/IVideoConfProvidersExtend.ts create mode 100644 packages/apps-engine/src/definition/accessors/IVideoConferenceBuilder.ts create mode 100644 packages/apps-engine/src/definition/accessors/IVideoConferenceExtend.ts create mode 100644 packages/apps-engine/src/definition/accessors/IVideoConferenceRead.ts create mode 100644 packages/apps-engine/src/definition/accessors/index.ts create mode 100644 packages/apps-engine/src/definition/api/ApiEndpoint.ts create mode 100644 packages/apps-engine/src/definition/api/IApi.ts create mode 100644 packages/apps-engine/src/definition/api/IApiEndpoint.ts create mode 100644 packages/apps-engine/src/definition/api/IApiEndpointInfo.ts create mode 100644 packages/apps-engine/src/definition/api/IApiEndpointMetadata.ts create mode 100644 packages/apps-engine/src/definition/api/IApiExample.ts create mode 100644 packages/apps-engine/src/definition/api/IRequest.ts create mode 100644 packages/apps-engine/src/definition/api/IResponse.ts create mode 100644 packages/apps-engine/src/definition/api/index.ts create mode 100644 packages/apps-engine/src/definition/app-schema.json create mode 100644 packages/apps-engine/src/definition/assets/IAsset.ts create mode 100644 packages/apps-engine/src/definition/assets/IAssetProvider.ts create mode 100644 packages/apps-engine/src/definition/assets/index.ts create mode 100644 packages/apps-engine/src/definition/cloud/IWorkspaceToken.ts create mode 100644 packages/apps-engine/src/definition/email/IEmail.ts create mode 100644 packages/apps-engine/src/definition/email/IEmailDescriptor.ts create mode 100644 packages/apps-engine/src/definition/email/IPreEmailSent.ts create mode 100644 packages/apps-engine/src/definition/email/IPreEmailSentContext.ts create mode 100644 packages/apps-engine/src/definition/email/index.ts create mode 100644 packages/apps-engine/src/definition/example-app.json create mode 100644 packages/apps-engine/src/definition/exceptions/AppsEngineException.ts create mode 100644 packages/apps-engine/src/definition/exceptions/EssentialAppDisabledException.ts create mode 100644 packages/apps-engine/src/definition/exceptions/FileUploadNotAllowedException.ts create mode 100644 packages/apps-engine/src/definition/exceptions/InvalidSettingValueException.ts create mode 100644 packages/apps-engine/src/definition/exceptions/UserNotAllowedException.ts create mode 100644 packages/apps-engine/src/definition/exceptions/index.ts create mode 100644 packages/apps-engine/src/definition/externalComponent/IExternalComponent.ts create mode 100644 packages/apps-engine/src/definition/externalComponent/IExternalComponentOptions.ts create mode 100644 packages/apps-engine/src/definition/externalComponent/IExternalComponentState.ts create mode 100644 packages/apps-engine/src/definition/externalComponent/IPostExternalComponentClosed.ts create mode 100644 packages/apps-engine/src/definition/externalComponent/IPostExternalComponentOpened.ts create mode 100644 packages/apps-engine/src/definition/externalComponent/index.ts create mode 100644 packages/apps-engine/src/definition/livechat/IDepartment.ts create mode 100644 packages/apps-engine/src/definition/livechat/ILivechatEventContext.ts create mode 100644 packages/apps-engine/src/definition/livechat/ILivechatMessage.ts create mode 100644 packages/apps-engine/src/definition/livechat/ILivechatRoom.ts create mode 100644 packages/apps-engine/src/definition/livechat/ILivechatRoomClosedHandler.ts create mode 100644 packages/apps-engine/src/definition/livechat/ILivechatTransferData.ts create mode 100644 packages/apps-engine/src/definition/livechat/ILivechatTransferEventContext.ts create mode 100644 packages/apps-engine/src/definition/livechat/IPostLivechatAgentAssigned.ts create mode 100644 packages/apps-engine/src/definition/livechat/IPostLivechatAgentUnassigned.ts create mode 100644 packages/apps-engine/src/definition/livechat/IPostLivechatGuestSaved.ts create mode 100644 packages/apps-engine/src/definition/livechat/IPostLivechatRoomClosed.ts create mode 100644 packages/apps-engine/src/definition/livechat/IPostLivechatRoomSaved.ts create mode 100644 packages/apps-engine/src/definition/livechat/IPostLivechatRoomStarted.ts create mode 100644 packages/apps-engine/src/definition/livechat/IPostLivechatRoomTransferred.ts create mode 100644 packages/apps-engine/src/definition/livechat/IVisitor.ts create mode 100644 packages/apps-engine/src/definition/livechat/IVisitorEmail.ts create mode 100644 packages/apps-engine/src/definition/livechat/IVisitorPhone.ts create mode 100644 packages/apps-engine/src/definition/livechat/index.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessage.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageAction.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageAttachment.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageAttachmentAuthor.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageAttachmentField.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageAttachmentTitle.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageDeleteContext.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageFile.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageFollowContext.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessagePinContext.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageRaw.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageReaction.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageReactionContext.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageReportContext.ts create mode 100644 packages/apps-engine/src/definition/messages/IMessageStarContext.ts create mode 100644 packages/apps-engine/src/definition/messages/IPostMessageDeleted.ts create mode 100644 packages/apps-engine/src/definition/messages/IPostMessageFollowed.ts create mode 100644 packages/apps-engine/src/definition/messages/IPostMessagePinned.ts create mode 100644 packages/apps-engine/src/definition/messages/IPostMessageReacted.ts create mode 100644 packages/apps-engine/src/definition/messages/IPostMessageReported.ts create mode 100644 packages/apps-engine/src/definition/messages/IPostMessageSent.ts create mode 100644 packages/apps-engine/src/definition/messages/IPostMessageSentToBot.ts create mode 100644 packages/apps-engine/src/definition/messages/IPostMessageStarred.ts create mode 100644 packages/apps-engine/src/definition/messages/IPostMessageUpdated.ts create mode 100644 packages/apps-engine/src/definition/messages/IPreMessageDeletePrevent.ts create mode 100644 packages/apps-engine/src/definition/messages/IPreMessageSentExtend.ts create mode 100644 packages/apps-engine/src/definition/messages/IPreMessageSentModify.ts create mode 100644 packages/apps-engine/src/definition/messages/IPreMessageSentPrevent.ts create mode 100644 packages/apps-engine/src/definition/messages/IPreMessageUpdatedExtend.ts create mode 100644 packages/apps-engine/src/definition/messages/IPreMessageUpdatedModify.ts create mode 100644 packages/apps-engine/src/definition/messages/IPreMessageUpdatedPrevent.ts create mode 100644 packages/apps-engine/src/definition/messages/MessageActionButtonsAlignment.ts create mode 100644 packages/apps-engine/src/definition/messages/MessageActionType.ts create mode 100644 packages/apps-engine/src/definition/messages/MessageProcessingType.ts create mode 100644 packages/apps-engine/src/definition/messages/index.ts create mode 100644 packages/apps-engine/src/definition/metadata/AppInterface.ts create mode 100644 packages/apps-engine/src/definition/metadata/AppMethod.ts create mode 100644 packages/apps-engine/src/definition/metadata/IAppAuthorInfo.ts create mode 100644 packages/apps-engine/src/definition/metadata/IAppInfo.ts create mode 100644 packages/apps-engine/src/definition/metadata/RocketChatAssociations.ts create mode 100644 packages/apps-engine/src/definition/metadata/index.ts create mode 100644 packages/apps-engine/src/definition/oauth2/IOAuth2.ts create mode 100644 packages/apps-engine/src/definition/oauth2/OAuth2.ts create mode 100644 packages/apps-engine/src/definition/permissions/IPermission.ts create mode 100644 packages/apps-engine/src/definition/persistence/IPersistenceItem.ts create mode 100644 packages/apps-engine/src/definition/persistence/index.ts create mode 100644 packages/apps-engine/src/definition/roles/IRole.ts create mode 100644 packages/apps-engine/src/definition/roles/index.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPostRoomCreate.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPostRoomDeleted.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPostRoomUserJoined.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPostRoomUserLeave.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPreRoomCreateExtend.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPreRoomCreateModify.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPreRoomCreatePrevent.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPreRoomDeletePrevent.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPreRoomUserJoined.ts create mode 100644 packages/apps-engine/src/definition/rooms/IPreRoomUserLeave.ts create mode 100644 packages/apps-engine/src/definition/rooms/IRoom.ts create mode 100644 packages/apps-engine/src/definition/rooms/IRoomUserJoinedContext.ts create mode 100644 packages/apps-engine/src/definition/rooms/IRoomUserLeaveContext.ts create mode 100644 packages/apps-engine/src/definition/rooms/RoomType.ts create mode 100644 packages/apps-engine/src/definition/rooms/index.ts create mode 100644 packages/apps-engine/src/definition/scheduler/IOnetimeSchedule.ts create mode 100644 packages/apps-engine/src/definition/scheduler/IProcessor.ts create mode 100644 packages/apps-engine/src/definition/scheduler/IRecurringSchedule.ts create mode 100644 packages/apps-engine/src/definition/scheduler/index.ts create mode 100644 packages/apps-engine/src/definition/settings/ISetting.ts create mode 100644 packages/apps-engine/src/definition/settings/ISettingUpdateContext.ts create mode 100644 packages/apps-engine/src/definition/settings/SettingType.ts create mode 100644 packages/apps-engine/src/definition/settings/index.ts create mode 100644 packages/apps-engine/src/definition/slashcommands/ISlashCommand.ts create mode 100644 packages/apps-engine/src/definition/slashcommands/ISlashCommandPreview.ts create mode 100644 packages/apps-engine/src/definition/slashcommands/SlashCommandContext.ts create mode 100644 packages/apps-engine/src/definition/slashcommands/index.ts create mode 100644 packages/apps-engine/src/definition/ui/IUIActionButtonDescriptor.ts create mode 100644 packages/apps-engine/src/definition/ui/UIActionButtonContext.ts create mode 100644 packages/apps-engine/src/definition/ui/index.ts create mode 100644 packages/apps-engine/src/definition/uikit/IUIKitActionHandler.ts create mode 100644 packages/apps-engine/src/definition/uikit/IUIKitIncomingInteraction.ts create mode 100644 packages/apps-engine/src/definition/uikit/IUIKitIncomingInteractionActionButton.ts create mode 100644 packages/apps-engine/src/definition/uikit/IUIKitInteractionType.ts create mode 100644 packages/apps-engine/src/definition/uikit/IUIKitSurface.ts create mode 100644 packages/apps-engine/src/definition/uikit/IUIKitView.ts create mode 100644 packages/apps-engine/src/definition/uikit/UIKitIncomingInteractionContainer.ts create mode 100644 packages/apps-engine/src/definition/uikit/UIKitIncomingInteractionTypes.ts create mode 100644 packages/apps-engine/src/definition/uikit/UIKitInteractionContext.ts create mode 100644 packages/apps-engine/src/definition/uikit/UIKitInteractionPayloadFormatter.ts create mode 100644 packages/apps-engine/src/definition/uikit/UIKitInteractionResponder.ts create mode 100644 packages/apps-engine/src/definition/uikit/blocks/BlockBuilder.ts create mode 100644 packages/apps-engine/src/definition/uikit/blocks/Blocks.ts create mode 100644 packages/apps-engine/src/definition/uikit/blocks/Elements.ts create mode 100644 packages/apps-engine/src/definition/uikit/blocks/Objects.ts create mode 100644 packages/apps-engine/src/definition/uikit/blocks/index.ts create mode 100644 packages/apps-engine/src/definition/uikit/index.ts create mode 100644 packages/apps-engine/src/definition/uikit/livechat/IUIKitLivechatActionHandler.ts create mode 100644 packages/apps-engine/src/definition/uikit/livechat/IUIKitLivechatIncomingInteraction.ts create mode 100644 packages/apps-engine/src/definition/uikit/livechat/UIKitLivechatIncomingInteractionType.ts create mode 100644 packages/apps-engine/src/definition/uikit/livechat/UIKitLivechatInteractionContext.ts create mode 100644 packages/apps-engine/src/definition/uikit/livechat/index.ts create mode 100644 packages/apps-engine/src/definition/uploads/IFileUploadContext.ts create mode 100644 packages/apps-engine/src/definition/uploads/IPreFileUpload.ts create mode 100644 packages/apps-engine/src/definition/uploads/IUpload.ts create mode 100644 packages/apps-engine/src/definition/uploads/IUploadDescriptor.ts create mode 100644 packages/apps-engine/src/definition/uploads/IUploadDetails.ts create mode 100644 packages/apps-engine/src/definition/uploads/StoreType.ts create mode 100644 packages/apps-engine/src/definition/uploads/index.ts create mode 100644 packages/apps-engine/src/definition/users/IBotUser.ts create mode 100644 packages/apps-engine/src/definition/users/IPostUserCreated.ts create mode 100644 packages/apps-engine/src/definition/users/IPostUserDeleted.ts create mode 100644 packages/apps-engine/src/definition/users/IPostUserLoggedIn.ts create mode 100644 packages/apps-engine/src/definition/users/IPostUserLoggedOut.ts create mode 100644 packages/apps-engine/src/definition/users/IPostUserStatusChanged.ts create mode 100644 packages/apps-engine/src/definition/users/IPostUserUpdated.ts create mode 100644 packages/apps-engine/src/definition/users/IUser.ts create mode 100644 packages/apps-engine/src/definition/users/IUserContext.ts create mode 100644 packages/apps-engine/src/definition/users/IUserCreationOptions.ts create mode 100644 packages/apps-engine/src/definition/users/IUserEmail.ts create mode 100644 packages/apps-engine/src/definition/users/IUserLookup.ts create mode 100644 packages/apps-engine/src/definition/users/IUserSettings.ts create mode 100644 packages/apps-engine/src/definition/users/IUserStatusContext.ts create mode 100644 packages/apps-engine/src/definition/users/IUserUpdateContex.ts create mode 100644 packages/apps-engine/src/definition/users/IUserUpdateContext.ts create mode 100644 packages/apps-engine/src/definition/users/UserStatusConnection.ts create mode 100644 packages/apps-engine/src/definition/users/UserType.ts create mode 100644 packages/apps-engine/src/definition/users/index.ts create mode 100644 packages/apps-engine/src/definition/videoConfProviders/IVideoConfProvider.ts create mode 100644 packages/apps-engine/src/definition/videoConfProviders/IVideoConferenceOptions.ts create mode 100644 packages/apps-engine/src/definition/videoConfProviders/VideoConfData.ts create mode 100644 packages/apps-engine/src/definition/videoConfProviders/index.ts create mode 100644 packages/apps-engine/src/definition/videoConferences/AppVideoConference.ts create mode 100644 packages/apps-engine/src/definition/videoConferences/IVideoConference.ts create mode 100644 packages/apps-engine/src/definition/videoConferences/IVideoConferenceUser.ts create mode 100644 packages/apps-engine/src/definition/videoConferences/index.ts create mode 100644 packages/apps-engine/src/lib/utils.ts create mode 100644 packages/apps-engine/src/server/AppManager.ts create mode 100644 packages/apps-engine/src/server/IGetAppsFilter.ts create mode 100644 packages/apps-engine/src/server/ProxiedApp.ts create mode 100644 packages/apps-engine/src/server/accessors/ApiExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/AppAccessors.ts create mode 100644 packages/apps-engine/src/server/accessors/CloudWorkspaceRead.ts create mode 100644 packages/apps-engine/src/server/accessors/ConfigurationExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/ConfigurationModify.ts create mode 100644 packages/apps-engine/src/server/accessors/DiscussionBuilder.ts create mode 100644 packages/apps-engine/src/server/accessors/EmailCreator.ts create mode 100644 packages/apps-engine/src/server/accessors/EnvironmentRead.ts create mode 100644 packages/apps-engine/src/server/accessors/EnvironmentWrite.ts create mode 100644 packages/apps-engine/src/server/accessors/EnvironmentalVariableRead.ts create mode 100644 packages/apps-engine/src/server/accessors/ExternalComponentsExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/Http.ts create mode 100644 packages/apps-engine/src/server/accessors/HttpExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/LivechatCreator.ts create mode 100644 packages/apps-engine/src/server/accessors/LivechatMessageBuilder.ts create mode 100644 packages/apps-engine/src/server/accessors/LivechatRead.ts create mode 100644 packages/apps-engine/src/server/accessors/LivechatUpdater.ts create mode 100644 packages/apps-engine/src/server/accessors/MessageBuilder.ts create mode 100644 packages/apps-engine/src/server/accessors/MessageExtender.ts create mode 100644 packages/apps-engine/src/server/accessors/MessageRead.ts create mode 100644 packages/apps-engine/src/server/accessors/ModerationModify.ts create mode 100644 packages/apps-engine/src/server/accessors/Modify.ts create mode 100644 packages/apps-engine/src/server/accessors/ModifyCreator.ts create mode 100644 packages/apps-engine/src/server/accessors/ModifyDeleter.ts create mode 100644 packages/apps-engine/src/server/accessors/ModifyExtender.ts create mode 100644 packages/apps-engine/src/server/accessors/ModifyUpdater.ts create mode 100644 packages/apps-engine/src/server/accessors/Notifier.ts create mode 100644 packages/apps-engine/src/server/accessors/OAuthAppsModify.ts create mode 100644 packages/apps-engine/src/server/accessors/OAuthAppsReader.ts create mode 100644 packages/apps-engine/src/server/accessors/Persistence.ts create mode 100644 packages/apps-engine/src/server/accessors/PersistenceRead.ts create mode 100644 packages/apps-engine/src/server/accessors/Reader.ts create mode 100644 packages/apps-engine/src/server/accessors/RoleRead.ts create mode 100644 packages/apps-engine/src/server/accessors/RoomBuilder.ts create mode 100644 packages/apps-engine/src/server/accessors/RoomExtender.ts create mode 100644 packages/apps-engine/src/server/accessors/RoomRead.ts create mode 100644 packages/apps-engine/src/server/accessors/SchedulerExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/SchedulerModify.ts create mode 100644 packages/apps-engine/src/server/accessors/ServerSettingRead.ts create mode 100644 packages/apps-engine/src/server/accessors/ServerSettingUpdater.ts create mode 100644 packages/apps-engine/src/server/accessors/ServerSettingsModify.ts create mode 100644 packages/apps-engine/src/server/accessors/SettingRead.ts create mode 100644 packages/apps-engine/src/server/accessors/SettingUpdater.ts create mode 100644 packages/apps-engine/src/server/accessors/SettingsExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/SlashCommandsExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/SlashCommandsModify.ts create mode 100644 packages/apps-engine/src/server/accessors/ThreadRead.ts create mode 100644 packages/apps-engine/src/server/accessors/UIController.ts create mode 100644 packages/apps-engine/src/server/accessors/UIExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/UploadCreator.ts create mode 100644 packages/apps-engine/src/server/accessors/UploadRead.ts create mode 100644 packages/apps-engine/src/server/accessors/UserBuilder.ts create mode 100644 packages/apps-engine/src/server/accessors/UserRead.ts create mode 100644 packages/apps-engine/src/server/accessors/UserUpdater.ts create mode 100644 packages/apps-engine/src/server/accessors/VideoConfProviderExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/VideoConferenceBuilder.ts create mode 100644 packages/apps-engine/src/server/accessors/VideoConferenceExtend.ts create mode 100644 packages/apps-engine/src/server/accessors/VideoConferenceRead.ts create mode 100644 packages/apps-engine/src/server/accessors/index.ts create mode 100644 packages/apps-engine/src/server/bridges/ApiBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/AppActivationBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/AppBridges.ts create mode 100644 packages/apps-engine/src/server/bridges/AppDetailChangesBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/BaseBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/CloudWorkspaceBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/CommandBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/EmailBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/EnvironmentalVariableBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/HttpBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/IInternalBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/IInternalFederationBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/IInternalPersistenceBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/IInternalSchedulerBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/IInternalUserBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/IListenerBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/InternalBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/ListenerBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/LivechatBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/MessageBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/ModerationBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/OAuthAppsBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/PersistenceBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/RoleBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/RoomBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/SchedulerBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/ServerSettingBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/ThreadBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/UiInteractionBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/UploadBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/UserBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/VideoConferenceBridge.ts create mode 100644 packages/apps-engine/src/server/bridges/index.ts create mode 100644 packages/apps-engine/src/server/compiler/AppCompiler.ts create mode 100644 packages/apps-engine/src/server/compiler/AppFabricationFulfillment.ts create mode 100644 packages/apps-engine/src/server/compiler/AppImplements.ts create mode 100644 packages/apps-engine/src/server/compiler/AppPackageParser.ts create mode 100644 packages/apps-engine/src/server/compiler/IParseAppPackageResult.ts create mode 100644 packages/apps-engine/src/server/compiler/index.ts create mode 100644 packages/apps-engine/src/server/compiler/modules/index.ts create mode 100644 packages/apps-engine/src/server/compiler/modules/networking.ts create mode 100644 packages/apps-engine/src/server/errors/CommandAlreadyExistsError.ts create mode 100644 packages/apps-engine/src/server/errors/CommandHasAlreadyBeenTouchedError.ts create mode 100644 packages/apps-engine/src/server/errors/CompilerError.ts create mode 100644 packages/apps-engine/src/server/errors/InvalidInstallationError.ts create mode 100644 packages/apps-engine/src/server/errors/InvalidLicenseError.ts create mode 100644 packages/apps-engine/src/server/errors/MustContainFunctionError.ts create mode 100644 packages/apps-engine/src/server/errors/MustExtendAppError.ts create mode 100644 packages/apps-engine/src/server/errors/NotEnoughMethodArgumentsError.ts create mode 100644 packages/apps-engine/src/server/errors/PathAlreadyExistsError.ts create mode 100644 packages/apps-engine/src/server/errors/PermissionDeniedError.ts create mode 100644 packages/apps-engine/src/server/errors/RequiredApiVersionError.ts create mode 100644 packages/apps-engine/src/server/errors/VideoConfProviderAlreadyExistsError.ts create mode 100644 packages/apps-engine/src/server/errors/VideoConfProviderNotRegisteredError.ts create mode 100644 packages/apps-engine/src/server/errors/index.ts create mode 100644 packages/apps-engine/src/server/logging/AppConsole.ts create mode 100644 packages/apps-engine/src/server/logging/ILoggerStorageEntry.ts create mode 100644 packages/apps-engine/src/server/logging/index.ts create mode 100644 packages/apps-engine/src/server/managers/AppAccessorManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppApi.ts create mode 100644 packages/apps-engine/src/server/managers/AppApiManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppExternalComponentManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppLicenseManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppListenerManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppPermissionManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppRuntimeManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppSchedulerManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppSettingsManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppSignatureManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppSlashCommand.ts create mode 100644 packages/apps-engine/src/server/managers/AppSlashCommandManager.ts create mode 100644 packages/apps-engine/src/server/managers/AppVideoConfProvider.ts create mode 100644 packages/apps-engine/src/server/managers/AppVideoConfProviderManager.ts create mode 100644 packages/apps-engine/src/server/managers/UIActionButtonManager.ts create mode 100644 packages/apps-engine/src/server/managers/index.ts create mode 100644 packages/apps-engine/src/server/marketplace/IAppLicenseMetadata.ts create mode 100644 packages/apps-engine/src/server/marketplace/IMarketplaceInfo.ts create mode 100644 packages/apps-engine/src/server/marketplace/IMarketplacePricingPlan.ts create mode 100644 packages/apps-engine/src/server/marketplace/IMarketplacePricingTier.ts create mode 100644 packages/apps-engine/src/server/marketplace/IMarketplaceSimpleBundleInfo.ts create mode 100644 packages/apps-engine/src/server/marketplace/IMarketplaceSubscriptionInfo.ts create mode 100644 packages/apps-engine/src/server/marketplace/MarketplacePricingStrategy.ts create mode 100644 packages/apps-engine/src/server/marketplace/MarketplacePurchaseType.ts create mode 100644 packages/apps-engine/src/server/marketplace/MarketplaceSubscriptionStatus.ts create mode 100644 packages/apps-engine/src/server/marketplace/MarketplaceSubscriptionType.ts create mode 100644 packages/apps-engine/src/server/marketplace/index.ts create mode 100644 packages/apps-engine/src/server/marketplace/license/AppLicenseValidationResult.ts create mode 100644 packages/apps-engine/src/server/marketplace/license/Crypto.ts create mode 100644 packages/apps-engine/src/server/marketplace/license/index.ts create mode 100644 packages/apps-engine/src/server/messages/Message.ts create mode 100644 packages/apps-engine/src/server/misc/UIHelper.ts create mode 100644 packages/apps-engine/src/server/misc/Utilities.ts create mode 100644 packages/apps-engine/src/server/oauth2/OAuth2Client.ts create mode 100644 packages/apps-engine/src/server/permissions/AppPermissions.ts create mode 100644 packages/apps-engine/src/server/rooms/Room.ts create mode 100644 packages/apps-engine/src/server/runtime/AppsEngineEmptyRuntime.ts create mode 100644 packages/apps-engine/src/server/runtime/AppsEngineNodeRuntime.ts create mode 100644 packages/apps-engine/src/server/runtime/AppsEngineRuntime.ts create mode 100644 packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts create mode 100644 packages/apps-engine/src/server/runtime/deno/LivenessManager.ts create mode 100644 packages/apps-engine/src/server/runtime/deno/ProcessMessenger.ts create mode 100644 packages/apps-engine/src/server/runtime/deno/bundler.ts create mode 100644 packages/apps-engine/src/server/runtime/deno/codec.ts create mode 100644 packages/apps-engine/src/server/storage/AppLogStorage.ts create mode 100644 packages/apps-engine/src/server/storage/AppMetadataStorage.ts create mode 100644 packages/apps-engine/src/server/storage/AppSourceStorage.ts create mode 100644 packages/apps-engine/src/server/storage/IAppStorageItem.ts create mode 100644 packages/apps-engine/src/server/storage/index.ts create mode 100644 packages/apps-engine/tests/runner.ts create mode 100644 packages/apps-engine/tests/server/AppManager.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/AppAccessors.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/ConfigurationExtend.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/ConfigurationModify.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/EnvironmentRead.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/EnvironmentWrite.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/EnvironmentalVariableRead.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/Http.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/HttpExtend.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/MessageBuilder.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/MessageExtender.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/MessageRead.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/Modify.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/ModifyCreator.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/ModifyExtender.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/ModifyUpdater.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/Notifier.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/Persistence.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/PersistenceRead.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/Reader.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/RoomBuilder.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/RoomExtender.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/RoomRead.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/ServerSettingRead.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/ServerSettingsModify.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/SettingRead.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/SettingsExtend.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/SlashCommandsExtend.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/SlashCommandsModify.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/UserBuilder.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/UserRead.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/VideoConfProviderExtend.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/VideoConferenceBuilder.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/VideoConferenceExtend.spec.ts create mode 100644 packages/apps-engine/tests/server/accessors/VideoConferenceRead.spec.ts create mode 100644 packages/apps-engine/tests/server/compiler/AppCompiler.spec.ts create mode 100644 packages/apps-engine/tests/server/compiler/AppFabricationFulfillment.spec.ts create mode 100644 packages/apps-engine/tests/server/compiler/AppImplements.spec.ts create mode 100644 packages/apps-engine/tests/server/errors/CommandAlreadyExistsError.spec.ts create mode 100644 packages/apps-engine/tests/server/errors/CommandHasAlreadyBeenTouchedError.spec.ts create mode 100644 packages/apps-engine/tests/server/errors/CompilerError.spec.ts create mode 100644 packages/apps-engine/tests/server/errors/MustContainFunctionError.spec.ts create mode 100644 packages/apps-engine/tests/server/errors/MustExtendAppError.spec.ts create mode 100644 packages/apps-engine/tests/server/errors/NotEnoughMethodArgumentsError.spec.ts create mode 100644 packages/apps-engine/tests/server/errors/RequiredApiVersionError.spec.ts create mode 100644 packages/apps-engine/tests/server/logging/AppConsole.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppAccessorManager.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppApi.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppApiManager.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppExternalComponentManager.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppListenerManager.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppSettingsManager.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppSlashCommand.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppSlashCommandManager.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppVideoConfProvider.spec.ts create mode 100644 packages/apps-engine/tests/server/managers/AppVideoConfProviderManager.spec.ts create mode 100644 packages/apps-engine/tests/server/misc/Utilities.spec.ts create mode 100644 packages/apps-engine/tests/server/runtime/DenoRuntimeSubprocessController.spec.ts create mode 100644 packages/apps-engine/tests/test-data/README.md create mode 100644 packages/apps-engine/tests/test-data/apps/hello-world-test_0.0.1.zip create mode 100644 packages/apps-engine/tests/test-data/apps/testing-app_0.0.8.zip create mode 100644 packages/apps-engine/tests/test-data/bridges/OAuthAppsBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/activationBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/apiBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/appBridges.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/appDetailChanges.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/cloudBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/commandBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/emailBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/environmentalVariableBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/httpBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/internalBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/internalFederationBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/livechatBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/messageBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/moderationBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/persisBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/roleBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/roomBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/schedulerBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/serverSettingBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/threadBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/uiIntegrationBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/uploadBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/userBridge.ts create mode 100644 packages/apps-engine/tests/test-data/bridges/videoConferenceBridge.ts create mode 100644 packages/apps-engine/tests/test-data/misc/fake-library-file.d.ts create mode 100644 packages/apps-engine/tests/test-data/storage/TestSourceStorage.ts create mode 100644 packages/apps-engine/tests/test-data/storage/logStorage.ts create mode 100644 packages/apps-engine/tests/test-data/storage/storage.ts create mode 100644 packages/apps-engine/tests/test-data/utilities.ts create mode 100644 packages/apps-engine/tsconfig-lint.json create mode 100644 packages/apps-engine/tsconfig.json create mode 100644 packages/apps-engine/turbo.json create mode 100644 packages/apps-engine/typedoc.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a834776aeff5..f66c5d29de5b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,5 @@ /packages/* @RocketChat/Architecture +/packages/apps-engine/ @RocketChat/apps /packages/core-typings/ @RocketChat/Architecture /packages/rest-typings/ @RocketChat/Architecture @RocketChat/backend /packages/ui-contexts/ @RocketChat/frontend diff --git a/.github/actions/build-docker-image/action.yml b/.github/actions/build-docker-image/action.yml index 378f6bdb01b9..02a05d9605a7 100644 --- a/.github/actions/build-docker-image/action.yml +++ b/.github/actions/build-docker-image/action.yml @@ -12,6 +12,9 @@ inputs: required: false password: required: false + deno-version: + required: true + type: string outputs: image-name: @@ -59,7 +62,7 @@ runs: fi; echo "Build ${{ inputs.release }} Docker image" - docker build -t $IMAGE_NAME . + docker build --build-arg DENO_VERSION=${{ inputs.deno-version }} -t $IMAGE_NAME . echo "image-name-base=${IMAGE_NAME_BASE}" >> $GITHUB_OUTPUT echo "image-name=${IMAGE_NAME}" >> $GITHUB_OUTPUT diff --git a/.github/actions/build-docker/action.yml b/.github/actions/build-docker/action.yml index 5af39b924057..ae84e376a0d9 100644 --- a/.github/actions/build-docker/action.yml +++ b/.github/actions/build-docker/action.yml @@ -9,6 +9,10 @@ inputs: required: true description: 'Node version' type: string + deno-version: + required: true + description: 'Deno version' + type: string platform: required: false description: 'Platform' @@ -66,6 +70,7 @@ runs: if: inputs.setup == 'true' with: node-version: ${{ inputs.node-version }} + deno-version: ${{ inputs.deno-version }} cache-modules: true install: true NPM_TOKEN: ${{ inputs.NPM_TOKEN }} @@ -79,6 +84,8 @@ runs: run: | args=(rocketchat ${{ inputs.build-containers }}) + export DENO_VERSION="${{ inputs.deno-version }}" + docker compose -f docker-compose-ci.yml build "${args[@]}" - name: Publish Docker images to GitHub Container Registry diff --git a/.github/actions/meteor-build/action.yml b/.github/actions/meteor-build/action.yml index 551a57d28a7c..bfd4ae7f5c20 100644 --- a/.github/actions/meteor-build/action.yml +++ b/.github/actions/meteor-build/action.yml @@ -16,6 +16,10 @@ inputs: NPM_TOKEN: required: false description: 'NPM token' + deno-version: + required: true + description: 'Deno version' + type: string runs: using: composite @@ -30,6 +34,7 @@ runs: uses: ./.github/actions/setup-node with: node-version: ${{ inputs.node-version }} + deno-version: ${{ inputs.deno-version }} cache-modules: true install: true NPM_TOKEN: ${{ inputs.NPM_TOKEN }} diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml index 1035e2835792..120797d2ba3c 100644 --- a/.github/actions/setup-node/action.yml +++ b/.github/actions/setup-node/action.yml @@ -11,10 +11,11 @@ inputs: install: required: false description: 'Install dependencies' - deno-dir: - required: false - description: 'Deno directory' - default: ~/.deno-cache + type: boolean + deno-version: + required: true + description: 'Deno version' + type: string NPM_TOKEN: required: false description: 'NPM token' @@ -28,21 +29,20 @@ runs: using: composite steps: - - run: echo 'DENO_DIR=${{ inputs.deno-dir }}' >> $GITHUB_ENV - shell: bash - - - name: Cache Node Modules + - name: Cache Node Modules & Deno if: inputs.cache-modules id: cache-node-modules uses: actions/cache@v3 with: + # We need to cache node_modules for all workspaces with "hoistingLimits" defined path: | .turbo/cache node_modules - ${{ env.DENO_DIR }} apps/meteor/node_modules apps/meteor/ee/server/services/node_modules - key: node-modules-${{ hashFiles('yarn.lock') }} + packages/apps-engine/node_modules + packages/apps-engine/.deno-cache + key: node-modules-${{ hashFiles('yarn.lock') }}-deno-${{ hashFiles('packages/apps-engine/deno-runtime/deno.lock') }} # # Could use this command to list all paths to save: # find . -name 'node_modules' -prune | grep -v "/\.meteor/" | grep -v "/meteor/packages/" @@ -54,6 +54,11 @@ runs: node-version: ${{ inputs.node-version }} cache: 'yarn' + - name: Use Deno ${{ inputs.deno-version }} + uses: denoland/setup-deno@v1 + with: + deno-version: ${{ inputs.deno-version }} + - name: yarn login shell: bash if: inputs.NPM_TOKEN diff --git a/.github/workflows/ci-code-check.yml b/.github/workflows/ci-code-check.yml index af50b3230ba7..41facad89a03 100644 --- a/.github/workflows/ci-code-check.yml +++ b/.github/workflows/ci-code-check.yml @@ -6,6 +6,9 @@ on: node-version: required: true type: string + deno-version: + required: true + type: string env: TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }} @@ -33,6 +36,7 @@ jobs: uses: ./.github/actions/setup-node with: node-version: ${{ inputs.node-version }} + deno-version: ${{ inputs.deno-version }} cache-modules: true install: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/ci-deploy-gh-pages-preview.yml b/.github/workflows/ci-deploy-gh-pages-preview.yml index 17f247ddad94..8a0905a174bb 100644 --- a/.github/workflows/ci-deploy-gh-pages-preview.yml +++ b/.github/workflows/ci-deploy-gh-pages-preview.yml @@ -23,6 +23,7 @@ jobs: if: github.event.action != 'closed' with: node-version: 14.21.3 + deno-version: 1.37.1 cache-modules: true install: true diff --git a/.github/workflows/ci-deploy-gh-pages.yml b/.github/workflows/ci-deploy-gh-pages.yml index b381e05ae5d8..0aab8022c7e6 100644 --- a/.github/workflows/ci-deploy-gh-pages.yml +++ b/.github/workflows/ci-deploy-gh-pages.yml @@ -18,6 +18,7 @@ jobs: uses: ./.github/actions/setup-node with: node-version: 14.21.3 + deno-version: 1.37.1 cache-modules: true install: true diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index a80a40419e9f..f219f39c0614 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -6,6 +6,9 @@ on: node-version: required: true type: string + deno-version: + required: true + type: string lowercase-repo: required: true type: string @@ -128,6 +131,7 @@ jobs: uses: ./.github/actions/setup-node with: node-version: ${{ inputs.node-version }} + deno-version: ${{ inputs.deno-version }} cache-modules: true install: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/ci-test-unit.yml b/.github/workflows/ci-test-unit.yml index 840808ff5e31..883212d0cf3d 100644 --- a/.github/workflows/ci-test-unit.yml +++ b/.github/workflows/ci-test-unit.yml @@ -6,6 +6,9 @@ on: node-version: required: true type: string + deno-version: + required: true + type: string enterprise-license: required: false type: string @@ -37,6 +40,7 @@ jobs: uses: ./.github/actions/setup-node with: node-version: ${{ inputs.node-version }} + deno-version: ${{ inputs.deno-version }} cache-modules: true install: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40260f71d21f..6b6fa426ca96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,7 @@ jobs: rc-dockerfile-alpine: '${{ github.workspace }}/apps/meteor/.docker/Dockerfile.alpine' rc-docker-tag-alpine: '${{ steps.docker.outputs.gh-docker-tag }}.alpine' node-version: ${{ steps.var.outputs.node-version }} + deno-version: ${{ steps.var.outputs.deno-version }} # this is 100% intentional, secrets are not available for forks, so ee-tests will always fail # to avoid this, we are using a dummy license, expiring at 2025-06-31 enterprise-license: X/XumwIkgwQuld0alWKt37lVA90XjKOrfiMvMZ0/RtqsMtrdL9GoAk+4jXnaY1b2ePoG7XSzGhuxEDxFKIWJK3hIKGNTvrd980LgH5sM5+1T4P42ivSpd8UZi0bwjJkCFLIu9RozzYwslGG0IehMxe0S6VjcO0UYlUJtbMCBHuR2WmTAmO6YVU3ln+pZCbrPFaTPSS1RovhKaNCNkZwIx/CLWW8UTXUuFV/ML4PbKKVoa5nvvJwPeatgL7UCnlSD90lfCiiuikpzj/Y/JLkIL6velFbwNxsrxg9iRJ2k0sKheMMSmlTiGzSvZUm+na5WQq91aKGncih+DmaEZA7QGrjp4eoA0dqTk6OmItsy0fHmQhvZIOKNMeO7vNQiLbaSV6rqibrzu7WPpeIvsvL57T1h37USoCSB6+jDqkzdfoqIpz8BxTiJDj1d8xGPJFVrgxoqQqkj9qIP/gCaEz5DF39QFv5sovk4yK2O8fEQYod2d14V9yECYl4szZPMk1IBfCAC2w7czWGHHFonhL+CQGT403y5wmDmnsnjlCqMKF72odqfTPTI8XnCvJDriPMWohnQEAGtTTyciAhNokx/mjAVJ4NeZPcsbm4BjhvJvnjxx/BhYhBBTNWPaCSZzocfrGUj9Z+ZA7BEz+xAFQyGDx3xRzqIXfT0G7w8fvgYJMU= @@ -39,6 +40,7 @@ jobs: with: sparse-checkout: | package.json + .tool-versions sparse-checkout-cone-mode: false ref: ${{ github.ref }} @@ -53,6 +55,10 @@ jobs: echo "NODE_VERSION: ${NODE_VERSION}" echo "node-version=${NODE_VERSION}" >> $GITHUB_OUTPUT + DENO_VERSION=$(awk '$1=="deno"{ print $2 }' .tool-versions) + echo "DENO_VERSION: ${DENO_VERSION}" + echo "deno-version=${DENO_VERSION}" >> $GITHUB_OUTPUT + - id: by-tag run: | if echo "$GITHUB_REF_NAME" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' ; then @@ -150,6 +156,7 @@ jobs: uses: ./.github/actions/setup-node with: node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} cache-modules: true install: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -194,6 +201,7 @@ jobs: - uses: ./.github/actions/meteor-build with: node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} coverage: ${{ github.event_name != 'release' }} build-prod: @@ -224,6 +232,7 @@ jobs: - uses: ./.github/actions/meteor-build with: node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} coverage: ${{ github.event_name != 'release' }} build-gh-docker-coverage: @@ -252,6 +261,7 @@ jobs: CR_USER: ${{ secrets.CR_USER }} CR_PAT: ${{ secrets.CR_PAT }} node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} platform: ${{ matrix.platform }} build-containers: ${{ matrix.platform == 'alpine' && 'authorization-service account-service ddp-streamer-service presence-service stream-hub-service queue-worker-service omnichannel-transcript-service' || '' }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -280,6 +290,7 @@ jobs: CR_USER: ${{ secrets.CR_USER }} CR_PAT: ${{ secrets.CR_PAT }} node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} platform: ${{ matrix.platform }} build-containers: ${{ matrix.platform == 'alpine' && 'authorization-service account-service ddp-streamer-service presence-service stream-hub-service queue-worker-service omnichannel-transcript-service' || '' }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -300,6 +311,7 @@ jobs: uses: ./.github/workflows/ci-code-check.yml with: node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} test-unit: name: 🔨 Test Unit @@ -308,6 +320,7 @@ jobs: uses: ./.github/workflows/ci-test-unit.yml with: node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }} secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} @@ -321,6 +334,7 @@ jobs: type: api release: ce node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} rc-docker-tag: ${{ needs.release-versions.outputs.rc-docker-tag }} @@ -344,6 +358,7 @@ jobs: shard: '[1, 2, 3, 4]' total-shard: 4 node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} rc-docker-tag: ${{ needs.release-versions.outputs.rc-docker-tag }} @@ -371,6 +386,7 @@ jobs: enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }} mongodb-version: "['4.4']" node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} rc-docker-tag: ${{ needs.release-versions.outputs.rc-docker-tag }} @@ -395,6 +411,7 @@ jobs: total-shard: 5 mongodb-version: "['4.4']" node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} rc-docker-tag: ${{ needs.release-versions.outputs.rc-docker-tag }} @@ -425,6 +442,7 @@ jobs: total-shard: 5 mongodb-version: "['6.0']" node-version: ${{ needs.release-versions.outputs.node-version }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} rc-docker-tag: ${{ needs.release-versions.outputs.rc-docker-tag }} @@ -564,6 +582,7 @@ jobs: username: ${{ secrets.CR_USER }} password: ${{ secrets.CR_PAT }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + deno-version: ${{ needs.release-versions.outputs.deno-version }} docker-image-publish: name: 🚀 Publish Docker Image (main) diff --git a/.github/workflows/new-release.yml b/.github/workflows/new-release.yml index b2eae5d90b92..70e9eb354a06 100644 --- a/.github/workflows/new-release.yml +++ b/.github/workflows/new-release.yml @@ -35,6 +35,7 @@ jobs: uses: ./.github/actions/setup-node with: node-version: 14.21.3 + deno-version: 1.37.1 cache-modules: true install: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/pr-update-description.yml b/.github/workflows/pr-update-description.yml index 084f2a383480..26ffffc6c86f 100644 --- a/.github/workflows/pr-update-description.yml +++ b/.github/workflows/pr-update-description.yml @@ -22,6 +22,7 @@ jobs: uses: ./.github/actions/setup-node with: node-version: 14.21.3 + deno-version: 1.37.1 cache-modules: true install: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 3f2067ac7ec3..fe049f6a8369 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -25,6 +25,7 @@ jobs: uses: ./.github/actions/setup-node with: node-version: 14.21.3 + deno-version: 1.37.1 cache-modules: true install: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml index 4a1e67fca33a..8c9048710dd2 100644 --- a/.github/workflows/release-candidate.yml +++ b/.github/workflows/release-candidate.yml @@ -16,6 +16,7 @@ jobs: uses: ./.github/actions/setup-node with: node-version: 14.21.3 + deno-version: 1.37.1 cache-modules: true install: true NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 000000000000..bc89cc40f83e --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +deno 1.37.1 diff --git a/README.md b/README.md index 6461ad602516..564ca75d2b11 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ You can follow these instructions to setup a dev environment: - Install **Node 14.x (LTS)** either [manually](https://nodejs.org/dist/latest-v14.x/) or using a tool like [nvm](https://github.com/creationix/nvm) or [volta](https://volta.sh/) (recommended) - Install **Meteor** ([version here](apps/meteor/.meteor/release)): https://docs.meteor.com/about/install.html - Install **yarn**: https://yarnpkg.com/getting-started/install +- Install **Deno 1.x**: https://docs.deno.com/runtime/fundamentals/installation/ - Clone this repo: `git clone https://github.com/RocketChat/Rocket.Chat.git` - Run `yarn` to install dependencies diff --git a/apps/meteor/.docker/Dockerfile b/apps/meteor/.docker/Dockerfile index 1e9ed3f5e592..75df2cb90678 100644 --- a/apps/meteor/.docker/Dockerfile +++ b/apps/meteor/.docker/Dockerfile @@ -1,3 +1,7 @@ +ARG DENO_VERSION="1.37.1" + +FROM denoland/deno:bin-${DENO_VERSION} as deno + FROM node:14.21.3-bullseye-slim LABEL maintainer="buildmaster@rocket.chat" @@ -10,6 +14,8 @@ RUN groupadd -g 65533 -r rocketchat \ && apt-get update \ && apt-get install -y --no-install-recommends fontconfig +COPY --from=deno /deno /bin/deno + # --chown requires Docker 17.12 and works only on Linux ADD --chown=rocketchat:rocketchat . /app @@ -20,8 +26,7 @@ ENV DEPLOY_METHOD=docker \ HOME=/tmp \ PORT=3000 \ ROOT_URL=http://localhost:3000 \ - Accounts_AvatarStorePath=/app/uploads \ - DENO_DIR=/usr/share/deno + Accounts_AvatarStorePath=/app/uploads RUN aptMark="$(apt-mark showmanual)" \ && apt-get install -y --no-install-recommends g++ make python3 ca-certificates \ @@ -29,8 +34,6 @@ RUN aptMark="$(apt-mark showmanual)" \ && npm install \ && cd npm/node_modules/isolated-vm \ && npm install \ - && cd /app/bundle/programs/server/npm/node_modules/@rocket.chat/apps-engine/deno-runtime \ - && ../../../deno-bin/bin/deno cache main.ts \ && apt-mark auto '.*' > /dev/null \ && apt-mark manual $aptMark > /dev/null \ && find /usr/local -type f -executable -exec ldd '{}' ';' \ diff --git a/apps/meteor/.docker/Dockerfile.alpine b/apps/meteor/.docker/Dockerfile.alpine index feebf76a03e7..aaa2d2552ab3 100644 --- a/apps/meteor/.docker/Dockerfile.alpine +++ b/apps/meteor/.docker/Dockerfile.alpine @@ -1,7 +1,17 @@ +ARG DENO_VERSION="1.37.1" + +FROM denoland/deno:bin-${DENO_VERSION} as deno + FROM node:14.21.3-alpine3.16 +LABEL maintainer="buildmaster@rocket.chat" + ENV LANG=C.UTF-8 +## Alpine 3.16 does not have a deno package, but newer versions have it +## So as soon as we can update the Alpine version, we can replace the following +## GLIBC installation part by an `apk add deno` + # Installing glibc deps required by Deno # This replaces libc6-compat # Copied from https://github.com/Docker-Hub-frolvlad/docker-alpine-glibc, which denoland/deno:alpine-1.37.1 uses @@ -11,7 +21,7 @@ RUN ALPINE_GLIBC_BASE_URL="https://github.com/sgerrand/alpine-pkg-glibc/releases ALPINE_GLIBC_BASE_PACKAGE_FILENAME="glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \ ALPINE_GLIBC_BIN_PACKAGE_FILENAME="glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \ ALPINE_GLIBC_I18N_PACKAGE_FILENAME="glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \ - apk add --no-cache --virtual=.build-dependencies wget ca-certificates && \ + apk add --no-cache --virtual=.build-dependencies wget ca-certificates ttf-dejavu && \ echo \ "-----BEGIN PUBLIC KEY-----\ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApZ2u1KJKUu/fW4A25y9m\ @@ -44,12 +54,11 @@ RUN ALPINE_GLIBC_BASE_URL="https://github.com/sgerrand/alpine-pkg-glibc/releases rm \ "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \ "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \ - "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \ - apk add --no-cache ttf-dejavu + "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" -ADD . /app +COPY --from=deno /deno /bin/deno -LABEL maintainer="buildmaster@rocket.chat" +ADD . /app # needs a mongo instance - defaults to container linking with alias 'mongo' ENV DEPLOY_METHOD=docker \ @@ -58,13 +67,12 @@ ENV DEPLOY_METHOD=docker \ HOME=/tmp \ PORT=3000 \ ROOT_URL=http://localhost:3000 \ - Accounts_AvatarStorePath=/app/uploads \ - DENO_DIR=/usr/share/deno + Accounts_AvatarStorePath=/app/uploads RUN set -x \ && apk add --no-cache --virtual .fetch-deps python3 make g++ \ && cd /app/bundle/programs/server \ - && npm install --production \ + && npm install --omit=dev --unsafe-perm \ # Start hack for sharp... && rm -rf npm/node_modules/sharp \ && npm install sharp@0.32.6 \ @@ -75,9 +83,6 @@ RUN set -x \ && npm install isolated-vm@4.4.2 \ && mv node_modules/isolated-vm npm/node_modules/isolated-vm \ # End hack for isolated-vm - # Cache Deno dependencies for Apps-Engine - && cd npm/node_modules/@rocket.chat/apps-engine/deno-runtime \ - && /app/bundle/programs/server/npm/node_modules/deno-bin/bin/deno cache main.ts \ && cd /app/bundle/programs/server/npm \ && npm rebuild bcrypt --build-from-source \ && npm cache clear --force \ diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 390b2c646cd1..9eb2e917819d 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -18,7 +18,7 @@ "author": "Rocket.Chat", "license": "MIT", "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "workspace:^", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 3767939a7e3c..b5c9003b6974 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -230,7 +230,7 @@ "@rocket.chat/agenda": "workspace:^", "@rocket.chat/api-client": "workspace:^", "@rocket.chat/apps": "workspace:^", - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "workspace:^", "@rocket.chat/base64": "workspace:^", "@rocket.chat/cas-validate": "workspace:^", "@rocket.chat/core-services": "workspace:^", diff --git a/docker-compose-ci.yml b/docker-compose-ci.yml index 23ee3b125524..0fe101c8fab1 100644 --- a/docker-compose-ci.yml +++ b/docker-compose-ci.yml @@ -8,6 +8,8 @@ services: build: dockerfile: ${RC_DOCKERFILE} context: /tmp/build + args: + DENO_VERSION: ${DENO_VERSION} image: ghcr.io/${LOWERCASE_REPOSITORY}/rocket.chat:${RC_DOCKER_TAG} environment: - TEST_MODE=true @@ -39,6 +41,7 @@ services: context: . args: SERVICE: authorization-service + DENO_VERSION: ${DENO_VERSION} image: ghcr.io/${LOWERCASE_REPOSITORY}/authorization-service:${DOCKER_TAG} environment: - 'MONGO_URL=${MONGO_URL}' @@ -73,6 +76,7 @@ services: context: . args: SERVICE: presence-service + DENO_VERSION: ${DENO_VERSION} image: ghcr.io/${LOWERCASE_REPOSITORY}/presence-service:${DOCKER_TAG} environment: - MONGO_URL=${MONGO_URL} diff --git a/ee/apps/account-service/Dockerfile b/ee/apps/account-service/Dockerfile index c80d4f2eb376..a97290a43394 100644 --- a/ee/apps/account-service/Dockerfile +++ b/ee/apps/account-service/Dockerfile @@ -7,6 +7,10 @@ WORKDIR /app COPY ./packages/core-services/package.json packages/core-services/package.json COPY ./packages/core-services/dist packages/core-services/dist +COPY ./packages/apps-engine/package.json packages/apps-engine/package.json +COPY ./packages/apps-engine/client packages/apps-engine/client +COPY ./packages/apps-engine/definition packages/apps-engine/definition + COPY ./packages/agenda/package.json packages/agenda/package.json COPY ./packages/agenda/dist packages/agenda/dist diff --git a/ee/apps/authorization-service/Dockerfile b/ee/apps/authorization-service/Dockerfile index 9a9e8ded922c..9ddeadd380fe 100644 --- a/ee/apps/authorization-service/Dockerfile +++ b/ee/apps/authorization-service/Dockerfile @@ -7,6 +7,10 @@ WORKDIR /app COPY ./packages/core-services/package.json packages/core-services/package.json COPY ./packages/core-services/dist packages/core-services/dist +COPY ./packages/apps-engine/package.json packages/apps-engine/package.json +COPY ./packages/apps-engine/client packages/apps-engine/client +COPY ./packages/apps-engine/definition packages/apps-engine/definition + COPY ./packages/agenda/package.json packages/agenda/package.json COPY ./packages/agenda/dist packages/agenda/dist diff --git a/ee/apps/ddp-streamer/Dockerfile b/ee/apps/ddp-streamer/Dockerfile index 32103dc3528b..dea2bc3790a1 100644 --- a/ee/apps/ddp-streamer/Dockerfile +++ b/ee/apps/ddp-streamer/Dockerfile @@ -7,6 +7,10 @@ WORKDIR /app COPY ./packages/core-services/package.json packages/core-services/package.json COPY ./packages/core-services/dist packages/core-services/dist +COPY ./packages/apps-engine/package.json packages/apps-engine/package.json +COPY ./packages/apps-engine/client packages/apps-engine/client +COPY ./packages/apps-engine/definition packages/apps-engine/definition + COPY ./packages/agenda/package.json packages/agenda/package.json COPY ./packages/agenda/dist packages/agenda/dist diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 36c244f41180..f250b9e33106 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -15,7 +15,6 @@ ], "author": "Rocket.Chat", "dependencies": { - "@rocket.chat/apps-engine": "1.45.0-alpha.868", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", @@ -45,6 +44,7 @@ "ws": "^8.8.1" }, "devDependencies": { + "@rocket.chat/apps-engine": "workspace:^", "@rocket.chat/ddp-client": "workspace:~", "@rocket.chat/eslint-config": "workspace:^", "@types/ejson": "^2.2.2", diff --git a/ee/apps/omnichannel-transcript/Dockerfile b/ee/apps/omnichannel-transcript/Dockerfile index 9b7e47968e68..0f18534e1453 100644 --- a/ee/apps/omnichannel-transcript/Dockerfile +++ b/ee/apps/omnichannel-transcript/Dockerfile @@ -7,6 +7,10 @@ WORKDIR /app COPY ./packages/core-services/package.json packages/core-services/package.json COPY ./packages/core-services/dist packages/core-services/dist +COPY ./packages/apps-engine/package.json packages/apps-engine/package.json +COPY ./packages/apps-engine/client packages/apps-engine/client +COPY ./packages/apps-engine/definition packages/apps-engine/definition + COPY ./packages/agenda/package.json packages/agenda/package.json COPY ./packages/agenda/dist packages/agenda/dist diff --git a/ee/apps/presence-service/Dockerfile b/ee/apps/presence-service/Dockerfile index 430880d29606..78c6a98f809a 100644 --- a/ee/apps/presence-service/Dockerfile +++ b/ee/apps/presence-service/Dockerfile @@ -13,6 +13,10 @@ COPY ./packages/agenda/dist packages/agenda/dist COPY ./packages/core-services/package.json packages/core-services/package.json COPY ./packages/core-services/dist packages/core-services/dist +COPY ./packages/apps-engine/package.json packages/apps-engine/package.json +COPY ./packages/apps-engine/client packages/apps-engine/client +COPY ./packages/apps-engine/definition packages/apps-engine/definition + COPY ./packages/core-typings/package.json packages/core-typings/package.json COPY ./packages/core-typings/dist packages/core-typings/dist diff --git a/ee/apps/queue-worker/Dockerfile b/ee/apps/queue-worker/Dockerfile index 9b7e47968e68..0f18534e1453 100644 --- a/ee/apps/queue-worker/Dockerfile +++ b/ee/apps/queue-worker/Dockerfile @@ -7,6 +7,10 @@ WORKDIR /app COPY ./packages/core-services/package.json packages/core-services/package.json COPY ./packages/core-services/dist packages/core-services/dist +COPY ./packages/apps-engine/package.json packages/apps-engine/package.json +COPY ./packages/apps-engine/client packages/apps-engine/client +COPY ./packages/apps-engine/definition packages/apps-engine/definition + COPY ./packages/agenda/package.json packages/agenda/package.json COPY ./packages/agenda/dist packages/agenda/dist diff --git a/ee/apps/stream-hub-service/Dockerfile b/ee/apps/stream-hub-service/Dockerfile index 9a9e8ded922c..9ddeadd380fe 100644 --- a/ee/apps/stream-hub-service/Dockerfile +++ b/ee/apps/stream-hub-service/Dockerfile @@ -7,6 +7,10 @@ WORKDIR /app COPY ./packages/core-services/package.json packages/core-services/package.json COPY ./packages/core-services/dist packages/core-services/dist +COPY ./packages/apps-engine/package.json packages/apps-engine/package.json +COPY ./packages/apps-engine/client packages/apps-engine/client +COPY ./packages/apps-engine/definition packages/apps-engine/definition + COPY ./packages/agenda/package.json packages/agenda/package.json COPY ./packages/agenda/dist packages/agenda/dist diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 912b4bf453fd..06bbc244fd48 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@babel/preset-env": "~7.22.20", "@babel/preset-typescript": "~7.22.15", - "@rocket.chat/apps-engine": "1.45.0-alpha.868", + "@rocket.chat/apps-engine": "workspace:^", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@types/node": "^14.18.63", diff --git a/packages/apps-engine/.eslintignore b/packages/apps-engine/.eslintignore new file mode 100644 index 000000000000..f7e4e0b38e59 --- /dev/null +++ b/packages/apps-engine/.eslintignore @@ -0,0 +1,8 @@ +!/gulpfile.js +/client +/definition +/docs +/server +/lib +/deno-runtime +/.deno diff --git a/packages/apps-engine/.eslintrc.json b/packages/apps-engine/.eslintrc.json new file mode 100644 index 000000000000..8e42d7cfa9f6 --- /dev/null +++ b/packages/apps-engine/.eslintrc.json @@ -0,0 +1,58 @@ +{ + "extends": "@rocket.chat/eslint-config", + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig-lint.json" + }, + "rules": { + "@typescript-eslint/ban-types": [ + "error", + { + "types": { + "{}": false + } + } + ], + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": ["function", "parameter", "variable"], + "modifiers": ["destructured"], + "format": null + }, + { + "selector": ["variable"], + "format": ["camelCase", "UPPER_CASE", "PascalCase"], + "leadingUnderscore": "allowSingleOrDouble" + }, + { + "selector": ["function"], + "format": ["camelCase", "PascalCase"], + "leadingUnderscore": "allowSingleOrDouble" + }, + { + "selector": ["parameter"], + "format": ["camelCase"], + "leadingUnderscore": "allow" + }, + { + "selector": ["parameter"], + "format": ["camelCase"], + "modifiers": ["unused"], + "leadingUnderscore": "allow" + }, + { + "selector": ["interface"], + "format": ["PascalCase"], + "custom": { + "regex": "^I[A-Z]", + "match": true + } + } + ], + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], + "new-cap": "off", + "no-await-in-loop": "off" + } +} diff --git a/packages/apps-engine/.gitignore b/packages/apps-engine/.gitignore new file mode 100644 index 000000000000..c4568f9c7430 --- /dev/null +++ b/packages/apps-engine/.gitignore @@ -0,0 +1,61 @@ +# Created by https://www.gitignore.io/api/node + +### Node ### +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Optional npm cache directory +.npm + +.deno +.deno-cache + +# Optional REPL history +.node_repl_history + +### Typings ### +## Ignore downloaded typings +/typings + +## dev environment stuff +/examples/ +/dev-dist/ +/data/ +/tests/test-data/dbs +/client +/definition +/server +/lib + +.DS_Store +.idea/ diff --git a/packages/apps-engine/.prettierrc b/packages/apps-engine/.prettierrc new file mode 100644 index 000000000000..9b77117b35c0 --- /dev/null +++ b/packages/apps-engine/.prettierrc @@ -0,0 +1,7 @@ +{ + "tabWidth": 4, + "useTabs": false, + "singleQuote": true, + "trailingComma": "all", + "printWidth": 160 +} diff --git a/packages/apps-engine/README.md b/packages/apps-engine/README.md new file mode 100644 index 000000000000..d73e09f1aed7 --- /dev/null +++ b/packages/apps-engine/README.md @@ -0,0 +1,125 @@ +## Thoughts While Working (for docs) +- Apps which don't provide a valid uuid4 id will be assigned one, but this is not recommended and your App should provide an id +- The language strings are only done on the clients (`TAPi18next.addResourceBundle(lang, projectName, translations);`) +- The implementer of this should restrict the server setting access and environmental variables. Idea is to allow the implementer to have a default set of restricted ones while letting the admin/owner of the server to restrict it even further or lift the restriction on some more. Simple interface with settings and checkbox to allow/disallow them. :thinking: + +## What does the Apps-Engine enable you to do? +The Apps-Engine is Rocket.Chat's _plugin framework_ - it provides the APIs for Rocket.Chat Apps to interact with the host system. + +Currently, a Rocket.Chat App can: +- Listen to message events + - before/after sent + - before/after updated + - before/after deleted +- Listen to room events + - before/after created + - before/after deleted +- Send messages to users and livechat visitors +- Register new slash commands +- Register new HTTP endpoints + +Some features the Engine allows Apps to use: +- Key-Value Storage system +- App specific settings + +## Development environment with Rocket.Chat +When developing new functionalities, you need to integrate the local version of the Apps-Engine with your local version of Rocket.Chat. + +First of all, make sure you've installed all required packages and compiled the changes you've made to the Apps-Engine, since that is what Rocket.Chat will execute: +```sh +npm install +npm run compile +``` + +Now, you need to setup a local Rocket.Chat server, [so head to the project's README for instructions on getting started](https://github.com/RocketChat/Rocket.Chat#development) (if you haven't already). Make sure to actually clone the repo, since you will probably need to add some code to it in order to make your new functionality work. + +After that, `cd` into Rocket.Chat folder and run: +```sh +meteor npm install PATH_TO_APPS_ENGINE +``` + +Where `PATH_TO_APPS_ENGINE` is the path to the Apps-Engine repo you've cloned. + +That's it! Now when you start Rocket.Chat with the `meteor` command, it will use your local Apps-Engine instead of the one on NPM :) + +Whenever you make changes to the engine, run `npm run compile` again - meteor will take care of restarting the server due to the changes. + +## Troubleshooting +1. Sometimes, when you update the Apps-Engine code and compile it while Rocket.Chat is running, you might run on errors similar to these: + +``` +Unable to resolve some modules: + + "@rocket.chat/apps-engine/definition/AppStatus" in +/Users/dev/rocket.chat/Rocket.Chat/app/apps/client/admin/helpers.js (web.browser) + +If you notice problems related to these missing modules, consider running: + + meteor npm install --save @rocket.chat/apps-engine +``` + +Simply restart the meteor process and it should be fixed. + +2. Sometimes when using `meteor npm install PATH_TO_APPS_ENGINE` will cause the following error :- + +``` +npm ERR! code ENOENT +npm ERR! syscall rename +npm ERR! path PATH_TO_ROCKETCHAT/node_modules/.staging/@rocket.chat/apps-engine-c7135600/node_modules/@babel/code-frame +npm ERR! dest PATH_TO_ROCKETCHAT/node_modules/.staging/@babel/code-frame-f3697825 +npm ERR! errno -2 +npm ERR! enoent ENOENT: no such file or directory, rename 'PATH_TO_ROCKETCHAT/node_modules/.staging/@rocket.chat/apps-engine-c7135600/node_modules/@babel/code-frame' -> 'PATH_TO_ROCKETCHAT/node_modules/.staging/@babel/code-frame-f3697825' +npm ERR! enoent This is related to npm not being able to find a file. +npm ERR! enoent +``` +Here `PATH_TO_ROCKETCHAT` is the path to the main rocketchat server repo in your system +To correct this we reinstall the package once again deleting the previous package +``` +~/Rocket.Chat$ rm -rf node_modules/@rocket.chat/apps-engine +~/Rocket.Chat$ cd PATH_TO_APP_ENGINE +~/Rocket.Chat.Apps-engine$ npm install +~/Rocket.Chat.Apps-engine$ cd PATH_TO_ROCKETCHAT +~/Rocket.Chat$ meteor npm install ../Rocket.Chat.Apps-engine +``` + +## Implementer Needs to Implement: +- `src/server/storage/AppStorage` +- `src/server/storage/AppLogStorage` +- `src/server/bridges/*` + +## Testing Framework: +Makes great usage of TypeScript and decorators: https://github.com/alsatian-test/alsatian/wiki +* To run the tests do: `npm run unit-tests` +* To generate the coverage information: `npm run check-coverage` +* To view the coverage: `npm run view-coverage` + +# Rocket.Chat Apps TypeScript Definitions + +## Handlers +Handlers are essentially "listeners" for different events, except there are various ways to handle an event. +When something happens there is `pre` and `post` handlers. +The set of `pre` handlers happens before the event is finalized. +The set of `post` handlers happens after the event is finalized. +With that said, the rule of thumb is that if you are going to modify, extend, or change the data backing the event then that should be done in the `pre` handlers. If you are simply wanting to listen for when something happens and not modify anything, then the `post` is the way to go. + +The order in which they happen is: +* Pre**Event**Prevent +* Pre**Event**Extend +* Pre**Event**Modify +* Post**Event** + +Here is an explanation of what each of them means: +* **Prevent**: This is ran to determine whether the event should be prevented or not. +* **Extend**: This is ran to allow extending the data without being destructive of the data (adding an attachment to a message for example). +* **Modify**: This is ran and allows for destructive changes to the data (change any and everything). +* Post**Event**: Is mostly for simple listening and no changes can be made to the data. + +## Generating/Updating Documentation +To update or generate the documentation, please commit your changes first and then in a second commit provide the updated documentation. + +# Engage with us +## Share your story +We’d love to hear about [your experience](https://survey.zohopublic.com/zs/e4BUFG) and potentially feature it on our [Blog](https://rocket.chat/case-studies/?utm_source=github&utm_medium=readme&utm_campaign=community). + +## Subscribe for Updates +Once a month our marketing team releases an email update with news about product releases, company related topics, events and use cases. [Sign Up!](https://rocket.chat/newsletter/?utm_source=github&utm_medium=readme&utm_campaign=community) diff --git a/packages/apps-engine/deno-runtime/.gitignore b/packages/apps-engine/deno-runtime/.gitignore new file mode 100644 index 000000000000..5942ea3a153e --- /dev/null +++ b/packages/apps-engine/deno-runtime/.gitignore @@ -0,0 +1 @@ +.deno/ diff --git a/packages/apps-engine/deno-runtime/AppObjectRegistry.ts b/packages/apps-engine/deno-runtime/AppObjectRegistry.ts new file mode 100644 index 000000000000..9069c17eaac5 --- /dev/null +++ b/packages/apps-engine/deno-runtime/AppObjectRegistry.ts @@ -0,0 +1,26 @@ +export type Maybe = T | null | undefined; + +export const AppObjectRegistry = new class { + registry: Record = {}; + + public get(key: string): Maybe { + return this.registry[key] as Maybe; + } + + public set(key: string, value: unknown): void { + this.registry[key] = value; + } + + public has(key: string): boolean { + return key in this.registry; + } + + public delete(key: string): void { + delete this.registry[key]; + } + + public clear(): void { + this.registry = {}; + } +} + diff --git a/packages/apps-engine/deno-runtime/acorn-walk.d.ts b/packages/apps-engine/deno-runtime/acorn-walk.d.ts new file mode 100644 index 000000000000..25861f3bce0f --- /dev/null +++ b/packages/apps-engine/deno-runtime/acorn-walk.d.ts @@ -0,0 +1,170 @@ +import type acorn from "./acorn.d.ts"; + +export type FullWalkerCallback = ( + node: acorn.AnyNode, + state: TState, + type: string +) => void + +export type FullAncestorWalkerCallback = ( + node: acorn.AnyNode, + state: TState, + ancestors: acorn.AnyNode[], + type: string +) => void + +type AggregateType = { + Expression: acorn.Expression, + Statement: acorn.Statement, + Pattern: acorn.Pattern, + ForInit: acorn.VariableDeclaration | acorn.Expression +} + +export type SimpleVisitors = { + [type in acorn.AnyNode["type"]]?: (node: Extract, state: TState) => void +} & { + [type in keyof AggregateType]?: (node: AggregateType[type], state: TState) => void +} + +export type AncestorVisitors = { + [type in acorn.AnyNode["type"]]?: ( node: Extract, state: TState, ancestors: acorn.Node[] +) => void +} & { + [type in keyof AggregateType]?: (node: AggregateType[type], state: TState, ancestors: acorn.Node[]) => void +} + +export type WalkerCallback = (node: acorn.Node, state: TState) => void + +export type RecursiveVisitors = { + [type in acorn.AnyNode["type"]]?: ( node: Extract, state: TState, callback: WalkerCallback) => void +} & { + [type in keyof AggregateType]?: (node: AggregateType[type], state: TState, callback: WalkerCallback) => void +} + +export type FindPredicate = (type: string, node: acorn.Node) => boolean + +export interface Found { + node: acorn.Node, + state: TState +} + +/** + * does a 'simple' walk over a tree + * @param node the AST node to walk + * @param visitors an object with properties whose names correspond to node types in the {@link https://github.com/estree/estree | ESTree spec}. The properties should contain functions that will be called with the node object and, if applicable the state at that point. + * @param base a walker algorithm + * @param state a start state. The default walker will simply visit all statements and expressions and not produce a meaningful state. (An example of a use of state is to track scope at each point in the tree.) + */ +export function simple( + node: acorn.Node, + visitors: SimpleVisitors, + base?: RecursiveVisitors, + state?: TState +): void + +/** + * does a 'simple' walk over a tree, building up an array of ancestor nodes (including the current node) and passing the array to the callbacks as a third parameter. + * @param node + * @param visitors + * @param base + * @param state + */ +export function ancestor( + node: acorn.Node, + visitors: AncestorVisitors, + base?: RecursiveVisitors, + state?: TState + ): void + +/** + * does a 'recursive' walk, where the walker functions are responsible for continuing the walk on the child nodes of their target node. + * @param node + * @param state the start state + * @param functions contain an object that maps node types to walker functions + * @param base provides the fallback walker functions for node types that aren't handled in the {@link functions} object. If not given, the default walkers will be used. + */ +export function recursive( + node: acorn.Node, + state: TState, + functions: RecursiveVisitors, + base?: RecursiveVisitors +): void + +/** + * does a 'full' walk over a tree, calling the {@link callback} with the arguments (node, state, type) for each node + * @param node + * @param callback + * @param base + * @param state + */ +export function full( + node: acorn.Node, + callback: FullWalkerCallback, + base?: RecursiveVisitors, + state?: TState +): void + +/** + * does a 'full' walk over a tree, building up an array of ancestor nodes (including the current node) and passing the array to the callbacks as a third parameter. + * @param node + * @param callback + * @param base + * @param state + */ +export function fullAncestor( + node: acorn.AnyNode, + callback: FullAncestorWalkerCallback, + base?: RecursiveVisitors, + state?: TState +): void + +/** + * builds a new walker object by using the walker functions in {@link functions} and filling in the missing ones by taking defaults from {@link base}. + * @param functions + * @param base + */ +export function make( + functions: RecursiveVisitors, + base?: RecursiveVisitors +): RecursiveVisitors + +/** + * tries to locate a node in a tree at the given start and/or end offsets, which satisfies the predicate test. {@link start} and {@link end} can be either `null` (as wildcard) or a `number`. {@link test} may be a string (indicating a node type) or a function that takes (nodeType, node) arguments and returns a boolean indicating whether this node is interesting. {@link base} and {@link state} are optional, and can be used to specify a custom walker. Nodes are tested from inner to outer, so if two nodes match the boundaries, the inner one will be preferred. + * @param node + * @param start + * @param end + * @param type + * @param base + * @param state + */ +export function findNodeAt( + node: acorn.AnyNode, + start: number | undefined, + end?: number | undefined, + type?: FindPredicate | string, + base?: RecursiveVisitors, + state?: TState +): Found | undefined + +/** + * like {@link findNodeAt}, but will match any node that exists 'around' (spanning) the given position. + * @param node + * @param start + * @param type + * @param base + * @param state + */ +export function findNodeAround( + node: acorn.AnyNode, + start: number | undefined, + type?: FindPredicate | string, + base?: RecursiveVisitors, + state?: TState +): Found | undefined + +/** + * similar to {@link findNodeAround}, but will match all nodes after the given position (testing outer nodes before inner nodes). + */ +export const findNodeAfter: typeof findNodeAround + +export const base: RecursiveVisitors diff --git a/packages/apps-engine/deno-runtime/acorn.d.ts b/packages/apps-engine/deno-runtime/acorn.d.ts new file mode 100644 index 000000000000..0b5bc6b407b2 --- /dev/null +++ b/packages/apps-engine/deno-runtime/acorn.d.ts @@ -0,0 +1,857 @@ +export interface Node { + start?: number + end?: number + type: string + range?: [number, number] + loc?: SourceLocation | null +} + +export interface SourceLocation { + source?: string | null + start: Position + end: Position +} + +export interface Position { + /** 1-based */ + line: number + /** 0-based */ + column: number +} + +export interface Identifier extends Node { + type: "Identifier" + name: string +} + +export interface Literal extends Node { + type: "Literal" + value?: string | boolean | null | number | RegExp | bigint + raw?: string + regex?: { + pattern: string + flags: string + } + bigint?: string +} + +export interface Program extends Node { + type: "Program" + body: Array + sourceType: "script" | "module" +} + +export interface Function extends Node { + id?: Identifier | null + params: Array + body: BlockStatement | Expression + generator: boolean + expression: boolean + async: boolean +} + +export interface ExpressionStatement extends Node { + type: "ExpressionStatement" + expression: Expression | Literal + directive?: string +} + +export interface BlockStatement extends Node { + type: "BlockStatement" + body: Array +} + +export interface EmptyStatement extends Node { + type: "EmptyStatement" +} + +export interface DebuggerStatement extends Node { + type: "DebuggerStatement" +} + +export interface WithStatement extends Node { + type: "WithStatement" + object: Expression + body: Statement +} + +export interface ReturnStatement extends Node { + type: "ReturnStatement" + argument?: Expression | null +} + +export interface LabeledStatement extends Node { + type: "LabeledStatement" + label: Identifier + body: Statement +} + +export interface BreakStatement extends Node { + type: "BreakStatement" + label?: Identifier | null +} + +export interface ContinueStatement extends Node { + type: "ContinueStatement" + label?: Identifier | null +} + +export interface IfStatement extends Node { + type: "IfStatement" + test: Expression + consequent: Statement + alternate?: Statement | null +} + +export interface SwitchStatement extends Node { + type: "SwitchStatement" + discriminant: Expression + cases: Array +} + +export interface SwitchCase extends Node { + type: "SwitchCase" + test?: Expression | null + consequent: Array +} + +export interface ThrowStatement extends Node { + type: "ThrowStatement" + argument: Expression +} + +export interface TryStatement extends Node { + type: "TryStatement" + block: BlockStatement + handler?: CatchClause | null + finalizer?: BlockStatement | null +} + +export interface CatchClause extends Node { + type: "CatchClause" + param?: Pattern | null + body: BlockStatement +} + +export interface WhileStatement extends Node { + type: "WhileStatement" + test: Expression + body: Statement +} + +export interface DoWhileStatement extends Node { + type: "DoWhileStatement" + body: Statement + test: Expression +} + +export interface ForStatement extends Node { + type: "ForStatement" + init?: VariableDeclaration | Expression | null + test?: Expression | null + update?: Expression | null + body: Statement +} + +export interface ForInStatement extends Node { + type: "ForInStatement" + left: VariableDeclaration | Pattern + right: Expression + body: Statement +} + +export interface FunctionDeclaration extends Function { + type: "FunctionDeclaration" + id: Identifier + body: BlockStatement +} + +export interface VariableDeclaration extends Node { + type: "VariableDeclaration" + declarations: Array + kind: "var" | "let" | "const" +} + +export interface VariableDeclarator extends Node { + type: "VariableDeclarator" + id: Pattern + init?: Expression | null +} + +export interface ThisExpression extends Node { + type: "ThisExpression" +} + +export interface ArrayExpression extends Node { + type: "ArrayExpression" + elements: Array +} + +export interface ObjectExpression extends Node { + type: "ObjectExpression" + properties: Array +} + +export interface Property extends Node { + type: "Property" + key: Expression + value: Expression + kind: "init" | "get" | "set" + method: boolean + shorthand: boolean + computed: boolean +} + +export interface FunctionExpression extends Function { + type: "FunctionExpression" + body: BlockStatement +} + +export interface UnaryExpression extends Node { + type: "UnaryExpression" + operator: UnaryOperator + prefix: boolean + argument: Expression +} + +export type UnaryOperator = "-" | "+" | "!" | "~" | "typeof" | "void" | "delete" + +export interface UpdateExpression extends Node { + type: "UpdateExpression" + operator: UpdateOperator + argument: Expression + prefix: boolean +} + +export type UpdateOperator = "++" | "--" + +export interface BinaryExpression extends Node { + type: "BinaryExpression" + operator: BinaryOperator + left: Expression | PrivateIdentifier + right: Expression +} + +export type BinaryOperator = "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "|" | "^" | "&" | "in" | "instanceof" | "**" + +export interface AssignmentExpression extends Node { + type: "AssignmentExpression" + operator: AssignmentOperator + left: Pattern + right: Expression +} + +export type AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=" | "**=" | "||=" | "&&=" | "??=" + +export interface LogicalExpression extends Node { + type: "LogicalExpression" + operator: LogicalOperator + left: Expression + right: Expression +} + +export type LogicalOperator = "||" | "&&" | "??" + +export interface MemberExpression extends Node { + type: "MemberExpression" + object: Expression | Super + property: Expression | PrivateIdentifier + computed: boolean + optional: boolean +} + +export interface ConditionalExpression extends Node { + type: "ConditionalExpression" + test: Expression + alternate: Expression + consequent: Expression +} + +export interface CallExpression extends Node { + type: "CallExpression" + callee: Expression | Super + arguments: Array + optional: boolean +} + +export interface NewExpression extends Node { + type: "NewExpression" + callee: Expression + arguments: Array +} + +export interface SequenceExpression extends Node { + type: "SequenceExpression" + expressions: Array +} + +export interface ForOfStatement extends Node { + type: "ForOfStatement" + left: VariableDeclaration | Pattern + right: Expression + body: Statement + await: boolean +} + +export interface Super extends Node { + type: "Super" +} + +export interface SpreadElement extends Node { + type: "SpreadElement" + argument: Expression +} + +export interface ArrowFunctionExpression extends Function { + type: "ArrowFunctionExpression" +} + +export interface YieldExpression extends Node { + type: "YieldExpression" + argument?: Expression | null + delegate: boolean +} + +export interface TemplateLiteral extends Node { + type: "TemplateLiteral" + quasis: Array + expressions: Array +} + +export interface TaggedTemplateExpression extends Node { + type: "TaggedTemplateExpression" + tag: Expression + quasi: TemplateLiteral +} + +export interface TemplateElement extends Node { + type: "TemplateElement" + tail: boolean + value: { + cooked?: string | null + raw: string + } +} + +export interface AssignmentProperty extends Node { + type: "Property" + key: Expression + value: Pattern + kind: "init" + method: false + shorthand: boolean + computed: boolean +} + +export interface ObjectPattern extends Node { + type: "ObjectPattern" + properties: Array +} + +export interface ArrayPattern extends Node { + type: "ArrayPattern" + elements: Array +} + +export interface RestElement extends Node { + type: "RestElement" + argument: Pattern +} + +export interface AssignmentPattern extends Node { + type: "AssignmentPattern" + left: Pattern + right: Expression +} + +export interface Class extends Node { + id?: Identifier | null + superClass?: Expression | null + body: ClassBody +} + +export interface ClassBody extends Node { + type: "ClassBody" + body: Array +} + +export interface MethodDefinition extends Node { + type: "MethodDefinition" + key: Expression | PrivateIdentifier + value: FunctionExpression + kind: "constructor" | "method" | "get" | "set" + computed: boolean + static: boolean +} + +export interface ClassDeclaration extends Class { + type: "ClassDeclaration" + id: Identifier +} + +export interface ClassExpression extends Class { + type: "ClassExpression" +} + +export interface MetaProperty extends Node { + type: "MetaProperty" + meta: Identifier + property: Identifier +} + +export interface ImportDeclaration extends Node { + type: "ImportDeclaration" + specifiers: Array + source: Literal +} + +export interface ImportSpecifier extends Node { + type: "ImportSpecifier" + imported: Identifier | Literal + local: Identifier +} + +export interface ImportDefaultSpecifier extends Node { + type: "ImportDefaultSpecifier" + local: Identifier +} + +export interface ImportNamespaceSpecifier extends Node { + type: "ImportNamespaceSpecifier" + local: Identifier +} + +export interface ExportNamedDeclaration extends Node { + type: "ExportNamedDeclaration" + declaration?: Declaration | null + specifiers: Array + source?: Literal | null +} + +export interface ExportSpecifier extends Node { + type: "ExportSpecifier" + exported: Identifier | Literal + local: Identifier | Literal +} + +export interface AnonymousFunctionDeclaration extends Function { + type: "FunctionDeclaration" + id: null + body: BlockStatement +} + +export interface AnonymousClassDeclaration extends Class { + type: "ClassDeclaration" + id: null +} + +export interface ExportDefaultDeclaration extends Node { + type: "ExportDefaultDeclaration" + declaration: AnonymousFunctionDeclaration | FunctionDeclaration | AnonymousClassDeclaration | ClassDeclaration | Expression +} + +export interface ExportAllDeclaration extends Node { + type: "ExportAllDeclaration" + source: Literal + exported?: Identifier | Literal | null +} + +export interface AwaitExpression extends Node { + type: "AwaitExpression" + argument: Expression +} + +export interface ChainExpression extends Node { + type: "ChainExpression" + expression: MemberExpression | CallExpression +} + +export interface ImportExpression extends Node { + type: "ImportExpression" + source: Expression +} + +export interface ParenthesizedExpression extends Node { + type: "ParenthesizedExpression" + expression: Expression +} + +export interface PropertyDefinition extends Node { + type: "PropertyDefinition" + key: Expression | PrivateIdentifier + value?: Expression | null + computed: boolean + static: boolean +} + +export interface PrivateIdentifier extends Node { + type: "PrivateIdentifier" + name: string +} + +export interface StaticBlock extends Node { + type: "StaticBlock" + body: Array +} + +export type Statement = +| ExpressionStatement +| BlockStatement +| EmptyStatement +| DebuggerStatement +| WithStatement +| ReturnStatement +| LabeledStatement +| BreakStatement +| ContinueStatement +| IfStatement +| SwitchStatement +| ThrowStatement +| TryStatement +| WhileStatement +| DoWhileStatement +| ForStatement +| ForInStatement +| ForOfStatement +| Declaration + +export type Declaration = +| FunctionDeclaration +| VariableDeclaration +| ClassDeclaration + +export type Expression = +| Identifier +| Literal +| ThisExpression +| ArrayExpression +| ObjectExpression +| FunctionExpression +| UnaryExpression +| UpdateExpression +| BinaryExpression +| AssignmentExpression +| LogicalExpression +| MemberExpression +| ConditionalExpression +| CallExpression +| NewExpression +| SequenceExpression +| ArrowFunctionExpression +| YieldExpression +| TemplateLiteral +| TaggedTemplateExpression +| ClassExpression +| MetaProperty +| AwaitExpression +| ChainExpression +| ImportExpression +| ParenthesizedExpression + +export type Pattern = +| Identifier +| MemberExpression +| ObjectPattern +| ArrayPattern +| RestElement +| AssignmentPattern + +export type ModuleDeclaration = +| ImportDeclaration +| ExportNamedDeclaration +| ExportDefaultDeclaration +| ExportAllDeclaration + +export type AnyNode = Statement | Expression | Declaration | ModuleDeclaration | Literal | Program | SwitchCase | CatchClause | Property | Super | SpreadElement | TemplateElement | AssignmentProperty | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | ClassBody | MethodDefinition | MetaProperty | ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ExportSpecifier | AnonymousFunctionDeclaration | AnonymousClassDeclaration | PropertyDefinition | PrivateIdentifier | StaticBlock | VariableDeclaration | VariableDeclarator + +export function parse(input: string, options: Options): Program + +export function parseExpressionAt(input: string, pos: number, options: Options): Expression + +export function tokenizer(input: string, options: Options): { + getToken(): Token + [Symbol.iterator](): Iterator +} + +export type ecmaVersion = 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | "latest" + +export interface Options { + /** + * `ecmaVersion` indicates the ECMAScript version to parse. Must be + * either 3, 5, 6 (or 2015), 7 (2016), 8 (2017), 9 (2018), 10 + * (2019), 11 (2020), 12 (2021), 13 (2022), 14 (2023), or `"latest"` + * (the latest version the library supports). This influences + * support for strict mode, the set of reserved words, and support + * for new syntax features. + */ + ecmaVersion: ecmaVersion + + /** + * `sourceType` indicates the mode the code should be parsed in. + * Can be either `"script"` or `"module"`. This influences global + * strict mode and parsing of `import` and `export` declarations. + */ + sourceType?: "script" | "module" + + /** + * a callback that will be called when a semicolon is automatically inserted. + * @param lastTokEnd the position of the comma as an offset + * @param lastTokEndLoc location if {@link locations} is enabled + */ + onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void + + /** + * similar to `onInsertedSemicolon`, but for trailing commas + * @param lastTokEnd the position of the comma as an offset + * @param lastTokEndLoc location if `locations` is enabled + */ + onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void + + /** + * By default, reserved words are only enforced if ecmaVersion >= 5. + * Set `allowReserved` to a boolean value to explicitly turn this on + * an off. When this option has the value "never", reserved words + * and keywords can also not be used as property names. + */ + allowReserved?: boolean | "never" + + /** + * When enabled, a return at the top level is not considered an error. + */ + allowReturnOutsideFunction?: boolean + + /** + * When enabled, import/export statements are not constrained to + * appearing at the top of the program, and an import.meta expression + * in a script isn't considered an error. + */ + allowImportExportEverywhere?: boolean + + /** + * By default, `await` identifiers are allowed to appear at the top-level scope only if {@link ecmaVersion} >= 2022. + * When enabled, await identifiers are allowed to appear at the top-level scope, + * but they are still not allowed in non-async functions. + */ + allowAwaitOutsideFunction?: boolean + + /** + * When enabled, super identifiers are not constrained to + * appearing in methods and do not raise an error when they appear elsewhere. + */ + allowSuperOutsideMethod?: boolean + + /** + * When enabled, hashbang directive in the beginning of file is + * allowed and treated as a line comment. Enabled by default when + * {@link ecmaVersion} >= 2023. + */ + allowHashBang?: boolean + + /** + * By default, the parser will verify that private properties are + * only used in places where they are valid and have been declared. + * Set this to false to turn such checks off. + */ + checkPrivateFields?: boolean + + /** + * When `locations` is on, `loc` properties holding objects with + * `start` and `end` properties as {@link Position} objects will be attached to the + * nodes. + */ + locations?: boolean + + /** + * a callback that will cause Acorn to call that export function with object in the same + * format as tokens returned from `tokenizer().getToken()`. Note + * that you are not allowed to call the parser from the + * callback—that will corrupt its internal state. + */ + onToken?: ((token: Token) => void) | Token[] + + + /** + * This takes a export function or an array. + * + * When a export function is passed, Acorn will call that export function with `(block, text, start, + * end)` parameters whenever a comment is skipped. `block` is a + * boolean indicating whether this is a block (`/* *\/`) comment, + * `text` is the content of the comment, and `start` and `end` are + * character offsets that denote the start and end of the comment. + * When the {@link locations} option is on, two more parameters are + * passed, the full locations of {@link Position} export type of the start and + * end of the comments. + * + * When a array is passed, each found comment of {@link Comment} export type is pushed to the array. + * + * Note that you are not allowed to call the + * parser from the callback—that will corrupt its internal state. + */ + onComment?: (( + isBlock: boolean, text: string, start: number, end: number, startLoc?: Position, + endLoc?: Position + ) => void) | Comment[] + + /** + * Nodes have their start and end characters offsets recorded in + * `start` and `end` properties (directly on the node, rather than + * the `loc` object, which holds line/column data. To also add a + * [semi-standardized][range] `range` property holding a `[start, + * end]` array with the same numbers, set the `ranges` option to + * `true`. + */ + ranges?: boolean + + /** + * It is possible to parse multiple files into a single AST by + * passing the tree produced by parsing the first file as + * `program` option in subsequent parses. This will add the + * toplevel forms of the parsed file to the `Program` (top) node + * of an existing parse tree. + */ + program?: Node + + /** + * When {@link locations} is on, you can pass this to record the source + * file in every node's `loc` object. + */ + sourceFile?: string + + /** + * This value, if given, is stored in every node, whether {@link locations} is on or off. + */ + directSourceFile?: string + + /** + * When enabled, parenthesized expressions are represented by + * (non-standard) ParenthesizedExpression nodes + */ + preserveParens?: boolean +} + +export class Parser { + options: Options + input: string + + constructor(options: Options, input: string, startPos?: number) + parse(): Program + + static parse(input: string, options: Options): Program + static parseExpressionAt(input: string, pos: number, options: Options): Expression + static tokenizer(input: string, options: Options): { + getToken(): Token + [Symbol.iterator](): Iterator + } + static extend(...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser +} + +export const defaultOptions: Options + +export function getLineInfo(input: string, offset: number): Position + +export class TokenType { + label: string + keyword: string | undefined +} + +export const tokTypes: { + num: TokenType + regexp: TokenType + string: TokenType + name: TokenType + privateId: TokenType + eof: TokenType + + bracketL: TokenType + bracketR: TokenType + braceL: TokenType + braceR: TokenType + parenL: TokenType + parenR: TokenType + comma: TokenType + semi: TokenType + colon: TokenType + dot: TokenType + question: TokenType + questionDot: TokenType + arrow: TokenType + template: TokenType + invalidTemplate: TokenType + ellipsis: TokenType + backQuote: TokenType + dollarBraceL: TokenType + + eq: TokenType + assign: TokenType + incDec: TokenType + prefix: TokenType + logicalOR: TokenType + logicalAND: TokenType + bitwiseOR: TokenType + bitwiseXOR: TokenType + bitwiseAND: TokenType + equality: TokenType + relational: TokenType + bitShift: TokenType + plusMin: TokenType + modulo: TokenType + star: TokenType + slash: TokenType + starstar: TokenType + coalesce: TokenType + + _break: TokenType + _case: TokenType + _catch: TokenType + _continue: TokenType + _debugger: TokenType + _default: TokenType + _do: TokenType + _else: TokenType + _finally: TokenType + _for: TokenType + _function: TokenType + _if: TokenType + _return: TokenType + _switch: TokenType + _throw: TokenType + _try: TokenType + _var: TokenType + _const: TokenType + _while: TokenType + _with: TokenType + _new: TokenType + _this: TokenType + _super: TokenType + _class: TokenType + _extends: TokenType + _export: TokenType + _import: TokenType + _null: TokenType + _true: TokenType + _false: TokenType + _in: TokenType + _instanceof: TokenType + _typeof: TokenType + _void: TokenType + _delete: TokenType +} + +export interface Comment { + type: "Line" | "Block" + value: string + start: number + end: number + loc?: SourceLocation + range?: [number, number] +} + +export class Token { + type: TokenType + start: number + end: number + loc?: SourceLocation + range?: [number, number] +} + +export const version: string diff --git a/packages/apps-engine/deno-runtime/deno.jsonc b/packages/apps-engine/deno-runtime/deno.jsonc new file mode 100644 index 000000000000..231d0924237a --- /dev/null +++ b/packages/apps-engine/deno-runtime/deno.jsonc @@ -0,0 +1,16 @@ +{ + "imports": { + "@rocket.chat/apps-engine/": "./../src/", + "@rocket.chat/ui-kit": "npm:@rocket.chat/ui-kit@^0.31.22", + "@msgpack/msgpack": "npm:@msgpack/msgpack@3.0.0-beta2", + "acorn": "npm:acorn@8.10.0", + "acorn-walk": "npm:acorn-walk@8.2.0", + "astring": "npm:astring@1.8.6", + "jsonrpc-lite": "npm:jsonrpc-lite@2.2.0", + "stack-trace": "npm:stack-trace@0.0.10", + "uuid": "npm:uuid@8.3.2" + }, + "tasks": { + "test": "deno test --no-check --allow-read=../../../" + } +} diff --git a/packages/apps-engine/deno-runtime/deno.lock b/packages/apps-engine/deno-runtime/deno.lock new file mode 100644 index 000000000000..86cebf98f63a --- /dev/null +++ b/packages/apps-engine/deno-runtime/deno.lock @@ -0,0 +1,107 @@ +{ + "version": "3", + "packages": { + "specifiers": { + "npm:@msgpack/msgpack@3.0.0-beta2": "npm:@msgpack/msgpack@3.0.0-beta2", + "npm:@rocket.chat/ui-kit@^0.31.22": "npm:@rocket.chat/ui-kit@0.31.25_@rocket.chat+icons@0.32.0", + "npm:acorn-walk@8.2.0": "npm:acorn-walk@8.2.0", + "npm:acorn@8.10.0": "npm:acorn@8.10.0", + "npm:astring@1.8.6": "npm:astring@1.8.6", + "npm:jsonrpc-lite@2.2.0": "npm:jsonrpc-lite@2.2.0", + "npm:stack-trace": "npm:stack-trace@0.0.10", + "npm:stack-trace@0.0.10": "npm:stack-trace@0.0.10", + "npm:uuid@8.3.2": "npm:uuid@8.3.2" + }, + "npm": { + "@msgpack/msgpack@3.0.0-beta2": { + "integrity": "sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==", + "dependencies": {} + }, + "@rocket.chat/icons@0.32.0": { + "integrity": "sha512-7yhhELKNLb9kUtXCvau0V+iMXraV2bOsxcPjc/ZtLR5VeeIDTeaflqRWGtLroX6f3bE+J1n5qB5zi8A4YXuH2g==", + "dependencies": {} + }, + "@rocket.chat/ui-kit@0.31.25_@rocket.chat+icons@0.32.0": { + "integrity": "sha512-yTgTKDw9SMlJ6p8n0PDO6zSvox/nHYUrwCIvILQeAK6PvTrgSe/u9CvU7ATTYjnQiQ603yEGR6dxjF4euCGdNA==", + "dependencies": { + "@rocket.chat/icons": "@rocket.chat/icons@0.32.0" + } + }, + "acorn-walk@8.2.0": { + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dependencies": {} + }, + "acorn@8.10.0": { + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dependencies": {} + }, + "astring@1.8.6": { + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "dependencies": {} + }, + "jsonrpc-lite@2.2.0": { + "integrity": "sha512-/cbbSxtZWs1O7R4tWqabrCM/t3N8qKUZMAg9IUqpPvUs6UyRvm6pCNYkskyKN/XU0UgffW+NY2ZRr8t0AknX7g==", + "dependencies": {} + }, + "stack-trace@0.0.10": { + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "dependencies": {} + }, + "uuid@8.3.2": { + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dependencies": {} + } + } + }, + "remote": { + "https://deno.land/std@0.203.0/assert/_constants.ts": "8a9da298c26750b28b326b297316cdde860bc237533b07e1337c021379e6b2a9", + "https://deno.land/std@0.203.0/assert/_diff.ts": "1a3c044aedf77647d6cac86b798c6417603361b66b54c53331b312caeb447aea", + "https://deno.land/std@0.203.0/assert/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7", + "https://deno.land/std@0.203.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", + "https://deno.land/std@0.203.0/assert/assert_almost_equals.ts": "e15ca1f34d0d5e0afae63b3f5d975cbd18335a132e42b0c747d282f62ad2cd6c", + "https://deno.land/std@0.203.0/assert/assert_array_includes.ts": "6856d7f2c3544bc6e62fb4646dfefa3d1df5ff14744d1bca19f0cbaf3b0d66c9", + "https://deno.land/std@0.203.0/assert/assert_equals.ts": "d8ec8a22447fbaf2fc9d7c3ed2e66790fdb74beae3e482855d75782218d68227", + "https://deno.land/std@0.203.0/assert/assert_exists.ts": "407cb6b9fb23a835cd8d5ad804e2e2edbbbf3870e322d53f79e1c7a512e2efd7", + "https://deno.land/std@0.203.0/assert/assert_false.ts": "0ccbcaae910f52c857192ff16ea08bda40fdc79de80846c206bfc061e8c851c6", + "https://deno.land/std@0.203.0/assert/assert_greater.ts": "ae2158a2d19313bf675bf7251d31c6dc52973edb12ac64ac8fc7064152af3e63", + "https://deno.land/std@0.203.0/assert/assert_greater_or_equal.ts": "1439da5ebbe20855446cac50097ac78b9742abe8e9a43e7de1ce1426d556e89c", + "https://deno.land/std@0.203.0/assert/assert_instance_of.ts": "3aedb3d8186e120812d2b3a5dea66a6e42bf8c57a8bd927645770bd21eea554c", + "https://deno.land/std@0.203.0/assert/assert_is_error.ts": "c21113094a51a296ffaf036767d616a78a2ae5f9f7bbd464cd0197476498b94b", + "https://deno.land/std@0.203.0/assert/assert_less.ts": "aec695db57db42ec3e2b62e97e1e93db0063f5a6ec133326cc290ff4b71b47e4", + "https://deno.land/std@0.203.0/assert/assert_less_or_equal.ts": "5fa8b6a3ffa20fd0a05032fe7257bf985d207b85685fdbcd23651b70f928c848", + "https://deno.land/std@0.203.0/assert/assert_match.ts": "c4083f80600bc190309903c95e397a7c9257ff8b5ae5c7ef91e834704e672e9b", + "https://deno.land/std@0.203.0/assert/assert_not_equals.ts": "9f1acab95bd1f5fc9a1b17b8027d894509a745d91bac1718fdab51dc76831754", + "https://deno.land/std@0.203.0/assert/assert_not_instance_of.ts": "0c14d3dfd9ab7a5276ed8ed0b18c703d79a3d106102077ec437bfe7ed912bd22", + "https://deno.land/std@0.203.0/assert/assert_not_match.ts": "3796a5b0c57a1ce6c1c57883dd4286be13a26f715ea662318ab43a8491a13ab0", + "https://deno.land/std@0.203.0/assert/assert_not_strict_equals.ts": "ca6c6d645e95fbc873d25320efeb8c4c6089a9a5e09f92d7c1c4b6e935c2a6ad", + "https://deno.land/std@0.203.0/assert/assert_object_match.ts": "d8fc2867cfd92eeacf9cea621e10336b666de1874a6767b5ec48988838370b54", + "https://deno.land/std@0.203.0/assert/assert_rejects.ts": "45c59724de2701e3b1f67c391d6c71c392363635aad3f68a1b3408f9efca0057", + "https://deno.land/std@0.203.0/assert/assert_strict_equals.ts": "b1f538a7ea5f8348aeca261d4f9ca603127c665e0f2bbfeb91fa272787c87265", + "https://deno.land/std@0.203.0/assert/assert_string_includes.ts": "b821d39ebf5cb0200a348863c86d8c4c4b398e02012ce74ad15666fc4b631b0c", + "https://deno.land/std@0.203.0/assert/assert_throws.ts": "63784e951475cb7bdfd59878cd25a0931e18f6dc32a6077c454b2cd94f4f4bcd", + "https://deno.land/std@0.203.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", + "https://deno.land/std@0.203.0/assert/equal.ts": "9f1a46d5993966d2596c44e5858eec821859b45f783a5ee2f7a695dfc12d8ece", + "https://deno.land/std@0.203.0/assert/fail.ts": "c36353d7ae6e1f7933d45f8ea51e358c8c4b67d7e7502028598fe1fea062e278", + "https://deno.land/std@0.203.0/assert/mod.ts": "37c49a26aae2b254bbe25723434dc28cd7532e444cf0b481a97c045d110ec085", + "https://deno.land/std@0.203.0/assert/unimplemented.ts": "d56fbeecb1f108331a380f72e3e010a1f161baa6956fd0f7cf3e095ae1a4c75a", + "https://deno.land/std@0.203.0/assert/unreachable.ts": "4600dc0baf7d9c15a7f7d234f00c23bca8f3eba8b140286aaca7aa998cf9a536", + "https://deno.land/std@0.203.0/fmt/colors.ts": "c51c4642678eb690dcf5ffee5918b675bf01a33fba82acf303701ae1a4f8c8d9", + "https://deno.land/std@0.203.0/testing/_test_suite.ts": "30f018feeb3835f12ab198d8a518f9089b1bcb2e8c838a8b615ab10d5005465c", + "https://deno.land/std@0.203.0/testing/bdd.ts": "3f446df5ef8e856a869e8eec54c8482590415741ff0b6358a00c43486cc15769", + "https://deno.land/std@0.203.0/testing/mock.ts": "6576b4aa55ee20b1990d656a78fff83599e190948c00e9f25a7f3ac5e9d6492d", + "https://deno.land/std@0.216.0/io/types.ts": "748bbb3ac96abda03594ef5a0db15ce5450dcc6c0d841c8906f8b10ac8d32c96", + "https://deno.land/std@0.216.0/io/write_all.ts": "24aac2312bb21096ae3ae0b102b22c26164d3249dff96dbac130958aa736f038" + }, + "workspace": { + "dependencies": [ + "npm:@msgpack/msgpack@3.0.0-beta2", + "npm:@rocket.chat/ui-kit@^0.31.22", + "npm:acorn-walk@8.2.0", + "npm:acorn@8.10.0", + "npm:astring@1.8.6", + "npm:jsonrpc-lite@2.2.0", + "npm:stack-trace@0.0.10", + "npm:uuid@8.3.2" + ] + } +} diff --git a/packages/apps-engine/deno-runtime/handlers/api-handler.ts b/packages/apps-engine/deno-runtime/handlers/api-handler.ts new file mode 100644 index 000000000000..32d30e532fd3 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/api-handler.ts @@ -0,0 +1,46 @@ +import { Defined, JsonRpcError } from 'jsonrpc-lite'; +import type { IApiEndpoint } from '@rocket.chat/apps-engine/definition/api/IApiEndpoint.ts'; + +import { AppObjectRegistry } from '../AppObjectRegistry.ts'; +import { Logger } from '../lib/logger.ts'; +import { AppAccessorsInstance } from '../lib/accessors/mod.ts'; + +export default async function apiHandler(call: string, params: unknown): Promise { + const [, path, httpMethod] = call.split(':'); + + const endpoint = AppObjectRegistry.get(`api:${path}`); + const logger = AppObjectRegistry.get('logger'); + + if (!endpoint) { + return new JsonRpcError(`Endpoint ${path} not found`, -32000); + } + + const method = endpoint[httpMethod as keyof IApiEndpoint]; + + if (typeof method !== 'function') { + return new JsonRpcError(`${path}'s ${httpMethod} not exists`, -32000); + } + + const [request, endpointInfo] = params as Array; + + logger?.debug(`${path}'s ${call} is being executed...`, request); + + try { + // deno-lint-ignore ban-types + const result = await (method as Function).apply(endpoint, [ + request, + endpointInfo, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getModifier(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + ]); + + logger?.debug(`${path}'s ${call} was successfully executed.`); + + return result; + } catch (e) { + logger?.debug(`${path}'s ${call} was unsuccessful.`); + return new JsonRpcError(e.message || "Internal server error", -32000); + } +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/construct.ts b/packages/apps-engine/deno-runtime/handlers/app/construct.ts new file mode 100644 index 000000000000..798a83d0923c --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/construct.ts @@ -0,0 +1,126 @@ +import type { IParseAppPackageResult } from '@rocket.chat/apps-engine/server/compiler/IParseAppPackageResult.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { require } from '../../lib/require.ts'; +import { sanitizeDeprecatedUsage } from '../../lib/sanitizeDeprecatedUsage.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; +import { Socket } from 'node:net'; + +const ALLOWED_NATIVE_MODULES = ['path', 'url', 'crypto', 'buffer', 'stream', 'net', 'http', 'https', 'zlib', 'util', 'punycode', 'os', 'querystring', 'fs']; +const ALLOWED_EXTERNAL_MODULES = ['uuid']; + + +function prepareEnvironment() { + // Deno does not behave equally to Node when it comes to piping content to a socket + // So we intervene here + const originalFinal = Socket.prototype._final; + Socket.prototype._final = function _final(cb) { + // Deno closes the readable stream in the Socket earlier than Node + // The exact reason for that is yet unknown, so we'll need to simply delay the execution + // which allows data to be read in a response + setTimeout(() => originalFinal.call(this, cb), 1); + }; +} + +// As the apps are bundled, the only times they will call require are +// 1. To require native modules +// 2. To require external npm packages we may provide +// 3. To require apps-engine files +function buildRequire(): (module: string) => unknown { + return (module: string): unknown => { + if (ALLOWED_NATIVE_MODULES.includes(module)) { + return require(`node:${module}`); + } + + if (ALLOWED_EXTERNAL_MODULES.includes(module)) { + return require(`npm:${module}`); + } + + if (module.startsWith('@rocket.chat/apps-engine')) { + // Our `require` function knows how to handle these + return require(module); + } + + throw new Error(`Module ${module} is not allowed`); + }; +} + +function wrapAppCode(code: string): (require: (module: string) => unknown) => Promise> { + return new Function( + 'require', + ` + const { Buffer } = require('buffer'); + const exports = {}; + const module = { exports }; + const _error = console.error.bind(console); + const _console = { + log: _error, + error: _error, + debug: _error, + info: _error, + warn: _error, + }; + + const result = (async (exports,module,require,Buffer,console,globalThis,Deno) => { + ${code}; + })(exports,module,require,Buffer,_console,undefined,undefined); + + return result.then(() => module.exports);`, + ) as (require: (module: string) => unknown) => Promise>; +} + +export default async function handleConstructApp(params: unknown): Promise { + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } + + const [appPackage] = params as [IParseAppPackageResult]; + + if (!appPackage?.info?.id || !appPackage?.info?.classFile || !appPackage?.files) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } + + prepareEnvironment(); + + AppObjectRegistry.set('id', appPackage.info.id); + const source = sanitizeDeprecatedUsage(appPackage.files[appPackage.info.classFile]); + + const require = buildRequire(); + const exports = await wrapAppCode(source)(require); + + // This is the same naive logic we've been using in the App Compiler + // Applying the correct type here is quite difficult because of the dynamic nature of the code + // deno-lint-ignore no-explicit-any + const appClass = Object.values(exports)[0] as any; + const logger = AppObjectRegistry.get('logger'); + + const app = new appClass(appPackage.info, logger, AppAccessorsInstance.getDefaultAppAccessors()); + + if (typeof app.getName !== 'function') { + throw new Error('App must contain a getName function'); + } + + if (typeof app.getNameSlug !== 'function') { + throw new Error('App must contain a getNameSlug function'); + } + + if (typeof app.getVersion !== 'function') { + throw new Error('App must contain a getVersion function'); + } + + if (typeof app.getID !== 'function') { + throw new Error('App must contain a getID function'); + } + + if (typeof app.getDescription !== 'function') { + throw new Error('App must contain a getDescription function'); + } + + if (typeof app.getRequiredApiVersion !== 'function') { + throw new Error('App must contain a getRequiredApiVersion function'); + } + + AppObjectRegistry.set('app', app); + + return true; +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleGetStatus.ts b/packages/apps-engine/deno-runtime/handlers/app/handleGetStatus.ts new file mode 100644 index 000000000000..5428d989812e --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleGetStatus.ts @@ -0,0 +1,15 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; + +export default function handleGetStatus(): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.getStatus !== 'function') { + throw new Error('App must contain a getStatus function', { + cause: 'invalid_app', + }); + } + + return app.getStatus(); +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleInitialize.ts b/packages/apps-engine/deno-runtime/handlers/app/handleInitialize.ts new file mode 100644 index 000000000000..ad90d3b01e25 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleInitialize.ts @@ -0,0 +1,19 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export default async function handleInitialize(): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.initialize !== 'function') { + throw new Error('App must contain an initialize function', { + cause: 'invalid_app', + }); + } + + await app.initialize(AppAccessorsInstance.getConfigurationExtend(), AppAccessorsInstance.getEnvironmentRead()); + + return true; +} + diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnDisable.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnDisable.ts new file mode 100644 index 000000000000..e66c2414fd0a --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnDisable.ts @@ -0,0 +1,19 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export default async function handleOnDisable(): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.onDisable !== 'function') { + throw new Error('App must contain an onDisable function', { + cause: 'invalid_app', + }); + } + + await app.onDisable(AppAccessorsInstance.getConfigurationModify()); + + return true; +} + diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnEnable.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnEnable.ts new file mode 100644 index 000000000000..1bdf84476422 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnEnable.ts @@ -0,0 +1,16 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export default function handleOnEnable(): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.onEnable !== 'function') { + throw new Error('App must contain an onEnable function', { + cause: 'invalid_app', + }); + } + + return app.onEnable(AppAccessorsInstance.getEnvironmentRead(), AppAccessorsInstance.getConfigurationModify()); +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnInstall.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnInstall.ts new file mode 100644 index 000000000000..aebf7628a914 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnInstall.ts @@ -0,0 +1,30 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export default async function handleOnInstall(params: unknown): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.onInstall !== 'function') { + throw new Error('App must contain an onInstall function', { + cause: 'invalid_app', + }); + } + + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } + + const [context] = params as [Record]; + + await app.onInstall( + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + AppAccessorsInstance.getModifier(), + ); + + return true; +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnPreSettingUpdate.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnPreSettingUpdate.ts new file mode 100644 index 000000000000..19646fa6704f --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnPreSettingUpdate.ts @@ -0,0 +1,22 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export default function handleOnPreSettingUpdate(params: unknown): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.onPreSettingUpdate !== 'function') { + throw new Error('App must contain an onPreSettingUpdate function', { + cause: 'invalid_app', + }); + } + + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } + + const [setting] = params as [Record]; + + return app.onPreSettingUpdate(setting, AppAccessorsInstance.getConfigurationModify(), AppAccessorsInstance.getReader(), AppAccessorsInstance.getHttp()); +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnSettingUpdated.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnSettingUpdated.ts new file mode 100644 index 000000000000..07084bc22425 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnSettingUpdated.ts @@ -0,0 +1,24 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export default async function handleOnSettingUpdated(params: unknown): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.onSettingUpdated !== 'function') { + throw new Error('App must contain an onSettingUpdated function', { + cause: 'invalid_app', + }); + } + + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } + + const [setting] = params as [Record]; + + await app.onSettingUpdated(setting, AppAccessorsInstance.getConfigurationModify(), AppAccessorsInstance.getReader(), AppAccessorsInstance.getHttp()); + + return true; +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnUninstall.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnUninstall.ts new file mode 100644 index 000000000000..865819728ca4 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnUninstall.ts @@ -0,0 +1,30 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export default async function handleOnUninstall(params: unknown): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.onUninstall !== 'function') { + throw new Error('App must contain an onUninstall function', { + cause: 'invalid_app', + }); + } + + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } + + const [context] = params as [Record]; + + await app.onUninstall( + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + AppAccessorsInstance.getModifier(), + ); + + return true; +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleOnUpdate.ts b/packages/apps-engine/deno-runtime/handlers/app/handleOnUpdate.ts new file mode 100644 index 000000000000..f21e4f947d5d --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleOnUpdate.ts @@ -0,0 +1,30 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export default async function handleOnUpdate(params: unknown): Promise { + const app = AppObjectRegistry.get('app'); + + if (typeof app?.onUpdate !== 'function') { + throw new Error('App must contain an onUpdate function', { + cause: 'invalid_app', + }); + } + + if (!Array.isArray(params)) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } + + const [context] = params as [Record]; + + await app.onUpdate( + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + AppAccessorsInstance.getModifier(), + ); + + return true; +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handleSetStatus.ts b/packages/apps-engine/deno-runtime/handlers/app/handleSetStatus.ts new file mode 100644 index 000000000000..c39ab2a16d62 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handleSetStatus.ts @@ -0,0 +1,29 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; +import type { AppStatus as _AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { require } from '../../lib/require.ts'; + +const { AppStatus } = require('@rocket.chat/apps-engine/definition/AppStatus.js') as { + AppStatus: typeof _AppStatus; +}; + +export default async function handleSetStatus(params: unknown): Promise { + if (!Array.isArray(params) || !Object.values(AppStatus).includes(params[0])) { + throw new Error('Invalid params', { cause: 'invalid_param_type' }); + } + + const [status] = params as [typeof AppStatus]; + + const app = AppObjectRegistry.get('app'); + + if (!app || typeof app['setStatus'] !== 'function') { + throw new Error('App must contain a setStatus function', { + cause: 'invalid_app', + }); + } + + await app['setStatus'](status); + + return null; +} diff --git a/packages/apps-engine/deno-runtime/handlers/app/handler.ts b/packages/apps-engine/deno-runtime/handlers/app/handler.ts new file mode 100644 index 000000000000..2a44f34cb7fe --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/app/handler.ts @@ -0,0 +1,112 @@ +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; +import { Defined, JsonRpcError } from 'jsonrpc-lite'; + +import handleConstructApp from './construct.ts'; +import handleInitialize from './handleInitialize.ts'; +import handleGetStatus from './handleGetStatus.ts'; +import handleSetStatus from './handleSetStatus.ts'; +import handleOnEnable from './handleOnEnable.ts'; +import handleOnInstall from './handleOnInstall.ts'; +import handleOnDisable from './handleOnDisable.ts'; +import handleOnUninstall from './handleOnUninstall.ts'; +import handleOnPreSettingUpdate from './handleOnPreSettingUpdate.ts'; +import handleOnSettingUpdated from './handleOnSettingUpdated.ts'; +import handleListener from '../listener/handler.ts'; +import handleUIKitInteraction, { uikitInteractions } from '../uikit/handler.ts'; +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import handleOnUpdate from './handleOnUpdate.ts'; + +export default async function handleApp(method: string, params: unknown): Promise { + const [, appMethod] = method.split(':'); + + // We don't want the getStatus method to generate logs, so we handle it separately + if (appMethod === 'getStatus') { + return handleGetStatus(); + } + + // `app` will be undefined if the method here is "app:construct" + const app = AppObjectRegistry.get('app'); + + app?.getLogger().debug(`'${appMethod}' is being called...`); + + if (uikitInteractions.includes(appMethod)) { + return handleUIKitInteraction(appMethod, params).then((result) => { + if (result instanceof JsonRpcError) { + app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); + } else { + app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); + } + + return result; + }); + } + + if (appMethod.startsWith('check') || appMethod.startsWith('execute')) { + return handleListener(appMethod, params).then((result) => { + if (result instanceof JsonRpcError) { + app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); + } else { + app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); + } + + return result; + }); + } + + try { + let result: Defined | JsonRpcError; + + switch (appMethod) { + case 'construct': + result = await handleConstructApp(params); + break; + case 'initialize': + result = await handleInitialize(); + break; + case 'setStatus': + result = await handleSetStatus(params); + break; + case 'onEnable': + result = await handleOnEnable(); + break; + case 'onDisable': + result = await handleOnDisable(); + break; + case 'onInstall': + result = await handleOnInstall(params); + break; + case 'onUninstall': + result = await handleOnUninstall(params); + break; + case 'onPreSettingUpdate': + result = await handleOnPreSettingUpdate(params); + break; + case 'onSettingUpdated': + result = await handleOnSettingUpdated(params); + break; + case 'onUpdate': + result = await handleOnUpdate(params); + break; + default: + throw new JsonRpcError('Method not found', -32601); + } + + app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); + + return result; + } catch (e: unknown) { + if (!(e instanceof Error)) { + return new JsonRpcError('Unknown error', -32000, e); + } + + if ((e.cause as string)?.includes('invalid_param_type')) { + return JsonRpcError.invalidParams(null); + } + + if ((e.cause as string)?.includes('invalid_app')) { + return JsonRpcError.internalError({ message: 'App unavailable' }); + } + + return new JsonRpcError(e.message, -32000, e); + } +} diff --git a/packages/apps-engine/deno-runtime/handlers/listener/handler.ts b/packages/apps-engine/deno-runtime/handlers/listener/handler.ts new file mode 100644 index 000000000000..1e6de20538fc --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/listener/handler.ts @@ -0,0 +1,150 @@ +import { Defined, JsonRpcError } from 'jsonrpc-lite'; +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; +import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { AppsEngineException as _AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions/AppsEngineException.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { MessageExtender } from '../../lib/accessors/extenders/MessageExtender.ts'; +import { RoomExtender } from '../../lib/accessors/extenders/RoomExtender.ts'; +import { MessageBuilder } from '../../lib/accessors/builders/MessageBuilder.ts'; +import { RoomBuilder } from '../../lib/accessors/builders/RoomBuilder.ts'; +import { AppAccessors, AppAccessorsInstance } from '../../lib/accessors/mod.ts'; +import { require } from '../../lib/require.ts'; +import createRoom from '../../lib/roomFactory.ts'; +import { Room } from "../../lib/room.ts"; + +const { AppsEngineException } = require('@rocket.chat/apps-engine/definition/exceptions/AppsEngineException.js') as { + AppsEngineException: typeof _AppsEngineException; +}; + +export default async function handleListener(evtInterface: string, params: unknown): Promise { + const app = AppObjectRegistry.get('app'); + + const eventExecutor = app?.[evtInterface as keyof App]; + + if (typeof eventExecutor !== 'function') { + return JsonRpcError.methodNotFound({ + message: 'Invalid event interface called on app', + }); + } + + if (!Array.isArray(params) || params.length < 1 || params.length > 2) { + return JsonRpcError.invalidParams(null); + } + + try { + const args = parseArgs({ AppAccessorsInstance }, evtInterface, params); + return await (eventExecutor as (...args: unknown[]) => Promise).apply(app, args); + } catch (e) { + if (e instanceof JsonRpcError) { + return e; + } + + if (e instanceof AppsEngineException) { + return new JsonRpcError(e.message, AppsEngineException.JSONRPC_ERROR_CODE, { name: e.name }); + } + + return JsonRpcError.internalError({ message: e.message }); + } + +} + +export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMethod: string, params: unknown[]): unknown[] { + const { AppAccessorsInstance } = deps; + /** + * param1 is the context for the event handler execution + * param2 is an optional extra content that some hanlers require + */ + const [param1, param2] = params as [unknown, unknown]; + + if (!param1) { + throw JsonRpcError.invalidParams(null); + } + + let context = param1; + + if (evtMethod.includes('Message')) { + context = hydrateMessageObjects(context) as Record; + } else if (evtMethod.endsWith('RoomUserJoined') || evtMethod.endsWith('RoomUserLeave')) { + (context as Record).room = createRoom((context as Record).room as IRoom, AppAccessorsInstance.getSenderFn()); + } else if (evtMethod.includes('PreRoom')) { + context = createRoom(context as IRoom, AppAccessorsInstance.getSenderFn()); + } + + const args: unknown[] = [context, AppAccessorsInstance.getReader(), AppAccessorsInstance.getHttp()]; + + // "check" events will only go this far - (context, reader, http) + if (evtMethod.startsWith('check')) { + // "checkPostMessageDeleted" has an extra param - (context, reader, http, extraContext) + if (param2) { + args.push(hydrateMessageObjects(param2)); + } + + return args; + } + + // From this point on, all events will require (reader, http, persistence) injected + args.push(AppAccessorsInstance.getPersistence()); + + // "extend" events have an additional "Extender" param - (context, extender, reader, http, persistence) + if (evtMethod.endsWith('Extend')) { + if (evtMethod.includes('Message')) { + args.splice(1, 0, new MessageExtender(param1 as IMessage)); + } else if (evtMethod.includes('Room')) { + args.splice(1, 0, new RoomExtender(param1 as IRoom)); + } + + return args; + } + + // "Modify" events have an additional "Builder" param - (context, builder, reader, http, persistence) + if (evtMethod.endsWith('Modify')) { + if (evtMethod.includes('Message')) { + args.splice(1, 0, new MessageBuilder(param1 as IMessage)); + } else if (evtMethod.includes('Room')) { + args.splice(1, 0, new RoomBuilder(param1 as IRoom)); + } + + return args; + } + + // From this point on, all events will require (reader, http, persistence, modifier) injected + args.push(AppAccessorsInstance.getModifier()); + + // This guy gets an extra one + if (evtMethod === 'executePostMessageDeleted') { + if (!param2) { + throw JsonRpcError.invalidParams(null); + } + + args.push(hydrateMessageObjects(param2)); + } + + return args; +} + +/** + * Hydrate the context object with the correct IMessage + * + * Some information is lost upon serializing the data from listeners through the pipes, + * so here we hydrate the complete object as necessary + */ +function hydrateMessageObjects(context: unknown): unknown { + if (objectIsRawMessage(context)) { + context.room = createRoom(context.room as IRoom, AppAccessorsInstance.getSenderFn()); + } else if ((context as Record)?.message) { + (context as Record).message = hydrateMessageObjects((context as Record).message); + } + + return context; +} + +function objectIsRawMessage(value: unknown): value is IMessage { + if (!value) return false; + + const { id, room, sender, createdAt } = value as Record; + + // Check if we have the fields of a message and the room hasn't already been hydrated + return !!(id && room && sender && createdAt) && !(room instanceof Room); +} diff --git a/packages/apps-engine/deno-runtime/handlers/scheduler-handler.ts b/packages/apps-engine/deno-runtime/handlers/scheduler-handler.ts new file mode 100644 index 000000000000..0145034957f2 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/scheduler-handler.ts @@ -0,0 +1,51 @@ +import { Defined, JsonRpcError } from 'jsonrpc-lite'; +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; +import type { IProcessor } from '@rocket.chat/apps-engine/definition/scheduler/IProcessor.ts'; + +import { AppObjectRegistry } from '../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../lib/accessors/mod.ts'; + +export default async function handleScheduler(method: string, params: unknown): Promise { + const [, processorId] = method.split(':'); + if (!Array.isArray(params)) { + return JsonRpcError.invalidParams({ message: 'Invalid params' }); + } + + const [context] = params as [Record]; + + const app = AppObjectRegistry.get('app'); + + if (!app) { + return JsonRpcError.internalError({ message: 'App not found' }); + } + + // AppSchedulerManager will append the appId to the processor name to avoid conflicts + const processor = AppObjectRegistry.get(`scheduler:${processorId}`); + + if (!processor) { + return JsonRpcError.methodNotFound({ + message: `Could not find processor for method ${method}`, + }); + } + + app.getLogger().debug(`Job processor ${processor.id} is being executed...`); + + try { + await processor.processor( + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getModifier(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + ); + + app.getLogger().debug(`Job processor ${processor.id} was successfully executed`); + + return null; + } catch (e) { + app.getLogger().error(e); + app.getLogger().error(`Job processor ${processor.id} was unsuccessful`); + + return JsonRpcError.internalError({ message: e.message }); + } +} diff --git a/packages/apps-engine/deno-runtime/handlers/slashcommand-handler.ts b/packages/apps-engine/deno-runtime/handlers/slashcommand-handler.ts new file mode 100644 index 000000000000..cfebf0d1460e --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/slashcommand-handler.ts @@ -0,0 +1,122 @@ +import { Defined, JsonRpcError } from 'jsonrpc-lite'; + +import type { App } from "@rocket.chat/apps-engine/definition/App.ts"; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { ISlashCommand } from '@rocket.chat/apps-engine/definition/slashcommands/ISlashCommand.ts'; +import type { SlashCommandContext as _SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands/SlashCommandContext.ts'; +import type { Room as _Room } from '@rocket.chat/apps-engine/server/rooms/Room.ts'; + +import { AppObjectRegistry } from '../AppObjectRegistry.ts'; +import { AppAccessors, AppAccessorsInstance } from '../lib/accessors/mod.ts'; +import { require } from '../lib/require.ts'; +import createRoom from '../lib/roomFactory.ts'; + +// For some reason Deno couldn't understand the typecast to the original interfaces and said it wasn't a constructor type +const { SlashCommandContext } = require('@rocket.chat/apps-engine/definition/slashcommands/SlashCommandContext.js') as { + SlashCommandContext: typeof _SlashCommandContext; +}; + +export default async function slashCommandHandler(call: string, params: unknown): Promise { + const [, commandName, method] = call.split(':'); + + const command = AppObjectRegistry.get(`slashcommand:${commandName}`); + + if (!command) { + return new JsonRpcError(`Slashcommand ${commandName} not found`, -32000); + } + + let result: Awaited> | Awaited>; + + // If the command is registered, we're pretty safe to assume the app is not undefined + const app = AppObjectRegistry.get('app')!; + + app.getLogger().debug(`${commandName}'s ${method} is being executed...`, params); + + try { + if (method === 'executor' || method === 'previewer') { + result = await handleExecutor({ AppAccessorsInstance }, command, method, params); + } else if (method === 'executePreviewItem') { + result = await handlePreviewItem({ AppAccessorsInstance }, command, params); + } else { + return new JsonRpcError(`Method ${method} not found on slashcommand ${commandName}`, -32000); + } + + app.getLogger().debug(`${commandName}'s ${method} was successfully executed.`); + } catch (error) { + app.getLogger().debug(`${commandName}'s ${method} was unsuccessful.`); + + return new JsonRpcError(error.message, -32000); + } + + return result; +} + +/** + * @param deps Dependencies that need to be injected into the slashcommand + * @param command The slashcommand that is being executed + * @param method The method that is being executed + * @param params The parameters that are being passed to the method + */ +export function handleExecutor(deps: { AppAccessorsInstance: AppAccessors }, command: ISlashCommand, method: 'executor' | 'previewer', params: unknown) { + const executor = command[method]; + + if (typeof executor !== 'function') { + throw new Error(`Method ${method} not found on slashcommand ${command.command}`); + } + + if (!Array.isArray(params) || typeof params[0] !== 'object' || !params[0]) { + throw new Error(`First parameter must be an object`); + } + + const { sender, room, params: args, threadId, triggerId } = params[0] as Record; + + const context = new SlashCommandContext( + sender as _SlashCommandContext['sender'], + createRoom(room as IRoom, deps.AppAccessorsInstance.getSenderFn()), + args as _SlashCommandContext['params'], + threadId as _SlashCommandContext['threadId'], + triggerId as _SlashCommandContext['triggerId'], + ); + + return executor.apply(command, [ + context, + deps.AppAccessorsInstance.getReader(), + deps.AppAccessorsInstance.getModifier(), + deps.AppAccessorsInstance.getHttp(), + deps.AppAccessorsInstance.getPersistence(), + ]); +} + +/** + * @param deps Dependencies that need to be injected into the slashcommand + * @param command The slashcommand that is being executed + * @param params The parameters that are being passed to the method + */ +export function handlePreviewItem(deps: { AppAccessorsInstance: AppAccessors }, command: ISlashCommand, params: unknown) { + if (typeof command.executePreviewItem !== 'function') { + throw new Error(`Method not found on slashcommand ${command.command}`); + } + + if (!Array.isArray(params) || typeof params[0] !== 'object' || !params[0]) { + throw new Error(`First parameter must be an object`); + } + + const [previewItem, { sender, room, params: args, threadId, triggerId }] = params as [Record, Record]; + + const context = new SlashCommandContext( + sender as _SlashCommandContext['sender'], + createRoom(room as IRoom, deps.AppAccessorsInstance.getSenderFn()), + args as _SlashCommandContext['params'], + threadId as _SlashCommandContext['threadId'], + triggerId as _SlashCommandContext['triggerId'], + ); + + return command.executePreviewItem( + previewItem, + context, + deps.AppAccessorsInstance.getReader(), + deps.AppAccessorsInstance.getModifier(), + deps.AppAccessorsInstance.getHttp(), + deps.AppAccessorsInstance.getPersistence(), + ); +} diff --git a/packages/apps-engine/deno-runtime/handlers/tests/api-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/api-handler.test.ts new file mode 100644 index 000000000000..a3789f755542 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/tests/api-handler.test.ts @@ -0,0 +1,79 @@ +// deno-lint-ignore-file no-explicit-any +import { assertEquals, assertObjectMatch } from 'https://deno.land/std@0.203.0/assert/mod.ts'; +import { beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; +import { spy } from "https://deno.land/std@0.203.0/testing/mock.ts"; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { assertInstanceOf } from "https://deno.land/std@0.203.0/assert/assert_instance_of.ts"; +import { JsonRpcError } from "jsonrpc-lite"; +import type { IApiEndpoint } from "@rocket.chat/apps-engine/definition/api/IApiEndpoint.ts"; +import apiHandler from "../api-handler.ts"; + +describe('handlers > api', () => { + const mockEndpoint: IApiEndpoint = { + path: '/test', + // deno-lint-ignore no-unused-vars + get: (request: any, endpoint: any, read: any, modify: any, http: any, persis: any) => Promise.resolve('ok'), + // deno-lint-ignore no-unused-vars + post: (request: any, endpoint: any, read: any, modify: any, http: any, persis: any) => Promise.resolve('ok'), + // deno-lint-ignore no-unused-vars + put: (request: any, endpoint: any, read: any, modify: any, http: any, persis: any) => { throw new Error('Method execution error example') }, + } + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('api:/test', mockEndpoint); + }); + + it('correctly handles execution of an api endpoint method GET', async () => { + const _spy = spy(mockEndpoint, 'get'); + + const result = await apiHandler('api:/test:get', ['request', 'endpointInfo']); + + assertEquals(result, 'ok'); + assertEquals(_spy.calls[0].args.length, 6); + assertEquals(_spy.calls[0].args[0], 'request'); + assertEquals(_spy.calls[0].args[1], 'endpointInfo'); + }); + + it('correctly handles execution of an api endpoint method POST', async () => { + const _spy = spy(mockEndpoint, 'post'); + + const result = await apiHandler('api:/test:post', ['request', 'endpointInfo']); + + assertEquals(result, 'ok'); + assertEquals(_spy.calls[0].args.length, 6); + assertEquals(_spy.calls[0].args[0], 'request'); + assertEquals(_spy.calls[0].args[1], 'endpointInfo'); + }); + + it('correctly handles an error if the method not exists for the selected endpoint', async () => { + const result = await apiHandler(`api:/test:delete`, ['request', 'endpointInfo']); + + assertInstanceOf(result, JsonRpcError) + assertObjectMatch(result, { + message: `/test's delete not exists`, + code: -32000 + }) + }); + + it('correctly handles an error if endpoint not exists', async () => { + const result = await apiHandler(`api:/error:get`, ['request', 'endpointInfo']); + + assertInstanceOf(result, JsonRpcError) + assertObjectMatch(result, { + message: `Endpoint /error not found`, + code: -32000 + }) + }); + + it('correctly handles an error if the method execution fails', async () => { + const result = await apiHandler(`api:/test:put`, ['request', 'endpointInfo']); + + assertInstanceOf(result, JsonRpcError) + assertObjectMatch(result, { + message: `Method execution error example`, + code: -32000 + }) + }); +}); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/listener-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/listener-handler.test.ts new file mode 100644 index 000000000000..3e3663b06d22 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/tests/listener-handler.test.ts @@ -0,0 +1,234 @@ +// deno-lint-ignore-file no-explicit-any +import { assertEquals, assertInstanceOf, assertObjectMatch } from 'https://deno.land/std@0.203.0/assert/mod.ts'; +import { describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; + +import { parseArgs } from '../listener/handler.ts'; +import { AppAccessors } from '../../lib/accessors/mod.ts'; +import { Room } from '../../lib/room.ts'; +import { MessageExtender } from '../../lib/accessors/extenders/MessageExtender.ts'; +import { RoomExtender } from '../../lib/accessors/extenders/RoomExtender.ts'; +import { MessageBuilder } from '../../lib/accessors/builders/MessageBuilder.ts'; +import { RoomBuilder } from '../../lib/accessors/builders/RoomBuilder.ts'; + +describe('handlers > listeners', () => { + const mockAppAccessors = { + getReader: () => ({ __type: 'reader' }), + getHttp: () => ({ __type: 'http' }), + getModifier: () => ({ __type: 'modifier' }), + getPersistence: () => ({ __type: 'persistence' }), + getSenderFn: () => (id: string) => Promise.resolve([{ __type: 'bridgeCall' }, { id }]), + } as unknown as AppAccessors; + + it('correctly parses the arguments for a request to trigger the "checkPreMessageSentPrevent" method', () => { + const evtMethod = 'checkPreMessageSentPrevent'; + // For the 'checkPreMessageSentPrevent' method, the context will be a message in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 3); + assertEquals(params[0], { __type: 'context' }); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + }); + + it('correctly parses the arguments for a request to trigger the "checkPostMessageDeleted" method', () => { + const evtMethod = 'checkPostMessageDeleted'; + // For the 'checkPostMessageDeleted' method, the context will be a message in a real scenario, + // and the extraContext will provide further information such the user who deleted the message + const evtArgs = [{ __type: 'context' }, { __type: 'extraContext' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 4); + assertEquals(params[0], { __type: 'context' }); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'extraContext' }); + }); + + it('correctly parses the arguments for a request to trigger the "checkPreRoomCreateExtend" method', () => { + const evtMethod = 'checkPreRoomCreateExtend'; + // For the 'checkPreRoomCreateExtend' method, the context will be a room in a real scenario + const evtArgs = [ + { + id: 'fake', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }, + ]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 3); + + assertInstanceOf(params[0], Room); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePreMessageSentExtend" method', () => { + const evtMethod = 'executePreMessageSentExtend'; + // For the 'executePreMessageSentExtend' method, the context will be a message in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + // Instantiating the MessageExtender might modify the original object, so we need to assert it matches instead of equals + assertObjectMatch(params[0] as Record, { + __type: 'context', + }); + assertInstanceOf(params[1], MessageExtender); + assertEquals(params[2], { __type: 'reader' }); + assertEquals(params[3], { __type: 'http' }); + assertEquals(params[4], { __type: 'persistence' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePreRoomCreateExtend" method', () => { + const evtMethod = 'executePreRoomCreateExtend'; + // For the 'executePreRoomCreateExtend' method, the context will be a room in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + // Instantiating the RoomExtender might modify the original object, so we need to assert it matches instead of equals + assertObjectMatch(params[0] as Record, { + __type: 'context', + }); + assertInstanceOf(params[1], RoomExtender); + assertEquals(params[2], { __type: 'reader' }); + assertEquals(params[3], { __type: 'http' }); + assertEquals(params[4], { __type: 'persistence' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePreMessageSentModify" method', () => { + const evtMethod = 'executePreMessageSentModify'; + // For the 'executePreMessageSentModify' method, the context will be a message in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + // Instantiating the MessageBuilder might modify the original object, so we need to assert it matches instead of equals + assertObjectMatch(params[0] as Record, { + __type: 'context', + }); + assertInstanceOf(params[1], MessageBuilder); + assertEquals(params[2], { __type: 'reader' }); + assertEquals(params[3], { __type: 'http' }); + assertEquals(params[4], { __type: 'persistence' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePreRoomCreateModify" method', () => { + const evtMethod = 'executePreRoomCreateModify'; + // For the 'executePreRoomCreateModify' method, the context will be a room in a real scenario + const evtArgs = [{ __type: 'context' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + // Instantiating the RoomBuilder might modify the original object, so we need to assert it matches instead of equals + assertObjectMatch(params[0] as Record, { + __type: 'context', + }); + assertInstanceOf(params[1], RoomBuilder); + assertEquals(params[2], { __type: 'reader' }); + assertEquals(params[3], { __type: 'http' }); + assertEquals(params[4], { __type: 'persistence' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePostRoomUserJoined" method', () => { + const evtMethod = 'executePostRoomUserJoined'; + // For the 'executePostRoomUserJoined' method, the context will be a room in a real scenario + const room = { + id: 'fake', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }; + + const evtArgs = [{ __type: 'context', room }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + assertInstanceOf((params[0] as any).room, Room); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'persistence' }); + assertEquals(params[4], { __type: 'modifier' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePostRoomUserLeave" method', () => { + const evtMethod = 'executePostRoomUserLeave'; + // For the 'executePostRoomUserLeave' method, the context will be a room in a real scenario + const room = { + id: 'fake', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }; + + const evtArgs = [{ __type: 'context', room }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + assertInstanceOf((params[0] as any).room, Room); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'persistence' }); + assertEquals(params[4], { __type: 'modifier' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePostMessageDeleted" method', () => { + const evtMethod = 'executePostMessageDeleted'; + // For the 'executePostMessageDeleted' method, the context will be a message in a real scenario + const evtArgs = [{ __type: 'context' }, { __type: 'extraContext' }]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 6); + assertEquals(params[0], { __type: 'context' }); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'persistence' }); + assertEquals(params[4], { __type: 'modifier' }); + assertEquals(params[5], { __type: 'extraContext' }); + }); + + it('correctly parses the arguments for a request to trigger the "executePostMessageSent" method', () => { + const evtMethod = 'executePostMessageSent'; + // For the 'executePostMessageDeleted' method, the context will be a message in a real scenario + const evtArgs = [ + { + id: 'fake', + sender: 'fake', + createdAt: Date.now(), + room: { + id: 'fake-room', + type: 'fake', + slugifiedName: 'fake', + creator: 'fake', + createdAt: Date.now(), + }, + }, + ]; + + const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs); + + assertEquals(params.length, 5); + assertObjectMatch((params[0] as Record), { id: 'fake' }); + assertInstanceOf((params[0] as any).room, Room); + assertEquals(params[1], { __type: 'reader' }); + assertEquals(params[2], { __type: 'http' }); + assertEquals(params[3], { __type: 'persistence' }); + assertEquals(params[4], { __type: 'modifier' }); + }); +}); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/scheduler-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/scheduler-handler.test.ts new file mode 100644 index 000000000000..681f228bdb3e --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/tests/scheduler-handler.test.ts @@ -0,0 +1,46 @@ +import { assertEquals } from 'https://deno.land/std@0.203.0/assert/mod.ts'; +import { afterAll, beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessors } from '../../lib/accessors/mod.ts'; +import handleScheduler from '../scheduler-handler.ts'; + +describe('handlers > scheduler', () => { + const mockAppAccessors = new AppAccessors(() => + Promise.resolve({ + id: 'mockId', + result: {}, + jsonrpc: '2.0', + serialize: () => '', + }), + ); + + const mockApp = { + getID: () => 'mockApp', + getLogger: () => ({ + debug: () => {}, + error: () => {}, + }), + }; + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('app', mockApp); + mockAppAccessors.getConfigurationExtend().scheduler.registerProcessors([ + { + id: 'mockId', + processor: () => Promise.resolve('it works!'), + }, + ]); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('correctly executes a request to a processor', async () => { + const result = await handleScheduler('scheduler:mockId', [{}]); + + assertEquals(result, null); + }); +}); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/slashcommand-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/slashcommand-handler.test.ts new file mode 100644 index 000000000000..d3da4b132d66 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/tests/slashcommand-handler.test.ts @@ -0,0 +1,152 @@ +// deno-lint-ignore-file no-explicit-any +import { assertEquals, assertInstanceOf } from 'https://deno.land/std@0.203.0/assert/mod.ts'; +import { beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; +import { spy } from 'https://deno.land/std@0.203.0/testing/mock.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessors } from '../../lib/accessors/mod.ts'; +import { handleExecutor, handlePreviewItem } from '../slashcommand-handler.ts'; +import { Room } from "../../lib/room.ts"; + +describe('handlers > slashcommand', () => { + const mockAppAccessors = { + getReader: () => ({ __type: 'reader' }), + getHttp: () => ({ __type: 'http' }), + getModifier: () => ({ __type: 'modifier' }), + getPersistence: () => ({ __type: 'persistence' }), + getSenderFn: () => (id: string) => Promise.resolve([{ __type: 'bridgeCall' }, { id }]), + } as unknown as AppAccessors; + + const mockCommandExecutorOnly = { + command: 'executor-only', + i18nParamsExample: 'test', + i18nDescription: 'test', + providesPreview: false, + // deno-lint-ignore no-unused-vars + async executor(context: any, read: any, modify: any, http: any, persis: any): Promise {}, + }; + + const mockCommandExecutorAndPreview = { + command: 'executor-and-preview', + i18nParamsExample: 'test', + i18nDescription: 'test', + providesPreview: true, + // deno-lint-ignore no-unused-vars + async executor(context: any, read: any, modify: any, http: any, persis: any): Promise {}, + // deno-lint-ignore no-unused-vars + async previewer(context: any, read: any, modify: any, http: any, persis: any): Promise {}, + // deno-lint-ignore no-unused-vars + async executePreviewItem(previewItem: any, context: any, read: any, modify: any, http: any, persis: any): Promise {}, + }; + + const mockCommandPreviewWithNoExecutor = { + command: 'preview-with-no-executor', + i18nParamsExample: 'test', + i18nDescription: 'test', + providesPreview: true, + // deno-lint-ignore no-unused-vars + async previewer(context: any, read: any, modify: any, http: any, persis: any): Promise {}, + // deno-lint-ignore no-unused-vars + async executePreviewItem(previewItem: any, context: any, read: any, modify: any, http: any, persis: any): Promise {}, + }; + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('slashcommand:executor-only', mockCommandExecutorOnly); + AppObjectRegistry.set('slashcommand:executor-and-preview', mockCommandExecutorAndPreview); + AppObjectRegistry.set('slashcommand:preview-with-no-executor', mockCommandPreviewWithNoExecutor); + }); + + it('correctly handles execution of a slash command', async () => { + const mockContext = { + sender: { __type: 'sender' }, + room: { __type: 'room' }, + params: { __type: 'params' }, + threadId: 'threadId', + triggerId: 'triggerId', + }; + + const _spy = spy(mockCommandExecutorOnly, 'executor'); + + await handleExecutor({ AppAccessorsInstance: mockAppAccessors }, mockCommandExecutorOnly, 'executor', [mockContext]); + + const context = _spy.calls[0].args[0]; + + assertInstanceOf(context.getRoom(), Room); + assertEquals(context.getSender(), { __type: 'sender' }); + assertEquals(context.getArguments(), { __type: 'params' }); + assertEquals(context.getThreadId(), 'threadId'); + assertEquals(context.getTriggerId(), 'triggerId'); + + assertEquals(_spy.calls[0].args[1], mockAppAccessors.getReader()); + assertEquals(_spy.calls[0].args[2], mockAppAccessors.getModifier()); + assertEquals(_spy.calls[0].args[3], mockAppAccessors.getHttp()); + assertEquals(_spy.calls[0].args[4], mockAppAccessors.getPersistence()); + + _spy.restore(); + }); + + it('correctly handles execution of a slash command previewer', async () => { + const mockContext = { + sender: { __type: 'sender' }, + room: { __type: 'room' }, + params: { __type: 'params' }, + threadId: 'threadId', + triggerId: 'triggerId', + }; + + const _spy = spy(mockCommandExecutorAndPreview, 'previewer'); + + await handleExecutor({ AppAccessorsInstance: mockAppAccessors }, mockCommandExecutorAndPreview, 'previewer', [mockContext]); + + const context = _spy.calls[0].args[0]; + + assertInstanceOf(context.getRoom(), Room); + assertEquals(context.getSender(), { __type: 'sender' }); + assertEquals(context.getArguments(), { __type: 'params' }); + assertEquals(context.getThreadId(), 'threadId'); + assertEquals(context.getTriggerId(), 'triggerId'); + + assertEquals(_spy.calls[0].args[1], mockAppAccessors.getReader()); + assertEquals(_spy.calls[0].args[2], mockAppAccessors.getModifier()); + assertEquals(_spy.calls[0].args[3], mockAppAccessors.getHttp()); + assertEquals(_spy.calls[0].args[4], mockAppAccessors.getPersistence()); + + _spy.restore(); + }); + + it('correctly handles execution of a slash command preview item executor', async () => { + const mockContext = { + sender: { __type: 'sender' }, + room: { __type: 'room' }, + params: { __type: 'params' }, + threadId: 'threadId', + triggerId: 'triggerId', + }; + + const mockPreviewItem = { + id: 'previewItemId', + type: 'image', + value: 'https://example.com/image.png', + }; + + const _spy = spy(mockCommandExecutorAndPreview, 'executePreviewItem'); + + await handlePreviewItem({ AppAccessorsInstance: mockAppAccessors }, mockCommandExecutorAndPreview, [mockPreviewItem, mockContext]); + + const context = _spy.calls[0].args[1]; + + assertInstanceOf(context.getRoom(), Room); + assertEquals(context.getSender(), { __type: 'sender' }); + assertEquals(context.getArguments(), { __type: 'params' }); + assertEquals(context.getThreadId(), 'threadId'); + assertEquals(context.getTriggerId(), 'triggerId'); + + assertEquals(_spy.calls[0].args[2], mockAppAccessors.getReader()); + assertEquals(_spy.calls[0].args[3], mockAppAccessors.getModifier()); + assertEquals(_spy.calls[0].args[4], mockAppAccessors.getHttp()); + assertEquals(_spy.calls[0].args[5], mockAppAccessors.getPersistence()); + + _spy.restore(); + }); +}); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/uikit-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/uikit-handler.test.ts new file mode 100644 index 000000000000..f2293d6c98e0 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/tests/uikit-handler.test.ts @@ -0,0 +1,99 @@ +// deno-lint-ignore-file no-explicit-any +import { assertInstanceOf } from 'https://deno.land/std@0.203.0/assert/mod.ts'; +import { afterAll, beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import handleUIKitInteraction, { + UIKitActionButtonInteractionContext, + UIKitBlockInteractionContext, + UIKitLivechatBlockInteractionContext, + UIKitViewCloseInteractionContext, + UIKitViewSubmitInteractionContext, +} from '../uikit/handler.ts'; + +describe('handlers > uikit', () => { + const mockApp = { + getID: (): string => 'appId', + executeBlockActionHandler: (context: any): Promise => Promise.resolve(context), + executeViewSubmitHandler: (context: any): Promise => Promise.resolve(context), + executeViewClosedHandler: (context: any): Promise => Promise.resolve(context), + executeActionButtonHandler: (context: any): Promise => Promise.resolve(context), + executeLivechatBlockActionHandler: (context: any): Promise => Promise.resolve(context), + }; + + beforeEach(() => { + AppObjectRegistry.set('app', mockApp); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('successfully handles a call for "executeBlockActionHandler"', async () => { + const result = await handleUIKitInteraction('executeBlockActionHandler', [ + { + actionId: 'actionId', + blockId: 'blockId', + value: 'value', + viewId: 'viewId', + }, + ]); + + assertInstanceOf(result, UIKitBlockInteractionContext); + }); + + it('successfully handles a call for "executeViewSubmitHandler"', async () => { + const result = await handleUIKitInteraction('executeViewSubmitHandler', [ + { + viewId: 'viewId', + appId: 'appId', + userId: 'userId', + isAppUser: true, + values: {}, + }, + ]); + + assertInstanceOf(result, UIKitViewSubmitInteractionContext); + }); + + it('successfully handles a call for "executeViewClosedHandler"', async () => { + const result = await handleUIKitInteraction('executeViewClosedHandler', [ + { + viewId: 'viewId', + appId: 'appId', + userId: 'userId', + isAppUser: true, + }, + ]); + + assertInstanceOf(result, UIKitViewCloseInteractionContext); + }); + + it('successfully handles a call for "executeActionButtonHandler"', async () => { + const result = await handleUIKitInteraction('executeActionButtonHandler', [ + { + actionId: 'actionId', + appId: 'appId', + userId: 'userId', + isAppUser: true, + }, + ]); + + assertInstanceOf(result, UIKitActionButtonInteractionContext); + }); + + it('successfully handles a call for "executeLivechatBlockActionHandler"', async () => { + const result = await handleUIKitInteraction('executeLivechatBlockActionHandler', [ + { + actionId: 'actionId', + appId: 'appId', + userId: 'userId', + visitor: {}, + isAppUser: true, + room: {}, + }, + ]); + + assertInstanceOf(result, UIKitLivechatBlockInteractionContext); + }); +}); diff --git a/packages/apps-engine/deno-runtime/handlers/tests/videoconference-handler.test.ts b/packages/apps-engine/deno-runtime/handlers/tests/videoconference-handler.test.ts new file mode 100644 index 000000000000..a32d3175e24d --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/tests/videoconference-handler.test.ts @@ -0,0 +1,122 @@ +// deno-lint-ignore-file no-explicit-any +import { assertEquals, assertObjectMatch } from 'https://deno.land/std@0.203.0/assert/mod.ts'; +import { beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; +import { spy } from 'https://deno.land/std@0.203.0/testing/mock.ts'; + +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import videoconfHandler from '../videoconference-handler.ts'; +import { assertInstanceOf } from 'https://deno.land/std@0.203.0/assert/assert_instance_of.ts'; +import { JsonRpcError } from 'jsonrpc-lite'; + +describe('handlers > videoconference', () => { + // deno-lint-ignore no-unused-vars + const mockMethodWithoutParam = (read: any, modify: any, http: any, persis: any): Promise => Promise.resolve('ok none'); + // deno-lint-ignore no-unused-vars + const mockMethodWithOneParam = (call: any, read: any, modify: any, http: any, persis: any): Promise => Promise.resolve('ok one'); + // deno-lint-ignore no-unused-vars + const mockMethodWithTwoParam = (call: any, user: any, read: any, modify: any, http: any, persis: any): Promise => Promise.resolve('ok two'); + // deno-lint-ignore no-unused-vars + const mockMethodWithThreeParam = (call: any, user: any, options: any, read: any, modify: any, http: any, persis: any): Promise => + Promise.resolve('ok three'); + const mockProvider = { + empty: mockMethodWithoutParam, + one: mockMethodWithOneParam, + two: mockMethodWithTwoParam, + three: mockMethodWithThreeParam, + notAFunction: true, + error: () => { + throw new Error('Method execution error example'); + }, + }; + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('videoConfProvider:test-provider', mockProvider); + }); + + it('correctly handles execution of a videoconf method without additional params', async () => { + const _spy = spy(mockProvider, 'empty'); + + const result = await videoconfHandler('videoconference:test-provider:empty', []); + + assertEquals(result, 'ok none'); + assertEquals(_spy.calls[0].args.length, 4); + + _spy.restore(); + }); + + it('correctly handles execution of a videoconf method with one param', async () => { + const _spy = spy(mockProvider, 'one'); + + const result = await videoconfHandler('videoconference:test-provider:one', ['call']); + + assertEquals(result, 'ok one'); + assertEquals(_spy.calls[0].args.length, 5); + assertEquals(_spy.calls[0].args[0], 'call'); + + _spy.restore(); + }); + + it('correctly handles execution of a videoconf method with two params', async () => { + const _spy = spy(mockProvider, 'two'); + + const result = await videoconfHandler('videoconference:test-provider:two', ['call', 'user']); + + assertEquals(result, 'ok two'); + assertEquals(_spy.calls[0].args.length, 6); + assertEquals(_spy.calls[0].args[0], 'call'); + assertEquals(_spy.calls[0].args[1], 'user'); + + _spy.restore(); + }); + + it('correctly handles execution of a videoconf method with three params', async () => { + const _spy = spy(mockProvider, 'three'); + + const result = await videoconfHandler('videoconference:test-provider:three', ['call', 'user', 'options']); + + assertEquals(result, 'ok three'); + assertEquals(_spy.calls[0].args.length, 7); + assertEquals(_spy.calls[0].args[0], 'call'); + assertEquals(_spy.calls[0].args[1], 'user'); + assertEquals(_spy.calls[0].args[2], 'options'); + + _spy.restore(); + }); + + it('correctly handles an error on execution of a videoconf method', async () => { + const result = await videoconfHandler('videoconference:test-provider:error', []); + + assertInstanceOf(result, JsonRpcError); + assertObjectMatch(result, { + message: 'Method execution error example', + code: -32000, + }); + }); + + it('correctly handles an error when provider is not found', async () => { + const providerName = 'error-provider'; + const result = await videoconfHandler(`videoconference:${providerName}:method`, []); + + assertInstanceOf(result, JsonRpcError); + assertObjectMatch(result, { + message: `Provider ${providerName} not found`, + code: -32000, + }); + }); + + it('correctly handles an error if method is not a function of provider', async () => { + const methodName = 'notAFunction'; + const providerName = 'test-provider'; + const result = await videoconfHandler(`videoconference:${providerName}:${methodName}`, []); + + assertInstanceOf(result, JsonRpcError); + assertObjectMatch(result, { + message: 'Method not found', + code: -32601, + data: { + message: `Method ${methodName} not found on provider ${providerName}`, + }, + }); + }); +}); diff --git a/packages/apps-engine/deno-runtime/handlers/uikit/handler.ts b/packages/apps-engine/deno-runtime/handlers/uikit/handler.ts new file mode 100644 index 000000000000..5a418f242ad9 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/uikit/handler.ts @@ -0,0 +1,82 @@ +import { Defined, JsonRpcError } from 'jsonrpc-lite'; +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import { require } from '../../lib/require.ts'; +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../../lib/accessors/mod.ts'; + +export const uikitInteractions = [ + 'executeBlockActionHandler', + 'executeViewSubmitHandler', + 'executeViewClosedHandler', + 'executeActionButtonHandler', + 'executeLivechatBlockActionHandler', +]; + +export const { + UIKitBlockInteractionContext, + UIKitViewSubmitInteractionContext, + UIKitViewCloseInteractionContext, + UIKitActionButtonInteractionContext, +} = require('@rocket.chat/apps-engine/definition/uikit/UIKitInteractionContext.js'); + +export const { UIKitLivechatBlockInteractionContext } = require('@rocket.chat/apps-engine/definition/uikit/livechat/UIKitLivechatInteractionContext.js'); + +export default async function handleUIKitInteraction(method: string, params: unknown): Promise { + if (!uikitInteractions.includes(method)) { + return JsonRpcError.methodNotFound(null); + } + + if (!Array.isArray(params)) { + return JsonRpcError.invalidParams(null); + } + + const app = AppObjectRegistry.get('app'); + + const interactionHandler = app?.[method as keyof App] as unknown; + + if (!app || typeof interactionHandler !== 'function') { + return JsonRpcError.methodNotFound({ + message: `App does not implement method "${method}"`, + }); + } + + const [payload] = params as [Record]; + + if (!payload) { + return JsonRpcError.invalidParams(null); + } + + let context; + + switch (method) { + case 'executeBlockActionHandler': + context = new UIKitBlockInteractionContext(payload); + break; + case 'executeViewSubmitHandler': + context = new UIKitViewSubmitInteractionContext(payload); + break; + case 'executeViewClosedHandler': + context = new UIKitViewCloseInteractionContext(payload); + break; + case 'executeActionButtonHandler': + context = new UIKitActionButtonInteractionContext(payload); + break; + case 'executeLivechatBlockActionHandler': + context = new UIKitLivechatBlockInteractionContext(payload); + break; + } + + try { + return await interactionHandler.call( + app, + context, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + AppAccessorsInstance.getModifier(), + ); + } catch (e) { + return JsonRpcError.internalError({ message: e.message }); + } +} diff --git a/packages/apps-engine/deno-runtime/handlers/videoconference-handler.ts b/packages/apps-engine/deno-runtime/handlers/videoconference-handler.ts new file mode 100644 index 000000000000..0347519db2e6 --- /dev/null +++ b/packages/apps-engine/deno-runtime/handlers/videoconference-handler.ts @@ -0,0 +1,49 @@ +import { Defined, JsonRpcError } from 'jsonrpc-lite'; +import type { IVideoConfProvider } from '@rocket.chat/apps-engine/definition/videoConfProviders/IVideoConfProvider.ts'; + +import { AppObjectRegistry } from '../AppObjectRegistry.ts'; +import { AppAccessorsInstance } from '../lib/accessors/mod.ts'; +import { Logger } from '../lib/logger.ts'; + +export default async function videoConferenceHandler(call: string, params: unknown): Promise { + const [, providerName, methodName] = call.split(':'); + + const provider = AppObjectRegistry.get(`videoConfProvider:${providerName}`); + const logger = AppObjectRegistry.get('logger'); + + if (!provider) { + return new JsonRpcError(`Provider ${providerName} not found`, -32000); + } + + const method = provider[methodName as keyof IVideoConfProvider]; + + if (typeof method !== 'function') { + return JsonRpcError.methodNotFound({ + message: `Method ${methodName} not found on provider ${providerName}`, + }); + } + + const [videoconf, user, options] = params as Array; + + logger?.debug(`Executing ${methodName} on video conference provider...`); + + const args = [...(videoconf ? [videoconf] : []), ...(user ? [user] : []), ...(options ? [options] : [])]; + + try { + // deno-lint-ignore ban-types + const result = await (method as Function).apply(provider, [ + ...args, + AppAccessorsInstance.getReader(), + AppAccessorsInstance.getModifier(), + AppAccessorsInstance.getHttp(), + AppAccessorsInstance.getPersistence(), + ]); + + logger?.debug(`Video Conference Provider's ${methodName} was successfully executed.`); + + return result; + } catch (e) { + logger?.debug(`Video Conference Provider's ${methodName} was unsuccessful.`); + return new JsonRpcError(e.message, -32000); + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/BlockBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/BlockBuilder.ts new file mode 100644 index 000000000000..e1602860fe97 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/BlockBuilder.ts @@ -0,0 +1,216 @@ +import { v1 as uuid } from 'uuid'; + +import type { + BlockType as _BlockType, + IActionsBlock, + IBlock, + IConditionalBlock, + IConditionalBlockFilters, + IContextBlock, + IImageBlock, + IInputBlock, + ISectionBlock, +} from '@rocket.chat/apps-engine/definition/uikit/blocks/Blocks.ts'; +import type { + BlockElementType as _BlockElementType, + IBlockElement, + IButtonElement, + IImageElement, + IInputElement, + IInteractiveElement, + IMultiStaticSelectElement, + IOverflowMenuElement, + IPlainTextInputElement, + ISelectElement, + IStaticSelectElement, +} from '@rocket.chat/apps-engine/definition/uikit/blocks/Elements.ts'; +import type { ITextObject, TextObjectType as _TextObjectType } from '@rocket.chat/apps-engine/definition/uikit/blocks/Objects.ts'; + +import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; +import { require } from '../../../lib/require.ts'; + +const { BlockType } = require('@rocket.chat/apps-engine/definition/uikit/blocks/Blocks.js') as { BlockType: typeof _BlockType }; +const { BlockElementType } = require('@rocket.chat/apps-engine/definition/uikit/blocks/Elements.js') as { BlockElementType: typeof _BlockElementType }; +const { TextObjectType } = require('@rocket.chat/apps-engine/definition/uikit/blocks/Objects.js') as { TextObjectType: typeof _TextObjectType }; + +type BlockFunctionParameter = Omit; +type ElementFunctionParameter = T extends IInteractiveElement + ? Omit | Partial> + : Omit; + +type SectionBlockParam = BlockFunctionParameter; +type ImageBlockParam = BlockFunctionParameter; +type ActionsBlockParam = BlockFunctionParameter; +type ContextBlockParam = BlockFunctionParameter; +type InputBlockParam = BlockFunctionParameter; + +type ButtonElementParam = ElementFunctionParameter; +type ImageElementParam = ElementFunctionParameter; +type OverflowMenuElementParam = ElementFunctionParameter; +type PlainTextInputElementParam = ElementFunctionParameter; +type StaticSelectElementParam = ElementFunctionParameter; +type MultiStaticSelectElementParam = ElementFunctionParameter; + +/** + * @deprecated please prefer the rocket.chat/ui-kit components + */ +export class BlockBuilder { + private readonly blocks: Array; + private readonly appId: string; + + constructor() { + this.blocks = []; + this.appId = String(AppObjectRegistry.get('id')); + } + + public addSectionBlock(block: SectionBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.SECTION, ...block } as ISectionBlock); + + return this; + } + + public addImageBlock(block: ImageBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.IMAGE, ...block } as IImageBlock); + + return this; + } + + public addDividerBlock(): BlockBuilder { + this.addBlock({ type: BlockType.DIVIDER }); + + return this; + } + + public addActionsBlock(block: ActionsBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.ACTIONS, ...block } as IActionsBlock); + + return this; + } + + public addContextBlock(block: ContextBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.CONTEXT, ...block } as IContextBlock); + + return this; + } + + public addInputBlock(block: InputBlockParam): BlockBuilder { + this.addBlock({ type: BlockType.INPUT, ...block } as IInputBlock); + + return this; + } + + public addConditionalBlock(innerBlocks: BlockBuilder | Array, condition?: IConditionalBlockFilters): BlockBuilder { + const render = innerBlocks instanceof BlockBuilder ? innerBlocks.getBlocks() : innerBlocks; + + this.addBlock({ + type: BlockType.CONDITIONAL, + render, + when: condition, + } as IConditionalBlock); + + return this; + } + + public getBlocks() { + return this.blocks; + } + + public newPlainTextObject(text: string, emoji = false): ITextObject { + return { + type: TextObjectType.PLAINTEXT, + text, + emoji, + }; + } + + public newMarkdownTextObject(text: string): ITextObject { + return { + type: TextObjectType.MARKDOWN, + text, + }; + } + + public newButtonElement(info: ButtonElementParam): IButtonElement { + return this.newInteractiveElement({ + type: BlockElementType.BUTTON, + ...info, + } as IButtonElement); + } + + public newImageElement(info: ImageElementParam): IImageElement { + return { + type: BlockElementType.IMAGE, + ...info, + }; + } + + public newOverflowMenuElement(info: OverflowMenuElementParam): IOverflowMenuElement { + return this.newInteractiveElement({ + type: BlockElementType.OVERFLOW_MENU, + ...info, + } as IOverflowMenuElement); + } + + public newPlainTextInputElement(info: PlainTextInputElementParam): IPlainTextInputElement { + return this.newInputElement({ + type: BlockElementType.PLAIN_TEXT_INPUT, + ...info, + } as IPlainTextInputElement); + } + + public newStaticSelectElement(info: StaticSelectElementParam): IStaticSelectElement { + return this.newSelectElement({ + type: BlockElementType.STATIC_SELECT, + ...info, + } as IStaticSelectElement); + } + + public newMultiStaticElement(info: MultiStaticSelectElementParam): IMultiStaticSelectElement { + return this.newSelectElement({ + type: BlockElementType.MULTI_STATIC_SELECT, + ...info, + } as IMultiStaticSelectElement); + } + + private newInteractiveElement(element: T): T { + if (!element.actionId) { + element.actionId = this.generateActionId(); + } + + return element; + } + + private newInputElement(element: T): T { + if (!element.actionId) { + element.actionId = this.generateActionId(); + } + + return element; + } + + private newSelectElement(element: T): T { + if (!element.actionId) { + element.actionId = this.generateActionId(); + } + + return element; + } + + private addBlock(block: IBlock): void { + if (!block.blockId) { + block.blockId = this.generateBlockId(); + } + + block.appId = this.appId; + + this.blocks.push(block); + } + + private generateBlockId(): string { + return uuid(); + } + + private generateActionId(): string { + return uuid(); + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/DiscussionBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/DiscussionBuilder.ts new file mode 100644 index 000000000000..e2c2dc021438 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/DiscussionBuilder.ts @@ -0,0 +1,59 @@ +import type { IDiscussionBuilder as _IDiscussionBuilder } from '@rocket.chat/apps-engine/definition/accessors/IDiscussionBuilder.ts'; +import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { IRoomBuilder } from '@rocket.chat/apps-engine/definition/accessors/IRoomBuilder.ts'; + +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; +import type { RoomType as _RoomType } from '@rocket.chat/apps-engine/definition/rooms/RoomType.ts'; + +import { RoomBuilder } from './RoomBuilder.ts'; +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType.js') as { RoomType: typeof _RoomType }; + +export interface IDiscussionBuilder extends _IDiscussionBuilder, IRoomBuilder {} + +export class DiscussionBuilder extends RoomBuilder implements IDiscussionBuilder { + public kind: _RocketChatAssociationModel.DISCUSSION; + + private reply?: string; + + private parentMessage?: IMessage; + + constructor(data?: Partial) { + super(data); + this.kind = RocketChatAssociationModel.DISCUSSION; + this.room.type = RoomType.PRIVATE_GROUP; + } + + public setParentRoom(parentRoom: IRoom): IDiscussionBuilder { + this.room.parentRoom = parentRoom; + return this; + } + + public getParentRoom(): IRoom { + return this.room.parentRoom!; + } + + public setReply(reply: string): IDiscussionBuilder { + this.reply = reply; + return this; + } + + public getReply(): string { + return this.reply!; + } + + public setParentMessage(parentMessage: IMessage): IDiscussionBuilder { + this.parentMessage = parentMessage; + return this; + } + + public getParentMessage(): IMessage { + return this.parentMessage!; + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/LivechatMessageBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/LivechatMessageBuilder.ts new file mode 100644 index 000000000000..a12024ab7b5d --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/LivechatMessageBuilder.ts @@ -0,0 +1,204 @@ +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; +import type { RoomType as _RoomType } from '@rocket.chat/apps-engine/definition/rooms/RoomType.ts'; + +import type { ILivechatMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/ILivechatMessageBuilder.ts'; +import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; +import type { IMessageAttachment } from '@rocket.chat/apps-engine/definition/messages/IMessageAttachment.ts'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; +import type { ILivechatMessage as EngineLivechatMessage } from '@rocket.chat/apps-engine/definition/livechat/ILivechatMessage.ts'; +import type { IVisitor } from '@rocket.chat/apps-engine/definition/livechat/IVisitor.ts'; +import type { IMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/IMessageBuilder.ts'; + +import { MessageBuilder } from './MessageBuilder.ts'; +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType.js') as { RoomType: typeof _RoomType }; + +export interface ILivechatMessage extends EngineLivechatMessage, IMessage {} + +export class LivechatMessageBuilder implements ILivechatMessageBuilder { + public kind: _RocketChatAssociationModel.LIVECHAT_MESSAGE; + + private msg: ILivechatMessage; + + constructor(message?: ILivechatMessage) { + this.kind = RocketChatAssociationModel.LIVECHAT_MESSAGE; + this.msg = message || ({} as ILivechatMessage); + } + + public setData(data: ILivechatMessage): ILivechatMessageBuilder { + delete data.id; + this.msg = data; + + return this; + } + + public setRoom(room: IRoom): ILivechatMessageBuilder { + this.msg.room = room; + return this; + } + + public getRoom(): IRoom { + return this.msg.room; + } + + public setSender(sender: IUser): ILivechatMessageBuilder { + this.msg.sender = sender; + delete this.msg.visitor; + + return this; + } + + public getSender(): IUser { + return this.msg.sender; + } + + public setText(text: string): ILivechatMessageBuilder { + this.msg.text = text; + return this; + } + + public getText(): string { + return this.msg.text!; + } + + public setEmojiAvatar(emoji: string): ILivechatMessageBuilder { + this.msg.emoji = emoji; + return this; + } + + public getEmojiAvatar(): string { + return this.msg.emoji!; + } + + public setAvatarUrl(avatarUrl: string): ILivechatMessageBuilder { + this.msg.avatarUrl = avatarUrl; + return this; + } + + public getAvatarUrl(): string { + return this.msg.avatarUrl!; + } + + public setUsernameAlias(alias: string): ILivechatMessageBuilder { + this.msg.alias = alias; + return this; + } + + public getUsernameAlias(): string { + return this.msg.alias!; + } + + public addAttachment(attachment: IMessageAttachment): ILivechatMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } + + this.msg.attachments.push(attachment); + return this; + } + + public setAttachments(attachments: Array): ILivechatMessageBuilder { + this.msg.attachments = attachments; + return this; + } + + public getAttachments(): Array { + return this.msg.attachments!; + } + + public replaceAttachment(position: number, attachment: IMessageAttachment): ILivechatMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } + + if (!this.msg.attachments[position]) { + throw new Error(`No attachment found at the index of "${position}" to replace.`); + } + + this.msg.attachments[position] = attachment; + return this; + } + + public removeAttachment(position: number): ILivechatMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } + + if (!this.msg.attachments[position]) { + throw new Error(`No attachment found at the index of "${position}" to remove.`); + } + + this.msg.attachments.splice(position, 1); + + return this; + } + + public setEditor(user: IUser): ILivechatMessageBuilder { + this.msg.editor = user; + return this; + } + + public getEditor(): IUser { + return this.msg.editor; + } + + public setGroupable(groupable: boolean): ILivechatMessageBuilder { + this.msg.groupable = groupable; + return this; + } + + public getGroupable(): boolean { + return this.msg.groupable!; + } + + public setParseUrls(parseUrls: boolean): ILivechatMessageBuilder { + this.msg.parseUrls = parseUrls; + return this; + } + + public getParseUrls(): boolean { + return this.msg.parseUrls!; + } + + public setToken(token: string): ILivechatMessageBuilder { + this.msg.token = token; + return this; + } + + public getToken(): string { + return this.msg.token!; + } + + public setVisitor(visitor: IVisitor): ILivechatMessageBuilder { + this.msg.visitor = visitor; + delete this.msg.sender; + + return this; + } + + public getVisitor(): IVisitor { + return this.msg.visitor; + } + + public getMessage(): ILivechatMessage { + if (!this.msg.room) { + throw new Error('The "room" property is required.'); + } + + if (this.msg.room.type !== RoomType.LIVE_CHAT) { + throw new Error('The room is not a Livechat room'); + } + + return this.msg; + } + + public getMessageBuilder(): IMessageBuilder { + return new MessageBuilder(this.msg as IMessage); + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/MessageBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/MessageBuilder.ts new file mode 100644 index 000000000000..98cd919f7b00 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/MessageBuilder.ts @@ -0,0 +1,232 @@ +import { LayoutBlock } from '@rocket.chat/ui-kit'; + +import type { IMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/IMessageBuilder.ts'; +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; +import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; +import type { IMessageAttachment } from '@rocket.chat/apps-engine/definition/messages/IMessageAttachment.ts'; +import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { IBlock } from '@rocket.chat/apps-engine/definition/uikit/blocks/Blocks.ts'; + +import { BlockBuilder } from './BlockBuilder.ts'; +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export class MessageBuilder implements IMessageBuilder { + public kind: _RocketChatAssociationModel.MESSAGE; + + private msg: IMessage; + + constructor(message?: IMessage) { + this.kind = RocketChatAssociationModel.MESSAGE; + this.msg = message || ({} as IMessage); + } + + public setData(data: IMessage): IMessageBuilder { + delete data.id; + this.msg = data; + + return this as IMessageBuilder; + } + + public setUpdateData(data: IMessage, editor: IUser): IMessageBuilder { + this.msg = data; + this.msg.editor = editor; + this.msg.editedAt = new Date(); + + return this as IMessageBuilder; + } + + public setThreadId(threadId: string): IMessageBuilder { + this.msg.threadId = threadId; + + return this as IMessageBuilder; + } + + public getThreadId(): string { + return this.msg.threadId!; + } + + public setRoom(room: IRoom): IMessageBuilder { + this.msg.room = room; + return this as IMessageBuilder; + } + + public getRoom(): IRoom { + return this.msg.room; + } + + public setSender(sender: IUser): IMessageBuilder { + this.msg.sender = sender; + return this as IMessageBuilder; + } + + public getSender(): IUser { + return this.msg.sender; + } + + public setText(text: string): IMessageBuilder { + this.msg.text = text; + return this as IMessageBuilder; + } + + public getText(): string { + return this.msg.text!; + } + + public setEmojiAvatar(emoji: string): IMessageBuilder { + this.msg.emoji = emoji; + return this as IMessageBuilder; + } + + public getEmojiAvatar(): string { + return this.msg.emoji!; + } + + public setAvatarUrl(avatarUrl: string): IMessageBuilder { + this.msg.avatarUrl = avatarUrl; + return this as IMessageBuilder; + } + + public getAvatarUrl(): string { + return this.msg.avatarUrl!; + } + + public setUsernameAlias(alias: string): IMessageBuilder { + this.msg.alias = alias; + return this as IMessageBuilder; + } + + public getUsernameAlias(): string { + return this.msg.alias!; + } + + public addAttachment(attachment: IMessageAttachment): IMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } + + this.msg.attachments.push(attachment); + return this as IMessageBuilder; + } + + public setAttachments(attachments: Array): IMessageBuilder { + this.msg.attachments = attachments; + return this as IMessageBuilder; + } + + public getAttachments(): Array { + return this.msg.attachments!; + } + + public replaceAttachment(position: number, attachment: IMessageAttachment): IMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } + + if (!this.msg.attachments[position]) { + throw new Error(`No attachment found at the index of "${position}" to replace.`); + } + + this.msg.attachments[position] = attachment; + return this as IMessageBuilder; + } + + public removeAttachment(position: number): IMessageBuilder { + if (!this.msg.attachments) { + this.msg.attachments = []; + } + + if (!this.msg.attachments[position]) { + throw new Error(`No attachment found at the index of "${position}" to remove.`); + } + + this.msg.attachments.splice(position, 1); + + return this as IMessageBuilder; + } + + public setEditor(user: IUser): IMessageBuilder { + this.msg.editor = user; + return this as IMessageBuilder; + } + + public getEditor(): IUser { + return this.msg.editor; + } + + public setGroupable(groupable: boolean): IMessageBuilder { + this.msg.groupable = groupable; + return this as IMessageBuilder; + } + + public getGroupable(): boolean { + return this.msg.groupable!; + } + + public setParseUrls(parseUrls: boolean): IMessageBuilder { + this.msg.parseUrls = parseUrls; + return this as IMessageBuilder; + } + + public getParseUrls(): boolean { + return this.msg.parseUrls!; + } + + public getMessage(): IMessage { + if (!this.msg.room) { + throw new Error('The "room" property is required.'); + } + + return this.msg; + } + + public addBlocks(blocks: BlockBuilder | Array) { + if (!Array.isArray(this.msg.blocks)) { + this.msg.blocks = []; + } + + if (blocks instanceof BlockBuilder) { + this.msg.blocks.push(...blocks.getBlocks()); + } else { + this.msg.blocks.push(...blocks); + } + + return this as IMessageBuilder; + } + + public setBlocks(blocks: BlockBuilder | Array) { + if (blocks instanceof BlockBuilder) { + this.msg.blocks = blocks.getBlocks(); + } else { + this.msg.blocks = blocks; + } + + return this as IMessageBuilder; + } + + public getBlocks() { + return this.msg.blocks!; + } + + public addCustomField(key: string, value: unknown): IMessageBuilder { + if (!this.msg.customFields) { + this.msg.customFields = {}; + } + + if (this.msg.customFields[key]) { + throw new Error(`The message already contains a custom field by the key: ${key}`); + } + + if (key.includes('.')) { + throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); + } + + this.msg.customFields[key] = value; + + return this as IMessageBuilder; + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/RoomBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/RoomBuilder.ts new file mode 100644 index 000000000000..38983475162d --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/RoomBuilder.ts @@ -0,0 +1,163 @@ +import type { IRoomBuilder } from '@rocket.chat/apps-engine/definition/accessors/IRoomBuilder.ts'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; + +import type { RoomType } from '@rocket.chat/apps-engine/definition/rooms/RoomType.ts'; +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; + +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export class RoomBuilder implements IRoomBuilder { + public kind: _RocketChatAssociationModel.ROOM | _RocketChatAssociationModel.DISCUSSION; + + protected room: IRoom; + + private members: Array; + + constructor(data?: Partial) { + this.kind = RocketChatAssociationModel.ROOM; + this.room = (data || { customFields: {} }) as IRoom; + this.members = []; + } + + public setData(data: Partial): IRoomBuilder { + delete data.id; + this.room = data as IRoom; + + return this; + } + + public setDisplayName(name: string): IRoomBuilder { + this.room.displayName = name; + return this; + } + + public getDisplayName(): string { + return this.room.displayName!; + } + + public setSlugifiedName(name: string): IRoomBuilder { + this.room.slugifiedName = name; + return this; + } + + public getSlugifiedName(): string { + return this.room.slugifiedName; + } + + public setType(type: RoomType): IRoomBuilder { + this.room.type = type; + return this; + } + + public getType(): RoomType { + return this.room.type; + } + + public setCreator(creator: IUser): IRoomBuilder { + this.room.creator = creator; + return this; + } + + public getCreator(): IUser { + return this.room.creator; + } + + /** + * @deprecated + */ + public addUsername(username: string): IRoomBuilder { + this.addMemberToBeAddedByUsername(username); + return this; + } + + /** + * @deprecated + */ + public setUsernames(usernames: Array): IRoomBuilder { + this.setMembersToBeAddedByUsernames(usernames); + return this; + } + + /** + * @deprecated + */ + public getUsernames(): Array { + const usernames = this.getMembersToBeAddedUsernames(); + if (usernames && usernames.length > 0) { + return usernames; + } + return this.room.usernames || []; + } + + public addMemberToBeAddedByUsername(username: string): IRoomBuilder { + this.members.push(username); + return this; + } + + public setMembersToBeAddedByUsernames(usernames: Array): IRoomBuilder { + this.members = usernames; + return this; + } + + public getMembersToBeAddedUsernames(): Array { + return this.members; + } + + public setDefault(isDefault: boolean): IRoomBuilder { + this.room.isDefault = isDefault; + return this; + } + + public getIsDefault(): boolean { + return this.room.isDefault!; + } + + public setReadOnly(isReadOnly: boolean): IRoomBuilder { + this.room.isReadOnly = isReadOnly; + return this; + } + + public getIsReadOnly(): boolean { + return this.room.isReadOnly!; + } + + public setDisplayingOfSystemMessages(displaySystemMessages: boolean): IRoomBuilder { + this.room.displaySystemMessages = displaySystemMessages; + return this; + } + + public getDisplayingOfSystemMessages(): boolean { + return this.room.displaySystemMessages!; + } + + public addCustomField(key: string, value: object): IRoomBuilder { + if (typeof this.room.customFields !== 'object') { + this.room.customFields = {}; + } + + this.room.customFields[key] = value; + return this; + } + + public setCustomFields(fields: { [key: string]: object }): IRoomBuilder { + this.room.customFields = fields; + return this; + } + + public getCustomFields(): { [key: string]: object } { + return this.room.customFields!; + } + + public getUserIds(): Array { + return this.room.userIds!; + } + + public getRoom(): IRoom { + return this.room; + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/UserBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/UserBuilder.ts new file mode 100644 index 000000000000..01c11a13f7a3 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/UserBuilder.ts @@ -0,0 +1,81 @@ +import type { IUserBuilder } from '@rocket.chat/apps-engine/definition/accessors/IUserBuilder.ts'; +import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; +import type { IUserSettings } from '@rocket.chat/apps-engine/definition/users/IUserSettings.ts'; +import type { IUserEmail } from '@rocket.chat/apps-engine/definition/users/IUserEmail.ts'; +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; + +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export class UserBuilder implements IUserBuilder { + public kind: _RocketChatAssociationModel.USER; + + private user: Partial; + + constructor(user?: Partial) { + this.kind = RocketChatAssociationModel.USER; + this.user = user || ({} as Partial); + } + + public setData(data: Partial): IUserBuilder { + delete data.id; + this.user = data; + + return this; + } + + public setEmails(emails: Array): IUserBuilder { + this.user.emails = emails; + return this; + } + + public getEmails(): Array { + return this.user.emails!; + } + + public setDisplayName(name: string): IUserBuilder { + this.user.name = name; + return this; + } + + public getDisplayName(): string { + return this.user.name!; + } + + public setUsername(username: string): IUserBuilder { + this.user.username = username; + return this; + } + + public getUsername(): string { + return this.user.username!; + } + + public setRoles(roles: Array): IUserBuilder { + this.user.roles = roles; + return this; + } + + public getRoles(): Array { + return this.user.roles!; + } + + public getSettings(): Partial { + return this.user.settings; + } + + public getUser(): Partial { + if (!this.user.username) { + throw new Error('The "username" property is required.'); + } + + if (!this.user.name) { + throw new Error('The "name" property is required.'); + } + + return this.user; + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/builders/VideoConferenceBuilder.ts b/packages/apps-engine/deno-runtime/lib/accessors/builders/VideoConferenceBuilder.ts new file mode 100644 index 000000000000..e617cdddf154 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/builders/VideoConferenceBuilder.ts @@ -0,0 +1,94 @@ +import type { IVideoConferenceBuilder } from '@rocket.chat/apps-engine/definition/accessors/IVideoConferenceBuilder.ts'; +import type { IGroupVideoConference } from '@rocket.chat/apps-engine/definition/videoConferences/IVideoConference.ts'; + +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; + +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export type AppVideoConference = Pick & { + createdBy: IGroupVideoConference['createdBy']['_id']; +}; + +export class VideoConferenceBuilder implements IVideoConferenceBuilder { + public kind: _RocketChatAssociationModel.VIDEO_CONFERENCE = RocketChatAssociationModel.VIDEO_CONFERENCE; + + protected call: AppVideoConference; + + constructor(data?: Partial) { + this.call = (data || {}) as AppVideoConference; + } + + public setData(data: Partial): IVideoConferenceBuilder { + this.call = { + rid: data.rid!, + createdBy: data.createdBy, + providerName: data.providerName!, + title: data.title!, + discussionRid: data.discussionRid, + }; + + return this; + } + + public setRoomId(rid: string): IVideoConferenceBuilder { + this.call.rid = rid; + return this; + } + + public getRoomId(): string { + return this.call.rid; + } + + public setCreatedBy(userId: string): IVideoConferenceBuilder { + this.call.createdBy = userId; + return this; + } + + public getCreatedBy(): string { + return this.call.createdBy; + } + + public setProviderName(userId: string): IVideoConferenceBuilder { + this.call.providerName = userId; + return this; + } + + public getProviderName(): string { + return this.call.providerName; + } + + public setProviderData(data: Record | undefined): IVideoConferenceBuilder { + this.call.providerData = data; + return this; + } + + public getProviderData(): Record { + return this.call.providerData!; + } + + public setTitle(userId: string): IVideoConferenceBuilder { + this.call.title = userId; + return this; + } + + public getTitle(): string { + return this.call.title; + } + + public setDiscussionRid(rid: AppVideoConference['discussionRid']): IVideoConferenceBuilder { + this.call.discussionRid = rid; + return this; + } + + public getDiscussionRid(): AppVideoConference['discussionRid'] { + return this.call.discussionRid; + } + + public getVideoConference(): AppVideoConference { + return this.call; + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/extenders/HttpExtender.ts b/packages/apps-engine/deno-runtime/lib/accessors/extenders/HttpExtender.ts new file mode 100644 index 000000000000..c323d385de9d --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/extenders/HttpExtender.ts @@ -0,0 +1,62 @@ +import type { + IHttpExtend, + IHttpPreRequestHandler, + IHttpPreResponseHandler +} from "@rocket.chat/apps-engine/definition/accessors/IHttp.ts"; + +export class HttpExtend implements IHttpExtend { + private headers: Map; + + private params: Map; + + private requests: Array; + + private responses: Array; + + constructor() { + this.headers = new Map(); + this.params = new Map(); + this.requests = []; + this.responses = []; + } + + public provideDefaultHeader(key: string, value: string): void { + this.headers.set(key, value); + } + + public provideDefaultHeaders(headers: { [key: string]: string }): void { + Object.keys(headers).forEach((key) => this.headers.set(key, headers[key])); + } + + public provideDefaultParam(key: string, value: string): void { + this.params.set(key, value); + } + + public provideDefaultParams(params: { [key: string]: string }): void { + Object.keys(params).forEach((key) => this.params.set(key, params[key])); + } + + public providePreRequestHandler(handler: IHttpPreRequestHandler): void { + this.requests.push(handler); + } + + public providePreResponseHandler(handler: IHttpPreResponseHandler): void { + this.responses.push(handler); + } + + public getDefaultHeaders(): Map { + return new Map(this.headers); + } + + public getDefaultParams(): Map { + return new Map(this.params); + } + + public getPreRequestHandlers(): Array { + return Array.from(this.requests); + } + + public getPreResponseHandlers(): Array { + return Array.from(this.responses); + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/extenders/MessageExtender.ts b/packages/apps-engine/deno-runtime/lib/accessors/extenders/MessageExtender.ts new file mode 100644 index 000000000000..abf1629c760a --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/extenders/MessageExtender.ts @@ -0,0 +1,66 @@ +import type { IMessageExtender } from '@rocket.chat/apps-engine/definition/accessors/IMessageExtender.ts'; +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; +import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; +import type { IMessageAttachment } from '@rocket.chat/apps-engine/definition/messages/IMessageAttachment.ts'; + +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export class MessageExtender implements IMessageExtender { + public readonly kind: _RocketChatAssociationModel.MESSAGE; + + constructor(private msg: IMessage) { + this.kind = RocketChatAssociationModel.MESSAGE; + + if (!Array.isArray(msg.attachments)) { + this.msg.attachments = []; + } + } + + public addCustomField(key: string, value: unknown): IMessageExtender { + if (!this.msg.customFields) { + this.msg.customFields = {}; + } + + if (this.msg.customFields[key]) { + throw new Error(`The message already contains a custom field by the key: ${key}`); + } + + if (key.includes('.')) { + throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); + } + + this.msg.customFields[key] = value; + + return this; + } + + public addAttachment(attachment: IMessageAttachment): IMessageExtender { + this.ensureAttachment(); + + this.msg.attachments!.push(attachment); + + return this; + } + + public addAttachments(attachments: Array): IMessageExtender { + this.ensureAttachment(); + + this.msg.attachments = this.msg.attachments!.concat(attachments); + + return this; + } + + public getMessage(): IMessage { + return structuredClone(this.msg); + } + + private ensureAttachment(): void { + if (!Array.isArray(this.msg.attachments)) { + this.msg.attachments = []; + } + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/extenders/RoomExtender.ts b/packages/apps-engine/deno-runtime/lib/accessors/extenders/RoomExtender.ts new file mode 100644 index 000000000000..6509d5dae90e --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/extenders/RoomExtender.ts @@ -0,0 +1,61 @@ +import type { IRoomExtender } from '@rocket.chat/apps-engine/definition/accessors/IRoomExtender.ts'; +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; + +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export class RoomExtender implements IRoomExtender { + public kind: _RocketChatAssociationModel.ROOM; + + private members: Array; + + constructor(private room: IRoom) { + this.kind = RocketChatAssociationModel.ROOM; + this.members = []; + } + + public addCustomField(key: string, value: unknown): IRoomExtender { + if (!this.room.customFields) { + this.room.customFields = {}; + } + + if (this.room.customFields[key]) { + throw new Error(`The room already contains a custom field by the key: ${key}`); + } + + if (key.includes('.')) { + throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); + } + + this.room.customFields[key] = value; + + return this; + } + + public addMember(user: IUser): IRoomExtender { + if (this.members.find((u) => u.username === user.username)) { + throw new Error('The user is already in the room.'); + } + + this.members.push(user); + + return this; + } + + public getMembersBeingAdded(): Array { + return this.members; + } + + public getUsernamesOfMembersBeingAdded(): Array { + return this.members.map((u) => u.username); + } + + public getRoom(): IRoom { + return structuredClone(this.room); + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/extenders/VideoConferenceExtend.ts b/packages/apps-engine/deno-runtime/lib/accessors/extenders/VideoConferenceExtend.ts new file mode 100644 index 000000000000..9616bf619067 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/extenders/VideoConferenceExtend.ts @@ -0,0 +1,69 @@ +import type { IVideoConferenceExtender } from '@rocket.chat/apps-engine/definition/accessors/IVideoConferenceExtend.ts'; +import type { VideoConference, VideoConferenceMember } from '@rocket.chat/apps-engine/definition/videoConferences/IVideoConference.ts'; +import type { IVideoConferenceUser } from '@rocket.chat/apps-engine/definition/videoConferences/IVideoConferenceUser.ts'; +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; + +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export class VideoConferenceExtender implements IVideoConferenceExtender { + public kind: _RocketChatAssociationModel.VIDEO_CONFERENCE; + + constructor(private videoConference: VideoConference) { + this.kind = RocketChatAssociationModel.VIDEO_CONFERENCE; + } + + public setProviderData(value: Record): IVideoConferenceExtender { + this.videoConference.providerData = value; + + return this; + } + + public setStatus(value: VideoConference['status']): IVideoConferenceExtender { + this.videoConference.status = value; + + return this; + } + + public setEndedBy(value: IVideoConferenceUser['_id']): IVideoConferenceExtender { + this.videoConference.endedBy = { + _id: value, + // Name and username will be loaded automatically by the bridge + username: '', + name: '', + }; + + return this; + } + + public setEndedAt(value: VideoConference['endedAt']): IVideoConferenceExtender { + this.videoConference.endedAt = value; + + return this; + } + + public addUser(userId: VideoConferenceMember['_id'], ts?: VideoConferenceMember['ts']): IVideoConferenceExtender { + this.videoConference.users.push({ + _id: userId, + ts, + // Name and username will be loaded automatically by the bridge + username: '', + name: '', + }); + + return this; + } + + public setDiscussionRid(rid: VideoConference['discussionRid']): IVideoConferenceExtender { + this.videoConference.discussionRid = rid; + + return this; + } + + public getVideoConference(): VideoConference { + return structuredClone(this.videoConference); + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/http.ts b/packages/apps-engine/deno-runtime/lib/accessors/http.ts new file mode 100644 index 000000000000..f55838e60186 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/http.ts @@ -0,0 +1,92 @@ +import type { + IHttp, + IHttpExtend, + IHttpRequest, + IHttpResponse, +} from "@rocket.chat/apps-engine/definition/accessors/IHttp.ts"; +import type { IPersistence } from "@rocket.chat/apps-engine/definition/accessors/IPersistence.ts"; +import type { IRead } from "@rocket.chat/apps-engine/definition/accessors/IRead.ts"; + +import * as Messenger from '../messenger.ts'; +import { AppObjectRegistry } from "../../AppObjectRegistry.ts"; + +type RequestMethod = 'get' | 'post' | 'put' | 'head' | 'delete' | 'patch'; + +export class Http implements IHttp { + private httpExtender: IHttpExtend; + private read: IRead; + private persistence: IPersistence; + private senderFn: typeof Messenger.sendRequest; + + constructor(read: IRead, persistence: IPersistence, httpExtender: IHttpExtend, senderFn: typeof Messenger.sendRequest) { + this.read = read; + this.persistence = persistence; + this.httpExtender = httpExtender; + this.senderFn = senderFn; + // this.httpExtender = new HttpExtend(); + } + + public get(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'get', options); + } + + public put(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'put', options); + } + + public post(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'post', options); + } + + public del(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'delete', options); + } + + public patch(url: string, options?: IHttpRequest): Promise { + return this._processHandler(url, 'patch', options); + } + + private async _processHandler(url: string, method: RequestMethod, options?: IHttpRequest): Promise { + let request = options || {}; + + if (typeof request.headers === 'undefined') { + request.headers = {}; + } + + this.httpExtender.getDefaultHeaders().forEach((value: string, key: string) => { + if (typeof request.headers?.[key] !== 'string') { + request.headers![key] = value; + } + }); + + if (typeof request.params === 'undefined') { + request.params = {}; + } + + this.httpExtender.getDefaultParams().forEach((value: string, key: string) => { + if (typeof request.params?.[key] !== 'string') { + request.params![key] = value; + } + }); + + for (const handler of this.httpExtender.getPreRequestHandlers()) { + request = await handler.executePreHttpRequest(url, request, this.read, this.persistence); + } + + let { result: response } = await this.senderFn({ + method: `bridges:getHttpBridge:doCall`, + params: [{ + appId: AppObjectRegistry.get('id'), + method, + url, + request, + }], + }) + + for (const handler of this.httpExtender.getPreResponseHandlers()) { + response = await handler.executePreHttpResponse(response as IHttpResponse, this.read, this.persistence); + } + + return response as IHttpResponse; + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/mod.ts b/packages/apps-engine/deno-runtime/lib/accessors/mod.ts new file mode 100644 index 000000000000..e71f014421ab --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/mod.ts @@ -0,0 +1,302 @@ +import type { IAppAccessors } from '@rocket.chat/apps-engine/definition/accessors/IAppAccessors.ts'; +import type { IApiEndpointMetadata } from '@rocket.chat/apps-engine/definition/api/IApiEndpointMetadata.ts'; +import type { IEnvironmentWrite } from '@rocket.chat/apps-engine/definition/accessors/IEnvironmentWrite.ts'; +import type { IEnvironmentRead } from '@rocket.chat/apps-engine/definition/accessors/IEnvironmentRead.ts'; +import type { IConfigurationModify } from '@rocket.chat/apps-engine/definition/accessors/IConfigurationModify.ts'; +import type { IRead } from '@rocket.chat/apps-engine/definition/accessors/IRead.ts'; +import type { IModify } from '@rocket.chat/apps-engine/definition/accessors/IModify.ts'; +import type { INotifier } from '@rocket.chat/apps-engine/definition/accessors/INotifier.ts'; +import type { IPersistence } from '@rocket.chat/apps-engine/definition/accessors/IPersistence.ts'; +import type { IHttp, IHttpExtend } from '@rocket.chat/apps-engine/definition/accessors/IHttp.ts'; +import type { IConfigurationExtend } from '@rocket.chat/apps-engine/definition/accessors/IConfigurationExtend.ts'; +import type { ISlashCommand } from '@rocket.chat/apps-engine/definition/slashcommands/ISlashCommand.ts'; +import type { IProcessor } from '@rocket.chat/apps-engine/definition/scheduler/IProcessor.ts'; +import type { IApi } from '@rocket.chat/apps-engine/definition/api/IApi.ts'; +import type { IVideoConfProvider } from '@rocket.chat/apps-engine/definition/videoConfProviders/IVideoConfProvider.ts'; + +import { Http } from './http.ts'; +import { HttpExtend } from './extenders/HttpExtender.ts'; +import * as Messenger from '../messenger.ts'; +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { ModifyCreator } from './modify/ModifyCreator.ts'; +import { ModifyUpdater } from './modify/ModifyUpdater.ts'; +import { ModifyExtender } from './modify/ModifyExtender.ts'; +import { Notifier } from './notifier.ts'; + +const httpMethods = ['get', 'post', 'put', 'delete', 'head', 'options', 'patch'] as const; + +// We need to create this object first thing, as we'll handle references to it later on +if (!AppObjectRegistry.has('apiEndpoints')) { + AppObjectRegistry.set('apiEndpoints', []); +} + +export class AppAccessors { + private defaultAppAccessors?: IAppAccessors; + private environmentRead?: IEnvironmentRead; + private environmentWriter?: IEnvironmentWrite; + private configModifier?: IConfigurationModify; + private configExtender?: IConfigurationExtend; + private reader?: IRead; + private modifier?: IModify; + private persistence?: IPersistence; + private creator?: ModifyCreator; + private updater?: ModifyUpdater; + private extender?: ModifyExtender; + private httpExtend: IHttpExtend = new HttpExtend(); + private http?: IHttp; + private notifier?: INotifier; + + private proxify: (namespace: string, overrides?: Record unknown>) => T; + + constructor(private readonly senderFn: typeof Messenger.sendRequest) { + this.proxify = (namespace: string, overrides: Record unknown> = {}): T => + new Proxy( + { __kind: `accessor:${namespace}` }, + { + get: + (_target: unknown, prop: string) => + (...params: unknown[]) => { + // We don't want to send a request for this prop + if (prop === 'toJSON') { + return {}; + } + + // If the prop is inteded to be overriden by the caller + if (prop in overrides) { + return overrides[prop].apply(undefined, params); + } + + return senderFn({ + method: `accessor:${namespace}:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { throw new Error(err.error) }); + }, + }, + ) as T; + + this.http = new Http(this.getReader(), this.getPersistence(), this.httpExtend, this.getSenderFn()); + this.notifier = new Notifier(this.getSenderFn()); + } + + public getSenderFn() { + return this.senderFn; + } + + public getEnvironmentRead(): IEnvironmentRead { + if (!this.environmentRead) { + this.environmentRead = { + getSettings: () => this.proxify('getEnvironmentRead:getSettings'), + getServerSettings: () => this.proxify('getEnvironmentRead:getServerSettings'), + getEnvironmentVariables: () => this.proxify('getEnvironmentRead:getEnvironmentVariables'), + }; + } + + return this.environmentRead; + } + + public getEnvironmentWrite() { + if (!this.environmentWriter) { + this.environmentWriter = { + getSettings: () => this.proxify('getEnvironmentWrite:getSettings'), + getServerSettings: () => this.proxify('getEnvironmentWrite:getServerSettings'), + }; + } + + return this.environmentWriter; + } + + public getConfigurationModify() { + if (!this.configModifier) { + this.configModifier = { + scheduler: this.proxify('getConfigurationModify:scheduler'), + slashCommands: { + _proxy: this.proxify('getConfigurationModify:slashCommands'), + modifySlashCommand(slashcommand: ISlashCommand) { + // Store the slashcommand instance to use when the Apps-Engine calls the slashcommand + AppObjectRegistry.set(`slashcommand:${slashcommand.command}`, slashcommand); + + return this._proxy.modifySlashCommand(slashcommand); + }, + disableSlashCommand(command: string) { + return this._proxy.disableSlashCommand(command); + }, + enableSlashCommand(command: string) { + return this._proxy.enableSlashCommand(command); + }, + }, + serverSettings: this.proxify('getConfigurationModify:serverSettings'), + }; + } + + return this.configModifier; + } + + public getConfigurationExtend() { + if (!this.configExtender) { + const senderFn = this.senderFn; + + this.configExtender = { + ui: this.proxify('getConfigurationExtend:ui'), + http: this.httpExtend, + settings: this.proxify('getConfigurationExtend:settings'), + externalComponents: this.proxify('getConfigurationExtend:externalComponents'), + api: { + _proxy: this.proxify('getConfigurationExtend:api'), + async provideApi(api: IApi) { + const apiEndpoints = AppObjectRegistry.get('apiEndpoints')!; + + api.endpoints.forEach((endpoint) => { + endpoint._availableMethods = httpMethods.filter((method) => typeof endpoint[method] === 'function'); + + // We need to keep a reference to the endpoint around for us to call the executor later + AppObjectRegistry.set(`api:${endpoint.path}`, endpoint); + }); + + const result = await this._proxy.provideApi(api); + + // Let's call the listApis method to cache the info from the endpoints + // Also, since this is a side-effect, we do it async so we can return to the caller + senderFn({ method: 'accessor:api:listApis' }) + .then((response) => apiEndpoints.push(...(response.result as IApiEndpointMetadata[]))) + .catch((err) => err.error); + + return result; + }, + }, + scheduler: { + _proxy: this.proxify('getConfigurationExtend:scheduler'), + registerProcessors(processors: IProcessor[]) { + // Store the processor instance to use when the Apps-Engine calls the processor + processors.forEach((processor) => { + AppObjectRegistry.set(`scheduler:${processor.id}`, processor); + }); + + return this._proxy.registerProcessors(processors); + }, + }, + videoConfProviders: { + _proxy: this.proxify('getConfigurationExtend:videoConfProviders'), + provideVideoConfProvider(provider: IVideoConfProvider) { + // Store the videoConfProvider instance to use when the Apps-Engine calls the videoConfProvider + AppObjectRegistry.set(`videoConfProvider:${provider.name}`, provider); + + return this._proxy.provideVideoConfProvider(provider); + }, + }, + slashCommands: { + _proxy: this.proxify('getConfigurationExtend:slashCommands'), + provideSlashCommand(slashcommand: ISlashCommand) { + // Store the slashcommand instance to use when the Apps-Engine calls the slashcommand + AppObjectRegistry.set(`slashcommand:${slashcommand.command}`, slashcommand); + + return this._proxy.provideSlashCommand(slashcommand); + }, + }, + }; + } + + return this.configExtender; + } + + public getDefaultAppAccessors() { + if (!this.defaultAppAccessors) { + this.defaultAppAccessors = { + environmentReader: this.getEnvironmentRead(), + environmentWriter: this.getEnvironmentWrite(), + reader: this.getReader(), + http: this.getHttp(), + providedApiEndpoints: AppObjectRegistry.get('apiEndpoints') as IApiEndpointMetadata[], + }; + } + + return this.defaultAppAccessors; + } + + public getReader() { + if (!this.reader) { + this.reader = { + getEnvironmentReader: () => ({ + getSettings: () => this.proxify('getReader:getEnvironmentReader:getSettings'), + getServerSettings: () => this.proxify('getReader:getEnvironmentReader:getServerSettings'), + getEnvironmentVariables: () => this.proxify('getReader:getEnvironmentReader:getEnvironmentVariables'), + }), + getMessageReader: () => this.proxify('getReader:getMessageReader'), + getPersistenceReader: () => this.proxify('getReader:getPersistenceReader'), + getRoomReader: () => this.proxify('getReader:getRoomReader'), + getUserReader: () => this.proxify('getReader:getUserReader'), + getNotifier: () => this.getNotifier(), + getLivechatReader: () => this.proxify('getReader:getLivechatReader'), + getUploadReader: () => this.proxify('getReader:getUploadReader'), + getCloudWorkspaceReader: () => this.proxify('getReader:getCloudWorkspaceReader'), + getVideoConferenceReader: () => this.proxify('getReader:getVideoConferenceReader'), + getOAuthAppsReader: () => this.proxify('getReader:getOAuthAppsReader'), + getThreadReader: () => this.proxify('getReader:getThreadReader'), + getRoleReader: () => this.proxify('getReader:getRoleReader'), + }; + } + + return this.reader; + } + + public getModifier() { + if (!this.modifier) { + this.modifier = { + getCreator: this.getCreator.bind(this), + getUpdater: this.getUpdater.bind(this), + getExtender: this.getExtender.bind(this), + getDeleter: () => this.proxify('getModifier:getDeleter'), + getNotifier: () => this.getNotifier(), + getUiController: () => this.proxify('getModifier:getUiController'), + getScheduler: () => this.proxify('getModifier:getScheduler'), + getOAuthAppsModifier: () => this.proxify('getModifier:getOAuthAppsModifier'), + getModerationModifier: () => this.proxify('getModifier:getModerationModifier'), + }; + } + + return this.modifier; + } + + public getPersistence() { + if (!this.persistence) { + this.persistence = this.proxify('getPersistence'); + } + + return this.persistence; + } + + public getHttp() { + return this.http; + } + + private getCreator() { + if (!this.creator) { + this.creator = new ModifyCreator(this.senderFn); + } + + return this.creator; + } + + private getUpdater() { + if (!this.updater) { + this.updater = new ModifyUpdater(this.senderFn); + } + + return this.updater; + } + + private getExtender() { + if (!this.extender) { + this.extender = new ModifyExtender(this.senderFn); + } + + return this.extender; + } + + private getNotifier() { + return this.notifier; + } +} + +export const AppAccessorsInstance = new AppAccessors(Messenger.sendRequest); diff --git a/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyCreator.ts b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyCreator.ts new file mode 100644 index 000000000000..06797551a621 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyCreator.ts @@ -0,0 +1,344 @@ +import type { IModifyCreator } from '@rocket.chat/apps-engine/definition/accessors/IModifyCreator.ts'; +import type { IUploadCreator } from '@rocket.chat/apps-engine/definition/accessors/IUploadCreator.ts'; +import type { IEmailCreator } from '@rocket.chat/apps-engine/definition/accessors/IEmailCreator.ts'; +import type { ILivechatCreator } from '@rocket.chat/apps-engine/definition/accessors/ILivechatCreator.ts'; +import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { IBotUser } from '@rocket.chat/apps-engine/definition/users/IBotUser.ts'; +import type { UserType as _UserType } from '@rocket.chat/apps-engine/definition/users/UserType.ts'; +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; +import type { IMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/IMessageBuilder.ts'; +import type { IRoomBuilder } from '@rocket.chat/apps-engine/definition/accessors/IRoomBuilder.ts'; +import type { IUserBuilder } from '@rocket.chat/apps-engine/definition/accessors/IUserBuilder.ts'; +import type { IVideoConferenceBuilder } from '@rocket.chat/apps-engine/definition/accessors/IVideoConferenceBuilder.ts'; +import type { RoomType as _RoomType } from '@rocket.chat/apps-engine/definition/rooms/RoomType.ts'; +import type { ILivechatMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/ILivechatMessageBuilder.ts'; +import type { UIHelper as _UIHelper } from '@rocket.chat/apps-engine/server/misc/UIHelper.ts'; + +import * as Messenger from '../../messenger.ts'; + +import { BlockBuilder } from '../builders/BlockBuilder.ts'; +import { MessageBuilder } from '../builders/MessageBuilder.ts'; +import { DiscussionBuilder, IDiscussionBuilder } from '../builders/DiscussionBuilder.ts'; +import { ILivechatMessage, LivechatMessageBuilder } from '../builders/LivechatMessageBuilder.ts'; +import { RoomBuilder } from '../builders/RoomBuilder.ts'; +import { UserBuilder } from '../builders/UserBuilder.ts'; +import { AppVideoConference, VideoConferenceBuilder } from '../builders/VideoConferenceBuilder.ts'; +import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; +import { require } from '../../../lib/require.ts'; + +const { UIHelper } = require('@rocket.chat/apps-engine/server/misc/UIHelper.js') as { UIHelper: typeof _UIHelper }; +const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType.js') as { RoomType: typeof _RoomType }; +const { UserType } = require('@rocket.chat/apps-engine/definition/users/UserType.js') as { UserType: typeof _UserType }; +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export class ModifyCreator implements IModifyCreator { + constructor(private readonly senderFn: typeof Messenger.sendRequest) { } + + getLivechatCreator(): ILivechatCreator { + return new Proxy( + { __kind: 'getLivechatCreator' }, + { + get: (_target: unknown, prop: string) => { + // It's not worthwhile to make an asynchronous request for such a simple method + if (prop === 'createToken') { + return () => Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); + } + + if (prop === 'toJSON') { + return () => ({}); + } + + return (...params: unknown[]) => + this.senderFn({ + method: `accessor:getModifier:getCreator:getLivechatCreator:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + throw new Error(err.error); + }); + }, + }, + ) as ILivechatCreator; + } + + getUploadCreator(): IUploadCreator { + return new Proxy( + { __kind: 'getUploadCreator' }, + { + get: + (_target: unknown, prop: string) => + (...params: unknown[]) => + prop === 'toJSON' + ? {} + : this.senderFn({ + method: `accessor:getModifier:getCreator:getUploadCreator:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + throw new Error(err.error); + }), + }, + ) as IUploadCreator; + } + + getEmailCreator(): IEmailCreator { + return new Proxy( + { __kind: 'getEmailCreator' }, + { + get: (_target: unknown, prop: string) => + (...params: unknown[]) => + prop === 'toJSON' + ? {} + : this.senderFn({ + method: `accessor:getModifier:getCreator:getEmailCreator:${prop}`, + params + }) + .then((response) => response.result) + .catch((err) => { + throw new Error(err.error); + }), + } + ) + } + + getBlockBuilder() { + return new BlockBuilder(); + } + + startMessage(data?: IMessage) { + if (data) { + delete data.id; + } + + return new MessageBuilder(data); + } + + startLivechatMessage(data?: ILivechatMessage) { + if (data) { + delete data.id; + } + + return new LivechatMessageBuilder(data); + } + + startRoom(data?: IRoom) { + if (data) { + // @ts-ignore - this has been imported from the Apps-Engine + delete data.id; + } + + return new RoomBuilder(data); + } + + startDiscussion(data?: Partial) { + if (data) { + delete data.id; + } + + return new DiscussionBuilder(data); + } + + startVideoConference(data?: Partial) { + return new VideoConferenceBuilder(data); + } + + startBotUser(data?: Partial) { + if (data) { + delete data.id; + + const { roles } = data; + + if (roles?.length) { + const hasRole = roles + .map((role: string) => role.toLocaleLowerCase()) + .some((role: string) => role === 'admin' || role === 'owner' || role === 'moderator'); + + if (hasRole) { + throw new Error('Invalid role assigned to the user. Should not be admin, owner or moderator.'); + } + } + + if (!data.type) { + data.type = UserType.BOT; + } + } + + return new UserBuilder(data); + } + + public finish( + builder: IMessageBuilder | ILivechatMessageBuilder | IRoomBuilder | IDiscussionBuilder | IVideoConferenceBuilder | IUserBuilder, + ): Promise { + switch (builder.kind) { + case RocketChatAssociationModel.MESSAGE: + return this._finishMessage(builder as IMessageBuilder); + case RocketChatAssociationModel.LIVECHAT_MESSAGE: + return this._finishLivechatMessage(builder as ILivechatMessageBuilder); + case RocketChatAssociationModel.ROOM: + return this._finishRoom(builder as IRoomBuilder); + case RocketChatAssociationModel.DISCUSSION: + return this._finishDiscussion(builder as IDiscussionBuilder); + case RocketChatAssociationModel.VIDEO_CONFERENCE: + return this._finishVideoConference(builder as IVideoConferenceBuilder); + case RocketChatAssociationModel.USER: + return this._finishUser(builder as IUserBuilder); + default: + throw new Error('Invalid builder passed to the ModifyCreator.finish function.'); + } + } + + private async _finishMessage(builder: IMessageBuilder): Promise { + const result = builder.getMessage(); + delete result.id; + + if (!result.sender || !result.sender.id) { + const response = await this.senderFn({ + method: 'bridges:getUserBridge:doGetAppUser', + params: ['APP_ID'], + }); + + const appUser = response.result; + + if (!appUser) { + throw new Error('Invalid sender assigned to the message.'); + } + + result.sender = appUser; + } + + if (result.blocks?.length) { + // Can we move this elsewhere? This AppObjectRegistry usage doesn't really belong here, but where? + result.blocks = UIHelper.assignIds(result.blocks, AppObjectRegistry.get('id') || ''); + } + + const response = await this.senderFn({ + method: 'bridges:getMessageBridge:doCreate', + params: [result, AppObjectRegistry.get('id')], + }); + + return String(response.result); + } + + private async _finishLivechatMessage(builder: ILivechatMessageBuilder): Promise { + if (builder.getSender() && !builder.getVisitor()) { + return this._finishMessage(builder.getMessageBuilder()); + } + + const result = builder.getMessage(); + delete result.id; + + if (!result.token && (!result.visitor || !result.visitor.token)) { + throw new Error('Invalid visitor sending the message'); + } + + result.token = result.visitor ? result.visitor.token : result.token; + + const response = await this.senderFn({ + method: 'bridges:getLivechatBridge:doCreateMessage', + params: [result, AppObjectRegistry.get('id')], + }); + + return String(response.result); + } + + private async _finishRoom(builder: IRoomBuilder): Promise { + const result = builder.getRoom(); + delete result.id; + + if (!result.type) { + throw new Error('Invalid type assigned to the room.'); + } + + if (result.type !== RoomType.LIVE_CHAT) { + if (!result.creator || !result.creator.id) { + throw new Error('Invalid creator assigned to the room.'); + } + } + + if (result.type !== RoomType.DIRECT_MESSAGE) { + if (result.type !== RoomType.LIVE_CHAT) { + if (!result.slugifiedName || !result.slugifiedName.trim()) { + throw new Error('Invalid slugifiedName assigned to the room.'); + } + } + + if (!result.displayName || !result.displayName.trim()) { + throw new Error('Invalid displayName assigned to the room.'); + } + } + + const response = await this.senderFn({ + method: 'bridges:getRoomBridge:doCreate', + params: [result, builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')], + }); + + return String(response.result); + } + + private async _finishDiscussion(builder: IDiscussionBuilder): Promise { + const room = builder.getRoom(); + delete room.id; + + if (!room.creator || !room.creator.id) { + throw new Error('Invalid creator assigned to the discussion.'); + } + + if (!room.slugifiedName || !room.slugifiedName.trim()) { + throw new Error('Invalid slugifiedName assigned to the discussion.'); + } + + if (!room.displayName || !room.displayName.trim()) { + throw new Error('Invalid displayName assigned to the discussion.'); + } + + if (!room.parentRoom || !room.parentRoom.id) { + throw new Error('Invalid parentRoom assigned to the discussion.'); + } + + const response = await this.senderFn({ + method: 'bridges:getRoomBridge:doCreateDiscussion', + params: [room, builder.getParentMessage(), builder.getReply(), builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')], + }); + + return String(response.result); + } + + private async _finishVideoConference(builder: IVideoConferenceBuilder): Promise { + const videoConference = builder.getVideoConference(); + + if (!videoConference.createdBy) { + throw new Error('Invalid creator assigned to the video conference.'); + } + + if (!videoConference.providerName?.trim()) { + throw new Error('Invalid provider name assigned to the video conference.'); + } + + if (!videoConference.rid) { + throw new Error('Invalid roomId assigned to the video conference.'); + } + + const response = await this.senderFn({ + method: 'bridges:getVideoConferenceBridge:doCreate', + params: [videoConference, AppObjectRegistry.get('id')], + }); + + return String(response.result); + } + + private async _finishUser(builder: IUserBuilder): Promise { + const user = builder.getUser(); + + const response = await this.senderFn({ + method: 'bridges:getUserBridge:doCreate', + params: [user, AppObjectRegistry.get('id')], + }); + + return String(response.result); + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyExtender.ts b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyExtender.ts new file mode 100644 index 000000000000..c0793d015c64 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyExtender.ts @@ -0,0 +1,93 @@ +import type { IModifyExtender } from '@rocket.chat/apps-engine/definition/accessors/IModifyExtender.ts'; +import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; +import type { IMessageExtender } from '@rocket.chat/apps-engine/definition/accessors/IMessageExtender.ts'; +import type { IRoomExtender } from '@rocket.chat/apps-engine/definition/accessors/IRoomExtender.ts'; +import type { IVideoConferenceExtender } from '@rocket.chat/apps-engine/definition/accessors/IVideoConferenceExtend.ts'; +import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; +import type { VideoConference } from '@rocket.chat/apps-engine/definition/videoConferences/IVideoConference.ts'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; + +import * as Messenger from '../../messenger.ts'; +import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; +import { MessageExtender } from '../extenders/MessageExtender.ts'; +import { RoomExtender } from '../extenders/RoomExtender.ts'; +import { VideoConferenceExtender } from '../extenders/VideoConferenceExtend.ts'; +import { require } from '../../../lib/require.ts'; + +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export class ModifyExtender implements IModifyExtender { + constructor(private readonly senderFn: typeof Messenger.sendRequest) {} + + public async extendMessage(messageId: string, updater: IUser): Promise { + const result = await this.senderFn({ + method: 'bridges:getMessageBridge:doGetById', + params: [messageId, AppObjectRegistry.get('id')], + }); + + const msg = result.result as IMessage; + + msg.editor = updater; + msg.editedAt = new Date(); + + return new MessageExtender(msg); + } + + public async extendRoom(roomId: string, _updater: IUser): Promise { + const result = await this.senderFn({ + method: 'bridges:getRoomBridge:doGetById', + params: [roomId, AppObjectRegistry.get('id')], + }); + + const room = result.result as IRoom; + + room.updatedAt = new Date(); + + return new RoomExtender(room); + } + + public async extendVideoConference(id: string): Promise { + const result = await this.senderFn({ + method: 'bridges:getVideoConferenceBridge:doGetById', + params: [id, AppObjectRegistry.get('id')], + }); + + const call = result.result as VideoConference; + + call._updatedAt = new Date(); + + return new VideoConferenceExtender(call); + } + + public async finish(extender: IMessageExtender | IRoomExtender | IVideoConferenceExtender): Promise { + switch (extender.kind) { + case RocketChatAssociationModel.MESSAGE: + await this.senderFn({ + method: 'bridges:getMessageBridge:doUpdate', + params: [(extender as IMessageExtender).getMessage(), AppObjectRegistry.get('id')], + }); + break; + case RocketChatAssociationModel.ROOM: + await this.senderFn({ + method: 'bridges:getRoomBridge:doUpdate', + params: [ + (extender as IRoomExtender).getRoom(), + (extender as IRoomExtender).getUsernamesOfMembersBeingAdded(), + AppObjectRegistry.get('id'), + ], + }); + break; + case RocketChatAssociationModel.VIDEO_CONFERENCE: + await this.senderFn({ + method: 'bridges:getVideoConferenceBridge:doUpdate', + params: [(extender as IVideoConferenceExtender).getVideoConference(), AppObjectRegistry.get('id')], + }); + break; + default: + throw new Error('Invalid extender passed to the ModifyExtender.finish function.'); + } + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyUpdater.ts b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyUpdater.ts new file mode 100644 index 000000000000..8befe7bfa983 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/modify/ModifyUpdater.ts @@ -0,0 +1,153 @@ +import type { IModifyUpdater } from '@rocket.chat/apps-engine/definition/accessors/IModifyUpdater.ts'; +import type { ILivechatUpdater } from '@rocket.chat/apps-engine/definition/accessors/ILivechatUpdater.ts'; +import type { IUserUpdater } from '@rocket.chat/apps-engine/definition/accessors/IUserUpdater.ts'; +import type { IMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/IMessageBuilder.ts'; +import type { IRoomBuilder } from '@rocket.chat/apps-engine/definition/accessors/IRoomBuilder.ts'; +import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; +import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; + +import type { UIHelper as _UIHelper } from '@rocket.chat/apps-engine/server/misc/UIHelper.ts'; +import type { RoomType as _RoomType } from '@rocket.chat/apps-engine/definition/rooms/RoomType.ts'; +import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; + +import * as Messenger from '../../messenger.ts'; + +import { MessageBuilder } from '../builders/MessageBuilder.ts'; +import { RoomBuilder } from '../builders/RoomBuilder.ts'; +import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; + +import { require } from '../../../lib/require.ts'; + +const { UIHelper } = require('@rocket.chat/apps-engine/server/misc/UIHelper.js') as { UIHelper: typeof _UIHelper }; +const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType.js') as { RoomType: typeof _RoomType }; +const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as { + RocketChatAssociationModel: typeof _RocketChatAssociationModel; +}; + +export class ModifyUpdater implements IModifyUpdater { + constructor(private readonly senderFn: typeof Messenger.sendRequest) { } + + public getLivechatUpdater(): ILivechatUpdater { + return new Proxy( + { __kind: 'getLivechatUpdater' }, + { + get: + (_target: unknown, prop: string) => + (...params: unknown[]) => + prop === 'toJSON' + ? {} + : this.senderFn({ + method: `accessor:getModifier:getUpdater:getLivechatUpdater:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + throw new Error(err.error); + }), + }, + ) as ILivechatUpdater; + } + + public getUserUpdater(): IUserUpdater { + return new Proxy( + { __kind: 'getUserUpdater' }, + { + get: + (_target: unknown, prop: string) => + (...params: unknown[]) => + prop === 'toJSON' + ? {} + : this.senderFn({ + method: `accessor:getModifier:getUpdater:getUserUpdater:${prop}`, + params, + }) + .then((response) => response.result) + .catch((err) => { + throw new Error(err.error); + }), + }, + ) as IUserUpdater; + } + + public async message(messageId: string, _updater: IUser): Promise { + const response = await this.senderFn({ + method: 'bridges:getMessageBridge:doGetById', + params: [messageId, AppObjectRegistry.get('id')], + }); + + return new MessageBuilder(response.result as IMessage); + } + + public async room(roomId: string, _updater: IUser): Promise { + const response = await this.senderFn({ + method: 'bridges:getRoomBridge:doGetById', + params: [roomId, AppObjectRegistry.get('id')], + }); + + return new RoomBuilder(response.result as IRoom); + } + + public finish(builder: IMessageBuilder | IRoomBuilder): Promise { + switch (builder.kind) { + case RocketChatAssociationModel.MESSAGE: + return this._finishMessage(builder as IMessageBuilder); + case RocketChatAssociationModel.ROOM: + return this._finishRoom(builder as IRoomBuilder); + default: + throw new Error('Invalid builder passed to the ModifyUpdater.finish function.'); + } + } + + private async _finishMessage(builder: IMessageBuilder): Promise { + const result = builder.getMessage(); + + if (!result.id) { + throw new Error("Invalid message, can't update a message without an id."); + } + + if (!result.sender?.id) { + throw new Error('Invalid sender assigned to the message.'); + } + + if (result.blocks?.length) { + result.blocks = UIHelper.assignIds(result.blocks, AppObjectRegistry.get('id') || ''); + } + + await this.senderFn({ + method: 'bridges:getMessageBridge:doUpdate', + params: [result, AppObjectRegistry.get('id')], + }); + } + + private async _finishRoom(builder: IRoomBuilder): Promise { + const result = builder.getRoom(); + + if (!result.id) { + throw new Error("Invalid room, can't update a room without an id."); + } + + if (!result.type) { + throw new Error('Invalid type assigned to the room.'); + } + + if (result.type !== RoomType.LIVE_CHAT) { + if (!result.creator || !result.creator.id) { + throw new Error('Invalid creator assigned to the room.'); + } + + if (!result.slugifiedName || !result.slugifiedName.trim()) { + throw new Error('Invalid slugifiedName assigned to the room.'); + } + } + + if (!result.displayName || !result.displayName.trim()) { + throw new Error('Invalid displayName assigned to the room.'); + } + + await this.senderFn({ + method: 'bridges:getRoomBridge:doUpdate', + params: [result, builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')], + }); + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/notifier.ts b/packages/apps-engine/deno-runtime/lib/accessors/notifier.ts new file mode 100644 index 000000000000..625d68c1039f --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/notifier.ts @@ -0,0 +1,75 @@ +import type { IMessageBuilder, INotifier } from '@rocket.chat/apps-engine/definition/accessors'; +import type { ITypingOptions } from '@rocket.chat/apps-engine/definition/accessors/INotifier.ts'; +import type { _TypingScope } from '@rocket.chat/apps-engine/definition/accessors/INotifier.ts'; +import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; +import type { IUser } from '@rocket.chat/apps-engine/definition/users'; +import { MessageBuilder } from './builders/MessageBuilder.ts'; +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import * as Messenger from '../messenger.ts'; +import { require } from "../require.ts"; + +const { TypingScope } = require('@rocket.chat/apps-engine/definition/accessors/INotifier.js') as { + TypingScope: typeof _TypingScope; +}; + +export class Notifier implements INotifier { + private senderFn: typeof Messenger.sendRequest; + + constructor(senderFn: typeof Messenger.sendRequest) { + this.senderFn = senderFn; + } + + public async notifyUser(user: IUser, message: IMessage): Promise { + if (!message.sender || !message.sender.id) { + const appUser = await this.getAppUser(); + + message.sender = appUser; + } + + await this.callMessageBridge('doNotifyUser', [user, message, AppObjectRegistry.get('id')]); + } + + public async notifyRoom(room: IRoom, message: IMessage): Promise { + if (!message.sender || !message.sender.id) { + const appUser = await this.getAppUser(); + + message.sender = appUser; + } + + await this.callMessageBridge('doNotifyRoom', [room, message, AppObjectRegistry.get('id')]); + } + + public async typing(options: ITypingOptions): Promise<() => Promise> { + options.scope = options.scope || TypingScope.Room; + + if (!options.username) { + const appUser = await this.getAppUser(); + options.username = (appUser && appUser.name) || ''; + } + + const appId = AppObjectRegistry.get('id'); + + await this.callMessageBridge('doTyping', [{ ...options, isTyping: true }, appId]); + + return async () => { + await this.callMessageBridge('doTyping', [{ ...options, isTyping: false }, appId]); + }; + } + + public getMessageBuilder(): IMessageBuilder { + return new MessageBuilder(); + } + + private async callMessageBridge(method: string, params: Array): Promise { + await this.senderFn({ + method: `bridges:getMessageBridge:${method}`, + params, + }); + } + + private async getAppUser(): Promise { + const response = await this.senderFn({ method: 'bridges:getUserBridge:doGetAppUser', params: [AppObjectRegistry.get('id')] }); + return response.result; + } +} diff --git a/packages/apps-engine/deno-runtime/lib/accessors/tests/AppAccessors.test.ts b/packages/apps-engine/deno-runtime/lib/accessors/tests/AppAccessors.test.ts new file mode 100644 index 000000000000..04592eadd3db --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/tests/AppAccessors.test.ts @@ -0,0 +1,122 @@ +import { afterAll, beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; +import { assertEquals } from 'https://deno.land/std@0.203.0/assert/assert_equals.ts'; + +import { AppAccessors } from '../mod.ts'; +import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; + +describe('AppAccessors', () => { + let appAccessors: AppAccessors; + const senderFn = (r: object) => + Promise.resolve({ + id: Math.random().toString(36).substring(2), + jsonrpc: '2.0', + result: r, + serialize() { + return JSON.stringify(this); + }, + }); + + beforeEach(() => { + appAccessors = new AppAccessors(senderFn); + AppObjectRegistry.clear(); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('creates the correct format for IRead calls', async () => { + const roomRead = appAccessors.getReader().getRoomReader(); + const room = await roomRead.getById('123'); + + assertEquals(room, { + params: ['123'], + method: 'accessor:getReader:getRoomReader:getById', + }); + }); + + it('creates the correct format for IEnvironmentRead calls from IRead', async () => { + const reader = appAccessors.getReader().getEnvironmentReader().getEnvironmentVariables(); + const room = await reader.getValueByName('NODE_ENV'); + + assertEquals(room, { + params: ['NODE_ENV'], + method: 'accessor:getReader:getEnvironmentReader:getEnvironmentVariables:getValueByName', + }); + }); + + it('creates the correct format for IEvironmentRead calls', async () => { + const envRead = appAccessors.getEnvironmentRead(); + const env = await envRead.getServerSettings().getValueById('123'); + + assertEquals(env, { + params: ['123'], + method: 'accessor:getEnvironmentRead:getServerSettings:getValueById', + }); + }); + + it('creates the correct format for IEvironmentWrite calls', async () => { + const envRead = appAccessors.getEnvironmentWrite(); + const env = await envRead.getServerSettings().incrementValue('123', 6); + + assertEquals(env, { + params: ['123', 6], + method: 'accessor:getEnvironmentWrite:getServerSettings:incrementValue', + }); + }); + + it('creates the correct format for IConfigurationModify calls', async () => { + const configModify = appAccessors.getConfigurationModify(); + const command = await configModify.slashCommands.modifySlashCommand({ + command: 'test', + i18nDescription: 'test', + i18nParamsExample: 'test', + providesPreview: true, + }); + + assertEquals(command, { + params: [ + { + command: 'test', + i18nDescription: 'test', + i18nParamsExample: 'test', + providesPreview: true, + }, + ], + method: 'accessor:getConfigurationModify:slashCommands:modifySlashCommand', + }); + }); + + it('correctly stores a reference to a slashcommand object and sends a request via proxy', async () => { + const configExtend = appAccessors.getConfigurationExtend(); + + const slashcommand = { + command: 'test', + i18nDescription: 'test', + i18nParamsExample: 'test', + providesPreview: true, + executor() { + return Promise.resolve(); + }, + }; + + const result = await configExtend.slashCommands.provideSlashCommand(slashcommand); + + assertEquals(AppObjectRegistry.get('slashcommand:test'), slashcommand); + + // The function will not be serialized and sent to the main process + delete result.params[0].executor; + + assertEquals(result, { + method: 'accessor:getConfigurationExtend:slashCommands:provideSlashCommand', + params: [ + { + command: 'test', + i18nDescription: 'test', + i18nParamsExample: 'test', + providesPreview: true, + }, + ], + }); + }); +}); diff --git a/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyCreator.test.ts b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyCreator.test.ts new file mode 100644 index 000000000000..5927869e6c84 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyCreator.test.ts @@ -0,0 +1,106 @@ +// deno-lint-ignore-file no-explicit-any +import { afterAll, beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; +import { assertSpyCall, spy } from 'https://deno.land/std@0.203.0/testing/mock.ts'; +import { assert, assertEquals, assertNotInstanceOf } from 'https://deno.land/std@0.203.0/assert/mod.ts'; + +import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; +import { ModifyCreator } from '../modify/ModifyCreator.ts'; + +describe('ModifyCreator', () => { + const senderFn = (r: any) => + Promise.resolve({ + id: Math.random().toString(36).substring(2), + jsonrpc: '2.0', + result: r, + serialize() { + return JSON.stringify(this); + }, + }); + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('id', 'deno-test'); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('sends the correct payload in the request to create a message', async () => { + const spying = spy(senderFn); + const modifyCreator = new ModifyCreator(spying); + const messageBuilder = modifyCreator.startMessage(); + + // Importing types from the Apps-Engine is problematic, so we'll go with `any` here + messageBuilder + .setRoom({ id: '123' } as any) + .setSender({ id: '456' } as any) + .setText('Hello World') + .setUsernameAlias('alias') + .setAvatarUrl('https://avatars.com/123'); + + // We can't get a legitimate return value here, so we ignore it + // but we need to know that the request sent was well formed + await modifyCreator.finish(messageBuilder); + + assertSpyCall(spying, 0, { + args: [ + { + method: 'bridges:getMessageBridge:doCreate', + params: [ + { + room: { id: '123' }, + sender: { id: '456' }, + text: 'Hello World', + alias: 'alias', + avatarUrl: 'https://avatars.com/123', + }, + 'deno-test', + ], + }, + ], + }); + }); + + it('sends the correct payload in the request to upload a buffer', async () => { + const modifyCreator = new ModifyCreator(senderFn); + + const result = await modifyCreator.getUploadCreator().uploadBuffer(new Uint8Array([1, 2, 3, 4]), 'text/plain'); + + assertEquals(result, { + method: 'accessor:getModifier:getCreator:getUploadCreator:uploadBuffer', + params: [new Uint8Array([1, 2, 3, 4]), 'text/plain'], + }); + }); + + it('sends the correct payload in the request to create a visitor', async () => { + const modifyCreator = new ModifyCreator(senderFn); + + const result = (await modifyCreator.getLivechatCreator().createVisitor({ + token: 'random token', + username: 'random username for visitor', + name: 'Random Visitor', + })) as any; // We modified the send function so it changed the original return type of the function + + assertEquals(result, { + method: 'accessor:getModifier:getCreator:getLivechatCreator:createVisitor', + params: [ + { + token: 'random token', + username: 'random username for visitor', + name: 'Random Visitor', + }, + ], + }); + }); + + // This test is important because if we return a promise we break API compatibility + it('does not return a promise for calls of the createToken() method of the LivechatCreator', () => { + const modifyCreator = new ModifyCreator(senderFn); + + const result = modifyCreator.getLivechatCreator().createToken(); + + assertNotInstanceOf(result, Promise); + assert(typeof result === 'string', `Expected "${result}" to be of type "string", but got "${typeof result}"`); + }); +}); diff --git a/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyExtender.test.ts b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyExtender.test.ts new file mode 100644 index 000000000000..1ec056e02ce3 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyExtender.test.ts @@ -0,0 +1,120 @@ +// deno-lint-ignore-file no-explicit-any +import { afterAll, beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; +import { assertSpyCall, spy } from 'https://deno.land/std@0.203.0/testing/mock.ts'; + +import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; +import { ModifyExtender } from '../modify/ModifyExtender.ts'; + +describe('ModifyExtender', () => { + let extender: ModifyExtender; + + const senderFn = (r: any) => + Promise.resolve({ + id: Math.random().toString(36).substring(2), + jsonrpc: '2.0', + result: structuredClone(r), + serialize() { + return JSON.stringify(this); + }, + }); + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('id', 'deno-test'); + extender = new ModifyExtender(senderFn); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('correctly formats requests for the extend message requests', async () => { + const _spy = spy(extender, 'senderFn' as keyof ModifyExtender); + + const messageExtender = await extender.extendMessage('message-id', { _id: 'user-id' } as any); + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getMessageBridge:doGetById', + params: ['message-id', 'deno-test'], + }, + ], + }); + + messageExtender.addCustomField('key', 'value'); + + await extender.finish(messageExtender); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getMessageBridge:doUpdate', + params: [messageExtender.getMessage(), 'deno-test'], + }, + ], + }); + + _spy.restore(); + }); + + it('correctly formats requests for the extend room requests', async () => { + const _spy = spy(extender, 'senderFn' as keyof ModifyExtender); + + const roomExtender = await extender.extendRoom('room-id', { _id: 'user-id' } as any); + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getRoomBridge:doGetById', + params: ['room-id', 'deno-test'], + }, + ], + }); + + roomExtender.addCustomField('key', 'value'); + + await extender.finish(roomExtender); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getRoomBridge:doUpdate', + params: [roomExtender.getRoom(), [], 'deno-test'], + }, + ], + }); + + _spy.restore(); + }); + + it('correctly formats requests for the extend video conference requests', async () => { + const _spy = spy(extender, 'senderFn' as keyof ModifyExtender); + + const videoConferenceExtender = await extender.extendVideoConference('video-conference-id'); + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getVideoConferenceBridge:doGetById', + params: ['video-conference-id', 'deno-test'], + }, + ], + }); + + videoConferenceExtender.setStatus(4); + + await extender.finish(videoConferenceExtender); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getVideoConferenceBridge:doUpdate', + params: [videoConferenceExtender.getVideoConference(), 'deno-test'], + }, + ], + }); + + _spy.restore(); + }); +}); diff --git a/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyUpdater.test.ts b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyUpdater.test.ts new file mode 100644 index 000000000000..313275c967cf --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/accessors/tests/ModifyUpdater.test.ts @@ -0,0 +1,128 @@ +// deno-lint-ignore-file no-explicit-any +import { afterAll, beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; +import { assertSpyCall, spy } from 'https://deno.land/std@0.203.0/testing/mock.ts'; +import { assertEquals } from 'https://deno.land/std@0.203.0/assert/mod.ts'; + +import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; +import { ModifyUpdater } from '../modify/ModifyUpdater.ts'; + +describe('ModifyUpdater', () => { + let modifyUpdater: ModifyUpdater; + + const senderFn = (r: any) => + Promise.resolve({ + id: Math.random().toString(36).substring(2), + jsonrpc: '2.0', + result: structuredClone(r), + serialize() { + return JSON.stringify(this); + }, + }); + + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('id', 'deno-test'); + modifyUpdater = new ModifyUpdater(senderFn); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + }); + + it('correctly formats requests for the update message flow', async () => { + const _spy = spy(modifyUpdater, 'senderFn' as keyof ModifyUpdater); + + const messageBuilder = await modifyUpdater.message('123', { id: '456' } as any); + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getMessageBridge:doGetById', + params: ['123', 'deno-test'], + }, + ], + }); + + messageBuilder.setUpdateData( + { + id: '123', + room: { id: '123' }, + sender: { id: '456' }, + text: 'Hello World', + }, + { + id: '456', + }, + ); + + await modifyUpdater.finish(messageBuilder); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getMessageBridge:doUpdate', + params: [messageBuilder.getMessage(), 'deno-test'], + }, + ], + }); + + _spy.restore(); + }); + + it('correctly formats requests for the update room flow', async () => { + const _spy = spy(modifyUpdater, 'senderFn' as keyof ModifyUpdater); + + const roomBuilder = await modifyUpdater.room('123', { id: '456' } as any); + + assertSpyCall(_spy, 0, { + args: [ + { + method: 'bridges:getRoomBridge:doGetById', + params: ['123', 'deno-test'], + }, + ], + }); + + roomBuilder.setData({ + id: '123', + type: 'c', + displayName: 'Test Room', + slugifiedName: 'test-room', + creator: { id: '456' }, + }); + + roomBuilder.setMembersToBeAddedByUsernames(['username1', 'username2']); + + // We need to sneak in the id as the `modifyUpdater.room` call won't have legitimate data + roomBuilder.getRoom().id = '123'; + + await modifyUpdater.finish(roomBuilder); + + assertSpyCall(_spy, 1, { + args: [ + { + method: 'bridges:getRoomBridge:doUpdate', + params: [roomBuilder.getRoom(), roomBuilder.getMembersToBeAddedUsernames(), 'deno-test'], + }, + ], + }); + }); + + it('correctly formats requests to UserUpdater methods', async () => { + const result = await modifyUpdater.getUserUpdater().updateStatusText({ id: '123' } as any, 'Hello World') as any; + + assertEquals(result, { + method: 'accessor:getModifier:getUpdater:getUserUpdater:updateStatusText', + params: [{ id: '123' }, 'Hello World'], + }); + }); + + it('correctly formats requests to LivechatUpdater methods', async () => { + const result = await modifyUpdater.getLivechatUpdater().closeRoom({ id: '123' } as any, 'close it!') as any; + + assertEquals(result, { + method: 'accessor:getModifier:getUpdater:getLivechatUpdater:closeRoom', + params: [{ id: '123' }, 'close it!'], + }); + }); +}); diff --git a/packages/apps-engine/deno-runtime/lib/ast/mod.ts b/packages/apps-engine/deno-runtime/lib/ast/mod.ts new file mode 100644 index 000000000000..09f4994f2bad --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/ast/mod.ts @@ -0,0 +1,64 @@ +import { generate } from "astring"; +// @deno-types="../../acorn.d.ts" +import { Program, parse } from "acorn"; +// @deno-types="../../acorn-walk.d.ts" +import { fullAncestor } from "acorn-walk"; + +import * as operations from "./operations.ts"; +import type { WalkerState } from "./operations.ts"; + +function fixAst(ast: Program): boolean { + const pendingOperations = [ + operations.fixLivechatIsOnlineCalls, + operations.checkReassignmentOfModifiedIdentifiers, + operations.fixRoomUsernamesCalls, + ]; + + // Have we touched the tree? + let isModified = false; + + while (pendingOperations.length) { + const ops = pendingOperations.splice(0); + const state: WalkerState = { + isModified: false, + functionIdentifiers: new Set(), + }; + + fullAncestor(ast, (node, state, ancestors, type) => { + ops.forEach(operation => operation(node, state, ancestors, type)); + }, undefined, state); + + if (state.isModified) { + isModified = true; + } + + if (state.functionIdentifiers.size) { + pendingOperations.push( + operations.buildFixModifiedFunctionsOperation(state.functionIdentifiers), + operations.checkReassignmentOfModifiedIdentifiers + ); + } + } + + return isModified; +} + +export function fixBrokenSynchronousAPICalls(appSource: string): string { + const astRootNode = parse(appSource, { + ecmaVersion: 2017, + // Allow everything, we don't want to complain if code is badly written + // Also, since the code itself has been transpiled, the chance of getting + // shenanigans is lower + allowReserved: true, + allowReturnOutsideFunction: true, + allowImportExportEverywhere: true, + allowAwaitOutsideFunction: true, + allowSuperOutsideMethod: true, + }); + + if (fixAst(astRootNode)) { + return generate(astRootNode); + } + + return appSource; +} diff --git a/packages/apps-engine/deno-runtime/lib/ast/operations.ts b/packages/apps-engine/deno-runtime/lib/ast/operations.ts new file mode 100644 index 000000000000..d3886348041f --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/ast/operations.ts @@ -0,0 +1,239 @@ +// @deno-types="../../acorn.d.ts" +import { AnyNode, AssignmentExpression, AwaitExpression, Expression, Function, Identifier, MethodDefinition, Property } from 'acorn'; +// @deno-types="../../acorn-walk.d.ts" +import { FullAncestorWalkerCallback } from 'acorn-walk'; + +export type WalkerState = { + isModified: boolean; + functionIdentifiers: Set; +}; + +export function getFunctionIdentifier(ancestors: AnyNode[], functionNodeIndex: number) { + const parent = ancestors[functionNodeIndex - 1]; + + // If there is a parent node and it's not a computed property, we can try to + // extract an identifier for our function from it. This needs to be done first + // because when functions are assigned to named symbols, this will be the only + // way to call it, even if the function itself has an identifier + // Consider the following block: + // + // const foo = function bar() {} + // + // Even though the function itself has a name, the only way to call it in the + // program is wiht `foo()` + if (parent && !(parent as Property | MethodDefinition).computed) { + // Several node types can have an id prop of type Identifier + const { id } = parent as unknown as { id?: Identifier }; + if (id?.type === 'Identifier') { + return id.name; + } + + // Usually assignments to object properties (MethodDefinition, Property) + const { key } = parent as MethodDefinition | Property; + if (key?.type === 'Identifier') { + return key.name; + } + + // Variable assignments have left hand side that can be used as Identifier + const { left } = parent as AssignmentExpression; + + // Simple assignment: `const fn = () => {}` + if (left?.type === 'Identifier') { + return left.name; + } + + // Object property assignment: `obj.fn = () => {}` + if (left?.type === 'MemberExpression' && !left.computed) { + return (left.property as Identifier).name; + } + } + + // nodeIndex needs to be the index of a Function node (either FunctionDeclaration or FunctionExpression) + const currentNode = ancestors[functionNodeIndex] as Function; + + // Function declarations or expressions can be directly named + if (currentNode.id?.type === 'Identifier') { + return currentNode.id.name; + } +} + +export function wrapWithAwait(node: Expression) { + if (!node.type.endsWith('Expression')) { + throw new Error(`Can't wrap "${node.type}" with await`); + } + + const innerNode: Expression = { ...node }; + + node.type = 'AwaitExpression'; + // starting here node has become an AwaitExpression + (node as AwaitExpression).argument = innerNode; + + Object.keys(node).forEach((key) => !['type', 'argument'].includes(key) && delete node[key as keyof AnyNode]); +} + +export function asyncifyScope(ancestors: AnyNode[], state: WalkerState) { + const functionNodeIndex = ancestors.findLastIndex((n) => 'async' in n); + if (functionNodeIndex === -1) return; + + // At this point this is a node with an "async" property, so it has to be + // of type Function - let TS know about that + const functionScopeNode = ancestors[functionNodeIndex] as Function; + + if (functionScopeNode.async) { + return; + } + + functionScopeNode.async = true; + + // If the parent of a function node is a call expression, we're talking about an IIFE + // Should we care about this case as well? + // const parentNode = ancestors[functionScopeIndex-1]; + // if (parentNode?.type === 'CallExpression' && ancestors[functionScopeIndex-2] && ancestors[functionScopeIndex-2].type !== 'AwaitExpression') { + // pendingOperations.push(buildFunctionPredicate(getFunctionIdentifier(ancestors, functionScopeIndex-2))); + // } + + const identifier = getFunctionIdentifier(ancestors, functionNodeIndex); + + // We can't fix calls of functions which name we can't determine at compile time + if (!identifier) return; + + state.functionIdentifiers.add(identifier); +} + +export function buildFixModifiedFunctionsOperation(functionIdentifiers: Set): FullAncestorWalkerCallback { + return function _fixModifiedFunctionsOperation(node, state, ancestors) { + if (node.type !== 'CallExpression') return; + + let isWrappable = false; + + // This node is a simple call to a function, like `fn()` + isWrappable = node.callee.type === 'Identifier' && functionIdentifiers.has(node.callee.name); + + // This node is a call to an object property or instance method, like `obj.fn()`, but not computed like `obj[fn]()` + isWrappable ||= + node.callee.type === 'MemberExpression' && + !node.callee.computed && + node.callee.property?.type === 'Identifier' && + functionIdentifiers.has(node.callee.property.name); + + // This is a weird dereferencing technique used by bundlers, and since we'll be dealing with bundled sources we have to check for it + // e.g. `r=(0,fn)(e)` + if (!isWrappable && node.callee.type === 'SequenceExpression') { + const [, secondExpression] = node.callee.expressions; + isWrappable = secondExpression?.type === 'Identifier' && functionIdentifiers.has(secondExpression.name); + isWrappable ||= + secondExpression?.type === 'MemberExpression' && + !secondExpression.computed && + secondExpression.property.type === 'Identifier' && + functionIdentifiers.has(secondExpression.property.name); + } + + if (!isWrappable) return; + + // ancestors[ancestors.length-1] === node, so here we're checking for parent node + const parentNode = ancestors[ancestors.length - 2]; + if (!parentNode || parentNode.type === 'AwaitExpression') return; + + wrapWithAwait(node); + asyncifyScope(ancestors, state); + + state.isModified = true; + }; +} + +export const checkReassignmentOfModifiedIdentifiers: FullAncestorWalkerCallback = (node, { functionIdentifiers }, _ancestors) => { + if (node.type === 'AssignmentExpression') { + if (node.operator !== '=') return; + + let identifier = ''; + + if (node.left.type === 'Identifier') identifier = node.left.name; + + if (node.left.type === 'MemberExpression' && !node.left.computed) { + identifier = (node.left.property as Identifier).name; + } + + if (!identifier || node.right.type !== 'Identifier' || !functionIdentifiers.has(node.right.name)) return; + + functionIdentifiers.add(identifier); + + return; + } + + if (node.type === 'VariableDeclarator') { + if (node.id.type !== 'Identifier' || functionIdentifiers.has(node.id.name)) return; + + if (node.init?.type !== 'Identifier' || !functionIdentifiers.has(node.init?.name)) return; + + functionIdentifiers.add(node.id.name); + + return; + } + + // "Property" is for plain objects, "PropertyDefinition" is for classes + // but both share the same structure + if (node.type === 'Property' || node.type === 'PropertyDefinition') { + if (node.key.type !== 'Identifier' || functionIdentifiers.has(node.key.name)) return; + + if (node.value?.type !== 'Identifier' || !functionIdentifiers.has(node.value.name)) return; + + functionIdentifiers.add(node.key.name); + + return; + } +}; + +export const fixLivechatIsOnlineCalls: FullAncestorWalkerCallback = (node, state, ancestors) => { + if (node.type !== 'MemberExpression' || node.computed) return; + + if ((node.property as Identifier).name !== 'isOnline') return; + + if (node.object.type !== 'CallExpression') return; + + if (node.object.callee.type !== 'MemberExpression') return; + + if ((node.object.callee.property as Identifier).name !== 'getLivechatReader') return; + + let parentIndex = ancestors.length - 2; + let targetNode = ancestors[parentIndex]; + + if (targetNode.type !== 'CallExpression') { + targetNode = node; + } else { + parentIndex--; + } + + // If we're already wrapped with an await, nothing to do + if (ancestors[parentIndex].type === 'AwaitExpression') return; + + // If we're in the middle of a chained member access, we can't wrap with await + if (ancestors[parentIndex].type === 'MemberExpression') return; + + wrapWithAwait(targetNode); + asyncifyScope(ancestors, state); + + state.isModified = true; +}; + +export const fixRoomUsernamesCalls: FullAncestorWalkerCallback = (node, state, ancestors) => { + if (node.type !== 'MemberExpression' || node.computed) return; + + if ((node.property as Identifier).name !== 'usernames') return; + + let parentIndex = ancestors.length - 2; + let targetNode = ancestors[parentIndex]; + + if (targetNode.type !== 'CallExpression') { + targetNode = node; + } else { + parentIndex--; + } + + // If we're already wrapped with an await, nothing to do + if (ancestors[parentIndex].type === 'AwaitExpression') return; + + wrapWithAwait(targetNode); + asyncifyScope(ancestors, state); + + state.isModified = true; +} diff --git a/packages/apps-engine/deno-runtime/lib/ast/tests/data/ast_blocks.ts b/packages/apps-engine/deno-runtime/lib/ast/tests/data/ast_blocks.ts new file mode 100644 index 000000000000..330d2bf52620 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/ast/tests/data/ast_blocks.ts @@ -0,0 +1,436 @@ +// @deno-types="../../../../acorn.d.ts" +import { AnyNode, ClassDeclaration, ExpressionStatement, FunctionDeclaration, VariableDeclaration } from 'acorn'; + +/** + * Partial AST blocks to support testing. + * `start` and `end` properties are omitted for brevity. + */ + +type TestNodeExcerpt = { + code: string; + node: N; +}; + +export const FunctionDeclarationFoo: TestNodeExcerpt = { + code: 'function foo() {}', + node: { + type: 'FunctionDeclaration', + id: { + type: 'Identifier', + name: 'foo', + }, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, +}; + +export const ConstFooAssignedFunctionExpression: TestNodeExcerpt = { + code: 'const foo = function() {}', + node: { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'foo', + }, + init: { + type: 'FunctionExpression', + id: null, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, + }, + ], + }, +}; + +export const AssignmentExpressionOfArrowFunctionToFooIdentifier: TestNodeExcerpt = { + code: 'foo = () => {}', + node: { + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: { + type: 'Identifier', + name: 'foo', + }, + right: { + type: 'ArrowFunctionExpression', + id: null, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, + }, + }, +}; + +export const AssignmentExpressionOfNamedFunctionToFooMemberExpression: TestNodeExcerpt = { + code: 'obj.foo = function bar() {}', + node: { + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'a', + }, + property: { + type: 'Identifier', + name: 'foo', + }, + computed: false, + optional: false, + }, + right: { + type: 'FunctionExpression', + id: null, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, + }, + }, +}; + +export const MethodDefinitionOfFooInClassBar: TestNodeExcerpt = { + code: 'class Bar { foo() {} }', + node: { + type: 'ClassDeclaration', + id: { + type: 'Identifier', + name: 'Bar', + }, + superClass: null, + body: { + type: 'ClassBody', + body: [ + { + type: 'MethodDefinition', + key: { + type: 'Identifier', + name: 'foo', + }, + value: { + type: 'FunctionExpression', + id: null, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [], + }, + }, + kind: 'method', + computed: false, + static: false, + }, + ], + }, + }, +}; + +export const SimpleCallExpressionOfFoo: TestNodeExcerpt = { + code: 'foo()', + node: { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo', + }, + arguments: [], + optional: false, + }, + }, +}; + +export const SyncFunctionDeclarationWithAsyncCallExpression: TestNodeExcerpt = { + // NOTE: this is invalid syntax, it won't be parsed by acorn + // but it can be an intermediary state of the AST after we run + // `wrapWithAwait` on "bar" call expressions, for instance + code: 'function foo() { return () => await bar() }', + node: { + type: 'FunctionDeclaration', + id: { + type: 'Identifier', + name: 'foo', + }, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'ReturnStatement', + argument: { + type: 'ArrowFunctionExpression', + id: null, + expression: true, + generator: false, + async: false, + params: [], + body: { + type: 'AwaitExpression', + argument: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'bar', + }, + arguments: [], + optional: false, + }, + }, + }, + }, + ], + }, + }, +}; + +export const AssignmentOfFooToBar: TestNodeExcerpt = { + code: 'bar = foo', + node: { + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: { + type: 'Identifier', + name: 'bar', + }, + right: { + type: 'Identifier', + name: 'foo', + }, + }, + }, +}; + +export const AssignmentOfFooToBarMemberExpression: TestNodeExcerpt = { + code: 'obj.bar = foo', + node: { + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + operator: '=', + left: { + type: 'MemberExpression', + computed: false, + optional: false, + object: { + type: 'Identifier', + name: 'obj', + }, + property: { + type: 'Identifier', + name: 'bar', + }, + }, + right: { + type: 'Identifier', + name: 'foo', + }, + }, + }, +}; + +export const AssignmentOfFooToBarVariableDeclarator: TestNodeExcerpt = { + code: 'const bar = foo', + node: { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'bar', + }, + init: { + type: 'Identifier', + name: 'foo', + }, + }, + ], + }, +}; + +export const AssignmentOfFooToBarPropertyDefinition: TestNodeExcerpt = { + code: 'class baz { bar = foo }', + node: { + type: 'ClassDeclaration', + id: { + type: 'Identifier', + name: 'baz', + }, + superClass: null, + body: { + type: 'ClassBody', + body: [ + { + type: 'PropertyDefinition', + static: false, + computed: false, + key: { + type: 'Identifier', + name: 'bar', + }, + value: { + type: 'Identifier', + name: 'foo', + }, + }, + ], + }, + }, +}; + +const fixSimpleCallExpressionCode = ` +function bar() { + const a = foo(); + + return a; +}`; + +export const FixSimpleCallExpression: TestNodeExcerpt = { + code: fixSimpleCallExpressionCode, + node: { + type: 'FunctionDeclaration', + id: { + type: 'Identifier', + name: 'bar', + }, + expression: false, + generator: false, + async: false, + params: [], + body: { + type: 'BlockStatement', + body: [ + { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'a', + }, + init: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo', + }, + arguments: [], + optional: false, + }, + }, + ], + }, + { + type: 'ReturnStatement', + argument: { + type: 'Identifier', + name: 'a', + }, + }, + ], + }, + }, +}; + +export const ArrowFunctionDerefCallExpression: TestNodeExcerpt = { + // NOTE: this call strategy is widely used by bundlers; it's used to sever the `this` + // reference in the method from the object that contains it. This is mostly because + // the bundler wants to ensure that it does not messes up the bindings in the code it + // generates. + // + // This would be similar to doing `foo.call(undefined)` + code: 'const bar = () => (0, e.foo)();', + node: { + type: 'VariableDeclaration', + kind: 'const', + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: 'bar', + }, + init: { + type: 'ArrowFunctionExpression', + id: null, + expression: true, + generator: false, + async: false, + params: [], + body: { + type: 'CallExpression', + optional: false, + arguments: [], + callee: { + type: 'SequenceExpression', + expressions: [ + { + type: 'Literal', + value: 0, + }, + { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'e', + }, + property: { + type: 'Identifier', + name: 'foo', + }, + computed: false, + optional: false, + }, + ], + }, + }, + }, + }, + ], + }, +}; diff --git a/packages/apps-engine/deno-runtime/lib/ast/tests/operations.test.ts b/packages/apps-engine/deno-runtime/lib/ast/tests/operations.test.ts new file mode 100644 index 000000000000..2b00c271f730 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/ast/tests/operations.test.ts @@ -0,0 +1,245 @@ +import { assertEquals, assertThrows } from 'https://deno.land/std@0.203.0/assert/mod.ts'; +import { beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; + +import { WalkerState, asyncifyScope, buildFixModifiedFunctionsOperation, checkReassignmentOfModifiedIdentifiers, getFunctionIdentifier, wrapWithAwait } from '../operations.ts'; +import { + ArrowFunctionDerefCallExpression, + AssignmentExpressionOfArrowFunctionToFooIdentifier, + AssignmentExpressionOfNamedFunctionToFooMemberExpression, + AssignmentOfFooToBar, + AssignmentOfFooToBarMemberExpression, + AssignmentOfFooToBarPropertyDefinition, + AssignmentOfFooToBarVariableDeclarator, + ConstFooAssignedFunctionExpression, + FixSimpleCallExpression, + FunctionDeclarationFoo, + MethodDefinitionOfFooInClassBar, + SimpleCallExpressionOfFoo, + SyncFunctionDeclarationWithAsyncCallExpression, +} from './data/ast_blocks.ts'; +import { AnyNode, ArrowFunctionExpression, AssignmentExpression, AwaitExpression, Expression, MethodDefinition, ReturnStatement, VariableDeclaration } from '../../../acorn.d.ts'; +import { assertNotEquals } from 'https://deno.land/std@0.203.0/assert/assert_not_equals.ts'; + +describe('getFunctionIdentifier', () => { + it(`identifies the name "foo" for the code \`${FunctionDeclarationFoo.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [FunctionDeclarationFoo.node]; + const functionNodeIndex = 0; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); + + it(`identifies the name "foo" for the code \`${ConstFooAssignedFunctionExpression.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [ + ConstFooAssignedFunctionExpression.node, // VariableDeclaration + ConstFooAssignedFunctionExpression.node.declarations[0], // VariableDeclarator + ConstFooAssignedFunctionExpression.node.declarations[0].init! // FunctionExpression + ]; + const functionNodeIndex = 2; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); + + it(`identifies the name "foo" for the code \`${AssignmentExpressionOfArrowFunctionToFooIdentifier.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [ + AssignmentExpressionOfArrowFunctionToFooIdentifier.node, // ExpressionStatement + AssignmentExpressionOfArrowFunctionToFooIdentifier.node.expression, // AssignmentExpression + (AssignmentExpressionOfArrowFunctionToFooIdentifier.node.expression as AssignmentExpression).right, // ArrowFunctionExpression + ]; + const functionNodeIndex = 2; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); + + it(`identifies the name "foo" for the code \`${AssignmentExpressionOfNamedFunctionToFooMemberExpression.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [ + AssignmentExpressionOfNamedFunctionToFooMemberExpression.node, // ExpressionStatement + AssignmentExpressionOfNamedFunctionToFooMemberExpression.node.expression, // AssignmentExpression + (AssignmentExpressionOfNamedFunctionToFooMemberExpression.node.expression as AssignmentExpression).right, // FunctionExpression + ]; + const functionNodeIndex = 2; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); + + it(`identifies the name "foo" for the code \`${MethodDefinitionOfFooInClassBar.code}\``, () => { + // ancestors array is built by the walking lib + const nodeAncestors = [ + MethodDefinitionOfFooInClassBar.node, // ClassDeclaration + MethodDefinitionOfFooInClassBar.node.body, // ClassBody + MethodDefinitionOfFooInClassBar.node.body!.body[0], // MethodDefinition + (MethodDefinitionOfFooInClassBar.node.body!.body[0] as MethodDefinition).value, // FunctionExpression + ]; + const functionNodeIndex = 3; + assertEquals('foo', getFunctionIdentifier(nodeAncestors, functionNodeIndex)); + }); +}); + +describe('wrapWithAwait', () => { + it('wraps a call expression with await', () => { + const node = structuredClone(SimpleCallExpressionOfFoo.node.expression); + wrapWithAwait(node); + + assertEquals('AwaitExpression', node.type); + assertNotEquals(SimpleCallExpressionOfFoo.node.expression.type, node.type); + assertEquals(SimpleCallExpressionOfFoo.node.expression, (node as AwaitExpression).argument); + }); + + it('throws if node is not an expression', () => { + const node = structuredClone(SimpleCallExpressionOfFoo.node); + assertThrows(() => wrapWithAwait(node as unknown as Expression)); + }) +}); + +describe('asyncifyScope', () => { + it('makes only the first function scope async', () => { + const node = structuredClone(SyncFunctionDeclarationWithAsyncCallExpression.node); + const ancestors: AnyNode[] = [ + node, // FunctionDeclaration + node.body, // BlockStatement + node.body!.body[0], // ReturnStatement + (node.body!.body[0] as ReturnStatement).argument!, // ArrowFunctionExpression + ((node.body!.body[0] as ReturnStatement).argument! as ArrowFunctionExpression).body, // AwaitExpression + (((node.body!.body[0] as ReturnStatement).argument! as ArrowFunctionExpression).body as AwaitExpression).argument, // CallExpression + ]; + const state: WalkerState = { + isModified: false, + functionIdentifiers: new Set(), + } + + asyncifyScope(ancestors, state); + + // Assert the function did indeed change the expression to async + assertEquals(((node.body.body[0] as ReturnStatement).argument as ArrowFunctionExpression).async, true) + + // Assert the function did NOT change all ancestors in the chain + assertEquals(node.async, false); + + // Assert it couldn't find a function identifier + assertEquals(state.functionIdentifiers.size, 0); + }); +}); + +describe('checkReassignmentofModifiedIdentifiers', () => { + it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBar.code}"`, () => { + const node = structuredClone(AssignmentOfFooToBar.node); + const ancestors: AnyNode[] = [ + node, // ExpressionStatement + node.expression, // AssignmentExpression + (node.expression as AssignmentExpression).right, // Identifier + ]; + const state: WalkerState = { + isModified: true, + functionIdentifiers: new Set(['foo']), + } + + checkReassignmentOfModifiedIdentifiers(node.expression, state, ancestors, ''); + + assertEquals(state.functionIdentifiers.has('bar'), true); + }); + + it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBarMemberExpression.code}"`, () => { + const node = structuredClone(AssignmentOfFooToBarMemberExpression.node); + const ancestors: AnyNode[] = [ + node, // ExpressionStatement + node.expression, // AssignmentExpression + (node.expression as AssignmentExpression).right, // Identifier + ]; + const state: WalkerState = { + isModified: true, + functionIdentifiers: new Set(['foo']), + } + + checkReassignmentOfModifiedIdentifiers(node.expression, state, ancestors, ''); + + assertEquals(state.functionIdentifiers.has('bar'), true); + }); + + it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBarVariableDeclarator.code}"`, () => { + const node = structuredClone(AssignmentOfFooToBarVariableDeclarator.node); + const ancestors: AnyNode[] = [ + node, // VariableDeclaration + node.declarations[0], // VariableDeclarator + ]; + const state: WalkerState = { + isModified: true, + functionIdentifiers: new Set(['foo']), + } + + checkReassignmentOfModifiedIdentifiers(node.declarations[0], state, ancestors, ''); + + assertEquals(state.functionIdentifiers.has('bar'), true); + }); + + it(`identifies the reassignment of "foo" in the code "${AssignmentOfFooToBarPropertyDefinition.code}"`, () => { + const node = structuredClone(AssignmentOfFooToBarPropertyDefinition.node); + const ancestors: AnyNode[] = [ + node, // ClassDeclaration + node.body, // ClassBody + node.body.body[0], // PropertyDefinition + ]; + const state: WalkerState = { + isModified: true, + functionIdentifiers: new Set(['foo']), + } + + checkReassignmentOfModifiedIdentifiers(node.body.body[0], state, ancestors, ''); + + assertEquals(state.functionIdentifiers.has('bar'), true); + }); +}); + +describe('buildFixModifiedFunctionsOperation', function() { + const state: WalkerState = { + isModified: false, + functionIdentifiers: new Set(['foo']), + }; + + const fixFunction = buildFixModifiedFunctionsOperation(state.functionIdentifiers); + + beforeEach(() => { + state.isModified = false; + state.functionIdentifiers = new Set(['foo']); + }); + + it(`fixes calls of "foo" in the code "${FixSimpleCallExpression.code}"`, () => { + const node = structuredClone(FixSimpleCallExpression.node); + const ancestors: AnyNode[] = [ + node, // FunctionDeclaration + node.body, // BlockStatement + node.body.body[0], // VariableDeclaration + (node.body.body[0] as VariableDeclaration).declarations[0], // VariableDeclarator + (node.body.body[0] as VariableDeclaration).declarations[0].init!, // CallExpression + ]; + + fixFunction(ancestors[4], state, ancestors, ''); + + assertEquals(state.isModified, true); + assertEquals(state.functionIdentifiers.has('bar'), true); + assertNotEquals(FixSimpleCallExpression.node, node); + assertEquals(node.async, true); + assertEquals(ancestors[4].type, 'AwaitExpression'); + }); + + it(`fixes calls of "foo" in the code "${ArrowFunctionDerefCallExpression.code}"`, () => { + const node = structuredClone(ArrowFunctionDerefCallExpression.node); + const ancestors: AnyNode[] = [ + node, // VariableDeclaration + node.declarations[0], // VariableDeclarator + node.declarations[0].init!, // ArrowFunctionExpression + (node.declarations[0].init as ArrowFunctionExpression).body, // CallExpression + ]; + + fixFunction(ancestors[3], state, ancestors, ''); + + // Recorded that a modification has been made + assertEquals(state.isModified, true); + // Recorded that the enclosing scope of the call also requires fixing + assertEquals(state.functionIdentifiers.has('bar'), true); + // Original node and fixed node are different + assertNotEquals(ArrowFunctionDerefCallExpression.node, node); + // The function call is now await'ed + assertEquals(ancestors[3].type, 'AwaitExpression'); + // The parent function of the call is now marked as async + assertEquals((ancestors[2] as ArrowFunctionExpression).async, true); + }); +}) diff --git a/packages/apps-engine/deno-runtime/lib/codec.ts b/packages/apps-engine/deno-runtime/lib/codec.ts new file mode 100644 index 000000000000..288db46169dc --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/codec.ts @@ -0,0 +1,43 @@ +import { Buffer } from 'node:buffer'; +import { Decoder, Encoder, ExtensionCodec } from '@msgpack/msgpack'; + +import type { App as _App } from '@rocket.chat/apps-engine/definition/App.ts'; +import { require } from "./require.ts"; + +const { App } = require('@rocket.chat/apps-engine/definition/App.js') as { + App: typeof _App; +}; + +const extensionCodec = new ExtensionCodec(); + +extensionCodec.register({ + type: 0, + encode: (object: unknown) => { + // We don't care about functions, but also don't want to throw an error + if (typeof object === 'function' || object instanceof App) { + return new Uint8Array(0); + } + + return null; + }, + decode: (_data: Uint8Array) => undefined, +}); + +// Since Deno doesn't have Buffer by default, we need to use Uint8Array +extensionCodec.register({ + type: 1, + encode: (object: unknown) => { + if (object instanceof Buffer) { + return new Uint8Array(object.buffer, object.byteOffset, object.byteLength); + } + + return null; + }, + // msgpack will reuse the Uint8Array instance, so WE NEED to copy it instead of simply creating a view + decode: (data: Uint8Array) => { + return Buffer.from(data); + }, +}); + +export const encoder = new Encoder({ extensionCodec }); +export const decoder = new Decoder({ extensionCodec }); diff --git a/packages/apps-engine/deno-runtime/lib/logger.ts b/packages/apps-engine/deno-runtime/lib/logger.ts new file mode 100644 index 000000000000..ea2701c70230 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/logger.ts @@ -0,0 +1,142 @@ +import stackTrace from 'stack-trace'; +import { AppObjectRegistry } from '../AppObjectRegistry.ts'; + +export interface StackFrame { + getTypeName(): string; + getFunctionName(): string; + getMethodName(): string; + getFileName(): string; + getLineNumber(): number; + getColumnNumber(): number; + isNative(): boolean; + isConstructor(): boolean; +} + +enum LogMessageSeverity { + DEBUG = 'debug', + INFORMATION = 'info', + LOG = 'log', + WARNING = 'warning', + ERROR = 'error', + SUCCESS = 'success', +} + +type Entry = { + caller: string; + severity: LogMessageSeverity; + method: string; + timestamp: Date; + args: Array; +}; + +interface ILoggerStorageEntry { + appId: string; + method: string; + entries: Array; + startTime: Date; + endTime: Date; + totalTime: number; + _createdAt: Date; +} + +export class Logger { + private entries: Array; + private start: Date; + private method: string; + + constructor(method: string) { + this.method = method; + this.entries = []; + this.start = new Date(); + } + + public debug(...args: Array): void { + this.addEntry(LogMessageSeverity.DEBUG, this.getStack(stackTrace.get()), ...args); + } + + public info(...args: Array): void { + this.addEntry(LogMessageSeverity.INFORMATION, this.getStack(stackTrace.get()), ...args); + } + + public log(...args: Array): void { + this.addEntry(LogMessageSeverity.LOG, this.getStack(stackTrace.get()), ...args); + } + + public warn(...args: Array): void { + this.addEntry(LogMessageSeverity.WARNING, this.getStack(stackTrace.get()), ...args); + } + + public error(...args: Array): void { + this.addEntry(LogMessageSeverity.ERROR, this.getStack(stackTrace.get()), ...args); + } + + public success(...args: Array): void { + this.addEntry(LogMessageSeverity.SUCCESS, this.getStack(stackTrace.get()), ...args); + } + + private addEntry(severity: LogMessageSeverity, caller: string, ...items: Array): void { + const i = items.map((args) => { + if (args instanceof Error) { + return JSON.stringify(args, Object.getOwnPropertyNames(args)); + } + if (typeof args === 'object' && args !== null && 'stack' in args) { + return JSON.stringify(args, Object.getOwnPropertyNames(args)); + } + if (typeof args === 'object' && args !== null && 'message' in args) { + return JSON.stringify(args, Object.getOwnPropertyNames(args)); + } + const str = JSON.stringify(args, null, 2); + return str ? JSON.parse(str) : str; // force call toJSON to prevent circular references + }); + + this.entries.push({ + caller, + severity, + method: this.method, + timestamp: new Date(), + args: i, + }); + } + + private getStack(stack: Array): string { + let func = 'anonymous'; + + if (stack.length === 1) { + return func; + } + + const frame = stack[1]; + + if (frame.getMethodName() === null) { + func = 'anonymous OR constructor'; + } else { + func = frame.getMethodName(); + } + + if (frame.getFunctionName() !== null) { + func = `${func} -> ${frame.getFunctionName()}`; + } + + return func; + } + + private getTotalTime(): number { + return new Date().getTime() - this.start.getTime(); + } + + public hasEntries(): boolean { + return this.entries.length > 0; + } + + public getLogs(): ILoggerStorageEntry { + return { + appId: AppObjectRegistry.get('id')!, + method: this.method, + entries: this.entries, + startTime: this.start, + endTime: new Date(), + totalTime: this.getTotalTime(), + _createdAt: new Date(), + }; + } +} diff --git a/packages/apps-engine/deno-runtime/lib/messenger.ts b/packages/apps-engine/deno-runtime/lib/messenger.ts new file mode 100644 index 000000000000..1e9ffe05c6c5 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/messenger.ts @@ -0,0 +1,199 @@ +import { writeAll } from "https://deno.land/std@0.216.0/io/write_all.ts"; + +import * as jsonrpc from 'jsonrpc-lite'; + +import { AppObjectRegistry } from '../AppObjectRegistry.ts'; +import type { Logger } from './logger.ts'; +import { encoder } from './codec.ts'; + +export type RequestDescriptor = Pick; + +export type NotificationDescriptor = Pick; + +export type SuccessResponseDescriptor = Pick; + +export type ErrorResponseDescriptor = Pick; + +export type JsonRpcRequest = jsonrpc.IParsedObjectRequest | jsonrpc.IParsedObjectNotification; +export type JsonRpcResponse = jsonrpc.IParsedObjectSuccess | jsonrpc.IParsedObjectError; + +export function isRequest(message: jsonrpc.IParsedObject): message is JsonRpcRequest { + return message.type === 'request' || message.type === 'notification'; +} + +export function isResponse(message: jsonrpc.IParsedObject): message is JsonRpcResponse { + return message.type === 'success' || message.type === 'error'; +} + +export function isErrorResponse(message: jsonrpc.JsonRpc): message is jsonrpc.ErrorObject { + return message instanceof jsonrpc.ErrorObject; +} + +const COMMAND_PONG = '_zPONG'; + +export const RPCResponseObserver = new EventTarget(); + +export const Queue = new (class Queue { + private queue: Uint8Array[] = []; + private isProcessing = false; + + private async processQueue() { + if (this.isProcessing) { + return; + } + + this.isProcessing = true; + + while (this.queue.length) { + const message = this.queue.shift(); + + if (message) { + await Transport.send(message); + } + } + + this.isProcessing = false; + } + + public enqueue(message: jsonrpc.JsonRpc | typeof COMMAND_PONG) { + this.queue.push(encoder.encode(message)); + this.processQueue(); + } +}); + +export const Transport = new (class Transporter { + private selectedTransport: Transporter['stdoutTransport'] | Transporter['noopTransport']; + + constructor() { + this.selectedTransport = this.stdoutTransport.bind(this); + } + + private async stdoutTransport(message: Uint8Array): Promise { + await writeAll(Deno.stdout, message); + } + + private async noopTransport(_message: Uint8Array): Promise {} + + public selectTransport(transport: 'stdout' | 'noop'): void { + switch (transport) { + case 'stdout': + this.selectedTransport = this.stdoutTransport.bind(this); + break; + case 'noop': + this.selectedTransport = this.noopTransport.bind(this); + break; + } + } + + public send(message: Uint8Array): Promise { + return this.selectedTransport(message); + } +})(); + +export function parseMessage(message: string | Record) { + let parsed: jsonrpc.IParsedObject | jsonrpc.IParsedObject[]; + + if (typeof message === 'string') { + parsed = jsonrpc.parse(message); + } else { + parsed = jsonrpc.parseObject(message); + } + + if (Array.isArray(parsed)) { + throw jsonrpc.error(null, jsonrpc.JsonRpcError.invalidRequest(null)); + } + + if (parsed.type === 'invalid') { + throw jsonrpc.error(null, parsed.payload); + } + + return parsed; +} + +export async function sendInvalidRequestError(): Promise { + const rpc = jsonrpc.error(null, jsonrpc.JsonRpcError.invalidRequest(null)); + + await Queue.enqueue(rpc); +} + +export async function sendInvalidParamsError(id: jsonrpc.ID): Promise { + const rpc = jsonrpc.error(id, jsonrpc.JsonRpcError.invalidParams(null)); + + await Queue.enqueue(rpc); +} + +export async function sendParseError(): Promise { + const rpc = jsonrpc.error(null, jsonrpc.JsonRpcError.parseError(null)); + + await Queue.enqueue(rpc); +} + +export async function sendMethodNotFound(id: jsonrpc.ID): Promise { + const rpc = jsonrpc.error(id, jsonrpc.JsonRpcError.methodNotFound(null)); + + await Queue.enqueue(rpc); +} + +export async function errorResponse({ error: { message, code = -32000, data = {} }, id }: ErrorResponseDescriptor): Promise { + const logger = AppObjectRegistry.get('logger'); + + if (logger?.hasEntries()) { + data.logs = logger.getLogs(); + } + + const rpc = jsonrpc.error(id, new jsonrpc.JsonRpcError(message, code, data)); + + await Queue.enqueue(rpc); +} + +export async function successResponse({ id, result }: SuccessResponseDescriptor): Promise { + const payload = { value: result } as Record; + const logger = AppObjectRegistry.get('logger'); + + if (logger?.hasEntries()) { + payload.logs = logger.getLogs(); + } + + const rpc = jsonrpc.success(id, payload); + + await Queue.enqueue(rpc); +} + +export function pongResponse(): Promise { + return Promise.resolve(Queue.enqueue(COMMAND_PONG)); +} + +export async function sendRequest(requestDescriptor: RequestDescriptor): Promise { + const request = jsonrpc.request(Math.random().toString(36).slice(2), requestDescriptor.method, requestDescriptor.params); + + // TODO: add timeout to this + const responsePromise = new Promise((resolve, reject) => { + const handler = (event: Event) => { + if (event instanceof ErrorEvent) { + reject(event.error); + } + + if (event instanceof CustomEvent) { + resolve(event.detail); + } + + RPCResponseObserver.removeEventListener(`response:${request.id}`, handler); + }; + + RPCResponseObserver.addEventListener(`response:${request.id}`, handler); + }); + + await Queue.enqueue(request); + + return responsePromise as Promise; +} + +export function sendNotification({ method, params }: NotificationDescriptor) { + const request = jsonrpc.notification(method, params); + + Queue.enqueue(request); +} + +export function log(params: jsonrpc.RpcParams) { + sendNotification({ method: 'log', params }); +} diff --git a/packages/apps-engine/deno-runtime/lib/require.ts b/packages/apps-engine/deno-runtime/lib/require.ts new file mode 100644 index 000000000000..3288ecf67ffa --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/require.ts @@ -0,0 +1,14 @@ +import { createRequire } from 'node:module'; + +const _require = createRequire(import.meta.url); + +export const require = (mod: string) => { + // When we try to import something from the apps-engine, we resolve the path using import maps from Deno + // However, the import maps are configured to look at the source folder for typescript files, but during + // runtime those files are not available + if (mod.startsWith('@rocket.chat/apps-engine')) { + mod = import.meta.resolve(mod).replace('file://', '').replace('src/', ''); + } + + return _require(mod); +} diff --git a/packages/apps-engine/deno-runtime/lib/room.ts b/packages/apps-engine/deno-runtime/lib/room.ts new file mode 100644 index 000000000000..b7423cdd31ff --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/room.ts @@ -0,0 +1,104 @@ +import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; +import type { RoomType } from '@rocket.chat/apps-engine/definition/rooms/RoomType.ts'; +import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; +import type { AppManager } from '@rocket.chat/apps-engine/server/AppManager.ts'; + +const PrivateManager = Symbol('RoomPrivateManager'); + +export class Room { + public id: string | undefined; + + public displayName?: string; + + public slugifiedName: string | undefined; + + public type: RoomType | undefined; + + public creator: IUser | undefined; + + public isDefault?: boolean; + + public isReadOnly?: boolean; + + public displaySystemMessages?: boolean; + + public messageCount?: number; + + public createdAt?: Date; + + public updatedAt?: Date; + + public lastModifiedAt?: Date; + + public customFields?: { [key: string]: unknown }; + + public userIds?: Array; + + private _USERNAMES: Promise> | undefined; + + private [PrivateManager]: AppManager | undefined; + + /** + * @deprecated + */ + public get usernames(): Promise> { + if (!this._USERNAMES) { + this._USERNAMES = this[PrivateManager]?.getBridges().getInternalBridge().doGetUsernamesOfRoomById(this.id); + } + + return this._USERNAMES || Promise.resolve([]); + } + + public set usernames(usernames) {} + + public constructor(room: IRoom, manager: AppManager) { + Object.assign(this, room); + + Object.defineProperty(this, PrivateManager, { + configurable: false, + enumerable: false, + writable: false, + value: manager, + }); + } + + get value(): object { + return { + id: this.id, + displayName: this.displayName, + slugifiedName: this.slugifiedName, + type: this.type, + creator: this.creator, + isDefault: this.isDefault, + isReadOnly: this.isReadOnly, + displaySystemMessages: this.displaySystemMessages, + messageCount: this.messageCount, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + lastModifiedAt: this.lastModifiedAt, + customFields: this.customFields, + userIds: this.userIds, + }; + } + + public async getUsernames(): Promise> { + // Get usernames + if (!this._USERNAMES) { + this._USERNAMES = await this[PrivateManager]?.getBridges().getInternalBridge().doGetUsernamesOfRoomById(this.id); + } + + return this._USERNAMES || []; + } + + public toJSON() { + return this.value; + } + + public toString() { + return this.value; + } + + public valueOf() { + return this.value; + } +} diff --git a/packages/apps-engine/deno-runtime/lib/roomFactory.ts b/packages/apps-engine/deno-runtime/lib/roomFactory.ts new file mode 100644 index 000000000000..8c270eeb86b9 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/roomFactory.ts @@ -0,0 +1,27 @@ +import type { IRoom } from "@rocket.chat/apps-engine/definition/rooms/IRoom.ts"; +import type { AppManager } from "@rocket.chat/apps-engine/server/AppManager.ts"; + +import { AppAccessors } from "./accessors/mod.ts"; +import { Room } from "./room.ts"; +import { JsonRpcError } from "jsonrpc-lite"; + +const getMockAppManager = (senderFn: AppAccessors['senderFn']) => ({ + getBridges: () => ({ + getInternalBridge: () => ({ + doGetUsernamesOfRoomById: (roomId: string) => { + return senderFn({ + method: 'bridges:getInternalBridge:doGetUsernamesOfRoomById', + params: [roomId], + }).then((result) => result.result).catch((err) => { + throw new JsonRpcError(`Error getting usernames of room: ${err}`, -32000); + }) + }, + }), + }), +}); + +export default function createRoom(room: IRoom, senderFn: AppAccessors['senderFn']) { + const mockAppManager = getMockAppManager(senderFn); + + return new Room(room, mockAppManager as unknown as AppManager); +} diff --git a/packages/apps-engine/deno-runtime/lib/sanitizeDeprecatedUsage.ts b/packages/apps-engine/deno-runtime/lib/sanitizeDeprecatedUsage.ts new file mode 100644 index 000000000000..91cf6587e741 --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/sanitizeDeprecatedUsage.ts @@ -0,0 +1,20 @@ +import { fixBrokenSynchronousAPICalls } from "./ast/mod.ts"; + +function hasPotentialDeprecatedUsage(source: string) { + return ( + // potential usage of Room.usernames getter + source.includes('.usernames') || + // potential usage of LivechatRead.isOnline method + source.includes('.isOnline(') || + // potential usage of LivechatCreator.createToken method + source.includes('.createToken(') + ) +} + +export function sanitizeDeprecatedUsage(source: string) { + if (!hasPotentialDeprecatedUsage(source)) { + return source; + } + + return fixBrokenSynchronousAPICalls(source); +} diff --git a/packages/apps-engine/deno-runtime/lib/tests/logger.test.ts b/packages/apps-engine/deno-runtime/lib/tests/logger.test.ts new file mode 100644 index 000000000000..f69a728e79af --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/tests/logger.test.ts @@ -0,0 +1,111 @@ +import { assertEquals } from 'https://deno.land/std@0.203.0/assert/mod.ts'; +import { describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; +import { Logger } from "../logger.ts"; + +describe('Logger', () => { + it('getLogs should return an array of entries', () => { + const logger = new Logger('test'); + logger.info('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.method, 'test'); + }) + + it('should be able to add entries of different severity', () => { + const logger = new Logger('test'); + logger.info('test'); + logger.debug('test'); + logger.error('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 3); + assertEquals(logs.entries[0].severity, 'info'); + assertEquals(logs.entries[1].severity, 'debug'); + assertEquals(logs.entries[2].severity, 'error'); + }) + + it('should be able to add an info entry', () => { + const logger = new Logger('test'); + logger.info('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'info'); + }); + + it('should be able to add an debug entry', () => { + const logger = new Logger('test'); + logger.debug('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'debug'); + }); + + it('should be able to add an error entry', () => { + const logger = new Logger('test'); + logger.error('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'error'); + }); + + it('should be able to add an success entry', () => { + const logger = new Logger('test'); + logger.success('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'success'); + }); + + it('should be able to add an warning entry', () => { + const logger = new Logger('test'); + logger.warn('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'warning'); + }); + + it('should be able to add an log entry', () => { + const logger = new Logger('test'); + logger.log('test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'log'); + }); + + it('should be able to add an entry with multiple arguments', () => { + const logger = new Logger('test'); + logger.log('test', 'test', 'test'); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].args[1], 'test'); + assertEquals(logs.entries[0].args[2], 'test'); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'log'); + }); + + it('should be able to add an entry with multiple arguments of different types', () => { + const logger = new Logger('test'); + logger.log('test', 1, true, { foo: 'bar' }); + const logs = logger.getLogs(); + assertEquals(logs.entries.length, 1); + assertEquals(logs.entries[0].args[0], 'test'); + assertEquals(logs.entries[0].args[1], 1); + assertEquals(logs.entries[0].args[2], true); + assertEquals(logs.entries[0].args[3], { foo: 'bar' }); + assertEquals(logs.entries[0].method, 'test'); + assertEquals(logs.entries[0].severity, 'log'); + }); + +}) diff --git a/packages/apps-engine/deno-runtime/lib/tests/messenger.test.ts b/packages/apps-engine/deno-runtime/lib/tests/messenger.test.ts new file mode 100644 index 000000000000..9b4f128380bc --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/tests/messenger.test.ts @@ -0,0 +1,96 @@ +import { assertEquals, assertObjectMatch } from 'https://deno.land/std@0.203.0/assert/mod.ts'; +import { afterAll, beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; +import { spy } from 'https://deno.land/std@0.203.0/testing/mock.ts'; + +import * as Messenger from '../messenger.ts'; +import { AppObjectRegistry } from '../../AppObjectRegistry.ts'; +import { Logger } from '../logger.ts'; + +describe('Messenger', () => { + beforeEach(() => { + AppObjectRegistry.clear(); + AppObjectRegistry.set('logger', new Logger('test')); + AppObjectRegistry.set('id', 'test'); + Messenger.Transport.selectTransport('noop'); + }); + + afterAll(() => { + AppObjectRegistry.clear(); + Messenger.Transport.selectTransport('stdout'); + }); + + it('should add logs to success responses', async () => { + const theSpy = spy(Messenger.Queue, 'enqueue'); + + const logger = AppObjectRegistry.get('logger') as Logger; + + logger.info('test'); + + await Messenger.successResponse({ id: 'test', result: 'test' }); + + assertEquals(theSpy.calls.length, 1); + + const [responseArgument] = theSpy.calls[0].args; + + assertObjectMatch(responseArgument, { + jsonrpc: '2.0', + id: 'test', + result: { + value: 'test', + logs: { + appId: 'test', + method: 'test', + entries: [ + { + severity: 'info', + method: 'test', + args: ['test'], + caller: 'anonymous OR constructor', + }, + ], + }, + }, + }); + + theSpy.restore(); + }); + + it('should add logs to error responses', async () => { + const theSpy = spy(Messenger.Queue, 'enqueue'); + + const logger = AppObjectRegistry.get('logger') as Logger; + + logger.info('test'); + + await Messenger.errorResponse({ id: 'test', error: { code: -32000, message: 'test' } }); + + assertEquals(theSpy.calls.length, 1); + + const [responseArgument] = theSpy.calls[0].args; + + assertObjectMatch(responseArgument, { + jsonrpc: '2.0', + id: 'test', + error: { + code: -32000, + message: 'test', + data: { + logs: { + appId: 'test', + method: 'test', + entries: [ + { + severity: 'info', + method: 'test', + args: ['test'], + caller: 'anonymous OR constructor', + }, + ], + }, + }, + }, + }); + + theSpy.restore(); + }); +}); diff --git a/packages/apps-engine/deno-runtime/main.ts b/packages/apps-engine/deno-runtime/main.ts new file mode 100644 index 000000000000..09be5258ecd0 --- /dev/null +++ b/packages/apps-engine/deno-runtime/main.ts @@ -0,0 +1,129 @@ +if (!Deno.args.includes('--subprocess')) { + Deno.stderr.writeSync( + new TextEncoder().encode(` + This is a Deno wrapper for Rocket.Chat Apps. It is not meant to be executed stand-alone; + It is instead meant to be executed as a subprocess by the Apps-Engine framework. + `), + ); + Deno.exit(1001); +} + +import { JsonRpcError } from 'jsonrpc-lite'; +import type { App } from '@rocket.chat/apps-engine/definition/App.ts'; + +import * as Messenger from './lib/messenger.ts'; +import { decoder } from './lib/codec.ts'; +import { AppObjectRegistry } from './AppObjectRegistry.ts'; +import { Logger } from './lib/logger.ts'; + +import slashcommandHandler from './handlers/slashcommand-handler.ts'; +import videoConferenceHandler from './handlers/videoconference-handler.ts'; +import apiHandler from './handlers/api-handler.ts'; +import handleApp from './handlers/app/handler.ts'; +import handleScheduler from './handlers/scheduler-handler.ts'; + +type Handlers = { + app: typeof handleApp; + api: typeof apiHandler; + slashcommand: typeof slashcommandHandler; + videoconference: typeof videoConferenceHandler; + scheduler: typeof handleScheduler; + ping: (method: string, params: unknown) => 'pong'; +}; + +const COMMAND_PING = '_zPING'; + +async function requestRouter({ type, payload }: Messenger.JsonRpcRequest): Promise { + const methodHandlers: Handlers = { + app: handleApp, + api: apiHandler, + slashcommand: slashcommandHandler, + videoconference: videoConferenceHandler, + scheduler: handleScheduler, + ping: (_method, _params) => 'pong', + }; + + // We're not handling notifications at the moment + if (type === 'notification') { + return Messenger.sendInvalidRequestError(); + } + + const { id, method, params } = payload; + + const logger = new Logger(method); + AppObjectRegistry.set('logger', logger); + + const app = AppObjectRegistry.get('app'); + + if (app) { + // Same logic as applied in the ProxiedApp class previously + (app as unknown as Record).logger = logger; + } + + const [methodPrefix] = method.split(':') as [keyof Handlers]; + const handler = methodHandlers[methodPrefix]; + + if (!handler) { + return Messenger.errorResponse({ + error: { message: 'Method not found', code: -32601 }, + id, + }); + } + + const result = await handler(method, params); + + if (result instanceof JsonRpcError) { + return Messenger.errorResponse({ id, error: result }); + } + + return Messenger.successResponse({ id, result }); +} + +function handleResponse(response: Messenger.JsonRpcResponse): void { + let event: Event; + + if (response.type === 'error') { + event = new ErrorEvent(`response:${response.payload.id}`, { + error: response.payload, + }); + } else { + event = new CustomEvent(`response:${response.payload.id}`, { + detail: response.payload, + }); + } + + Messenger.RPCResponseObserver.dispatchEvent(event); +} + +async function main() { + Messenger.sendNotification({ method: 'ready' }); + + for await (const message of decoder.decodeStream(Deno.stdin.readable)) { + try { + // Process PING command first as it is not JSON RPC + if (message === COMMAND_PING) { + Messenger.pongResponse(); + continue; + } + + const JSONRPCMessage = Messenger.parseMessage(message as Record); + + if (Messenger.isRequest(JSONRPCMessage)) { + void requestRouter(JSONRPCMessage); + continue; + } + + if (Messenger.isResponse(JSONRPCMessage)) { + handleResponse(JSONRPCMessage); + } + } catch (error) { + if (Messenger.isErrorResponse(error)) { + await Messenger.errorResponse(error); + } else { + await Messenger.sendParseError(); + } + } + } +} + +main(); diff --git a/packages/apps-engine/package.json b/packages/apps-engine/package.json new file mode 100644 index 000000000000..c229ff447000 --- /dev/null +++ b/packages/apps-engine/package.json @@ -0,0 +1,132 @@ +{ + "name": "@rocket.chat/apps-engine", + "version": "1.47.0-alpha", + "description": "The engine code for the Rocket.Chat Apps which manages, runs, translates, coordinates and all of that.", + "main": "index", + "typings": "index", + "scripts": { + "start": "run-s .:build:clean .:build:watch", + "testunit": "run-p .:test:node .:test:deno", + ".:test:node": "NODE_ENV=test ts-node ./tests/runner.ts", + ".:test:deno": "cd deno-runtime && deno task test", + "lint": "run-p .:lint:eslint .:lint:deno", + ".:lint:eslint": "eslint .", + ".:lint:deno": "deno lint --ignore=deno-runtime/.deno deno-runtime/", + "fix-lint": "eslint . --fix", + "build": "run-s .:build:clean .:build:default .:build:deno-cache", + ".:build:clean": "rimraf client definition server", + ".:build:default": "tsc -p tsconfig.json", + ".:build:deno-cache": "node scripts/deno-cache.js", + ".:build:watch": "yarn .:build:default --watch", + "typecheck": "tsc -p tsconfig.json --noEmit", + "bundle": "node scripts/bundle.js", + "gen-doc": "typedoc", + "prepack": "yarn bundle" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/RocketChat/Rocket.Chat.Apps-engine.git" + }, + "keywords": [ + "rocket.chat", + "team chat", + "apps engine" + ], + "files": [ + "client/**", + "definition/**", + "deno-runtime/**", + "lib/**", + "scripts/**", + "server/**" + ], + "publishConfig": { + "access": "public" + }, + "author": { + "name": "Rocket.Chat", + "url": "https://rocket.chat/" + }, + "contributors": [ + { + "name": "Bradley Hilton", + "email": "bradley.hilton@rocket.chat" + }, + { + "name": "Rodrigo Nascimento", + "email": "rodrigo.nascimento@rocket.chat" + }, + { + "name": "Douglas Gubert", + "email": "douglas.gubert@rocket.chat" + } + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/RocketChat/Rocket.Chat.Apps-engine/issues" + }, + "homepage": "https://github.com/RocketChat/Rocket.Chat.Apps-engine#readme", + "devDependencies": { + "@rocket.chat/eslint-config": "workspace:~", + "@rocket.chat/ui-kit": "workspace:~", + "@types/adm-zip": "^0.5.0", + "@types/debug": "^4.1.12", + "@types/lodash.clonedeep": "^4.5.7", + "@types/nedb": "^1.8.12", + "@types/node": "^18.0.0", + "@types/semver": "^5.5.0", + "@types/stack-trace": "0.0.29", + "@types/uuid": "~8.3.4", + "@typescript-eslint/eslint-plugin": "~5.60.1", + "@typescript-eslint/parser": "~5.60.1", + "alsatian": "^2.4.0", + "browserify": "^16.5.2", + "eslint": "~8.45.0", + "nedb": "^1.8.0", + "npm-run-all": "^4.1.5", + "nyc": "^14.1.1", + "rimraf": "^6.0.1", + "tap-bark": "^1.0.0", + "ts-node": "^6.2.0", + "typedoc": "~0.24.8", + "typescript": "~5.1.6", + "uglify-es": "^3.3.9" + }, + "dependencies": { + "@msgpack/msgpack": "3.0.0-beta2", + "adm-zip": "^0.5.9", + "cryptiles": "^4.1.3", + "debug": "^4.3.4", + "esbuild": "^0.20.2", + "jose": "^4.11.1", + "jsonrpc-lite": "^2.2.0", + "lodash.clonedeep": "^4.5.0", + "semver": "^5.7.1", + "stack-trace": "0.0.10", + "uuid": "~8.3.2" + }, + "peerDependencies": { + "@rocket.chat/ui-kit": "workspace:^" + }, + "nyc": { + "include": [ + "src/*.ts", + "src/server/**/*.ts" + ], + "extension": [ + ".ts" + ], + "reporter": [ + "lcov", + "json", + "html" + ], + "all": true + }, + "volta": { + "extends": "../../package.json" + }, + "installConfig": { + "hoistingLimits": "workspaces" + } +} diff --git a/packages/apps-engine/scripts/bundle.js b/packages/apps-engine/scripts/bundle.js new file mode 100644 index 000000000000..a7f8932bec12 --- /dev/null +++ b/packages/apps-engine/scripts/bundle.js @@ -0,0 +1,35 @@ +const fs = require('fs'); +const path = require('path'); +const { Readable } = require('stream'); + +const browserify = require('browserify'); +const { minify } = require('uglify-es'); + +const targetDir = path.join(__dirname, '..', 'client'); + +// browserify accepts either a stream or a file path +const glue = new Readable({ + read() { + console.log('read'); + this.push("window.AppsEngineUIClient = require('./AppsEngineUIClient').AppsEngineUIClient;"); + this.push(null); + }, +}); + +async function main() { + const bundle = await new Promise((resolve, reject) => + browserify(glue, { + basedir: targetDir, + }).bundle((err, bundle) => { + if (err) return reject(err); + + resolve(bundle.toString()); + }), + ); + + const result = minify(bundle); + + fs.writeFileSync(path.join(targetDir, 'AppsEngineUIClient.min.js'), result.code); +} + +main(); diff --git a/packages/apps-engine/scripts/deno-cache.js b/packages/apps-engine/scripts/deno-cache.js new file mode 100644 index 000000000000..acf2f4b977b4 --- /dev/null +++ b/packages/apps-engine/scripts/deno-cache.js @@ -0,0 +1,25 @@ +const childProcess = require('child_process'); +const path = require('path'); + +try { + childProcess.execSync('deno info'); +} catch (e) { + console.error( + 'Could not execute "deno" in the system. It is now a requirement for the Apps-Engine framework, and Rocket.Chat apps will not work without it.\n', + 'Make sure to install Deno and run the installation process for the Apps-Engine again. More info on https://docs.deno.com/runtime/manual/getting_started/installation', + ); + process.exit(1); +} + +const rootPath = path.join(__dirname, '..'); +const denoRuntimePath = path.join(rootPath, 'deno-runtime'); +const DENO_DIR = process.env.DENO_DIR ?? path.join(rootPath, '.deno-cache'); + +childProcess.execSync('deno cache main.ts', { + cwd: denoRuntimePath, + env: { + DENO_DIR, + PATH: process.env.PATH, + }, + stdio: 'inherit', +}); diff --git a/packages/apps-engine/src/client/AppClientManager.ts b/packages/apps-engine/src/client/AppClientManager.ts new file mode 100644 index 000000000000..5d409f148f5f --- /dev/null +++ b/packages/apps-engine/src/client/AppClientManager.ts @@ -0,0 +1,28 @@ +import type { IAppInfo } from '../definition/metadata'; +import { AppServerCommunicator } from './AppServerCommunicator'; +import { AppsEngineUIHost } from './AppsEngineUIHost'; + +export class AppClientManager { + private apps: Array; + + constructor(private readonly appsEngineUIHost: AppsEngineUIHost, private readonly communicator?: AppServerCommunicator) { + if (!(appsEngineUIHost instanceof AppsEngineUIHost)) { + throw new Error('The appClientUIHost must extend appClientUIHost'); + } + + if (communicator && !(communicator instanceof AppServerCommunicator)) { + throw new Error('The communicator must extend AppServerCommunicator'); + } + + this.apps = []; + } + + public async load(): Promise { + this.apps = await this.communicator.getEnabledApps(); + console.log('Enabled apps:', this.apps); + } + + public async initialize(): Promise { + this.appsEngineUIHost.initialize(); + } +} diff --git a/packages/apps-engine/src/client/AppServerCommunicator.ts b/packages/apps-engine/src/client/AppServerCommunicator.ts new file mode 100644 index 000000000000..fae400bc7ff7 --- /dev/null +++ b/packages/apps-engine/src/client/AppServerCommunicator.ts @@ -0,0 +1,16 @@ +import type { IAppInfo } from '../definition/metadata'; + +export abstract class AppServerCommunicator { + public abstract getEnabledApps(): Promise>; + + public abstract getDisabledApps(): Promise>; + + // Map> + public abstract getLanguageAdditions(): Promise>>; + + // Map> + public abstract getSlashCommands(): Promise>>; + + // Map> + public abstract getContextualBarButtons(): Promise>>; +} diff --git a/packages/apps-engine/src/client/AppsEngineUIClient.ts b/packages/apps-engine/src/client/AppsEngineUIClient.ts new file mode 100644 index 000000000000..620be5e21d01 --- /dev/null +++ b/packages/apps-engine/src/client/AppsEngineUIClient.ts @@ -0,0 +1,70 @@ +import { ACTION_ID_LENGTH, MESSAGE_ID } from './constants'; +import type { IExternalComponentRoomInfo, IExternalComponentUserInfo } from './definition'; +import { AppsEngineUIMethods } from './definition/AppsEngineUIMethods'; +import { randomString } from './utils'; + +/** + * Represents the SDK provided to the external component. + */ +export class AppsEngineUIClient { + private listener: (this: Window, ev: MessageEvent) => any; + + private callbacks: Map any>; + + constructor() { + this.listener = () => console.log('init'); + this.callbacks = new Map(); + } + + /** + * Get the current user's information. + * + * @return the information of the current user. + */ + public getUserInfo(): Promise { + return this.call(AppsEngineUIMethods.GET_USER_INFO); + } + + /** + * Get the current room's information. + * + * @return the information of the current room. + */ + public getRoomInfo(): Promise { + return this.call(AppsEngineUIMethods.GET_ROOM_INFO); + } + + /** + * Initialize the app SDK for communicating with Rocket.Chat + */ + public init(): void { + this.listener = ({ data }) => { + if (!data?.hasOwnProperty(MESSAGE_ID)) { + return; + } + + const { + [MESSAGE_ID]: { id, payload }, + } = data; + + if (this.callbacks.has(id)) { + const resolve = this.callbacks.get(id); + + if (typeof resolve === 'function') { + resolve(payload); + } + this.callbacks.delete(id); + } + }; + window.addEventListener('message', this.listener); + } + + private call(action: string, payload?: any): Promise { + return new Promise((resolve) => { + const id = randomString(ACTION_ID_LENGTH); + + window.parent.postMessage({ [MESSAGE_ID]: { action, payload, id } }, '*'); + this.callbacks.set(id, resolve); + }); + } +} diff --git a/packages/apps-engine/src/client/AppsEngineUIHost.ts b/packages/apps-engine/src/client/AppsEngineUIHost.ts new file mode 100644 index 000000000000..02f82f236ed2 --- /dev/null +++ b/packages/apps-engine/src/client/AppsEngineUIHost.ts @@ -0,0 +1,78 @@ +import { MESSAGE_ID } from './constants'; +import type { IAppsEngineUIResponse, IExternalComponentRoomInfo, IExternalComponentUserInfo } from './definition'; +import { AppsEngineUIMethods } from './definition'; + +type HandleActionData = IExternalComponentUserInfo | IExternalComponentRoomInfo; + +/** + * Represents the host which handles API calls from external components. + */ +export abstract class AppsEngineUIHost { + /** + * The message emitter who calling the API. + */ + private responseDestination!: Window; + + constructor() { + this.initialize(); + } + + /** + * initialize the AppClientUIHost by registering window `message` listener + */ + public initialize() { + window.addEventListener('message', async ({ data, source }) => { + if (!data?.hasOwnProperty(MESSAGE_ID)) { + return; + } + + this.responseDestination = source as Window; + + const { + [MESSAGE_ID]: { action, id }, + } = data; + + switch (action) { + case AppsEngineUIMethods.GET_USER_INFO: + this.handleAction(action, id, await this.getClientUserInfo()); + break; + case AppsEngineUIMethods.GET_ROOM_INFO: + this.handleAction(action, id, await this.getClientRoomInfo()); + break; + } + }); + } + + /** + * Get the current user's information. + */ + public abstract getClientUserInfo(): Promise; + + /** + * Get the opened room's information. + */ + public abstract getClientRoomInfo(): Promise; + + /** + * Handle the action sent from the external component. + * @param action the name of the action + * @param id the unique id of the API call + * @param data The data that will return to the caller + */ + private async handleAction(action: AppsEngineUIMethods, id: string, data: HandleActionData): Promise { + if (this.responseDestination instanceof MessagePort || this.responseDestination instanceof ServiceWorker) { + return; + } + + this.responseDestination.postMessage( + { + [MESSAGE_ID]: { + id, + action, + payload: data, + } as IAppsEngineUIResponse, + }, + '*', + ); + } +} diff --git a/packages/apps-engine/src/client/constants/index.ts b/packages/apps-engine/src/client/constants/index.ts new file mode 100644 index 000000000000..bd7f2e779ca1 --- /dev/null +++ b/packages/apps-engine/src/client/constants/index.ts @@ -0,0 +1,6 @@ +/** + * The id length of each action. + */ +export const ACTION_ID_LENGTH = 80; + +export const MESSAGE_ID = 'rc-apps-engine-ui'; diff --git a/packages/apps-engine/src/client/definition/AppsEngineUIMethods.ts b/packages/apps-engine/src/client/definition/AppsEngineUIMethods.ts new file mode 100644 index 000000000000..df150f9ce62b --- /dev/null +++ b/packages/apps-engine/src/client/definition/AppsEngineUIMethods.ts @@ -0,0 +1,7 @@ +/** + * The actions provided by the AppClientSDK. + */ +export enum AppsEngineUIMethods { + GET_USER_INFO = 'getUserInfo', + GET_ROOM_INFO = 'getRoomInfo', +} diff --git a/packages/apps-engine/src/client/definition/IAppsEngineUIResponse.ts b/packages/apps-engine/src/client/definition/IAppsEngineUIResponse.ts new file mode 100644 index 000000000000..dff7289226a4 --- /dev/null +++ b/packages/apps-engine/src/client/definition/IAppsEngineUIResponse.ts @@ -0,0 +1,19 @@ +import type { IExternalComponentRoomInfo, IExternalComponentUserInfo } from './index'; + +/** + * The response to the AppClientSDK's API call. + */ +export interface IAppsEngineUIResponse { + /** + * The name of the action + */ + action: string; + /** + * The unique id of the API call + */ + id: string; + /** + * The data that will return to the caller + */ + payload: IExternalComponentUserInfo | IExternalComponentRoomInfo; +} diff --git a/packages/apps-engine/src/client/definition/IExternalComponentRoomInfo.ts b/packages/apps-engine/src/client/definition/IExternalComponentRoomInfo.ts new file mode 100644 index 000000000000..32ca449e9650 --- /dev/null +++ b/packages/apps-engine/src/client/definition/IExternalComponentRoomInfo.ts @@ -0,0 +1,16 @@ +import type { IRoom } from '../../definition/rooms'; +import type { IExternalComponentUserInfo } from './IExternalComponentUserInfo'; + +type ClientRoomInfo = Pick; + +/** + * Represents the room's information returned to the + * external component. + */ +export interface IExternalComponentRoomInfo extends ClientRoomInfo { + /** + * the list that contains all the users belonging + * to this room. + */ + members: Array; +} diff --git a/packages/apps-engine/src/client/definition/IExternalComponentUserInfo.ts b/packages/apps-engine/src/client/definition/IExternalComponentUserInfo.ts new file mode 100644 index 000000000000..9212f5b39876 --- /dev/null +++ b/packages/apps-engine/src/client/definition/IExternalComponentUserInfo.ts @@ -0,0 +1,14 @@ +import type { IUser } from '../../definition/users'; + +type ClientUserInfo = Pick; + +/** + * Represents the user's information returned to + * the external component. + */ +export interface IExternalComponentUserInfo extends ClientUserInfo { + /** + * the avatar URL of the Rocket.Chat user + */ + avatarUrl: string; +} diff --git a/packages/apps-engine/src/client/definition/index.ts b/packages/apps-engine/src/client/definition/index.ts new file mode 100644 index 000000000000..70a1fe884a6a --- /dev/null +++ b/packages/apps-engine/src/client/definition/index.ts @@ -0,0 +1,4 @@ +export * from './AppsEngineUIMethods'; +export * from './IExternalComponentUserInfo'; +export * from './IExternalComponentRoomInfo'; +export * from './IAppsEngineUIResponse'; diff --git a/packages/apps-engine/src/client/index.ts b/packages/apps-engine/src/client/index.ts new file mode 100644 index 000000000000..2ebfee0264d2 --- /dev/null +++ b/packages/apps-engine/src/client/index.ts @@ -0,0 +1,4 @@ +import { AppClientManager } from './AppClientManager'; +import { AppServerCommunicator } from './AppServerCommunicator'; + +export { AppClientManager, AppServerCommunicator }; diff --git a/packages/apps-engine/src/client/utils/index.ts b/packages/apps-engine/src/client/utils/index.ts new file mode 100644 index 000000000000..f5e851e7d50f --- /dev/null +++ b/packages/apps-engine/src/client/utils/index.ts @@ -0,0 +1,18 @@ +/** + * Generate a random string with the specified length. + * @param length the length for the generated random string. + */ +export function randomString(length: number): string { + const buffer: Array = []; + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + + for (let i = 0; i < length; i++) { + buffer.push(chars[getRandomInt(chars.length)]); + } + + return buffer.join(''); +} + +function getRandomInt(max: number): number { + return Math.floor(Math.random() * Math.floor(max)); +} diff --git a/packages/apps-engine/src/definition/App.ts b/packages/apps-engine/src/definition/App.ts new file mode 100644 index 000000000000..0044f35134b6 --- /dev/null +++ b/packages/apps-engine/src/definition/App.ts @@ -0,0 +1,236 @@ +import { AppStatus } from './AppStatus'; +import type { IApp } from './IApp'; +import type { + IAppAccessors, + IAppInstallationContext, + IAppUninstallationContext, + IConfigurationExtend, + IConfigurationModify, + IEnvironmentRead, + IHttp, + ILogger, + IModify, + IPersistence, + IRead, + IAppUpdateContext, +} from './accessors'; +import type { IAppAuthorInfo } from './metadata/IAppAuthorInfo'; +import type { IAppInfo } from './metadata/IAppInfo'; +import type { ISetting } from './settings'; +import type { ISettingUpdateContext } from './settings/ISettingUpdateContext'; + +export abstract class App implements IApp { + private status: AppStatus = AppStatus.UNKNOWN; + + /** + * Create a new App, this is called whenever the server starts up and initiates the Apps. + * Note, your implementation of this class should call `super(name, id, version)` so we have it. + * Also, please use the `initialize()` method to do items instead of the constructor as the constructor + * *might* be called more than once but the `initialize()` will only be called once. + */ + public constructor(private readonly info: IAppInfo, private readonly logger: ILogger, private readonly accessors?: IAppAccessors) { + this.logger.debug( + `Constructed the App ${this.info.name} (${this.info.id})`, + `v${this.info.version} which depends on the API v${this.info.requiredApiVersion}!`, + `Created by ${this.info.author.name}`, + ); + + this.setStatus(AppStatus.CONSTRUCTED); + } + + public async getStatus(): Promise { + return this.status; + } + + /** + * Get the name of this App. + * + * @return {string} the name + */ + public getName(): string { + return this.info.name; + } + + /** + * Gets the sluggified name of this App. + * + * @return {string} the name slugged + */ + public getNameSlug(): string { + return this.info.nameSlug; + } + + /** + * Gets the username of this App's app user. + * + * @return {string} the username of the app user + * + * @deprecated This method will be removed in the next major version. + * Please use read.getUserReader().getAppUser() instead. + */ + public getAppUserUsername(): string { + return `${this.info.nameSlug}.bot`; + } + + /** + * Get the ID of this App, please see for how to obtain an ID for your App. + * + * @return {number} the ID + */ + public getID(): string { + return this.info.id; + } + + /** + * Get the version of this App, using http://semver.org/. + * + * @return {string} the version + */ + public getVersion(): string { + return this.info.version; + } + + /** + * Get the description of this App, mostly used to show to the clients/administrators. + * + * @return {string} the description + */ + public getDescription(): string { + return this.info.description; + } + + /** + * Gets the API Version which this App depends on (http://semver.org/). + * This property is used for the dependency injections. + * + * @return {string} the required api version + */ + public getRequiredApiVersion(): string { + return this.info.requiredApiVersion; + } + + /** + * Gets the information regarding the author/maintainer of this App. + * + * @return author information + */ + public getAuthorInfo(): IAppAuthorInfo { + return this.info.author; + } + + /** + * Gets the entirity of the App's information. + * + * @return App information + */ + public getInfo(): IAppInfo { + return this.info; + } + + /** + * Gets the ILogger instance for this App. + * + * @return the logger instance + */ + public getLogger(): ILogger { + return this.logger; + } + + public getAccessors(): IAppAccessors { + return this.accessors; + } + + /** + * Method which will be called when the App is initialized. This is the recommended place + * to add settings and slash commands. If an error is thrown, all commands will be unregistered. + */ + public async initialize(configurationExtend: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise { + await this.extendConfiguration(configurationExtend, environmentRead); + } + + /** + * Method which is called when this App is enabled and can be called several + * times during this instance's life time. Once after the `initialize()` is called, + * pending it doesn't throw an error, and then anytime the App is enabled by the user. + * If this method, `onEnable()`, returns false, then this App will not + * actually be enabled (ex: a setting isn't configured). + * + * @return whether the App should be enabled or not + */ + public async onEnable(environment: IEnvironmentRead, configurationModify: IConfigurationModify): Promise { + return true; + } + + /** + * Method which is called when this App is disabled and it can be called several times. + * If this App was enabled and then the user disabled it, this method will be called. + */ + public async onDisable(configurationModify: IConfigurationModify): Promise {} + + /** + * Method which is called when the App is uninstalled and it is called one single time. + * + * This method will NOT be called when an App is getting disabled manually, ONLY when + * it's being uninstalled from Rocket.Chat. + */ + public async onUninstall(context: IAppUninstallationContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise {} + + /** + * Method which is called when the App is installed and it is called one single time. + * + * This method is NOT called when the App is updated. + */ + public async onInstall(context: IAppInstallationContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise {} + + /** + * Method which is called when the App is updated and it is called one single time. + * + * This method is NOT called when the App is installed. + */ + public async onUpdate(context: IAppUpdateContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise {} + + /** + * Method which is called whenever a setting which belongs to this App has been updated + * by an external system and not this App itself. The setting passed is the newly updated one. + * + * @param setting the setting which was updated + * @param configurationModify the accessor to modifiy the system + * @param reader the reader accessor + * @param http an accessor to the outside world + */ + public async onSettingUpdated(setting: ISetting, configurationModify: IConfigurationModify, read: IRead, http: IHttp): Promise {} + + /** + * Method which is called before a setting which belongs to this App is going to be updated + * by an external system and not this App itself. The setting passed is the newly updated one. + * + * @param setting the setting which is going to be updated + * @param configurationModify the accessor to modifiy the system + * @param reader the reader accessor + * @param http an accessor to the outside world + */ + public async onPreSettingUpdate(context: ISettingUpdateContext, configurationModify: IConfigurationModify, read: IRead, http: IHttp): Promise { + return context.newSetting; + } + + /** + * Method will be called during initialization. It allows for adding custom configuration options and defaults + * @param configuration + */ + protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise {} + + /** + * Sets the status this App is now at, use only when 100% true (it's protected for a reason). + * + * @param status the new status of this App + */ + protected async setStatus(status: AppStatus): Promise { + this.logger.debug(`The status is now: ${status}`); + this.status = status; + } + + // Avoid leaking references if object is serialized (e.g. to be sent over IPC) + public toJSON(): Record { + return this.info; + } +} diff --git a/packages/apps-engine/src/definition/AppStatus.ts b/packages/apps-engine/src/definition/AppStatus.ts new file mode 100644 index 000000000000..31638a8d0f1c --- /dev/null +++ b/packages/apps-engine/src/definition/AppStatus.ts @@ -0,0 +1,65 @@ +export enum AppStatus { + /** The status is known, aka not been constructed the proper way. */ + UNKNOWN = 'unknown', + /** The App has been constructed but that's it. */ + CONSTRUCTED = 'constructed', + /** The App's `initialize()` was called and returned true. */ + INITIALIZED = 'initialized', + /** The App's `onEnable()` was called, returned true, and this was done automatically (system start up). */ + AUTO_ENABLED = 'auto_enabled', + /** The App's `onEnable()` was called, returned true, and this was done by the user such as installing a new one. */ + MANUALLY_ENABLED = 'manually_enabled', + /** + * The App was disabled due to an error while attempting to compile it. + * An attempt to enable it again will fail, as it needs to be updated. + */ + COMPILER_ERROR_DISABLED = 'compiler_error_disabled', + /** + * The App was disable due to its license being invalid + */ + INVALID_LICENSE_DISABLED = 'invalid_license_disabled', + /** + * The app was disabled due to an invalid installation or validation in its signature. + */ + INVALID_INSTALLATION_DISABLED = 'invalid_installation_disabled', + /** The App was disabled due to an unrecoverable error being thrown. */ + ERROR_DISABLED = 'error_disabled', + /** The App was manually disabled by a user. */ + MANUALLY_DISABLED = 'manually_disabled', + INVALID_SETTINGS_DISABLED = 'invalid_settings_disabled', + /** The App was disabled due to other circumstances. */ + DISABLED = 'disabled', +} + +export class AppStatusUtilsDef { + public isEnabled(status: AppStatus): boolean { + switch (status) { + case AppStatus.AUTO_ENABLED: + case AppStatus.MANUALLY_ENABLED: + return true; + default: + return false; + } + } + + public isDisabled(status: AppStatus): boolean { + switch (status) { + case AppStatus.COMPILER_ERROR_DISABLED: + case AppStatus.ERROR_DISABLED: + case AppStatus.MANUALLY_DISABLED: + case AppStatus.INVALID_SETTINGS_DISABLED: + case AppStatus.INVALID_LICENSE_DISABLED: + case AppStatus.INVALID_INSTALLATION_DISABLED: + case AppStatus.DISABLED: + return true; + default: + return false; + } + } + + public isError(status: AppStatus): boolean { + return [AppStatus.ERROR_DISABLED, AppStatus.COMPILER_ERROR_DISABLED].includes(status); + } +} + +export const AppStatusUtils = new AppStatusUtilsDef(); diff --git a/packages/apps-engine/src/definition/IApp.ts b/packages/apps-engine/src/definition/IApp.ts new file mode 100644 index 000000000000..53faff9647f4 --- /dev/null +++ b/packages/apps-engine/src/definition/IApp.ts @@ -0,0 +1,90 @@ +import type { AppStatus } from './AppStatus'; +import type { IAppAccessors } from './accessors'; +import type { ILogger } from './accessors/ILogger'; +import type { IAppAuthorInfo } from './metadata/IAppAuthorInfo'; +import type { IAppInfo } from './metadata/IAppInfo'; + +export interface IApp { + /** + * Gets the status of this App. + * + * @return {AppStatus} the status/state of the App + */ + getStatus(): Promise; + + /** + * Get the name of this App. + * + * @return {string} the name + */ + getName(): string; + + /** + * Gets the sluggified name of this App. + * + * @return {string} the name slugged + */ + getNameSlug(): string; + + /** + * Gets the username of this App's app user. + * + * @return {string} the username of the app user + * + * @deprecated This method will be removed in the next major version. + * Please use read.getAppUser instead. + */ + getAppUserUsername(): string; + + /** + * Get the ID of this App, please see for how to obtain an ID for your App. + * + * @return {number} the ID + */ + getID(): string; + + /** + * Get the version of this App, using http://semver.org/. + * + * @return {string} the version + */ + getVersion(): string; + + /** + * Get the description of this App, mostly used to show to the clients/administrators. + * + * @return {string} the description + */ + getDescription(): string; + + /** + * Gets the API Version which this App depends on (http://semver.org/). + * This property is used for the dependency injections. + * + * @return {string} the required api version + */ + getRequiredApiVersion(): string; + + /** + * Gets the information regarding the author/maintainer of this App. + * + * @return author information + */ + getAuthorInfo(): IAppAuthorInfo; + + /** + * Gets the entirity of the App's information. + * + * @return App information + */ + getInfo(): IAppInfo; + + /** + * Gets the ILogger instance for this App. + * + * @return the logger instance + */ + getLogger(): ILogger; + + getAccessors(): IAppAccessors; +} diff --git a/packages/apps-engine/src/definition/LICENSE b/packages/apps-engine/src/definition/LICENSE new file mode 100644 index 000000000000..42ea81dc8cdb --- /dev/null +++ b/packages/apps-engine/src/definition/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015-2023 Rocket.Chat Technologies Corp. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/apps-engine/src/definition/accessors/IApiExtend.ts b/packages/apps-engine/src/definition/accessors/IApiExtend.ts new file mode 100644 index 000000000000..ab3210105e9c --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IApiExtend.ts @@ -0,0 +1,16 @@ +import type { IApi } from '../api'; + +/** + * This accessor provides methods for adding a custom api. + * It is provided during the initialization of your App + */ + +export interface IApiExtend { + /** + * Adds an api which can be called by external services lateron. + * Should an api already exists an error will be thrown. + * + * @param api the command information + */ + provideApi(api: IApi): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IAppAccessors.ts b/packages/apps-engine/src/definition/accessors/IAppAccessors.ts new file mode 100644 index 000000000000..c2ea3bfcacea --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IAppAccessors.ts @@ -0,0 +1,11 @@ +import type { IEnvironmentRead, IHttp, IRead } from '.'; +import type { IApiEndpointMetadata } from '../api'; +import type { IEnvironmentWrite } from './IEnvironmentWrite'; + +export interface IAppAccessors { + readonly environmentReader: IEnvironmentRead; + readonly environmentWriter: IEnvironmentWrite; + readonly reader: IRead; + readonly http: IHttp; + readonly providedApiEndpoints: Array; +} diff --git a/packages/apps-engine/src/definition/accessors/IAppInstallationContext.ts b/packages/apps-engine/src/definition/accessors/IAppInstallationContext.ts new file mode 100644 index 000000000000..0ca1c08ba0dc --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IAppInstallationContext.ts @@ -0,0 +1,5 @@ +import type { IUser } from '../users'; + +export interface IAppInstallationContext { + user: IUser; +} diff --git a/packages/apps-engine/src/definition/accessors/IAppUninstallationContext.ts b/packages/apps-engine/src/definition/accessors/IAppUninstallationContext.ts new file mode 100644 index 000000000000..96ddbfa03298 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IAppUninstallationContext.ts @@ -0,0 +1,5 @@ +import type { IUser } from '../users'; + +export interface IAppUninstallationContext { + user: IUser; +} diff --git a/packages/apps-engine/src/definition/accessors/IAppUpdateContext.ts b/packages/apps-engine/src/definition/accessors/IAppUpdateContext.ts new file mode 100644 index 000000000000..d0bcf7ea280b --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IAppUpdateContext.ts @@ -0,0 +1,6 @@ +import type { IUser } from '../users'; + +export interface IAppUpdateContext { + user?: IUser; + oldAppVersion: string; +} diff --git a/packages/apps-engine/src/definition/accessors/ICloudWorkspaceRead.ts b/packages/apps-engine/src/definition/accessors/ICloudWorkspaceRead.ts new file mode 100644 index 000000000000..c78749fae59b --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ICloudWorkspaceRead.ts @@ -0,0 +1,24 @@ +import type { IWorkspaceToken } from '../cloud/IWorkspaceToken'; + +/** + * Accessor that enables apps to read information + * related to the Cloud connectivity of the workspace. + * + * Methods in this accessor will usually connect to the + * Rocket.Chat Cloud, which means they won't work properly + * in air-gapped environment. + * + * This accessor available via `IRead` object, which is + * usually received as a parameter wherever it's available. + */ +export interface ICloudWorkspaceRead { + /** + * Returns an access token that can be used to access + * Cloud Services on the workspace's behalf. + * + * @param scope The scope that the token should be authorized with + * + * @RequiresPermission cloud.workspace-token; scopes: Array + */ + getWorkspaceToken(scope: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IConfigurationExtend.ts b/packages/apps-engine/src/definition/accessors/IConfigurationExtend.ts new file mode 100644 index 000000000000..a58f127a0421 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IConfigurationExtend.ts @@ -0,0 +1,36 @@ +import type { IApiExtend } from './IApiExtend'; +import type { IExternalComponentsExtend } from './IExternalComponentsExtend'; +import type { IHttpExtend } from './IHttp'; +import type { ISchedulerExtend } from './ISchedulerExtend'; +import type { ISettingsExtend } from './ISettingsExtend'; +import type { ISlashCommandsExtend } from './ISlashCommandsExtend'; +import type { IUIExtend } from './IUIExtend'; +import type { IVideoConfProvidersExtend } from './IVideoConfProvidersExtend'; + +/** + * This accessor provides methods for declaring the configuration + * of your App. It is provided during initialization of your App. + */ +export interface IConfigurationExtend { + /** Accessor for customing the handling of IHttp requests and responses your App causes. */ + readonly http: IHttpExtend; + + /** Accessor for declaring the settings your App provides. */ + readonly settings: ISettingsExtend; + + /** Accessor for declaring the commands which your App provides. */ + readonly slashCommands: ISlashCommandsExtend; + + /** Accessor for declaring api endpoints. */ + readonly api: IApiExtend; + + readonly externalComponents: IExternalComponentsExtend; + + /** Accessor for declaring tasks that can be scheduled (like cron) */ + readonly scheduler: ISchedulerExtend; + /** Accessor for registering different elements in the host UI */ + readonly ui: IUIExtend; + + /** Accessor for declaring the videoconf providers which your App provides. */ + readonly videoConfProviders: IVideoConfProvidersExtend; +} diff --git a/packages/apps-engine/src/definition/accessors/IConfigurationModify.ts b/packages/apps-engine/src/definition/accessors/IConfigurationModify.ts new file mode 100644 index 000000000000..d0f818e2e028 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IConfigurationModify.ts @@ -0,0 +1,18 @@ +import type { ISchedulerModify } from './ISchedulerModify'; +import type { IServerSettingsModify } from './IServerSettingsModify'; +import type { ISlashCommandsModify } from './ISlashCommandsModify'; + +/** + * This accessor provides methods for modifying the configuration + * of Rocket.Chat. It is provided during "onEnable" of your App. + */ +export interface IConfigurationModify { + /** Accessor for modifying the settings inside of Rocket.Chat. */ + readonly serverSettings: IServerSettingsModify; + + /** Accessor for modifying the slash commands inside of Rocket.Chat. */ + readonly slashCommands: ISlashCommandsModify; + + /** Accessor for modifying schedulers */ + readonly scheduler: ISchedulerModify; +} diff --git a/packages/apps-engine/src/definition/accessors/IDiscussionBuilder.ts b/packages/apps-engine/src/definition/accessors/IDiscussionBuilder.ts new file mode 100644 index 000000000000..51dc0c2c4f92 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IDiscussionBuilder.ts @@ -0,0 +1,25 @@ +import type { IRoomBuilder } from '.'; +import type { IMessage } from '../messages'; +import type { RocketChatAssociationModel } from '../metadata'; +import type { IRoom } from '../rooms'; + +/** + * Interface for building out a room. + * Please note, a room creator, name, and type must be set otherwise you will NOT + * be able to successfully save the room object. + */ +export interface IDiscussionBuilder extends IRoomBuilder { + kind: RocketChatAssociationModel.DISCUSSION; + + setParentRoom(parentRoom: IRoom): IDiscussionBuilder; + + getParentRoom(): IRoom; + + setParentMessage(parentMessage: IMessage): IDiscussionBuilder; + + getParentMessage(): IMessage; + + setReply(reply: string): IDiscussionBuilder; + + getReply(): string; +} diff --git a/packages/apps-engine/src/definition/accessors/IEmailCreator.ts b/packages/apps-engine/src/definition/accessors/IEmailCreator.ts new file mode 100644 index 000000000000..d5d051bc2dff --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IEmailCreator.ts @@ -0,0 +1,10 @@ +import type { IEmail } from '../email'; + +export interface IEmailCreator { + /** + * Sends an email through Rocket.Chat + * + * @param email the email data + */ + send(email: IEmail): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IEnvironmentRead.ts b/packages/apps-engine/src/definition/accessors/IEnvironmentRead.ts new file mode 100644 index 000000000000..81b50bee77c4 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IEnvironmentRead.ts @@ -0,0 +1,27 @@ +import type { IEnvironmentalVariableRead } from './IEnvironmentalVariableRead'; +import type { IServerSettingRead } from './IServerSettingRead'; +import type { ISettingRead } from './ISettingRead'; + +/** + * Allows read-access to the App's settings, + * the certain server's settings along with environmental + * variables all of which are not user created. + */ +export interface IEnvironmentRead { + /** Gets an instance of the App's settings reader. */ + getSettings(): ISettingRead; + + /** + * Gets an instance of the Server's Settings reader. + * Please note: Due to security concerns, only a subset of settings + * are accessible. + */ + getServerSettings(): IServerSettingRead; + + /** + * Gets an instance of the Environmental Variables reader. + * Please note: Due to security concerns, only a subset of + * them are readable. + */ + getEnvironmentVariables(): IEnvironmentalVariableRead; +} diff --git a/packages/apps-engine/src/definition/accessors/IEnvironmentWrite.ts b/packages/apps-engine/src/definition/accessors/IEnvironmentWrite.ts new file mode 100644 index 000000000000..ab1869ab67cb --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IEnvironmentWrite.ts @@ -0,0 +1,10 @@ +import type { IServerSettingUpdater } from './IServerSettingUpdater'; +import type { ISettingUpdater } from './ISettingUpdater'; + +/** + * Allows write-access to the App's settings, + */ +export interface IEnvironmentWrite { + getSettings(): ISettingUpdater; + getServerSettings(): IServerSettingUpdater; +} diff --git a/packages/apps-engine/src/definition/accessors/IEnvironmentalVariableRead.ts b/packages/apps-engine/src/definition/accessors/IEnvironmentalVariableRead.ts new file mode 100644 index 000000000000..3bb77b033e83 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IEnvironmentalVariableRead.ts @@ -0,0 +1,11 @@ +/** A reader for reading the Environmental Variables. */ +export interface IEnvironmentalVariableRead { + /** Gets the value for a variable. */ + getValueByName(envVarName: string): Promise; + + /** Checks to see if Apps can access the given variable name. */ + isReadable(envVarName: string): Promise; + + /** Checks to see if any value is set for the given variable name. */ + isSet(envVarName: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IExternalComponentsExtend.ts b/packages/apps-engine/src/definition/accessors/IExternalComponentsExtend.ts new file mode 100644 index 000000000000..6a3dc781056f --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IExternalComponentsExtend.ts @@ -0,0 +1,17 @@ +import type { IExternalComponent } from '../externalComponent'; + +/** + * This accessor provides a method for registering external + * components. This is provided during the initialization of your App. + */ +export interface IExternalComponentsExtend { + /** + * Register an external component to the system. + * If you call this method twice and the component + * has the same name as before, the first one will be + * overwritten as the names provided **must** be unique. + * + * @param externalComponent the external component to be registered + */ + register(externalComponent: IExternalComponent): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IHttp.ts b/packages/apps-engine/src/definition/accessors/IHttp.ts new file mode 100644 index 000000000000..8c5eeb9a4d55 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IHttp.ts @@ -0,0 +1,202 @@ +import type { IPersistence } from './IPersistence'; +import type { IRead } from './IRead'; + +/** + * The Http package allows users to call out to an external web service. + * Based off of: https://github.com/meteor-typings/meteor/blob/master/1.4/main.d.ts#L869 + */ +export interface IHttp { + get(url: string, options?: IHttpRequest): Promise; + + post(url: string, options?: IHttpRequest): Promise; + + put(url: string, options?: IHttpRequest): Promise; + + del(url: string, options?: IHttpRequest): Promise; + + patch(url: string, options?: IHttpRequest): Promise; +} + +export enum RequestMethod { + GET = 'get', + POST = 'post', + PUT = 'put', + DELETE = 'delete', + HEAD = 'head', + OPTIONS = 'options', + PATCH = 'patch', +} + +export interface IHttpRequest { + content?: string; + data?: any; + query?: string; + params?: { + [key: string]: string; + }; + auth?: string; + headers?: { + [key: string]: string; + }; + timeout?: number; + /** + * The encoding to be used on response data. + * + * If null, the body is returned as a Buffer. Anything else (including the default value of undefined) + * will be passed as the encoding parameter to toString() (meaning this is effectively 'utf8' by default). + * (Note: if you expect binary data, you should set encoding: null.) + */ + encoding?: string | null; + /** + * if `true`, requires SSL certificates be valid. + * + * Defaul: `true`; + */ + strictSSL?: boolean; + /** + * If `true`, the server certificate is verified against the list of supplied CAs. + * + * Default: `true`. + * + * https://nodejs.org/api/tls.html#tls_tls_connect_options_callback + */ + rejectUnauthorized?: boolean; +} + +export interface IHttpResponse { + url: string; + method: RequestMethod; + statusCode: number; + headers?: { + [key: string]: string; + }; + content?: string; + data?: any; +} + +export interface IHttpExtend { + /** + * A method for providing a single header which is added to every request. + * + * @param key the name of the header + * @param value the header's content + */ + provideDefaultHeader(key: string, value: string): void; + + /** + * A method for providing more than one header which are added to every request. + * + * @param headers an object with strings as the keys (header name) and strings as values (header content) + */ + provideDefaultHeaders(headers: { [key: string]: string }): void; + + /** + * A method for providing a single query parameter which is added to every request. + * + * @param key the name of the query parameter + * @param value the query parameter's content + */ + provideDefaultParam(key: string, value: string): void; + + /** + * A method for providing more than one query parameters which are added to every request. + * + * @param headers an object with strings as the keys (parameter name) and strings as values (parameter content) + */ + provideDefaultParams(params: { [key: string]: string }): void; + + /** + * Method for providing a function which is called before every request is called out to the final destination. + * This can be called more than once which means there can be more than one handler. The order provided is the order called. + * Note: if this handler throws an error when it is executed then the request will be aborted. + * + * @param handler the instance of the IHttpPreRequestHandler + */ + providePreRequestHandler(handler: IHttpPreRequestHandler): void; + + /** + * Method for providing a function which is called after every response is got from the url and before the result is returned. + * This can be called more than once which means there can be more than one handler. The order provided is the order called. + * Note: if this handler throws an error when it is executed then the respone will not be returned + * + * @param handler the instance of the IHttpPreResponseHandler + */ + providePreResponseHandler(handler: IHttpPreResponseHandler): void; + + /** + * A method for getting all of the default headers provided, the value is a readonly and any modifications done will be ignored. + * Please use the provider methods for adding them. + */ + getDefaultHeaders(): Map; + + /** + * A method for getting all of the default parameters provided, the value is a readonly and any modifications done will be ignored. + * Please use the provider methods for adding them. + */ + getDefaultParams(): Map; + + /** + * A method for getting all of the pre-request handlers provided, the value is a readonly and any modifications done will be ignored. + * Please use the provider methods for adding them. + */ + getPreRequestHandlers(): Array; + + /** + * A method for getting all of the pre-response handlers provided, the value is a readonly and any modifications done will be ignored. + * Please use the provider methods for adding them. + */ + getPreResponseHandlers(): Array; +} + +export interface IHttpPreRequestHandler { + executePreHttpRequest(url: string, request: IHttpRequest, read: IRead, persistence: IPersistence): Promise; +} + +export interface IHttpPreResponseHandler { + executePreHttpResponse(response: IHttpResponse, read: IRead, persistence: IPersistence): Promise; +} + +export enum HttpStatusCode { + CONTINUE = 100, + SWITCHING_PROTOCOLS = 101, + OK = 200, + CREATED = 201, + ACCEPTED = 202, + NON_AUTHORITATIVE_INFORMATION = 203, + NO_CONTENT = 204, + RESET_CONTENT = 205, + PARTIAL_CONTENT = 206, + MULTIPLE_CHOICES = 300, + MOVED_PERMANENTLY = 301, + FOUND = 302, + SEE_OTHER = 303, + NOT_MODIFIED = 304, + USE_PROXY = 305, + TEMPORARY_REDIRECT = 307, + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + PAYMENT_REQUIRED = 402, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + NOT_ACCEPTABLE = 406, + PROXY_AUTHENTICATION_REQUIRED = 407, + REQUEST_TIMEOUT = 408, + CONFLICT = 409, + GONE = 410, + LENGTH_REQUIRED = 411, + PRECONDITION_FAILED = 412, + REQUEST_ENTITY_TOO_LARGE = 413, + REQUEST_URI_TOO_LONG = 414, + UNSUPPORTED_MEDIA_TYPE = 415, + REQUESTED_RANGE_NOT_SATISFIABLE = 416, + EXPECTATION_FAILED = 417, + UNPROCESSABLE_ENTITY = 422, + TOO_MANY_REQUESTS = 429, + INTERNAL_SERVER_ERROR = 500, + NOT_IMPLEMENTED = 501, + BAD_GATEWAY = 502, + SERVICE_UNAVAILABLE = 503, + GATEWAY_TIMEOUT = 504, + HTTP_VERSION_NOT_SUPPORTED = 505, +} diff --git a/packages/apps-engine/src/definition/accessors/ILivechatCreator.ts b/packages/apps-engine/src/definition/accessors/ILivechatCreator.ts new file mode 100644 index 000000000000..56a3ec17ec27 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ILivechatCreator.ts @@ -0,0 +1,43 @@ +import type { ILivechatRoom, IVisitor } from '../livechat'; +import type { IUser } from '../users'; + +export interface IExtraRoomParams { + source?: ILivechatRoom['source']; + customFields?: { + [key: string]: unknown; + }; +} + +export interface ILivechatCreator { + /** + * Creates a room to connect the `visitor` to an `agent`. + * + * This method uses the Livechat routing method configured + * in the server + * + * @param visitor The Livechat Visitor that started the conversation + * @param agent The agent responsible for the room + */ + createRoom(visitor: IVisitor, agent: IUser, extraParams?: IExtraRoomParams): Promise; + + /** + * @deprecated Use `createAndReturnVisitor` instead. + * Creates a Livechat visitor + * + * @param visitor Data of the visitor to be created + */ + createVisitor(visitor: IVisitor): Promise; + + /** + * Creates a Livechat visitor + * + * @param visitor Data of the visitor to be created + */ + createAndReturnVisitor(visitor: IVisitor): Promise; + + /** + * Creates a token to be used when + * creating a new livechat visitor + */ + createToken(): string; +} diff --git a/packages/apps-engine/src/definition/accessors/ILivechatMessageBuilder.ts b/packages/apps-engine/src/definition/accessors/ILivechatMessageBuilder.ts new file mode 100644 index 000000000000..c36b078f53a6 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ILivechatMessageBuilder.ts @@ -0,0 +1,219 @@ +import type { ILivechatMessage, IVisitor } from '../livechat'; +import type { IMessageAttachment } from '../messages'; +import type { RocketChatAssociationModel } from '../metadata'; +import type { IRoom } from '../rooms'; +import type { IUser } from '../users'; +import type { IMessageBuilder } from './IMessageBuilder'; + +/** + * Interface for building out a livechat message. + * Please note, that a room and sender must be associated otherwise you will NOT + * be able to successfully save the message object. + */ +export interface ILivechatMessageBuilder { + kind: RocketChatAssociationModel.LIVECHAT_MESSAGE; + + /** + * Provides a convient way to set the data for the message. + * Note: Providing an "id" field here will be ignored. + * + * @param message the message data to set + */ + setData(message: ILivechatMessage): ILivechatMessageBuilder; + + /** + * Sets the room where this message should be sent to. + * + * @param room the room where to send + */ + setRoom(room: IRoom): ILivechatMessageBuilder; + + /** + * Gets the room where this message was sent to. + */ + getRoom(): IRoom; + + /** + * Sets the sender of this message. + * + * @param sender the user sending the message + */ + setSender(sender: IUser): ILivechatMessageBuilder; + + /** + * Gets the User which sent the message. + */ + getSender(): IUser; + + /** + * Sets the text of the message. + * + * @param text the actual text + */ + setText(text: string): ILivechatMessageBuilder; + + /** + * Gets the message text. + */ + getText(): string; + + /** + * Sets the emoji to use for the avatar, this overwrites the current avatar + * whether it be the user's or the avatar url provided. + * + * @param emoji the emoji code + */ + setEmojiAvatar(emoji: string): ILivechatMessageBuilder; + + /** + * Gets the emoji used for the avatar. + */ + getEmojiAvatar(): string; + + /** + * Sets the url which to display for the avatar, this overwrites the current + * avatar whether it be the user's or an emoji one. + * + * @param avatarUrl image url to use as the avatar + */ + setAvatarUrl(avatarUrl: string): ILivechatMessageBuilder; + + /** + * Gets the url used for the avatar. + */ + getAvatarUrl(): string; + + /** + * Sets the display text of the sender's username that is visible. + * + * @param alias the username alias to display + */ + setUsernameAlias(alias: string): ILivechatMessageBuilder; + + /** + * Gets the display text of the sender's username that is visible. + */ + getUsernameAlias(): string; + + /** + * Adds one attachment to the message's list of attachments, this will not + * overwrite any existing ones but just adds. + * + * @param attachment the attachment to add + */ + addAttachment(attachment: IMessageAttachment): ILivechatMessageBuilder; + + /** + * Sets the attachments for the message, replacing and destroying all of the current attachments. + * + * @param attachments array of the attachments + */ + setAttachments(attachments: Array): ILivechatMessageBuilder; + + /** + * Gets the attachments array for the message + */ + getAttachments(): Array; + + /** + * Replaces an attachment at the given position (index). + * If there is no attachment at that position, there will be an error thrown. + * + * @param position the index of the attachment to replace + * @param attachment the attachment to replace with + */ + replaceAttachment(position: number, attachment: IMessageAttachment): ILivechatMessageBuilder; + + /** + * Removes an attachment at the given position (index). + * If there is no attachment at that position, there will be an error thrown. + * + * @param position the index of the attachment to remove + */ + removeAttachment(position: number): ILivechatMessageBuilder; + + /** + * Sets the user who is editing this message. + * This is required if you are modifying an existing message. + * + * @param user the editor + */ + setEditor(user: IUser): ILivechatMessageBuilder; + + /** + * Gets the user who edited the message + */ + getEditor(): IUser; + + /** + * Sets whether this message can group with others. + * This is desirable if you want to avoid confusion with other integrations. + * + * @param groupable whether this message can group with others + */ + setGroupable(groupable: boolean): ILivechatMessageBuilder; + + /** + * Gets whether this message can group with others. + */ + getGroupable(): boolean; + + /** + * Sets whether this message should have any URLs in the text + * parsed by Rocket.Chat and get the details added to the message's + * attachments. + * + * @param parseUrls whether URLs should be parsed in this message + */ + setParseUrls(parseUrls: boolean): ILivechatMessageBuilder; + + /** + * Gets whether this message should have its URLs parsed + */ + getParseUrls(): boolean; + + /** + * Set the token of the livechat visitor that + * sent the message + * + * @param token The Livechat visitor's token + */ + setToken(token: string): ILivechatMessageBuilder; + + /** + * Gets the token of the livechat visitor that + * sent the message + */ + getToken(): string; + + /** + * If the sender of the message is a Livechat Visitor, + * set the visitor who sent the message. + * + * If you set the visitor property of a message, the + * sender will be emptied + * + * @param visitor The visitor who sent the message + */ + setVisitor(visitor: IVisitor): ILivechatMessageBuilder; + + /** + * Get the visitor who sent the message, + * if any + */ + getVisitor(): IVisitor; + + /** + * Gets the resulting message that has been built up to the point of calling it. + * + * *Note:* This will error out if the Room has not been defined OR if the room + * is not of type RoomType.LIVE_CHAT. + */ + getMessage(): ILivechatMessage; + + /** + * Returns a message builder based on the + * livechat message of this builder + */ + getMessageBuilder(): IMessageBuilder; +} diff --git a/packages/apps-engine/src/definition/accessors/ILivechatRead.ts b/packages/apps-engine/src/definition/accessors/ILivechatRead.ts new file mode 100644 index 000000000000..a756d162c337 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ILivechatRead.ts @@ -0,0 +1,38 @@ +import type { IDepartment } from '../livechat'; +import type { ILivechatRoom } from '../livechat/ILivechatRoom'; +import type { IVisitor } from '../livechat/IVisitor'; +import type { IMessage } from '../messages'; + +export interface ILivechatRead { + /** + * Gets online status of the livechat. + * @param departmentId (optional) the id of the livechat department + * @deprecated use `isOnlineAsync` instead + */ + isOnline(departmentId?: string): boolean; + /** + * Gets online status of the livechat. + * @param departmentId (optional) the id of the livechat department + */ + isOnlineAsync(departmentId?: string): Promise; + getDepartmentsEnabledWithAgents(): Promise>; + getLivechatRooms(visitor: IVisitor, departmentId?: string): Promise>; + getLivechatOpenRoomsByAgentId(agentId: string): Promise>; + getLivechatTotalOpenRoomsByAgentId(agentId: string): Promise; + /** + * @deprecated This method does not adhere to the conversion practices applied + * elsewhere in the Apps-Engine and will be removed in the next major version. + * Prefer the alternative methods to fetch visitors. + */ + getLivechatVisitors(query: object): Promise>; + getLivechatVisitorById(id: string): Promise; + getLivechatVisitorByEmail(email: string): Promise; + getLivechatVisitorByToken(token: string): Promise; + getLivechatVisitorByPhoneNumber(phoneNumber: string): Promise; + getLivechatDepartmentByIdOrName(value: string): Promise; + /** + * @experimental we do not encourage the wider usage of this method, + * as we're evaluating its performance and fit for the API. + */ + _fetchLivechatRoomMessages(roomId: string): Promise>; +} diff --git a/packages/apps-engine/src/definition/accessors/ILivechatUpdater.ts b/packages/apps-engine/src/definition/accessors/ILivechatUpdater.ts new file mode 100644 index 000000000000..fb75cf9ecf3b --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ILivechatUpdater.ts @@ -0,0 +1,33 @@ +import type { ILivechatTransferData, IVisitor } from '../livechat'; +import type { IRoom } from '../rooms'; +import type { IUser } from '../users'; + +export interface ILivechatUpdater { + /** + * Transfer a Livechat visitor to another room + * + * @param visitor Visitor to be transferred + * @param transferData The data to execute the transferring + */ + transferVisitor(visitor: IVisitor, transferData: ILivechatTransferData): Promise; + + /** + * Closes a Livechat room + * + * @param room The room to be closed + * @param comment The comment explaining the reason for closing the room + * @param closer The user that closes the room + */ + closeRoom(room: IRoom, comment: string, closer?: IUser): Promise; + + /** + * Set a livechat visitor's custom fields by its token + * @param token The visitor's token + * @param key The key in the custom fields + * @param value The value to be set + * @param overwrite Whether overwrite or not + * + * @returns Promise to whether success or not + */ + setCustomFields(token: IVisitor['token'], key: string, value: string, overwrite: boolean): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/ILogEntry.ts b/packages/apps-engine/src/definition/accessors/ILogEntry.ts new file mode 100644 index 000000000000..4dc46693b6d9 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ILogEntry.ts @@ -0,0 +1,22 @@ +export enum LogMessageSeverity { + DEBUG = 'debug', + INFORMATION = 'info', + LOG = 'log', + WARNING = 'warning', + ERROR = 'error', + SUCCESS = 'success', +} + +/** + * Message which will be passed to a UI (either in a log or in the application's UI) + */ +export interface ILogEntry { + /** The function name who did this logging, this is automatically added (can be null). */ + caller?: string; + /** The severity rate, this is automatically added. */ + severity: LogMessageSeverity; + /** When this entry was made. */ + timestamp: Date; + /** The items which were logged. */ + args: Array; +} diff --git a/packages/apps-engine/src/definition/accessors/ILogger.ts b/packages/apps-engine/src/definition/accessors/ILogger.ts new file mode 100644 index 000000000000..eac6e531802d --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ILogger.ts @@ -0,0 +1,29 @@ +import type { AppMethod } from '../metadata/AppMethod'; +import type { ILogEntry } from './ILogEntry'; + +/** + * This logger provides a way to log various levels to the entire system. + * When used, the items passed in will be logged to the database. This will + * allow people to easily see what happened (users) or debug what went wrong. + */ +export interface ILogger { + method: `${AppMethod}`; + + debug(...items: Array): void; + info(...items: Array): void; + log(...items: Array): void; + warn(...items: Array): void; + error(...items: Array): void; + success(...items: Array): void; + + /** Gets the entries logged. */ + getEntries(): Array; + /** Gets the method which this logger is for. */ + getMethod(): `${AppMethod}`; + /** Gets when this logger was constructed. */ + getStartTime(): Date; + /** Gets the end time, usually Date.now(). */ + getEndTime(): Date; + /** Gets the amount of time this was a logger, start - Date.now(). */ + getTotalTime(): number; +} diff --git a/packages/apps-engine/src/definition/accessors/IMessageBuilder.ts b/packages/apps-engine/src/definition/accessors/IMessageBuilder.ts new file mode 100644 index 000000000000..024a4b123ff8 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IMessageBuilder.ts @@ -0,0 +1,236 @@ +import type { LayoutBlock } from '@rocket.chat/ui-kit'; + +import type { IMessage, IMessageAttachment } from '../messages'; +import type { RocketChatAssociationModel } from '../metadata'; +import type { IRoom } from '../rooms'; +import type { BlockBuilder, IBlock } from '../uikit'; +import type { IUser } from '../users'; + +/** + * Interface for building out a message. + * Please note, that a room and sender must be associated otherwise you will NOT + * be able to successfully save the message object. + */ +export interface IMessageBuilder { + kind: RocketChatAssociationModel.MESSAGE; + + /** + * Provides a convenient way to set the data for the message. + * Note: Providing an "id" field here will be ignored. + * + * @param message the message data to set + */ + setData(message: IMessage): IMessageBuilder; + + /** + * Provides a convenient way to set the data for the message + * keeping the "id" field so as to update the message later. + * + * @param message the message data to set + * @param editor the user who edited the updated message + */ + setUpdateData(message: IMessage, editor: IUser): IMessageBuilder; + + /** + * Sets the thread to which this message belongs, if any. + * + * @param threadId The id of the thread + */ + setThreadId(threadId: string): IMessageBuilder; + + /** + * Retrieves the threadId to which this message belongs, + * if any. + * + * If you would like to retrieve the actual message that + * the thread originated from, you can use the + * `IMessageRead.getById()` method + */ + getThreadId(): string; + + /** + * Sets the room where this message should be sent to. + * + * @param room the room where to send + */ + setRoom(room: IRoom): IMessageBuilder; + + /** + * Gets the room where this message was sent to. + */ + getRoom(): IRoom; + + /** + * Sets the sender of this message. + * + * @param sender the user sending the message + */ + setSender(sender: IUser): IMessageBuilder; + + /** + * Gets the User which sent the message. + */ + getSender(): IUser; + + /** + * Sets the text of the message. + * + * @param text the actual text + */ + setText(text: string): IMessageBuilder; + + /** + * Gets the message text. + */ + getText(): string; + + /** + * Sets the emoji to use for the avatar, this overwrites the current avatar + * whether it be the user's or the avatar url provided. + * + * @param emoji the emoji code + */ + setEmojiAvatar(emoji: string): IMessageBuilder; + + /** + * Gets the emoji used for the avatar. + */ + getEmojiAvatar(): string; + + /** + * Sets the url which to display for the avatar, this overwrites the current + * avatar whether it be the user's or an emoji one. + * + * @param avatarUrl image url to use as the avatar + */ + setAvatarUrl(avatarUrl: string): IMessageBuilder; + + /** + * Gets the url used for the avatar. + */ + getAvatarUrl(): string; + + /** + * Sets the display text of the sender's username that is visible. + * + * @param alias the username alias to display + */ + setUsernameAlias(alias: string): IMessageBuilder; + + /** + * Gets the display text of the sender's username that is visible. + */ + getUsernameAlias(): string; + + /** + * Adds one attachment to the message's list of attachments, this will not + * overwrite any existing ones but just adds. + * + * @param attachment the attachment to add + */ + addAttachment(attachment: IMessageAttachment): IMessageBuilder; + + /** + * Sets the attachments for the message, replacing and destroying all of the current attachments. + * + * @param attachments array of the attachments + */ + setAttachments(attachments: Array): IMessageBuilder; + + /** + * Gets the attachments array for the message + */ + getAttachments(): Array; + + /** + * Replaces an attachment at the given position (index). + * If there is no attachment at that position, there will be an error thrown. + * + * @param position the index of the attachment to replace + * @param attachment the attachment to replace with + */ + replaceAttachment(position: number, attachment: IMessageAttachment): IMessageBuilder; + + /** + * Removes an attachment at the given position (index). + * If there is no attachment at that position, there will be an error thrown. + * + * @param position the index of the attachment to remove + */ + removeAttachment(position: number): IMessageBuilder; + + /** + * Sets the user who is editing this message. + * This is required if you are modifying an existing message. + * + * @param user the editor + */ + setEditor(user: IUser): IMessageBuilder; + + /** + * Gets the user who edited the message + */ + getEditor(): IUser; + + /** + * Sets whether this message can group with others. + * This is desirable if you want to avoid confusion with other integrations. + * + * @param groupable whether this message can group with others + */ + setGroupable(groupable: boolean): IMessageBuilder; + + /** + * Gets whether this message can group with others. + */ + getGroupable(): boolean; + + /** + * Sets whether this message should have any URLs in the text + * parsed by Rocket.Chat and get the details added to the message's + * attachments. + * + * @param parseUrls whether URLs should be parsed in this message + */ + setParseUrls(parseUrls: boolean): IMessageBuilder; + + /** + * Gets whether this message should have its URLs parsed + */ + getParseUrls(): boolean; + + /** + * Gets the resulting message that has been built up to the point of calling it. + * + * *Note:* This will error out if the Room has not been defined. + */ + getMessage(): IMessage; + + /** + * Adds a block collection to the message's + * own collection + */ + addBlocks(blocks: BlockBuilder | Array): IMessageBuilder; + + /** + * Sets the block collection of the message + * + * @param blocks + */ + setBlocks(blocks: BlockBuilder | Array): IMessageBuilder; + + /** + * Gets the block collection of the message + */ + getBlocks(): Array; + + /** + * Adds a custom field to the message. + * Note: This key can not already exist or it will throw an error. + * Note: The key must not contain a period in it, an error will be thrown. + * + * @param key the name of the custom field + * @param value the value of this custom field + */ + addCustomField(key: string, value: any): IMessageBuilder; +} diff --git a/packages/apps-engine/src/definition/accessors/IMessageExtender.ts b/packages/apps-engine/src/definition/accessors/IMessageExtender.ts new file mode 100644 index 000000000000..7db010bae081 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IMessageExtender.ts @@ -0,0 +1,36 @@ +import type { IMessage, IMessageAttachment } from '../messages'; +import type { RocketChatAssociationModel } from '../metadata'; + +export interface IMessageExtender { + kind: RocketChatAssociationModel.MESSAGE; + + /** + * Adds a custom field to the message. + * Note: This key can not already exist or it will throw an error. + * Note: The key must not contain a period in it, an error will be thrown. + * + * @param key the name of the custom field + * @param value the value of this custom field + */ + addCustomField(key: string, value: any): IMessageExtender; + + /** + * Adds a single attachment to the message. + * + * @param attachment the item to add + */ + addAttachment(attachment: IMessageAttachment): IMessageExtender; + + /** + * Adds all of the provided attachments to the message. + * + * @param attachments an array of attachments + */ + addAttachments(attachments: Array): IMessageExtender; + + /** + * Gets the resulting message that has been extended at the point of calling it. + * Note: modifying the returned value will have no effect. + */ + getMessage(): IMessage; +} diff --git a/packages/apps-engine/src/definition/accessors/IMessageRead.ts b/packages/apps-engine/src/definition/accessors/IMessageRead.ts new file mode 100644 index 000000000000..10c99d26388b --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IMessageRead.ts @@ -0,0 +1,15 @@ +import type { IMessage } from '../messages/index'; +import type { IRoom } from '../rooms/IRoom'; +import type { IUser } from '../users/IUser'; + +/** + * This accessor provides methods for accessing + * messages in a read-only-fashion. + */ +export interface IMessageRead { + getById(id: string): Promise; + + getSenderUser(messageId: string): Promise; + + getRoom(messageId: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IMessageUpdater.ts b/packages/apps-engine/src/definition/accessors/IMessageUpdater.ts new file mode 100644 index 000000000000..b21baacae04f --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IMessageUpdater.ts @@ -0,0 +1,21 @@ +import type { Reaction } from '../messages'; + +export interface IMessageUpdater { + /** + * Add a reaction to a message + * + * @param messageId the id of the message + * @param userId the id of the user + * @param reaction the reaction + */ + addReaction(messageId: string, userId: string, reaction: Reaction): Promise; + + /** + * Remove a reaction from a message + * + * @param messageId the id of the message + * @param userId the id of the user + * @param reaction the reaction + */ + removeReaction(messageId: string, userId: string, reaction: Reaction): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IModerationModify.ts b/packages/apps-engine/src/definition/accessors/IModerationModify.ts new file mode 100644 index 000000000000..6b0f54968a04 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IModerationModify.ts @@ -0,0 +1,27 @@ +import type { IMessage } from '../messages'; +import type { IUser } from '../users'; + +export interface IModerationModify { + /** + * Provides a way for Apps to report a message. + * @param messageId the messageId to report + * @param description the description of the report + * @param userId the userId to be reported + * @param appId the app id + */ + report(messageId: string, description: string, userId: string, appId: string): Promise; + + /** + * Provides a way for Apps to dismiss reports by message id. + * @param messageId the messageId to dismiss reports + * @param appId the app id + */ + dismissReportsByMessageId(messageId: IMessage['id'], reason: string, action: string, appId: string): Promise; + + /** + * Provides a way for Apps to dismiss reports by user id. + * @param userId the userId to dismiss reports + * @param appId the app id + */ + dismissReportsByUserId(userId: IUser['id'], reason: string, action: string, appId: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IModify.ts b/packages/apps-engine/src/definition/accessors/IModify.ts new file mode 100644 index 000000000000..e76e4cc76824 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IModify.ts @@ -0,0 +1,45 @@ +import type { IModerationModify } from './IModerationModify'; +import type { IModifyCreator } from './IModifyCreator'; +import type { IModifyDeleter } from './IModifyDeleter'; +import type { IModifyExtender } from './IModifyExtender'; +import type { IModifyUpdater } from './IModifyUpdater'; +import type { INotifier } from './INotifier'; +import type { IOAuthAppsModify } from './IOAuthAppsModify'; +import type { ISchedulerModify } from './ISchedulerModify'; +import type { IUIController } from './IUIController'; + +export interface IModify { + getCreator(): IModifyCreator; + + getDeleter(): IModifyDeleter; + + getExtender(): IModifyExtender; + + getUpdater(): IModifyUpdater; + + /** + * Gets the accessor for sending notifications to a user or users in a room. + * + * @returns the notifier accessor + */ + getNotifier(): INotifier; + /** + * Gets the accessor for interacting with the UI + */ + getUiController(): IUIController; + + /** + * Gets the accessor for creating scheduled jobs + */ + getScheduler(): ISchedulerModify; + + /** + * Gets the accessor for creating OAuth apps + */ + getOAuthAppsModifier(): IOAuthAppsModify; + /** + * Gets the accessor for modifying moderation + * @returns the moderation accessor + */ + getModerationModifier(): IModerationModify; +} diff --git a/packages/apps-engine/src/definition/accessors/IModifyCreator.ts b/packages/apps-engine/src/definition/accessors/IModifyCreator.ts new file mode 100644 index 000000000000..6c2acd50493c --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IModifyCreator.ts @@ -0,0 +1,100 @@ +import type { ILivechatMessage } from '../livechat'; +import type { IMessage } from '../messages'; +import type { IRoom } from '../rooms'; +import type { BlockBuilder } from '../uikit'; +import type { IBotUser } from '../users/IBotUser'; +import type { AppVideoConference } from '../videoConferences'; +import type { IDiscussionBuilder } from './IDiscussionBuilder'; +import type { IEmailCreator } from './IEmailCreator'; +import type { ILivechatCreator } from './ILivechatCreator'; +import type { ILivechatMessageBuilder } from './ILivechatMessageBuilder'; +import type { IMessageBuilder } from './IMessageBuilder'; +import type { IRoomBuilder } from './IRoomBuilder'; +import type { IUploadCreator } from './IUploadCreator'; +import type { IUserBuilder } from './IUserBuilder'; +import type { IVideoConferenceBuilder } from './IVideoConferenceBuilder'; + +export interface IModifyCreator { + /** + * Get the creator object responsible for the + * Livechat integrations + */ + getLivechatCreator(): ILivechatCreator; + + /** + * Get the creator object responsible for the upload. + */ + getUploadCreator(): IUploadCreator; + + /** + * Gets the creator object responsible for email sending + */ + getEmailCreator(): IEmailCreator; + + /** + * @deprecated please prefer the rocket.chat/ui-kit components + * + * Gets a new instance of a BlockBuilder + */ + getBlockBuilder(): BlockBuilder; + /** + * Starts the process for building a new message object. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IMessageBuilder instance + */ + startMessage(data?: IMessage): IMessageBuilder; + + /** + * Starts the process for building a new livechat message object. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IMessageBuilder instance + */ + startLivechatMessage(data?: ILivechatMessage): ILivechatMessageBuilder; + + /** + * Starts the process for building a new room. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IRoomBuilder instance + */ + startRoom(data?: IRoom): IRoomBuilder; + + /** + * Starts the process for building a new discussion. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IDiscussionBuilder instance + */ + startDiscussion(data?: Partial): IDiscussionBuilder; + + /** + * Starts the process for building a new video conference. + * + * @param data (optional) the initial data to pass into the builder, + * @return an IVideoConferenceBuilder instance + */ + startVideoConference(data?: Partial): IVideoConferenceBuilder; + + /** + * Starts the process for building a new bot user. + * + * @param data (optional) the initial data to pass into the builder, + * the `id` property will be ignored + * @return an IUserBuilder instance + */ + startBotUser(data?: Partial): IUserBuilder; + + /** + * Finishes the creating process, saving the object to the database. + * + * @param builder the builder instance + * @return the resulting `id` of the resulting object + */ + finish(builder: IMessageBuilder | ILivechatMessageBuilder | IRoomBuilder | IDiscussionBuilder | IVideoConferenceBuilder | IUserBuilder): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IModifyDeleter.ts b/packages/apps-engine/src/definition/accessors/IModifyDeleter.ts new file mode 100644 index 000000000000..7d1103ba13f3 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IModifyDeleter.ts @@ -0,0 +1,12 @@ +import type { IMessage } from '../messages'; +import type { IUser, UserType } from '../users'; + +export interface IModifyDeleter { + deleteRoom(roomId: string): Promise; + + deleteUsers(appId: Exclude, userType: UserType.APP | UserType.BOT): Promise; + + deleteMessage(message: IMessage, user: IUser): Promise; + + removeUsersFromRoom(roomId: string, usernames: Array): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IModifyExtender.ts b/packages/apps-engine/src/definition/accessors/IModifyExtender.ts new file mode 100644 index 000000000000..786b23975407 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IModifyExtender.ts @@ -0,0 +1,40 @@ +import type { IUser } from '../users'; +import type { IMessageExtender } from './IMessageExtender'; +import type { IRoomExtender } from './IRoomExtender'; +import type { IVideoConferenceExtender } from './IVideoConferenceExtend'; + +export interface IModifyExtender { + /** + * Modifies a message in a non-destructive way: Properties can be added to it, + * but existing properties cannot be changed. + * + * @param messageId the id of the message to be extended + * @param updater the user who is updating/extending the message + * @return the extender instance for the message + */ + extendMessage(messageId: string, updater: IUser): Promise; + + /** + * Modifies a room in a non-destructive way: Properties can be added to it, + * but existing properties cannot be changed. + * + * @param roomId the id of the room to be extended + * @param updater the user who is updating/extending the room + * @return the extender instance for the room + */ + extendRoom(roomId: string, updater: IUser): Promise; + + /** + * Modifies a video conference in a non-destructive way: Properties can be added to it, + * but existing properties cannot be changed. + */ + extendVideoConference(id: string): Promise; + + /** + * Finishes the extending process, saving the object to the database. + * Note: If there is an issue or error while updating, this will throw an error. + * + * @param extender the extender instance + */ + finish(extender: IRoomExtender | IMessageExtender | IVideoConferenceExtender): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IModifyUpdater.ts b/packages/apps-engine/src/definition/accessors/IModifyUpdater.ts new file mode 100644 index 000000000000..60dcf90b2df7 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IModifyUpdater.ts @@ -0,0 +1,52 @@ +import type { IUser } from '../users'; +import type { ILivechatUpdater } from './ILivechatUpdater'; +import type { IMessageBuilder } from './IMessageBuilder'; +import type { IMessageUpdater } from './IMessageUpdater'; +import type { IRoomBuilder } from './IRoomBuilder'; +import type { IUserUpdater } from './IUserUpdater'; + +export interface IModifyUpdater { + /** + * Get the updater object responsible for the + * Livechat integrations + */ + getLivechatUpdater(): ILivechatUpdater; + + /** + * Gets the update object responsible for + * methods that update users + */ + getUserUpdater(): IUserUpdater; + + /** + * Get the updater object responsible for + * methods that update messages + */ + getMessageUpdater(): IMessageUpdater; + + /** + * Modifies an existing message. + * Raises an exception if a non-existent messageId is supplied + * + * @param messageId the id of the existing message to modfiy and build + * @param updater the user who is updating the message + */ + message(messageId: string, updater: IUser): Promise; + + /** + * Modifies an existing room. + * Raises an exception if a non-existent roomId is supplied + * + * @param roomId the id of the existing room to modify and build + * @param updater the user who is updating the room + */ + room(roomId: string, updater: IUser): Promise; + + /** + * Finishes the updating process, saving the object to the database. + * Note: If there is an issue or error while updating, this will throw an error. + * + * @param builder the builder instance + */ + finish(builder: IMessageBuilder | IRoomBuilder): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/INotifier.ts b/packages/apps-engine/src/definition/accessors/INotifier.ts new file mode 100644 index 000000000000..a41fb22c4ff6 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/INotifier.ts @@ -0,0 +1,63 @@ +import type { IMessage } from '../messages'; +import type { IRoom } from '../rooms'; +import type { IUser } from '../users'; +import type { IMessageBuilder } from './IMessageBuilder'; + +export enum TypingScope { + Room = 'room', +} + +export interface ITypingOptions { + /** + * The typing scope where the typing message should be presented, + * TypingScope.Room by default. + */ + scope?: TypingScope; + /** + * The id of the typing scope + * + * TypingScope.Room <-> room.id + */ + id: string; + /** + * The name of the user who is typing the message + * + * **Note**: If not provided, it will use app assigned + * user's name by default. + */ + username?: string; +} + +export interface INotifier { + /** + * Notifies the provided user of the provided message. + * + * **Note**: Notifications only are shown to the user if they are + * online and it only stays around for the duration of their session. + * + * @param user The user who should be notified + * @param message The message with the content to notify the user about + */ + notifyUser(user: IUser, message: IMessage): Promise; + + /** + * Notifies all of the users in the provided room. + * + * **Note**: Notifications only are shown to those online + * and it only stays around for the duration of their session. + * + * @param room The room which to notify the users in + * @param message The message content to notify users about + */ + notifyRoom(room: IRoom, message: IMessage): Promise; + + /** + * Notifies all of the users a typing indicator in the provided scope. + * + * @returns a cancellation function to stop typing + */ + typing(options: ITypingOptions): Promise<() => Promise>; + + /** Gets a new message builder for building a notification message. */ + getMessageBuilder(): IMessageBuilder; +} diff --git a/packages/apps-engine/src/definition/accessors/IOAuthApp.ts b/packages/apps-engine/src/definition/accessors/IOAuthApp.ts new file mode 100644 index 000000000000..1c2edbe19c95 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IOAuthApp.ts @@ -0,0 +1,13 @@ +export interface IOAuthApp { + id: string; + name: string; + active: boolean; + clientId?: string; + clientSecret?: string; + redirectUri: string; + createdAt?: string; + updatedAt?: string; + createdBy: { username: string; id: string }; +} + +export type IOAuthAppParams = Omit; diff --git a/packages/apps-engine/src/definition/accessors/IOAuthAppsModify.ts b/packages/apps-engine/src/definition/accessors/IOAuthAppsModify.ts new file mode 100644 index 000000000000..72d0a4ddce5a --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IOAuthAppsModify.ts @@ -0,0 +1,23 @@ +import type { IOAuthAppParams } from './IOAuthApp'; + +export interface IOAuthAppsModify { + /** + * Create an OAuthApp + * @param OAuthApp - the OAuth app to create, in case the clientId and the clientSecret is not sent it will generate automatically + * @param appId - the app id + */ + createOAuthApp(OAuthApp: IOAuthAppParams, appId: string): Promise; + /** + * Update the OAuth app info + * @param OAuthApp - OAuth data that will be updated + * @param id - OAuth app id + * @param appId - the app id + */ + updateOAuthApp(OAuthApp: IOAuthAppParams, id: string, appId: string): Promise; + /** + * Deletes the OAuth app + * @param id - OAuth app id + * @param appId - the app id + */ + deleteOAuthApp(id: string, appId: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IOAuthAppsReader.ts b/packages/apps-engine/src/definition/accessors/IOAuthAppsReader.ts new file mode 100644 index 000000000000..97d544cd9366 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IOAuthAppsReader.ts @@ -0,0 +1,16 @@ +import type { IOAuthApp } from './IOAuthApp'; + +export interface IOAuthAppsReader { + /** + * Returns the OAuth app info by its id + * @param id - OAuth app id + * @param appId - the app id + */ + getOAuthAppById(id: string, appId: string): Promise; + /** + * Returns the OAuth app info by its name + * @param name - OAuth app name + * @param appId - the app id + */ + getOAuthAppByName(name: string, appId: string): Promise>; +} diff --git a/packages/apps-engine/src/definition/accessors/IPersistence.ts b/packages/apps-engine/src/definition/accessors/IPersistence.ts new file mode 100644 index 000000000000..30f1d676539e --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IPersistence.ts @@ -0,0 +1,97 @@ +import type { RocketChatAssociationRecord } from '../metadata'; + +/** + * Provides an accessor write data to the App's persistent storage. + * A App only has access to its own persistent storage and does not + * have access to any other App's. + */ +export interface IPersistence { + /** + * Creates a new record in the App's persistent storage, returning the resulting "id". + * + * @param data the actual data to store, must be an object otherwise it will error out. + * @return the resulting record's id + */ + create(data: object): Promise; + + /** + * Creates a new record in the App's persistent storage with the associated information + * being provided. + * + * @param data the actual data to store, must be an object otherwise it will error out + * @param association the association data which includes the model and record id + * @return the resulting record's id + */ + createWithAssociation(data: object, association: RocketChatAssociationRecord): Promise; + + /** + * Creates a new record in the App's persistent storage with the data being + * associated with more than one Rocket.Chat record. + * + * @param data the actual data to store, must be an object otherwise it will error out + * @param associations an array of association data which includes the model and record id + * @return the resulting record's id + */ + createWithAssociations(data: object, associations: Array): Promise; + + /** + * Updates an existing record with the data provided in the App's persistent storage. + * This will throw an error if the record doesn't currently exist or if the data is not an object. + * + * @param id the data record's id + * @param data the actual data to store, must be an object otherwise it will error out + * @param upsert whether a record should be created if the id to be updated does not exist + * @return the id of the updated/upserted record + */ + update(id: string, data: object, upsert?: boolean): Promise; + + /** + * Updates an existing record with the data provided in the App's persistent storage which are + * associated with provided information. + * This will throw an error if the record doesn't currently exist or if the data is not an object. + * + * @param association the association record + * @param data the actual data to store, must be an object otherwise it will error out + * @param upsert whether a record should be created if the id to be updated does not exist + * @return the id of the updated/upserted record + */ + updateByAssociation(association: RocketChatAssociationRecord, data: object, upsert?: boolean): Promise; + + /** + * Updates an existing record with the data provided in the App's persistent storage which are + * associated with more than one Rocket.Chat record. + * This will throw an error if the record doesn't currently exist or if the data is not an object. + * + * @param associations an array of association data which includes the model and record id + * @param data the actual data to store, must be an object otherwise it will error out + * @param upsert whether a record should be created if the id to be updated does not exist + * @return the id of the updated/upserted record + */ + updateByAssociations(associations: Array, data: object, upsert?: boolean): Promise; + + /** + * Removes a record by the provided id and returns the removed record. + * + * @param id of the record to remove + * @return the data record which was removed + */ + remove(id: string): Promise; + + /** + * Removes all of the records in persistent storage which are associated with the provided information. + * + * @param association the information about the association for the records to be removed + * @return the data of the removed records + */ + removeByAssociation(association: RocketChatAssociationRecord): Promise>; + + /** + * Removes all of the records in persistent storage which are associated with the provided information. + * More than one association acts like an AND which means a record in persistent storage must have all + * of the associations to be considered a match. + * + * @param associations the information about the associations for the records to be removed + * @return the data of the removed records + */ + removeByAssociations(associations: Array): Promise>; +} diff --git a/packages/apps-engine/src/definition/accessors/IPersistenceRead.ts b/packages/apps-engine/src/definition/accessors/IPersistenceRead.ts new file mode 100644 index 000000000000..d0d1178a44d0 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IPersistenceRead.ts @@ -0,0 +1,40 @@ +import type { RocketChatAssociationRecord } from '../metadata'; + +/** + * Provides a read-only accessor for the App's persistent storage. + * A App only has access to its own persistent storage and does not + * have access to any other App's. + */ +export interface IPersistenceRead { + /** + * Retrieves a record from the App's persistent storage by the provided id. + * A "falsey" value (undefined or null or false) is returned should nothing exist + * in the storage by the provided id. + * + * @param id the record to get's id + * @return the record if it exists, falsey if not + */ + read(id: string): Promise; + + /** + * Retrieves a record from the App's persistent storage by the provided id. + * An empty array is returned should there be no records associated with the + * data provided. + * + * @param association the association record to query the persistent storage for + * @return array of the records if any exists, empty array if none exist + */ + readByAssociation(association: RocketChatAssociationRecord): Promise>; + + /** + * Retrieves a record from the App's persistent storage by the provided id. + * Providing more than one association record acts like an AND which means a record + * in persistent storage must have all of the associations to be considered a match. + * An empty array is returned should there be no records associated with the + * data provided. + * + * @param associations the association records to query the persistent storage for + * @return array of the records if any exists, empty array if none exist + */ + readByAssociations(associations: Array): Promise>; +} diff --git a/packages/apps-engine/src/definition/accessors/IRead.ts b/packages/apps-engine/src/definition/accessors/IRead.ts new file mode 100644 index 000000000000..17f66d6218dc --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IRead.ts @@ -0,0 +1,52 @@ +import type { ICloudWorkspaceRead } from './ICloudWorkspaceRead'; +import type { IEnvironmentRead } from './IEnvironmentRead'; +import type { ILivechatRead } from './ILivechatRead'; +import type { IMessageRead } from './IMessageRead'; +import type { INotifier } from './INotifier'; +import type { IOAuthAppsReader } from './IOAuthAppsReader'; +import type { IPersistenceRead } from './IPersistenceRead'; +import type { IRoleRead } from './IRoleRead'; +import type { IRoomRead } from './IRoomRead'; +import type { IThreadRead } from './IThreadRead'; +import type { IUploadRead } from './IUploadRead'; +import type { IUserRead } from './IUserRead'; +import type { IVideoConferenceRead } from './IVideoConferenceRead'; + +/** + * The IRead accessor provides methods for accessing the + * Rocket.Chat's environment in a read-only-fashion. + * It is safe to be injected in multiple places, idempotent and extensible + */ +export interface IRead { + /** Gets the IEnvironmentRead instance, contains settings and environmental variables. */ + getEnvironmentReader(): IEnvironmentRead; + + /** Gets the IThreadRead instance */ + + getThreadReader(): IThreadRead; + + /** Gets the IMessageRead instance. */ + getMessageReader(): IMessageRead; + + /** Gets the IPersistenceRead instance. */ + getPersistenceReader(): IPersistenceRead; + + /** Gets the IRoomRead instance. */ + getRoomReader(): IRoomRead; + + /** Gets the IUserRead instance. */ + getUserReader(): IUserRead; + + /** Gets the INotifier for notifying users/rooms. */ + getNotifier(): INotifier; + + getLivechatReader(): ILivechatRead; + getUploadReader(): IUploadRead; + getCloudWorkspaceReader(): ICloudWorkspaceRead; + + getVideoConferenceReader(): IVideoConferenceRead; + + getOAuthAppsReader(): IOAuthAppsReader; + + getRoleReader(): IRoleRead; +} diff --git a/packages/apps-engine/src/definition/accessors/IRoleRead.ts b/packages/apps-engine/src/definition/accessors/IRoleRead.ts new file mode 100644 index 000000000000..fb56ed306a32 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IRoleRead.ts @@ -0,0 +1,27 @@ +import type { IRole } from '../roles'; + +/** + * Interface for reading roles. + */ +export interface IRoleRead { + /** + * Retrieves a role by its id or name. + * @param idOrName The id or name of the role to retrieve. + * @param appId The id of the app. + * @returns The role, if found. + * @returns null if no role is found. + * @throws If there is an error while retrieving the role. + */ + getOneByIdOrName(idOrName: IRole['id'] | IRole['name'], appId: string): Promise; + + /** + * Retrieves all custom roles. + * @param appId The id of the app. + * @returns All custom roles. + * @throws If there is an error while retrieving the roles. + * @throws If the app does not have the necessary permissions. + * @see IRole.protected + * @see AppPermissions.role.read + */ + getCustomRoles(appId: string): Promise>; +} diff --git a/packages/apps-engine/src/definition/accessors/IRoomBuilder.ts b/packages/apps-engine/src/definition/accessors/IRoomBuilder.ts new file mode 100644 index 000000000000..b92955896380 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IRoomBuilder.ts @@ -0,0 +1,186 @@ +import type { RocketChatAssociationModel } from '../metadata'; +import type { IRoom, RoomType } from '../rooms'; +import type { IUser } from '../users'; + +/** + * Interface for building out a room. + * Please note, a room creator, name, and type must be set otherwise you will NOT + * be able to successfully save the room object. + */ +export interface IRoomBuilder { + kind: RocketChatAssociationModel.ROOM | RocketChatAssociationModel.DISCUSSION; + + /** + * Provides a convient way to set the data for the room. + * Note: Providing an "id" field here will be ignored. + * + * @param room the room data to set + */ + setData(room: Partial): IRoomBuilder; + + /** + * Sets the display name of this room. + * + * @param name the display name of the room + */ + setDisplayName(name: string): IRoomBuilder; + + /** + * Gets the display name of this room. + */ + getDisplayName(): string; + + /** + * Sets the slugified name of this room, it must align to the rules of Rocket.Chat room + * names otherwise there will be an error thrown (no spaces, special characters, etc). + * + * @param name the slugified name + */ + setSlugifiedName(name: string): IRoomBuilder; + + /** + * Gets the slugified name of this room. + */ + getSlugifiedName(): string; + + /** + * Sets the room's type. + * + * @param type the room type + */ + setType(type: RoomType): IRoomBuilder; + + /** + * Gets the room's type. + */ + getType(): RoomType; + + /** + * Sets the creator of the room. + * + * @param creator the user who created the room + */ + setCreator(creator: IUser): IRoomBuilder; + + /** + * Gets the room's creator. + */ + getCreator(): IUser; + + /** + * Adds a user to the room, these are by username until further notice. + * + * @param username the user's username to add to the room + * @deprecated in favor of `addMemberToBeAddedByUsername`. This method will be removed on version 2.0.0 + */ + addUsername(username: string): IRoomBuilder; + + /** + * Sets the usernames of who are joined to the room. + * + * @param usernames the list of usernames + * @deprecated in favor of `setMembersByUsernames`. This method will be removed on version 2.0.0 + */ + setUsernames(usernames: Array): IRoomBuilder; + + /** + * Gets the usernames of users in the room. + * @deprecated in favor of `getMembersUsernames`. This method will be removed on version 2.0.0 + */ + getUsernames(): Array; + + /** + * Adds a member to the room by username + * + * @param username the user's username to add to the room + */ + addMemberToBeAddedByUsername(username: string): IRoomBuilder; + + /** + * Sets a list of members to the room by usernames + * + * @param usernames the list of usernames + */ + setMembersToBeAddedByUsernames(usernames: Array): IRoomBuilder; + + /** + * Gets the list of usernames of the members who are been added to the room + */ + getMembersToBeAddedUsernames(): Array; + + /** + * Sets whether this room should be a default room or not. + * This means that new users will automatically join this room + * when they join the server. + * + * @param isDefault room should be default or not + */ + setDefault(isDefault: boolean): IRoomBuilder; + + /** + * Gets whether this room is a default room or not. + */ + getIsDefault(): boolean; + + /** + * Sets whether this room should be in read only state or not. + * This means that users without the required permission to talk when + * a room is muted will not be able to talk but instead will only be + * able to read the contents of the room. + * + * @param isReadOnly whether it should be read only or not + */ + setReadOnly(isReadOnly: boolean): IRoomBuilder; + + /** + * Gets whether this room is on read only state or not. + */ + getIsReadOnly(): boolean; + + /** + * Sets whether this room should display the system messages (like user join, etc) + * or not. This means that whenever a system event, such as joining or leaving, happens + * then Rocket.Chat won't send the message to the channel. + * + * @param displaySystemMessages whether the messages should display or not + */ + setDisplayingOfSystemMessages(displaySystemMessages: boolean): IRoomBuilder; + + /** + * Gets whether this room should display the system messages or not. + */ + getDisplayingOfSystemMessages(): boolean; + + /** + * Adds a custom field to the room. + * Note: This will replace an existing field with the same key should it exist already. + * + * @param key the name of the key + * @param value the value of the custom field + */ + addCustomField(key: string, value: object): IRoomBuilder; + + /** + * Sets the entire custom field property to an object provided. This will overwrite + * every existing key/values which are unrecoverable. + * + * @param fields the data to set + */ + setCustomFields(fields: { [key: string]: object }): IRoomBuilder; + + /** + * Gets the custom field property of the room. + */ + getCustomFields(): { [key: string]: object }; + + /** + * Gets user ids of members from a direct message + */ + getUserIds(): Array; + + /** + * Gets the resulting room that has been built up to the point of calling this method. + * Note: modifying the returned value will have no effect. + */ + getRoom(): IRoom; +} diff --git a/packages/apps-engine/src/definition/accessors/IRoomExtender.ts b/packages/apps-engine/src/definition/accessors/IRoomExtender.ts new file mode 100644 index 000000000000..4135c63edd13 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IRoomExtender.ts @@ -0,0 +1,40 @@ +import type { RocketChatAssociationModel } from '../metadata'; +import type { IRoom } from '../rooms'; +import type { IUser } from '../users'; + +export interface IRoomExtender { + kind: RocketChatAssociationModel.ROOM; + + /** + * Adds a custom field to the room. + * Note: This key can not already exist or it will throw an error. + * Note: The key must not contain a period in it, an error will be thrown. + * + * @param key the name of the custom field + * @param value the value of this custom field + */ + addCustomField(key: string, value: any): IRoomExtender; + + /** + * Adds a user to the room. + * + * @param user the user which is to be added to the room + */ + addMember(user: IUser): IRoomExtender; + + /** + * Get a list of users being added to the room. + */ + getMembersBeingAdded(): Array; + + /** + * Get a list of usernames of users being added to the room. + */ + getUsernamesOfMembersBeingAdded(): Array; + + /** + * Gets the resulting room that has been extended at the point of calling this. + * Note: modifying the returned value will have no effect. + */ + getRoom(): IRoom; +} diff --git a/packages/apps-engine/src/definition/accessors/IRoomRead.ts b/packages/apps-engine/src/definition/accessors/IRoomRead.ts new file mode 100644 index 000000000000..f4e0df33239d --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IRoomRead.ts @@ -0,0 +1,93 @@ +import type { GetMessagesOptions } from '../../server/bridges/RoomBridge'; +import type { IMessageRaw } from '../messages/index'; +import type { IRoom } from '../rooms/index'; +import type { IUser } from '../users/index'; + +/** + * This accessor provides methods for accessing + * rooms in a read-only-fashion. + */ +export interface IRoomRead { + /** + * Gets a room by an id. + * + * @param id the id of the room + * @returns the room + */ + getById(id: string): Promise; + + /** + * Gets just the creator of the room by the room's id. + * + * @param id the id of the room + * @returns the creator of the room + */ + getCreatorUserById(id: string): Promise; + + /** + * Gets a room by its name. + * + * @param name the name of the room + * @returns the room + */ + getByName(name: string): Promise; + + /** + * Gets just the creator of the room by the room's name. + * + * @param name the name of the room + * @returns the creator of the room + */ + getCreatorUserByName(name: string): Promise; + + /** + * Retrieves an array of messages from the specified room. + * + * @param roomId The unique identifier of the room from which to retrieve messages. + * @param options Optional parameters for retrieving messages: + * - limit: The maximum number of messages to retrieve. Maximum 100 + * - skip: The number of messages to skip (for pagination). + * - sort: An object defining the sorting order of the messages. Each key is a field to sort by, and the value is either "asc" for ascending order or "desc" for descending order. + * @returns A Promise that resolves to an array of IMessage objects representing the messages in the room. + */ + getMessages(roomId: string, options?: Partial): Promise>; + + /** + * Gets an iterator for all of the users in the provided room. + * + * @param roomId the room's id + * @returns an iterator for the users in the room + */ + getMembers(roomId: string): Promise>; + + /** + * Gets a direct room with all usernames + * @param usernames all usernames belonging to the direct room + * @returns the room + */ + getDirectByUsernames(usernames: Array): Promise; + + /** + * Get a list of the moderators of a given room + * + * @param roomId the room's id + * @returns a list of the users with the moderator role in the room + */ + getModerators(roomId: string): Promise>; + + /** + * Get a list of the owners of a given room + * + * @param roomId the room's id + * @returns a list of the users with the owner role in the room + */ + getOwners(roomId: string): Promise>; + + /** + * Get a list of the leaders of a given room + * + * @param roomId the room's id + * @returns a list of the users with the leader role in the room + */ + getLeaders(roomId: string): Promise>; +} diff --git a/packages/apps-engine/src/definition/accessors/ISchedulerExtend.ts b/packages/apps-engine/src/definition/accessors/ISchedulerExtend.ts new file mode 100644 index 000000000000..fc003e34b587 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ISchedulerExtend.ts @@ -0,0 +1,11 @@ +import type { IProcessor } from '../scheduler'; + +export interface ISchedulerExtend { + /** + * Register processors that can be scheduled to run + * + * @param {Array} processors An array of processors + * @returns List of task ids run at startup, or void no startup run is set + */ + registerProcessors(processors: Array): Promise>; +} diff --git a/packages/apps-engine/src/definition/accessors/ISchedulerModify.ts b/packages/apps-engine/src/definition/accessors/ISchedulerModify.ts new file mode 100644 index 000000000000..04faa8700799 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ISchedulerModify.ts @@ -0,0 +1,31 @@ +import type { IOnetimeSchedule, IRecurringSchedule } from '../scheduler'; + +/** + * This accessor provides methods to work with the Job Scheduler + */ +export interface ISchedulerModify { + /** + * Schedules a registered processor to run _once_. + * + * @param {IOnetimeSchedule} job + * @returns jobid as string + */ + scheduleOnce(job: IOnetimeSchedule): Promise; + /** + * Schedules a registered processor to run in recurrencly according to a given interval + * + * @param {IRecurringSchedule} job + * @returns jobid as string + */ + scheduleRecurring(job: IRecurringSchedule): Promise; + /** + * Cancels a running job given its jobId + * + * @param {string} jobId + */ + cancelJob(jobId: string): Promise; + /** + * Cancels all the running jobs from the app + */ + cancelAllJobs(): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IServerSettingRead.ts b/packages/apps-engine/src/definition/accessors/IServerSettingRead.ts new file mode 100644 index 000000000000..ecb7af279241 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IServerSettingRead.ts @@ -0,0 +1,43 @@ +import type { ISetting } from '../settings/ISetting'; + +/** + * Reader for the settings inside of the server (Rocket.Chat). + * Only a subset of them are exposed to Apps. + */ +export interface IServerSettingRead { + /** + * Gets a server setting by id. + * Please note: a error will be thrown if not found + * or trying to access one that isn't exposed. + * + * @param id the id of the setting to get + * @return the setting + */ + getOneById(id: string): Promise; + + /** + * Gets a server setting's value by id. + * Please note: a error will be thrown if not found + * or trying to access one that isn't exposed. + * + * @param id the id of the setting to get + * @return the setting's value + */ + getValueById(id: string): Promise; + + /** + * Gets all of the server settings which are exposed + * to the Apps. + * + * @return an iterator of the exposed settings + */ + getAll(): Promise>; + + /** + * Checks if the server setting for the id provided is readable, + * will return true or false and won't throw an error. + * + * @param id the server setting id + */ + isReadableById(id: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IServerSettingUpdater.ts b/packages/apps-engine/src/definition/accessors/IServerSettingUpdater.ts new file mode 100644 index 000000000000..766285c25953 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IServerSettingUpdater.ts @@ -0,0 +1,6 @@ +import type { ISetting } from '../settings/ISetting'; + +export interface IServerSettingUpdater { + updateOne(setting: ISetting): Promise; + incrementValue(id: ISetting['id'], value?: number): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IServerSettingsModify.ts b/packages/apps-engine/src/definition/accessors/IServerSettingsModify.ts new file mode 100644 index 000000000000..400bd5ae211f --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IServerSettingsModify.ts @@ -0,0 +1,40 @@ +import type { ISetting } from '../settings'; + +/** + * This accessor provides methods to change default setting options + * of Rocket.Chat in a compatible way. It is provided during + * your App's "onEnable". + */ +export interface IServerSettingsModify { + /** + * Hides an existing settings group. + * + * @param name The technical name of the group + */ + hideGroup(name: string): Promise; + + /** + * Hides a setting. This does not influence the actual functionality (the setting will still + * have its value and can be programatically read), but the administrator will not be able to see it anymore + * + * @param id the id of the setting to hide + */ + hideSetting(id: string): Promise; + + /** + * Modifies the configured value of another setting, please use it with caution as an invalid + * setting configuration could cause a Rocket.Chat instance to become unstable. + * + * @param setting the modified setting (id must be provided) + */ + modifySetting(setting: ISetting): Promise; + + /** + * Increases the setting value by the specified amount. + * To be used only with statistic settings that track the amount of times an action has been performed + * + * @param id the id of the existing Rocket.Chat setting + * @param value how much should the count be increased by. Defaults to 1. + */ + incrementValue(id: ISetting['id'], value?: number): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/ISettingRead.ts b/packages/apps-engine/src/definition/accessors/ISettingRead.ts new file mode 100644 index 000000000000..142ee895b161 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ISettingRead.ts @@ -0,0 +1,23 @@ +import type { ISetting } from '../settings/index'; + +/** + * This accessor provides methods for accessing + * App settings in a read-only-fashion. + */ +export interface ISettingRead { + /** + * Gets the App's setting by the provided id. + * Does not throw an error but instead will return undefined it doesn't exist. + * + * @param id the id of the setting + */ + getById(id: string): Promise; + + /** + * Gets the App's setting value by the provided id. + * Note: this will throw an error if the setting doesn't exist + * + * @param id the id of the setting value to get + */ + getValueById(id: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/ISettingUpdater.ts b/packages/apps-engine/src/definition/accessors/ISettingUpdater.ts new file mode 100644 index 000000000000..3826286df6c9 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ISettingUpdater.ts @@ -0,0 +1,5 @@ +import type { ISetting } from '../settings/ISetting'; + +export interface ISettingUpdater { + updateValue(id: ISetting['id'], value: ISetting['value']): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/ISettingsExtend.ts b/packages/apps-engine/src/definition/accessors/ISettingsExtend.ts new file mode 100644 index 000000000000..249776379645 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ISettingsExtend.ts @@ -0,0 +1,17 @@ +import type { ISetting } from '../settings/index'; + +/** + * This accessor provides methods for adding custom settings, + * which are displayed on your App's page. + * This is provided on initialization of your App. + */ +export interface ISettingsExtend { + /** + * Adds a setting which can be configured by an administrator. + * Settings can only be added to groups which have been provided by this App earlier + * and if a group is not provided, the setting will appear outside of a group. + * + * @param setting the setting + */ + provideSetting(setting: ISetting): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/ISlashCommandsExtend.ts b/packages/apps-engine/src/definition/accessors/ISlashCommandsExtend.ts new file mode 100644 index 000000000000..4895e61bf96f --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ISlashCommandsExtend.ts @@ -0,0 +1,16 @@ +import type { ISlashCommand } from '../slashcommands'; + +/** + * This accessor provides methods for adding custom slash commands. + * It is provided during the initialization of your App + */ + +export interface ISlashCommandsExtend { + /** + * Adds a slash command which can be used during conversations lateron. + * Should a command already exists an error will be thrown. + * + * @param slashCommand the command information + */ + provideSlashCommand(slashCommand: ISlashCommand): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/ISlashCommandsModify.ts b/packages/apps-engine/src/definition/accessors/ISlashCommandsModify.ts new file mode 100644 index 000000000000..b9e3d4c3e615 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/ISlashCommandsModify.ts @@ -0,0 +1,30 @@ +import type { ISlashCommand } from '../slashcommands'; + +/** + * This accessor provides methods for modifying existing Rocket.Chat slash commands. + * It is provided during "onEnable" of your App. + */ +export interface ISlashCommandsModify { + /** + * Modifies an existing command. The command must either be your App's + * own command or a system command. One App can not modify another + * App's command. + * + * @param slashCommand the modified slash command + */ + modifySlashCommand(slashCommand: ISlashCommand): Promise; + + /** + * Renders an existing slash command un-usable. + * + * @param command the command's usage without the slash + */ + disableSlashCommand(command: string): Promise; + + /** + * Enables an existing slash command to be usable again. + * + * @param command the command's usage without the slash + */ + enableSlashCommand(command: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IThreadRead.ts b/packages/apps-engine/src/definition/accessors/IThreadRead.ts new file mode 100644 index 000000000000..72ceae996eec --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IThreadRead.ts @@ -0,0 +1,9 @@ +import type { IMessage } from '../messages/index'; + +/** + * This accessor provides methods for accessing + * Thread messages in a read-only-fashion. + */ +export interface IThreadRead { + getThreadById(id: string): Promise | undefined>; +} diff --git a/packages/apps-engine/src/definition/accessors/IUIController.ts b/packages/apps-engine/src/definition/accessors/IUIController.ts new file mode 100644 index 000000000000..be7e91f5a05b --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IUIController.ts @@ -0,0 +1,31 @@ +import type { Omit } from '../../lib/utils'; +import type { IUIKitErrorInteraction, IUIKitInteraction, IUIKitSurface } from '../uikit'; +import type { IUIKitContextualBarViewParam, IUIKitModalViewParam } from '../uikit/UIKitInteractionResponder'; +import type { IUser } from '../users'; + +export type IUIKitInteractionParam = Omit; +export type IUIKitErrorInteractionParam = Omit; + +export type IUIKitSurfaceViewParam = Omit & Partial>; + +export interface IUIController { + /** + * @deprecated please prefer the `openSurfaceView` method + */ + openModalView(view: IUIKitModalViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + /** + * @deprecated please prefer the `updateSurfaceView` method + */ + updateModalView(view: IUIKitModalViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + /** + * @deprecated please prefer the `openSurfaceView` method + */ + openContextualBarView(view: IUIKitContextualBarViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + /** + * @deprecated please prefer the `updateSurfaceView` method + */ + updateContextualBarView(view: IUIKitContextualBarViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + setViewError(errorInteraction: IUIKitErrorInteractionParam, context: IUIKitInteractionParam, user: IUser): Promise; + openSurfaceView(view: IUIKitSurfaceViewParam, context: IUIKitInteractionParam, user: IUser): Promise; + updateSurfaceView(view: IUIKitSurfaceViewParam, context: IUIKitInteractionParam, user: IUser): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IUIExtend.ts b/packages/apps-engine/src/definition/accessors/IUIExtend.ts new file mode 100644 index 000000000000..3dca2e32809b --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IUIExtend.ts @@ -0,0 +1,5 @@ +import type { IUIActionButtonDescriptor } from '../ui'; + +export interface IUIExtend { + registerButton(button: IUIActionButtonDescriptor): void; +} diff --git a/packages/apps-engine/src/definition/accessors/IUploadCreator.ts b/packages/apps-engine/src/definition/accessors/IUploadCreator.ts new file mode 100644 index 000000000000..25262b42e7d3 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IUploadCreator.ts @@ -0,0 +1,12 @@ +import type { IUpload } from '../uploads'; +import type { IUploadDescriptor } from '../uploads/IUploadDescriptor'; + +export interface IUploadCreator { + /** + * Create an upload to a room + * + * @param buffer A Buffer with the file's content (See [here](https://nodejs.org/api/buffer.html) + * @param descriptor The metadata about the upload + */ + uploadBuffer(buffer: Buffer, descriptor: IUploadDescriptor): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IUploadRead.ts b/packages/apps-engine/src/definition/accessors/IUploadRead.ts new file mode 100644 index 000000000000..ce4029a8c0c8 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IUploadRead.ts @@ -0,0 +1,7 @@ +import type { IUpload } from '../uploads'; + +export interface IUploadRead { + getById(id: string): Promise; + getBufferById(id: string): Promise; + getBuffer(upload: IUpload): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IUserBuilder.ts b/packages/apps-engine/src/definition/accessors/IUserBuilder.ts new file mode 100644 index 000000000000..4e0c52aa893a --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IUserBuilder.ts @@ -0,0 +1,60 @@ +import type { RocketChatAssociationModel } from '../metadata'; +import type { IUser, IUserEmail } from '../users'; + +/** + * Interface for creating a user. + * Please note, a username and email provided must be unique else you will NOT + * be able to successfully save the user object. + */ +export interface IUserBuilder { + kind: RocketChatAssociationModel.USER; + + /** + * Provides a convient way to set the data for the user. + * Note: Providing an "id" field here will be ignored. + * + * @param user the user data to set + */ + setData(user: Partial): IUserBuilder; + + /** + * Sets emails of the user + * + * @param emails the array of email addresses of the user + */ + setEmails(emails: Array): IUserBuilder; + + /** + * Gets emails of the user + */ + getEmails(): Array; + + /** + * Sets the display name of this user. + * + * @param name the display name of the user + */ + setDisplayName(name: string): IUserBuilder; + + /** + * Gets the display name of this user. + */ + getDisplayName(): string; + + /** + * Sets the username for the user + * + * @param username username of the user + */ + setUsername(username: string): IUserBuilder; + + /** + * Gets the username of this user + */ + getUsername(): string; + + /** + * Gets the user + */ + getUser(): Partial; +} diff --git a/packages/apps-engine/src/definition/accessors/IUserRead.ts b/packages/apps-engine/src/definition/accessors/IUserRead.ts new file mode 100644 index 000000000000..33c4c6e455e4 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IUserRead.ts @@ -0,0 +1,22 @@ +import type { IUser } from '../users/index'; + +/** + * This accessor provides methods for accessing + * users in a read-only-fashion. + */ +export interface IUserRead { + getById(id: string): Promise; + + getByUsername(username: string): Promise; + + /** + * Gets the app user of this app. + */ + getAppUser(appId?: string): Promise; + + /** + * Gets the user's badge count (unread messages count). + * @param uid user's id + */ + getUserUnreadMessageCount(uid: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IUserUpdater.ts b/packages/apps-engine/src/definition/accessors/IUserUpdater.ts new file mode 100644 index 000000000000..8c57b4dadfa8 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IUserUpdater.ts @@ -0,0 +1,18 @@ +import type { IUser } from '../users/IUser'; + +/** + * Updating a user is a more granular approach, since + * it is one of the more sensitive aspects of Rocket.Chat - + * or any other system for that matter. + * + * Allowing apps to modify _all_ the aspects of a user + * would open a critical surface for them to abuse such + * power and "take hold" of a server, for instance. + */ +export interface IUserUpdater { + updateStatusText(user: IUser, statusText: IUser['statusText']): Promise; + updateStatus(user: IUser, statusText: IUser['statusText'], status: IUser['status']): Promise; + updateBio(user: IUser, bio: IUser['bio']): Promise; + updateCustomFields(user: IUser, customFields: IUser['customFields']): Promise; + deactivate(userId: IUser['id'], confirmRelinquish: boolean): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IVideoConfProvidersExtend.ts b/packages/apps-engine/src/definition/accessors/IVideoConfProvidersExtend.ts new file mode 100644 index 000000000000..c61224893e11 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IVideoConfProvidersExtend.ts @@ -0,0 +1,15 @@ +import type { IVideoConfProvider } from '../videoConfProviders'; + +/** + * This accessor provides methods for adding videoconf providers. + * It is provided during the initialization of your App + */ + +export interface IVideoConfProvidersExtend { + /** + * Adds a videoconf provider + * + * @param provider the provider information + */ + provideVideoConfProvider(provider: IVideoConfProvider): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/IVideoConferenceBuilder.ts b/packages/apps-engine/src/definition/accessors/IVideoConferenceBuilder.ts new file mode 100644 index 000000000000..11b96da0e4ef --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IVideoConferenceBuilder.ts @@ -0,0 +1,34 @@ +import type { RocketChatAssociationModel } from '../metadata'; +import type { AppVideoConference } from '../videoConferences'; + +export interface IVideoConferenceBuilder { + kind: RocketChatAssociationModel.VIDEO_CONFERENCE; + + setData(call: Partial): IVideoConferenceBuilder; + + setRoomId(rid: string): IVideoConferenceBuilder; + + getRoomId(): string; + + setCreatedBy(userId: string): IVideoConferenceBuilder; + + getCreatedBy(): string; + + setProviderName(name: string): IVideoConferenceBuilder; + + getProviderName(): string; + + setProviderData(data: Record): IVideoConferenceBuilder; + + getProviderData(): Record; + + setTitle(name: string): IVideoConferenceBuilder; + + getTitle(): string; + + setDiscussionRid(rid: string | undefined): IVideoConferenceBuilder; + + getDiscussionRid(): string | undefined; + + getVideoConference(): AppVideoConference; +} diff --git a/packages/apps-engine/src/definition/accessors/IVideoConferenceExtend.ts b/packages/apps-engine/src/definition/accessors/IVideoConferenceExtend.ts new file mode 100644 index 000000000000..d9b7e5838368 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IVideoConferenceExtend.ts @@ -0,0 +1,21 @@ +import type { RocketChatAssociationModel } from '../metadata'; +import type { IVideoConferenceUser, VideoConference } from '../videoConferences'; +import type { VideoConferenceMember } from '../videoConferences/IVideoConference'; + +export interface IVideoConferenceExtender { + kind: RocketChatAssociationModel.VIDEO_CONFERENCE; + + setProviderData(value: Record): IVideoConferenceExtender; + + setStatus(value: VideoConference['status']): IVideoConferenceExtender; + + setEndedBy(value: IVideoConferenceUser['_id']): IVideoConferenceExtender; + + setEndedAt(value: VideoConference['endedAt']): IVideoConferenceExtender; + + addUser(userId: VideoConferenceMember['_id'], ts?: VideoConferenceMember['ts']): IVideoConferenceExtender; + + setDiscussionRid(rid: VideoConference['discussionRid']): IVideoConferenceExtender; + + getVideoConference(): VideoConference; +} diff --git a/packages/apps-engine/src/definition/accessors/IVideoConferenceRead.ts b/packages/apps-engine/src/definition/accessors/IVideoConferenceRead.ts new file mode 100644 index 000000000000..aa2d53d70590 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/IVideoConferenceRead.ts @@ -0,0 +1,15 @@ +import type { VideoConference } from '../videoConferences/IVideoConference'; + +/** + * This accessor provides methods for accessing + * video conferences in a read-only-fashion. + */ +export interface IVideoConferenceRead { + /** + * Gets a video conference by an id. + * + * @param id the id of the video conference + * @returns the video conference + */ + getById(id: string): Promise; +} diff --git a/packages/apps-engine/src/definition/accessors/index.ts b/packages/apps-engine/src/definition/accessors/index.ts new file mode 100644 index 000000000000..e98a4208fe13 --- /dev/null +++ b/packages/apps-engine/src/definition/accessors/index.ts @@ -0,0 +1,58 @@ +export * from './IApiExtend'; +export * from './IAppAccessors'; +export * from './IAppInstallationContext'; +export * from './IAppUpdateContext'; +export * from './IAppUninstallationContext'; +export * from './ICloudWorkspaceRead'; +export * from './IConfigurationExtend'; +export * from './IConfigurationModify'; +export * from './IDiscussionBuilder'; +export * from './IEnvironmentalVariableRead'; +export * from './IEnvironmentRead'; +export * from './IEnvironmentWrite'; +export * from './IExternalComponentsExtend'; +export * from './IHttp'; +export * from './ILivechatCreator'; +export * from './ILivechatMessageBuilder'; +export * from './ILivechatRead'; +export * from './ILivechatUpdater'; +export * from './ILogEntry'; +export * from './ILogger'; +export * from './IMessageBuilder'; +export * from './IMessageExtender'; +export * from './IMessageRead'; +export * from './IMessageUpdater'; +export * from './IModify'; +export * from './IModifyCreator'; +export * from './IModifyDeleter'; +export * from './IModifyExtender'; +export * from './IModifyUpdater'; +export * from './INotifier'; +export * from './IPersistence'; +export * from './IPersistenceRead'; +export * from './IRead'; +export * from './IRoleRead'; +export * from './IRoomBuilder'; +export * from './IRoomExtender'; +export * from './IRoomRead'; +export * from './ISchedulerExtend'; +export * from './ISchedulerModify'; +export * from './IServerSettingRead'; +export * from './IServerSettingsModify'; +export * from './IServerSettingUpdater'; +export * from './ISettingRead'; +export * from './ISettingsExtend'; +export * from './ISettingUpdater'; +export * from './ISlashCommandsExtend'; +export * from './ISlashCommandsModify'; +export * from './IUIController'; +export * from './IUIExtend'; +export * from './IUploadCreator'; +export * from './IUploadRead'; +export * from './IUserBuilder'; +export * from './IUserRead'; +export * from './IVideoConferenceBuilder'; +export * from './IVideoConferenceExtend'; +export * from './IVideoConferenceRead'; +export * from './IVideoConfProvidersExtend'; +export * from './IModerationModify'; diff --git a/packages/apps-engine/src/definition/api/ApiEndpoint.ts b/packages/apps-engine/src/definition/api/ApiEndpoint.ts new file mode 100644 index 000000000000..8ab7610c9b4f --- /dev/null +++ b/packages/apps-engine/src/definition/api/ApiEndpoint.ts @@ -0,0 +1,40 @@ +import type { IApp } from '../IApp'; +import { HttpStatusCode } from '../accessors'; +import type { IApiEndpoint } from './IApiEndpoint'; +import type { IApiResponse, IApiResponseJSON } from './IResponse'; + +/** Represents an api endpoint that is being provided. */ +export abstract class ApiEndpoint implements IApiEndpoint { + /** + * The last part of the api URL. Example: https://{your-server-address}/api/apps/public/{your-app-id}/{path} + * or https://{your-server-address}/api/apps/private/{your-app-id}/{private-hash}/{path} + */ + public path: string; + + constructor(public app: IApp) {} + + /** + * Return response with status 200 (OK) and a optional content + * @param content + */ + protected success(content?: any): IApiResponse { + return { + status: HttpStatusCode.OK, + content, + }; + } + + /** + * Return a json response adding Content Type header as + * application/json if not already provided + * @param reponse + */ + protected json(response: IApiResponseJSON): IApiResponse { + if (!response.headers || !response.headers['content-type']) { + response.headers = response.headers || {}; + response.headers['content-type'] = 'application/json'; + } + + return response; + } +} diff --git a/packages/apps-engine/src/definition/api/IApi.ts b/packages/apps-engine/src/definition/api/IApi.ts new file mode 100644 index 000000000000..9ad2f42ed5a8 --- /dev/null +++ b/packages/apps-engine/src/definition/api/IApi.ts @@ -0,0 +1,58 @@ +import type { IApiEndpoint } from './IApiEndpoint'; + +/** + * Represents an api that is being provided. + */ +export interface IApi { + /** + * Provides the visibility method of the URL, see the ApiVisibility descriptions for more information + */ + visibility: ApiVisibility; + /** + * Provides the visibility method of the URL, see the ApiSecurity descriptions for more information + */ + security: ApiSecurity; + /** + * Provide enpoints for this api registry + */ + endpoints: Array; +} + +export enum ApiVisibility { + /** + * A public Api has a fixed format for a url. Using it enables an + * easy to remember structure, however, it also means the url is + * intelligently guessed. As a result, we recommend having some + * sort of security setup if you must have a public api.Whether + * you use the provided security, ApiSecurity, or implement your own. + * Url format: + * `https://{your-server-address}/api/apps/public/{your-app-id}/{path}` + */ + PUBLIC, + /** + * Private Api's contain a random value in the url format, + * making them harder go guess by default. The random value + * will be generated whenever the App is installed on a server. + * This means that the URL will not be the same on any server, + * but will remain the same throughout the lifecycle of an App + * including updates. As a result, if a user uninstalls the App + * and reinstalls the App, then the random value will change. + * Url format: + * `https://{your-server-address}/api/apps/private/{your-app-id}/{random-hash}/{path}` + */ + PRIVATE, +} + +export enum ApiSecurity { + /** + * No security check will be executed agains the calls made to this URL + */ + UNSECURE, + /** + * Only calls containing a valid token will be able to execute the api + * Mutiple tokens can be generated to access the api, by default one + * will be generated automatically. + * @param `X-Auth-Token` + */ + // CHECKSUM_SECRET, +} diff --git a/packages/apps-engine/src/definition/api/IApiEndpoint.ts b/packages/apps-engine/src/definition/api/IApiEndpoint.ts new file mode 100644 index 000000000000..b369fc175dc2 --- /dev/null +++ b/packages/apps-engine/src/definition/api/IApiEndpoint.ts @@ -0,0 +1,47 @@ +import type { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import type { IApiEndpointInfo } from './IApiEndpointInfo'; +import type { IApiExample } from './IApiExample'; +import type { IApiRequest } from './IRequest'; +import type { IApiResponse } from './IResponse'; + +/** + * Represents an api endpoint that is being provided. + */ +export interface IApiEndpoint { + /** + * The last part of the api URL. Example: https://{your-server-address}/api/apps/public/{your-app-id}/{path} + * or https://{your-server-address}/api/apps/private/{your-app-id}/{private-hash}/{path} + */ + path: string; + examples?: { [key: string]: IApiExample }; + /** + * Whether this endpoint requires an authenticated user to access it. + * + * The authentication will be done by the host server using its own + * authentication system. + * + * If no authentication is provided, the request will be automatically + * rejected with a 401 status code. + */ + authRequired?: boolean; + + /** + * The methods that are available for this endpoint. + * This property is provided by the Runtime and should not be set manually. + * + * Its values are used on the Apps-Engine to validate the request method. + */ + _availableMethods?: string[]; + + /** + * Called whenever the publically accessible url for this App is called, + * if you handle the methods differently then split it out so your code doesn't get too big. + */ + get?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; + post?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; + put?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; + delete?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; + head?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; + options?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; + patch?(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise; +} diff --git a/packages/apps-engine/src/definition/api/IApiEndpointInfo.ts b/packages/apps-engine/src/definition/api/IApiEndpointInfo.ts new file mode 100644 index 000000000000..de9144784b34 --- /dev/null +++ b/packages/apps-engine/src/definition/api/IApiEndpointInfo.ts @@ -0,0 +1,6 @@ +export interface IApiEndpointInfo { + basePath: string; + fullPath: string; + appId: string; + hash?: string; +} diff --git a/packages/apps-engine/src/definition/api/IApiEndpointMetadata.ts b/packages/apps-engine/src/definition/api/IApiEndpointMetadata.ts new file mode 100644 index 000000000000..0ede26045f79 --- /dev/null +++ b/packages/apps-engine/src/definition/api/IApiEndpointMetadata.ts @@ -0,0 +1,10 @@ +import type { IApiExample } from './IApiExample'; + +export interface IApiEndpointMetadata { + path: string; + computedPath: string; + methods: Array; + examples?: { + [key: string]: IApiExample; + }; +} diff --git a/packages/apps-engine/src/definition/api/IApiExample.ts b/packages/apps-engine/src/definition/api/IApiExample.ts new file mode 100644 index 000000000000..f870d59e643d --- /dev/null +++ b/packages/apps-engine/src/definition/api/IApiExample.ts @@ -0,0 +1,19 @@ +/** + * Represents the parameters of an api example. + */ +export interface IApiExample { + params?: { [key: string]: string }; + query?: { [key: string]: string }; + headers?: { [key: string]: string }; + content?: any; +} + +/** + * Decorator to describe api examples + */ +export function example(options: IApiExample) { + return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { + target.examples = target.examples || {}; + target.examples[propertyKey] = options; + }; +} diff --git a/packages/apps-engine/src/definition/api/IRequest.ts b/packages/apps-engine/src/definition/api/IRequest.ts new file mode 100644 index 000000000000..027de11b2026 --- /dev/null +++ b/packages/apps-engine/src/definition/api/IRequest.ts @@ -0,0 +1,16 @@ +import type { RequestMethod } from '../accessors'; +import type { IUser } from '../users'; + +export interface IApiRequest { + method: RequestMethod; + headers: { [key: string]: string }; + query: { [key: string]: string }; + params: { [key: string]: string }; + content: any; + privateHash?: string; + /** + * The user that is making the request, as + * authenticated by Rocket.Chat's strategy. + */ + user?: IUser; +} diff --git a/packages/apps-engine/src/definition/api/IResponse.ts b/packages/apps-engine/src/definition/api/IResponse.ts new file mode 100644 index 000000000000..8f394b8a93b0 --- /dev/null +++ b/packages/apps-engine/src/definition/api/IResponse.ts @@ -0,0 +1,13 @@ +import type { HttpStatusCode } from '../accessors'; + +export interface IApiResponse { + status: HttpStatusCode; + headers?: { [key: string]: string }; + content?: any; +} + +export interface IApiResponseJSON { + status: HttpStatusCode; + headers?: { [key: string]: string }; + content?: { [key: string]: any }; +} diff --git a/packages/apps-engine/src/definition/api/index.ts b/packages/apps-engine/src/definition/api/index.ts new file mode 100644 index 000000000000..41e4482f2ec6 --- /dev/null +++ b/packages/apps-engine/src/definition/api/index.ts @@ -0,0 +1,8 @@ +export { ApiEndpoint } from './ApiEndpoint'; +export { IApi, ApiVisibility, ApiSecurity } from './IApi'; +export { IApiEndpoint } from './IApiEndpoint'; +export { IApiEndpointInfo } from './IApiEndpointInfo'; +export { IApiExample, example } from './IApiExample'; +export { IApiRequest } from './IRequest'; +export { IApiResponse } from './IResponse'; +export { IApiEndpointMetadata } from './IApiEndpointMetadata'; diff --git a/packages/apps-engine/src/definition/app-schema.json b/packages/apps-engine/src/definition/app-schema.json new file mode 100644 index 000000000000..68c2e0c19edc --- /dev/null +++ b/packages/apps-engine/src/definition/app-schema.json @@ -0,0 +1,75 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rocket.Chat App", + "description": "A Rocket.Chat App declaration for usage inside of Rocket.Chat.", + "type": "object", + "properties": { + "id": { + "description": "The App's unique identifier in uuid v4 format. This is optional, although recommended, however if you are going to publish on the App store, you will be assigned one.", + "type": "string", + "pattern": "^[0-9a-fA-f]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$", + "minLength": 36, + "maxLength": 36 + }, + "name": { + "description": "The public visible name of this App.", + "type": "string" + }, + "nameSlug": { + "description": "A url friendly slugged version of your App's name.", + "type": "string", + "pattern": "^([a-z]|\\-)+$", + "minLength": 3 + }, + "version": { + "description": "The version of this App which will be used for display publicly and letting users know there is an update. This uses the semver format.", + "type": "string", + "pattern": "^(?:\\d*)\\.(?:\\d*)\\.(?:\\d*)$", + "minLength": 5 + }, + "description": { + "description": "A description of this App, used to explain what this App does and provides for the user.", + "type": "string" + }, + "requiredApiVersion": { + "description": "The required version of the App's API which this App depends on. This uses the semver format.", + "type": "string", + "pattern": "^(?:\\^|~)?(?:\\d*)\\.(?:\\d*)\\.(?:\\d*)$", + "minLength": 5 + }, + "author": { + "type": "object", + "properties": { + "name": { + "description": "The author's name who created this App.", + "type": "string" + }, + "support": { + "description": "The place where people can get support for this App, whether email or website.", + "type": "string" + }, + "homepage": { + "description": "The homepage for this App, it can be a Github or the author's website.", + "type": "string", + "format": "uri" + } + }, + "required": ["name", "support"] + }, + "classFile": { + "type": "string", + "description": "The name of the file which contains your App TypeScript source code.", + "pattern": "^.*\\.(ts)$" + }, + "iconFile": { + "type": "string", + "description": "The name of the file to use as the icon.", + "pattern": "^.*\\.(png|jpg|jpeg|gif)$" + }, + "assetsFolder": { + "type": "string", + "description": "The name of the folder which contains all of your resources, it should not start with a period." + } + }, + "required": ["id", "name", "nameSlug", "version", "description", "requiredApiVersion", "author", "classFile", "iconFile"] +} diff --git a/packages/apps-engine/src/definition/assets/IAsset.ts b/packages/apps-engine/src/definition/assets/IAsset.ts new file mode 100644 index 000000000000..30c54ae6565d --- /dev/null +++ b/packages/apps-engine/src/definition/assets/IAsset.ts @@ -0,0 +1,6 @@ +export interface IAsset { + name: string; + path: string; + type: string; + public: boolean; +} diff --git a/packages/apps-engine/src/definition/assets/IAssetProvider.ts b/packages/apps-engine/src/definition/assets/IAssetProvider.ts new file mode 100644 index 000000000000..4e1da50222fa --- /dev/null +++ b/packages/apps-engine/src/definition/assets/IAssetProvider.ts @@ -0,0 +1,5 @@ +import type { IAsset } from './IAsset'; + +export interface IAssetProvider { + getAssets(): Array; +} diff --git a/packages/apps-engine/src/definition/assets/index.ts b/packages/apps-engine/src/definition/assets/index.ts new file mode 100644 index 000000000000..98abab64ddf5 --- /dev/null +++ b/packages/apps-engine/src/definition/assets/index.ts @@ -0,0 +1,4 @@ +import { IAsset } from './IAsset'; +import { IAssetProvider } from './IAssetProvider'; + +export { IAsset, IAssetProvider }; diff --git a/packages/apps-engine/src/definition/cloud/IWorkspaceToken.ts b/packages/apps-engine/src/definition/cloud/IWorkspaceToken.ts new file mode 100644 index 000000000000..40a46bf7e37f --- /dev/null +++ b/packages/apps-engine/src/definition/cloud/IWorkspaceToken.ts @@ -0,0 +1,4 @@ +export interface IWorkspaceToken { + token: string; + expiresAt: Date; +} diff --git a/packages/apps-engine/src/definition/email/IEmail.ts b/packages/apps-engine/src/definition/email/IEmail.ts new file mode 100644 index 000000000000..ca81b23e5bcc --- /dev/null +++ b/packages/apps-engine/src/definition/email/IEmail.ts @@ -0,0 +1,9 @@ +export interface IEmail { + to: string | string[]; + from: string; + replyTo?: string; + subject: string; + html?: string; + text?: string; + headers?: string; +} diff --git a/packages/apps-engine/src/definition/email/IEmailDescriptor.ts b/packages/apps-engine/src/definition/email/IEmailDescriptor.ts new file mode 100644 index 000000000000..168bae039168 --- /dev/null +++ b/packages/apps-engine/src/definition/email/IEmailDescriptor.ts @@ -0,0 +1,11 @@ +export interface IEmailDescriptor { + from?: string | undefined; + to?: string | Array | undefined; + cc?: string | Array | undefined; + bcc?: string | Array | undefined; + replyTo?: string | Array | undefined; + subject?: string | undefined; + text?: string | undefined; + html?: string | undefined; + headers?: Record | undefined; +} diff --git a/packages/apps-engine/src/definition/email/IPreEmailSent.ts b/packages/apps-engine/src/definition/email/IPreEmailSent.ts new file mode 100644 index 000000000000..2d5e40c92851 --- /dev/null +++ b/packages/apps-engine/src/definition/email/IPreEmailSent.ts @@ -0,0 +1,25 @@ +import type { IEmailDescriptor, IPreEmailSentContext } from '.'; +import type { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import { AppMethod } from '../metadata'; + +/** + * Event interface that allows apps to + * register as a handler of of the `IPreEmailSent` + * event. + * + * This event is trigger before the mailer sends + * an email. + * + * To prevent the email from being sent, you can + * throw an error with a message specifying the + * reason for rejection. + */ +export interface IPreEmailSent { + [AppMethod.EXECUTE_PRE_EMAIL_SENT]( + context: IPreEmailSentContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify: IModify, + ): Promise; +} diff --git a/packages/apps-engine/src/definition/email/IPreEmailSentContext.ts b/packages/apps-engine/src/definition/email/IPreEmailSentContext.ts new file mode 100644 index 000000000000..7427424f88eb --- /dev/null +++ b/packages/apps-engine/src/definition/email/IPreEmailSentContext.ts @@ -0,0 +1,6 @@ +import type { IEmailDescriptor } from './IEmailDescriptor'; + +export interface IPreEmailSentContext { + context: unknown; + email: IEmailDescriptor; +} diff --git a/packages/apps-engine/src/definition/email/index.ts b/packages/apps-engine/src/definition/email/index.ts new file mode 100644 index 000000000000..6074ebaec4c3 --- /dev/null +++ b/packages/apps-engine/src/definition/email/index.ts @@ -0,0 +1,4 @@ +export * from './IEmailDescriptor'; +export * from './IPreEmailSent'; +export * from './IPreEmailSentContext'; +export * from './IEmail'; diff --git a/packages/apps-engine/src/definition/example-app.json b/packages/apps-engine/src/definition/example-app.json new file mode 100644 index 000000000000..e78048d1d316 --- /dev/null +++ b/packages/apps-engine/src/definition/example-app.json @@ -0,0 +1,13 @@ +{ + //This is an example of how a app.json file will look like + "name": "Testing", + "nameSlug": "testing", + "description": "Testing description", + "version": "1.0.0", + "requiredApiVersion": "0.0.1", + "author": { + "name": "Bradley Hilton", + "support": "https://github.com/RocketChat/Rocket.Chat.Apps-engine" + }, + "classFile": "ExampleApp.ts" +} diff --git a/packages/apps-engine/src/definition/exceptions/AppsEngineException.ts b/packages/apps-engine/src/definition/exceptions/AppsEngineException.ts new file mode 100644 index 000000000000..a3e802aa69d8 --- /dev/null +++ b/packages/apps-engine/src/definition/exceptions/AppsEngineException.ts @@ -0,0 +1,32 @@ +/** + * The internal exception from the framework + * + * It's used to signal to the outside world that + * a _known_ exception has happened during the execution + * of the apps. + * + * It's the base exception for other known classes + * such as UserNotAllowedException, which is used + * to inform the host that an app identified + * that a user cannot perform some action, e.g. + * join a room + */ +export class AppsEngineException extends Error { + public name = 'AppsEngineException'; + + public static JSONRPC_ERROR_CODE = -32070; + + public message: string; + + constructor(message?: string) { + super(); + this.message = message; + } + + public getErrorInfo() { + return { + name: this.name, + message: this.message, + }; + } +} diff --git a/packages/apps-engine/src/definition/exceptions/EssentialAppDisabledException.ts b/packages/apps-engine/src/definition/exceptions/EssentialAppDisabledException.ts new file mode 100644 index 000000000000..e5043d93e336 --- /dev/null +++ b/packages/apps-engine/src/definition/exceptions/EssentialAppDisabledException.ts @@ -0,0 +1,16 @@ +import { AppsEngineException } from '.'; + +/** + * This exception informs the host system that an + * app essential to the execution of a system action + * is disabled, so the action should be halted. + * + * Apps can register to be considered essential to + * the execution of internal events of the framework + * such as `IPreMessageSentPrevent`, `IPreRoomUserJoined`, + * etc. + * + * This is used interally by the framework and is not + * intended to be thrown manually by apps. + */ +export class EssentialAppDisabledException extends AppsEngineException {} diff --git a/packages/apps-engine/src/definition/exceptions/FileUploadNotAllowedException.ts b/packages/apps-engine/src/definition/exceptions/FileUploadNotAllowedException.ts new file mode 100644 index 000000000000..0ae9d98edb3f --- /dev/null +++ b/packages/apps-engine/src/definition/exceptions/FileUploadNotAllowedException.ts @@ -0,0 +1,12 @@ +import { AppsEngineException } from './AppsEngineException'; + +/** + * This exception informs the host system that an + * app has determined that a file upload is not + * allowed to be completed. + * + * Currently it is expected to be thrown by the + * following events: + * - IPreFileUpload + */ +export class FileUploadNotAllowedException extends AppsEngineException {} diff --git a/packages/apps-engine/src/definition/exceptions/InvalidSettingValueException.ts b/packages/apps-engine/src/definition/exceptions/InvalidSettingValueException.ts new file mode 100644 index 000000000000..2b1a193accb2 --- /dev/null +++ b/packages/apps-engine/src/definition/exceptions/InvalidSettingValueException.ts @@ -0,0 +1,8 @@ +import { AppsEngineException } from './AppsEngineException'; + +/** + * This exception informs the host system that an + * app has determined that an invalid setting value + * is passed. + */ +export class InvalidSettingValueException extends AppsEngineException {} diff --git a/packages/apps-engine/src/definition/exceptions/UserNotAllowedException.ts b/packages/apps-engine/src/definition/exceptions/UserNotAllowedException.ts new file mode 100644 index 000000000000..d81969d8f62a --- /dev/null +++ b/packages/apps-engine/src/definition/exceptions/UserNotAllowedException.ts @@ -0,0 +1,14 @@ +import { AppsEngineException } from '.'; + +/** + * This exception informs the host system that an + * app has determined that an user is not allowed + * to perform a specific action. + * + * Currently it is expected to be thrown by the + * following events: + * - IPreRoomCreatePrevent + * - IPreRoomUserJoined + * - IPreRoomUserLeave + */ +export class UserNotAllowedException extends AppsEngineException {} diff --git a/packages/apps-engine/src/definition/exceptions/index.ts b/packages/apps-engine/src/definition/exceptions/index.ts new file mode 100644 index 000000000000..6129978c2f89 --- /dev/null +++ b/packages/apps-engine/src/definition/exceptions/index.ts @@ -0,0 +1,5 @@ +export * from './AppsEngineException'; +export * from './EssentialAppDisabledException'; +export * from './UserNotAllowedException'; +export * from './FileUploadNotAllowedException'; +export * from './InvalidSettingValueException'; diff --git a/packages/apps-engine/src/definition/externalComponent/IExternalComponent.ts b/packages/apps-engine/src/definition/externalComponent/IExternalComponent.ts new file mode 100644 index 000000000000..7c750e1c7e22 --- /dev/null +++ b/packages/apps-engine/src/definition/externalComponent/IExternalComponent.ts @@ -0,0 +1,51 @@ +import type { IExternalComponentOptions } from './IExternalComponentOptions'; +import type { IExternalComponentState } from './IExternalComponentState'; +/** + * Represents an external component that is being provided. + */ +export interface IExternalComponent { + /** + * Provides the appId of the app which the external component belongs to. + */ + appId: string; + /** + * Provides the name of the external component. This key must be unique. + */ + name: string; + /** + * Provides the description of the external component. + */ + description: string; + /** + * Provides the icon's url or base64 string. + */ + icon: string; + /** + * Provides the location which external component needs + * to register, see the ExternalComponentLocation descriptions + * for the more information. + */ + location: ExternalComponentLocation; + /** + * Provides the url that external component will load. + */ + url: string; + /** + * Provides options for the external component. + */ + options?: IExternalComponentOptions; + /** + * Represents the current state of the external component. + * The value is *null* until the ExternalComponentOpened + * event is triggered. It doesn't make sense to get its value in + * PreExternalComponentOpenedPrevent, PreExternalComponentOpenedModify + * and PreExternalComponentOpenedExtend handlers. + */ + state?: IExternalComponentState; +} + +export enum ExternalComponentLocation { + CONTEXTUAL_BAR = 'CONTEXTUAL_BAR', + + MODAL = 'MODAL', +} diff --git a/packages/apps-engine/src/definition/externalComponent/IExternalComponentOptions.ts b/packages/apps-engine/src/definition/externalComponent/IExternalComponentOptions.ts new file mode 100644 index 000000000000..2581c047ab43 --- /dev/null +++ b/packages/apps-engine/src/definition/externalComponent/IExternalComponentOptions.ts @@ -0,0 +1,10 @@ +export interface IExternalComponentOptions { + /** + * The width of the external component + */ + width?: number; + /** + * The height of the external component + */ + height?: number; +} diff --git a/packages/apps-engine/src/definition/externalComponent/IExternalComponentState.ts b/packages/apps-engine/src/definition/externalComponent/IExternalComponentState.ts new file mode 100644 index 000000000000..4c401f3e28d1 --- /dev/null +++ b/packages/apps-engine/src/definition/externalComponent/IExternalComponentState.ts @@ -0,0 +1,16 @@ +import type { IExternalComponentRoomInfo, IExternalComponentUserInfo } from '../../client/definition'; + +/** + * The state of an external component, which contains the + * current user's information and the current room's information. + */ +export interface IExternalComponentState { + /** + * The user who opened this external component + */ + currentUser: IExternalComponentUserInfo; + /** + * The room where the external component belongs to + */ + currentRoom: IExternalComponentRoomInfo; +} diff --git a/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentClosed.ts b/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentClosed.ts new file mode 100644 index 000000000000..24d224ba2913 --- /dev/null +++ b/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentClosed.ts @@ -0,0 +1,16 @@ +import type { IHttp, IPersistence, IRead } from '../accessors'; +import type { IExternalComponent } from './IExternalComponent'; + +/** + * Handler called after an external component is closed. + */ +export interface IPostExternalComponentClosed { + /** + * Method called after an external component is closed. + * + * @param externalComponent The external component which was closed + * @param read An accessor to the environment + * @param http An accessor to the outside world + */ + executePostExternalComponentClosed(externalComponent: IExternalComponent, read: IRead, http: IHttp, persistence: IPersistence): Promise; +} diff --git a/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentOpened.ts b/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentOpened.ts new file mode 100644 index 000000000000..8a09ebe711d2 --- /dev/null +++ b/packages/apps-engine/src/definition/externalComponent/IPostExternalComponentOpened.ts @@ -0,0 +1,16 @@ +import type { IHttp, IPersistence, IRead } from '../accessors'; +import type { IExternalComponent } from './IExternalComponent'; + +/** + * Handler called after an external component is opened. + */ +export interface IPostExternalComponentOpened { + /** + * Method called after an external component is opened. + * + * @param externalComponent The external component which was opened + * @param read An accessor to the environment + * @param http An accessor to the outside world + */ + executePostExternalComponentOpened(externalComponent: IExternalComponent, read: IRead, http: IHttp, persistence: IPersistence): Promise; +} diff --git a/packages/apps-engine/src/definition/externalComponent/index.ts b/packages/apps-engine/src/definition/externalComponent/index.ts new file mode 100644 index 000000000000..acd4bbf44982 --- /dev/null +++ b/packages/apps-engine/src/definition/externalComponent/index.ts @@ -0,0 +1,5 @@ +import { IExternalComponent } from './IExternalComponent'; +import { IPostExternalComponentClosed } from './IPostExternalComponentClosed'; +import { IPostExternalComponentOpened } from './IPostExternalComponentOpened'; + +export { IExternalComponent, IPostExternalComponentClosed, IPostExternalComponentOpened }; diff --git a/packages/apps-engine/src/definition/livechat/IDepartment.ts b/packages/apps-engine/src/definition/livechat/IDepartment.ts new file mode 100644 index 000000000000..1a59c9835612 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IDepartment.ts @@ -0,0 +1,17 @@ +export interface IDepartment { + id: string; + name?: string; + email?: string; + description?: string; + offlineMessageChannelName?: string; + requestTagBeforeClosingChat?: false; + chatClosingTags?: Array; + abandonedRoomsCloseCustomMessage?: string; + waitingQueueMessage?: string; + departmentsAllowedToForward?: string; + enabled: boolean; + updatedAt: Date; + numberOfAgents: number; + showOnOfflineForm: boolean; + showOnRegistration: boolean; +} diff --git a/packages/apps-engine/src/definition/livechat/ILivechatEventContext.ts b/packages/apps-engine/src/definition/livechat/ILivechatEventContext.ts new file mode 100644 index 000000000000..b94f07ef0250 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/ILivechatEventContext.ts @@ -0,0 +1,7 @@ +import type { IUser } from '../users'; +import type { ILivechatRoom } from './ILivechatRoom'; + +export interface ILivechatEventContext { + agent: IUser; + room: ILivechatRoom; +} diff --git a/packages/apps-engine/src/definition/livechat/ILivechatMessage.ts b/packages/apps-engine/src/definition/livechat/ILivechatMessage.ts new file mode 100644 index 000000000000..d7cc5497d70e --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/ILivechatMessage.ts @@ -0,0 +1,7 @@ +import type { IMessage } from '../messages/IMessage'; +import type { IVisitor } from './IVisitor'; + +export interface ILivechatMessage extends IMessage { + visitor?: IVisitor; + token?: string; +} diff --git a/packages/apps-engine/src/definition/livechat/ILivechatRoom.ts b/packages/apps-engine/src/definition/livechat/ILivechatRoom.ts new file mode 100644 index 000000000000..e3f55142331a --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/ILivechatRoom.ts @@ -0,0 +1,55 @@ +import { RoomType } from '../rooms'; +import type { IRoom } from '../rooms/IRoom'; +import type { IUser } from '../users'; +import type { IDepartment } from './IDepartment'; +import type { IVisitor } from './IVisitor'; + +export enum OmnichannelSourceType { + WIDGET = 'widget', + EMAIL = 'email', + SMS = 'sms', + APP = 'app', + OTHER = 'other', +} + +interface IOmnichannelSourceApp { + type: 'app'; + id: string; + // A human readable alias that goes with the ID, for post analytical purposes + alias?: string; + // A label to be shown in the room info + label?: string; + sidebarIcon?: string; + defaultIcon?: string; +} +type OmnichannelSource = + | { + type: Exclude; + } + | IOmnichannelSourceApp; + +export interface IVisitorChannelInfo { + lastMessageTs?: Date; + phone?: string; +} + +export interface ILivechatRoom extends IRoom { + visitor: IVisitor; + visitorChannelInfo?: IVisitorChannelInfo; + department?: IDepartment; + closer: 'user' | 'visitor' | 'bot'; + closedBy?: IUser; + servedBy?: IUser; + responseBy?: IUser; + isWaitingResponse: boolean; + isOpen: boolean; + closedAt?: Date; + source?: OmnichannelSource; +} + +export const isLivechatRoom = (room: IRoom): room is ILivechatRoom => { + return room.type === RoomType.LIVE_CHAT; +}; +export const isLivechatFromApp = (room: ILivechatRoom): room is ILivechatRoom & { source: IOmnichannelSourceApp } => { + return room.source && room.source.type === 'app'; +}; diff --git a/packages/apps-engine/src/definition/livechat/ILivechatRoomClosedHandler.ts b/packages/apps-engine/src/definition/livechat/ILivechatRoomClosedHandler.ts new file mode 100644 index 000000000000..dba672ad391b --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/ILivechatRoomClosedHandler.ts @@ -0,0 +1,19 @@ +import type { IHttp, IPersistence, IRead } from '../accessors'; +import { AppMethod } from '../metadata'; +import type { ILivechatRoom } from './ILivechatRoom'; + +/** + * Handler called after a livechat room is closed. + * @deprecated please prefer the IPostLivechatRoomClosed event + */ +export interface ILivechatRoomClosedHandler { + /** + * Method called *after* a livechat room is closed. + * + * @param livechatRoom The livechat room which is closed. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persistence An accessor to the App's persistence + */ + [AppMethod.EXECUTE_LIVECHAT_ROOM_CLOSED_HANDLER](data: ILivechatRoom, read: IRead, http: IHttp, persistence: IPersistence): Promise; +} diff --git a/packages/apps-engine/src/definition/livechat/ILivechatTransferData.ts b/packages/apps-engine/src/definition/livechat/ILivechatTransferData.ts new file mode 100644 index 000000000000..988d0a2ec5fd --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/ILivechatTransferData.ts @@ -0,0 +1,8 @@ +import type { IUser } from '../users'; +import type { ILivechatRoom } from './ILivechatRoom'; + +export interface ILivechatTransferData { + currentRoom: ILivechatRoom; + targetAgent?: IUser; + targetDepartment?: string; +} diff --git a/packages/apps-engine/src/definition/livechat/ILivechatTransferEventContext.ts b/packages/apps-engine/src/definition/livechat/ILivechatTransferEventContext.ts new file mode 100644 index 000000000000..74db472751d4 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/ILivechatTransferEventContext.ts @@ -0,0 +1,15 @@ +import type { IRoom } from '../rooms'; +import type { IUser } from '../users'; +import type { IDepartment } from './IDepartment'; + +export enum LivechatTransferEventType { + AGENT = 'agent', + DEPARTMENT = 'department', +} + +export interface ILivechatTransferEventContext { + type: LivechatTransferEventType; + room: IRoom; + from: IUser | IDepartment; + to: IUser | IDepartment; +} diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatAgentAssigned.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatAgentAssigned.ts new file mode 100644 index 000000000000..5c322534c9ff --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatAgentAssigned.ts @@ -0,0 +1,25 @@ +import type { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import { AppMethod } from '../metadata'; +import type { ILivechatEventContext } from './ILivechatEventContext'; + +/** + * Handler called after the assignment of a livechat agent. + */ +export interface IPostLivechatAgentAssigned { + /** + * Handler called *after* the assignment of a livechat agent. + * + * @param data the livechat context data which contains agent's info and room's info. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_AGENT_ASSIGNED]( + context: ILivechatEventContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify?: IModify, + ): Promise; +} diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatAgentUnassigned.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatAgentUnassigned.ts new file mode 100644 index 000000000000..2884cfa94b83 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatAgentUnassigned.ts @@ -0,0 +1,25 @@ +import type { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import { AppMethod } from '../metadata'; +import type { ILivechatEventContext } from './ILivechatEventContext'; + +/** + * Handler called after the unassignment of a livechat agent. + */ +export interface IPostLivechatAgentUnassigned { + /** + * Handler called *after* the unassignment of a livechat agent. + * + * @param data the livechat context data which contains agent's info and room's info. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_AGENT_UNASSIGNED]( + context: ILivechatEventContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify?: IModify, + ): Promise; +} diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatGuestSaved.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatGuestSaved.ts new file mode 100644 index 000000000000..2c5edc0b9692 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatGuestSaved.ts @@ -0,0 +1,19 @@ +import type { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import { AppMethod } from '../metadata'; +import type { IVisitor } from './IVisitor'; + +/** + * Handler called after the guest's info get saved. + */ +export interface IPostLivechatGuestSaved { + /** + * Handler called *after* the guest's info get saved. + * + * @param data the livechat context data which contains guest's info and room's info. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_GUEST_SAVED](context: IVisitor, read: IRead, http: IHttp, persis: IPersistence, modify: IModify): Promise; +} diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomClosed.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomClosed.ts new file mode 100644 index 000000000000..072e02e8c721 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomClosed.ts @@ -0,0 +1,19 @@ +import type { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import { AppMethod } from '../metadata'; +import type { ILivechatRoom } from './ILivechatRoom'; + +/** + * Handler called after a livechat room is closed. + */ +export interface IPostLivechatRoomClosed { + /** + * Method called *after* a livechat room is closed. + * + * @param livechatRoom The livechat room which is closed. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_CLOSED](room: ILivechatRoom, read: IRead, http: IHttp, persis: IPersistence, modify?: IModify): Promise; +} diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomSaved.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomSaved.ts new file mode 100644 index 000000000000..13b6d1cb2e4b --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomSaved.ts @@ -0,0 +1,19 @@ +import type { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import { AppMethod } from '../metadata'; +import type { ILivechatRoom } from './ILivechatRoom'; + +/** + * Handler called after the room's info get saved. + */ +export interface IPostLivechatRoomSaved { + /** + * Handler called *after* the room's info get saved. + * + * @param data the livechat context data which contains room's info. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_SAVED](context: ILivechatRoom, read: IRead, http: IHttp, persis: IPersistence, modify: IModify): Promise; +} diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomStarted.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomStarted.ts new file mode 100644 index 000000000000..237dcd9566e9 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomStarted.ts @@ -0,0 +1,19 @@ +import type { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import { AppMethod } from '../metadata'; +import type { ILivechatRoom } from './ILivechatRoom'; + +/** + * Handler called after a livechat room is started. + */ +export interface IPostLivechatRoomStarted { + /** + * Method called *after* a livechat room is started. + * + * @param livechatRoom The livechat room which is started. + * @param read An accessor to the environment + * @param http An accessor to the outside world + * @param persis An accessor to the App's persistence + * @param modify An accessor to the modifier + */ + [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_STARTED](room: ILivechatRoom, read: IRead, http: IHttp, persis: IPersistence, modify?: IModify): Promise; +} diff --git a/packages/apps-engine/src/definition/livechat/IPostLivechatRoomTransferred.ts b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomTransferred.ts new file mode 100644 index 000000000000..aa86f8d358d3 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IPostLivechatRoomTransferred.ts @@ -0,0 +1,13 @@ +import type { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import { AppMethod } from '../metadata'; +import type { ILivechatTransferEventContext } from './ILivechatTransferEventContext'; + +export interface IPostLivechatRoomTransferred { + [AppMethod.EXECUTE_POST_LIVECHAT_ROOM_TRANSFERRED]( + context: ILivechatTransferEventContext, + read: IRead, + http: IHttp, + persis: IPersistence, + modify: IModify, + ): Promise; +} diff --git a/packages/apps-engine/src/definition/livechat/IVisitor.ts b/packages/apps-engine/src/definition/livechat/IVisitor.ts new file mode 100644 index 000000000000..db5876dd912d --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IVisitor.ts @@ -0,0 +1,16 @@ +import type { IVisitorEmail } from './IVisitorEmail'; +import type { IVisitorPhone } from './IVisitorPhone'; + +export interface IVisitor { + id?: string; + token: string; + username: string; + updatedAt?: Date; + name: string; + department?: string; + phone?: Array; + visitorEmails?: Array; + status?: string; + customFields?: { [key: string]: any }; + livechatData?: { [key: string]: any }; +} diff --git a/packages/apps-engine/src/definition/livechat/IVisitorEmail.ts b/packages/apps-engine/src/definition/livechat/IVisitorEmail.ts new file mode 100644 index 000000000000..a1e35380666e --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IVisitorEmail.ts @@ -0,0 +1,3 @@ +export interface IVisitorEmail { + address: string; +} diff --git a/packages/apps-engine/src/definition/livechat/IVisitorPhone.ts b/packages/apps-engine/src/definition/livechat/IVisitorPhone.ts new file mode 100644 index 000000000000..fe112777e7d7 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/IVisitorPhone.ts @@ -0,0 +1,3 @@ +export interface IVisitorPhone { + phoneNumber: string; +} diff --git a/packages/apps-engine/src/definition/livechat/index.ts b/packages/apps-engine/src/definition/livechat/index.ts new file mode 100644 index 000000000000..5ea8d9f42885 --- /dev/null +++ b/packages/apps-engine/src/definition/livechat/index.ts @@ -0,0 +1,38 @@ +import { IDepartment } from './IDepartment'; +import { ILivechatEventContext } from './ILivechatEventContext'; +import { ILivechatMessage } from './ILivechatMessage'; +import { ILivechatRoom } from './ILivechatRoom'; +import { ILivechatRoomClosedHandler } from './ILivechatRoomClosedHandler'; +import { ILivechatTransferData } from './ILivechatTransferData'; +import { ILivechatTransferEventContext, LivechatTransferEventType } from './ILivechatTransferEventContext'; +import { IPostLivechatAgentAssigned } from './IPostLivechatAgentAssigned'; +import { IPostLivechatAgentUnassigned } from './IPostLivechatAgentUnassigned'; +import { IPostLivechatGuestSaved } from './IPostLivechatGuestSaved'; +import { IPostLivechatRoomClosed } from './IPostLivechatRoomClosed'; +import { IPostLivechatRoomSaved } from './IPostLivechatRoomSaved'; +import { IPostLivechatRoomStarted } from './IPostLivechatRoomStarted'; +import { IPostLivechatRoomTransferred } from './IPostLivechatRoomTransferred'; +import { IVisitor } from './IVisitor'; +import { IVisitorEmail } from './IVisitorEmail'; +import { IVisitorPhone } from './IVisitorPhone'; + +export { + ILivechatEventContext, + ILivechatMessage, + ILivechatRoom, + IPostLivechatAgentAssigned, + IPostLivechatAgentUnassigned, + IPostLivechatGuestSaved, + IPostLivechatRoomStarted, + IPostLivechatRoomClosed, + IPostLivechatRoomSaved, + IPostLivechatRoomTransferred, + ILivechatRoomClosedHandler, + ILivechatTransferData, + ILivechatTransferEventContext, + IDepartment, + IVisitor, + IVisitorEmail, + IVisitorPhone, + LivechatTransferEventType, +}; diff --git a/packages/apps-engine/src/definition/messages/IMessage.ts b/packages/apps-engine/src/definition/messages/IMessage.ts new file mode 100644 index 000000000000..d7ea6357497a --- /dev/null +++ b/packages/apps-engine/src/definition/messages/IMessage.ts @@ -0,0 +1,34 @@ +import type { LayoutBlock } from '@rocket.chat/ui-kit'; + +import type { IRoom } from '../rooms'; +import type { IBlock } from '../uikit'; +import type { IUser, IUserLookup } from '../users'; +import type { IMessageAttachment } from './IMessageAttachment'; +import type { IMessageFile } from './IMessageFile'; +import type { IMessageReactions } from './IMessageReaction'; + +export interface IMessage { + id?: string; + threadId?: string; + room: IRoom; + sender: IUser; + text?: string; + createdAt?: Date; + updatedAt?: Date; + editor?: IUser; + editedAt?: Date; + emoji?: string; + avatarUrl?: string; + alias?: string; + file?: IMessageFile; + attachments?: Array; + reactions?: IMessageReactions; + groupable?: boolean; + parseUrls?: boolean; + customFields?: { [key: string]: any }; + blocks?: Array; + starred?: Array<{ _id: string }>; + pinned?: boolean; + pinnedAt?: Date; + pinnedBy?: IUserLookup; +} diff --git a/packages/apps-engine/src/definition/messages/IMessageAction.ts b/packages/apps-engine/src/definition/messages/IMessageAction.ts new file mode 100644 index 000000000000..3f32e4aa781d --- /dev/null +++ b/packages/apps-engine/src/definition/messages/IMessageAction.ts @@ -0,0 +1,17 @@ +import type { MessageActionType } from './MessageActionType'; +import type { MessageProcessingType } from './MessageProcessingType'; + +/** + * Interface which represents an action which can be added to a message. + */ +export interface IMessageAction { + type: MessageActionType; + text?: string; + url?: string; + image_url?: string; + is_webview?: boolean; + webview_height_ratio?: string; + msg?: string; + msg_in_chat_window?: boolean; + msg_processing_type?: MessageProcessingType; +} diff --git a/packages/apps-engine/src/definition/messages/IMessageAttachment.ts b/packages/apps-engine/src/definition/messages/IMessageAttachment.ts new file mode 100644 index 000000000000..96dd8aa1fe34 --- /dev/null +++ b/packages/apps-engine/src/definition/messages/IMessageAttachment.ts @@ -0,0 +1,43 @@ +import type { IMessageAction } from './IMessageAction'; +import type { IMessageAttachmentAuthor } from './IMessageAttachmentAuthor'; +import type { IMessageAttachmentField } from './IMessageAttachmentField'; +import type { IMessageAttachmentTitle } from './IMessageAttachmentTitle'; +import type { MessageActionButtonsAlignment } from './MessageActionButtonsAlignment'; + +/** + * Interface which represents an attachment which can be added to a message. + */ +export interface IMessageAttachment { + /** Causes the image, audio, and video sections to be hidding when this is true. */ + collapsed?: boolean; + /** The color you want the order on the left side to be, supports any valid background-css value. */ + color?: string; // TODO: Maybe we change this to a Color class which has helper methods? + /** The text to display for this attachment. */ + text?: string; + /** Displays the time next to the text portion. */ + timestamp?: Date; + /** Only applicable if the timestamp is provided, as it makes the time clickable to this link. */ + timestampLink?: string; + /** An image that displays to the left of the text, looks better when this is relatively small. */ + thumbnailUrl?: string; + /** Author portion of the attachment. */ + author?: IMessageAttachmentAuthor; + /** Title portion of the attachment. */ + title?: IMessageAttachmentTitle; + /** The image to display, will be "big" and easy to see. */ + imageUrl?: string; + /** Audio file to play, only supports what html's