diff --git a/.changeset/app-release-info-page.md b/.changeset/app-release-info-page.md
new file mode 100644
index 000000000000..245131c987e5
--- /dev/null
+++ b/.changeset/app-release-info-page.md
@@ -0,0 +1,5 @@
+---
+"@rocket.chat/meteor": patch
+---
+
+Fixed Marketplace Release Info tab loading loop
\ No newline at end of file
diff --git a/.changeset/flat-fireants-itch.md b/.changeset/flat-fireants-itch.md
new file mode 100644
index 000000000000..ffd919d3a774
--- /dev/null
+++ b/.changeset/flat-fireants-itch.md
@@ -0,0 +1,5 @@
+---
+'@rocket.chat/meteor': minor
+---
+
+fix: spotlight doesnt update with new rooms
diff --git a/.changeset/gorgeous-lamps-tan.md b/.changeset/gorgeous-lamps-tan.md
new file mode 100644
index 000000000000..8d31b582ca77
--- /dev/null
+++ b/.changeset/gorgeous-lamps-tan.md
@@ -0,0 +1,5 @@
+---
+'@rocket.chat/meteor': patch
+---
+
+fix emoji being rendered as big on headers and other places than message text
diff --git a/.changeset/moody-teachers-cheer.md b/.changeset/moody-teachers-cheer.md
new file mode 100644
index 000000000000..bed5e5eeb39a
--- /dev/null
+++ b/.changeset/moody-teachers-cheer.md
@@ -0,0 +1,9 @@
+---
+"@rocket.chat/meteor": patch
+"@rocket.chat/core-services": patch
+"@rocket.chat/core-typings": patch
+"@rocket.chat/model-typings": patch
+"@rocket.chat/rest-typings": patch
+---
+
+fix: Resume on-hold chat not working with max-chat's allowed per agent config
diff --git a/.changeset/nervous-bulldogs-fix.md b/.changeset/nervous-bulldogs-fix.md
new file mode 100644
index 000000000000..571184e4cecf
--- /dev/null
+++ b/.changeset/nervous-bulldogs-fix.md
@@ -0,0 +1,5 @@
+---
+'@rocket.chat/meteor': patch
+---
+
+Re-added pagination to Department's agents list
diff --git a/.changeset/shiny-donkeys-prove.md b/.changeset/shiny-donkeys-prove.md
new file mode 100644
index 000000000000..1aad73d1e1d7
--- /dev/null
+++ b/.changeset/shiny-donkeys-prove.md
@@ -0,0 +1,6 @@
+---
+"@rocket.chat/meteor": patch
+"@rocket.chat/model-typings": patch
+---
+
+fix: [ENTERPRISE] Guest users can join more than maxRoomsPerGuest rooms
diff --git a/.changeset/tricky-tomatoes-sit.md b/.changeset/tricky-tomatoes-sit.md
new file mode 100644
index 000000000000..5abba73ae52c
--- /dev/null
+++ b/.changeset/tricky-tomatoes-sit.md
@@ -0,0 +1,5 @@
+---
+'@rocket.chat/meteor': minor
+---
+
+fix: Message sent triggering thread subscriptions multiple times
diff --git a/.github/workflows/new-release.yml b/.github/workflows/new-release.yml
index feeaf0a7c8ae..f5869aa323c7 100644
--- a/.github/workflows/new-release.yml
+++ b/.github/workflows/new-release.yml
@@ -17,6 +17,9 @@ on:
default: master
required: false
+env:
+ HUSKY: 0
+
jobs:
new-release:
runs-on: ubuntu-latest
@@ -25,15 +28,15 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- # with:
- # ref: ${{ github.event.inputs.base-ref }}
- - name: Setup Node.js 16
- uses: actions/setup-node@v3
+ - name: Setup NodeJS
+ uses: ./.github/actions/setup-node
with:
- node-version: 16
+ node-version: 14.21.3
+ cache-modules: true
+ install: true
- - run: yarn install
+ - uses: dtinth/setup-github-actions-caching-for-turbo@v1
- name: Build
run: yarn build
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
index 854d91524c84..bb56beb975b9 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -7,6 +7,9 @@ on:
concurrency: ${{ github.workflow }}-${{ github.ref }}
+env:
+ HUSKY: 0
+
jobs:
release:
name: Release
@@ -15,13 +18,14 @@ jobs:
- name: Checkout Repo
uses: actions/checkout@v3
- - name: Setup Node.js 16
- uses: actions/setup-node@v3
+ - name: Setup NodeJS
+ uses: ./.github/actions/setup-node
with:
- node-version: 16
+ node-version: 14.21.3
+ cache-modules: true
+ install: true
- - name: Install Dependencies
- run: yarn
+ - uses: dtinth/setup-github-actions-caching-for-turbo@v1
- name: Build
run: yarn build
diff --git a/HISTORY.md b/HISTORY.md
index 30439bc8d1b7..07bbdbb660b5 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,3 +1,162 @@
+# 6.2.5
+
+`2023-06-07 ยท 1 ๐ ยท 1 ๐ฉโ๐ป๐จโ๐ป`
+
+### Engine versions
+- Node: `14.21.3`
+- NPM: `6.14.17`
+- MongoDB: `4.4, 5.0, 6.0`
+- Apps-Engine: `1.39.1`
+
+### ๐ Bug fixes
+
+
+- Seat counter including apps ([#29489](https://github.com/RocketChat/Rocket.Chat/pull/29489))
+
+### ๐ฉโ๐ป๐จโ๐ป Core Team ๐ค
+
+- [@ggazzo](https://github.com/ggazzo)
+
+# 6.2.4
+
+`2023-06-07 ยท 2 ๐ ยท 2 ๐ ยท 5 ๐ฉโ๐ป๐จโ๐ป`
+
+### Engine versions
+- Node: `14.21.3`
+- NPM: `6.14.17`
+- MongoDB: `4.4, 5.0, 6.0`
+- Apps-Engine: `1.39.1`
+
+### ๐ Bug fixes
+
+
+- Imported messages are not displayed ([#29485](https://github.com/RocketChat/Rocket.Chat/pull/29485))
+
+ - Fix issue with imported messages not being displayed in the room.
+ - Fix importer agent being added as a member of every imported room.
+
+- message deletion fails if has files attached on filesystem storage ([#29313](https://github.com/RocketChat/Rocket.Chat/pull/29313))
+
+
+๐ Minor changes
+
+
+- Fix Omnichannel Webhooks tests ([#29344](https://github.com/RocketChat/Rocket.Chat/pull/29344))
+
+- use local httpbin container on github CI's ([#29067](https://github.com/RocketChat/Rocket.Chat/pull/29067))
+
+
+
+### ๐ฉโ๐ป๐จโ๐ป Core Team ๐ค
+
+- [@KevLehman](https://github.com/KevLehman)
+- [@debdutdeb](https://github.com/debdutdeb)
+- [@matheusbsilva137](https://github.com/matheusbsilva137)
+- [@murtaza98](https://github.com/murtaza98)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+
+# 6.2.3
+
+`2023-06-05 ยท 1 ๐ ยท 9 ๐ ยท 9 ๐ฉโ๐ป๐จโ๐ป`
+
+### Engine versions
+- Node: `14.21.3`
+- NPM: `6.14.17`
+- MongoDB: `4.4, 5.0, 6.0`
+- Apps-Engine: `1.39.1`
+
+### ๐ New features
+
+
+- Add support to use `TRANSPORTER` env var for monolith deployments ([#29373](https://github.com/RocketChat/Rocket.Chat/pull/29373))
+
+### ๐ Bug fixes
+
+
+- `queuedForUser` endpoint not filtering by status ([#29189](https://github.com/RocketChat/Rocket.Chat/pull/29189))
+
+- Embedded layout stops working after navigation occurs ([#29147](https://github.com/RocketChat/Rocket.Chat/pull/29147))
+
+- File upload in Safari, IOS devices ([#27121](https://github.com/RocketChat/Rocket.Chat/pull/27121))
+
+- fix wrong %s translations ([#29395](https://github.com/RocketChat/Rocket.Chat/pull/29395))
+
+- getActiveLocalUserCount query ([#29349](https://github.com/RocketChat/Rocket.Chat/pull/29349))
+
+- Import progress page stuck at 0% ([#29421](https://github.com/RocketChat/Rocket.Chat/pull/29421))
+
+ - Fix incorrect percentage calc;
+ - Fix import progress page stuck at 0%.
+
+- Importer crashes when sending the "active status" e-mail notification to users ([#29401](https://github.com/RocketChat/Rocket.Chat/pull/29401))
+
+ - Fix `getImportProgress` endpoint returning incorrect count info (`total: 0, completed: 0`);
+ - Fix server crash when sending the "active status" e-mail notification to users on import.
+
+- OTR session closing after 10 seconds without warning ([#29245](https://github.com/RocketChat/Rocket.Chat/pull/29245))
+
+ The `Notifications` streamer is sending two events when there's a license applied to the workspace and it's not using Microservices. I'm avoiding this by simply ignoring the second event in OTRRoom.
+
+ There is still an issue where there's 2 system messages being fired after accepting, but that's not a really big concern since it doesn't break anything.
+
+- unable to create user if Accounts_ManuallyApproveNewUsers is enabled ([#29293](https://github.com/RocketChat/Rocket.Chat/pull/29293))
+
+### ๐ฉโ๐ป๐จโ๐ป Core Team ๐ค
+
+- [@KevLehman](https://github.com/KevLehman)
+- [@debdutdeb](https://github.com/debdutdeb)
+- [@gabriellsh](https://github.com/gabriellsh)
+- [@ggazzo](https://github.com/ggazzo)
+- [@jessicaschelly](https://github.com/jessicaschelly)
+- [@matheusbsilva137](https://github.com/matheusbsilva137)
+- [@murtaza98](https://github.com/murtaza98)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+- [@yash-rajpal](https://github.com/yash-rajpal)
+
+# 6.2.2
+
+`2023-05-19 ยท 1 ๐ ยท 2 ๐ฉโ๐ป๐จโ๐ป`
+
+### Engine versions
+- Node: `14.21.3`
+- NPM: `6.14.17`
+- MongoDB: `4.4, 5.0, 6.0`
+- Apps-Engine: `1.39.1`
+
+### ๐ Bug fixes
+
+
+- Livechat `CSP` whitelist validation ([#29278](https://github.com/RocketChat/Rocket.Chat/pull/29278))
+
+ This PR fixes the Livechat CSP validation, which was incorrectly blocking access to the widget for all non whitelisted domains.
+
+### ๐ฉโ๐ป๐จโ๐ป Core Team ๐ค
+
+- [@aleksandernsilva](https://github.com/aleksandernsilva)
+- [@ggazzo](https://github.com/ggazzo)
+
+# 6.2.1
+
+`2023-05-17 ยท 1 ๐ ยท 1 ๐ฉโ๐ป๐จโ๐ป`
+
+### Engine versions
+- Node: `14.21.3`
+- NPM: `6.14.17`
+- MongoDB: `4.4, 5.0, 6.0`
+- Apps-Engine: `1.39.1`
+
+
+๐ Minor changes
+
+
+- Bump apps engine and vm2 ([#29262](https://github.com/RocketChat/Rocket.Chat/pull/29262))
+
+
+
+### ๐ฉโ๐ป๐จโ๐ป Core Team ๐ค
+
+- [@AllanPazRibeiro](https://github.com/AllanPazRibeiro)
+
# 6.2.0
`2023-05-15 ยท 9 ๐ ยท 2 ๐ ยท 80 ๐ ยท 290 ๐ ยท 56 ๐ฉโ๐ป๐จโ๐ป`
diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md
new file mode 100644
index 000000000000..20542d3f6726
--- /dev/null
+++ b/apps/meteor/CHANGELOG.md
@@ -0,0 +1,26 @@
+# @rocket.chat/meteor
+
+## 6.2.6
+
+### Patch Changes
+
+- [#29545](https://github.com/RocketChat/Rocket.Chat/pull/29545) [`8ade880306`](https://github.com/RocketChat/Rocket.Chat/commit/8ade880306a2f4be6fb979c9db32a1ca5bdf4c1f) Thanks [@github-actions](https://github.com/apps/github-actions)! - fix: Frontend crash if IndexedDB is not available, i.e. in Firefox private mode
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/rest-typings@6.2.6
+ - @rocket.chat/omnichannel-services@0.0.2
+ - @rocket.chat/pdf-worker@0.0.2
+ - @rocket.chat/presence@0.0.2
+ - @rocket.chat/api-client@0.0.2
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/gazzodown@0.0.1
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/ui-contexts@0.0.2
+ - @rocket.chat/models@0.0.2
+ - @rocket.chat/ui-theming@0.0.1
+ - @rocket.chat/fuselage-ui-kit@0.31.16
+ - @rocket.chat/ui-client@0.0.1
+ - @rocket.chat/ui-video-conf@0.0.1
+ - @rocket.chat/web-ui-registration@0.0.1
+ - @rocket.chat/instance-status@0.0.2
diff --git a/apps/meteor/app/emoji-emojione/client/emojione-sprites.css b/apps/meteor/app/emoji-emojione/client/emojione-sprites.css
index 2a480d6294b1..f6c4cf58512e 100644
--- a/apps/meteor/app/emoji-emojione/client/emojione-sprites.css
+++ b/apps/meteor/app/emoji-emojione/client/emojione-sprites.css
@@ -28,8 +28,3 @@
image-rendering: -webkit-optimize-contrast;
image-rendering: optimizeQuality;
}
-
-.big > .emojione {
- width: 44px;
- height: 44px;
-}
diff --git a/apps/meteor/app/emoji-emojione/lib/generateEmojiIndex.mjs b/apps/meteor/app/emoji-emojione/lib/generateEmojiIndex.mjs
index d300fd64c6c7..1361a72c0dd2 100644
--- a/apps/meteor/app/emoji-emojione/lib/generateEmojiIndex.mjs
+++ b/apps/meteor/app/emoji-emojione/lib/generateEmojiIndex.mjs
@@ -9,11 +9,11 @@ import _ from 'underscore';
import gm from 'gm'; // lgtm[js/unused-local-variable]
const assetFolder = '../../../node_modules/emojione-assets';
-const emojiJsonFile = `${ assetFolder }/emoji.json`;
+const emojiJsonFile = `${assetFolder}/emoji.json`;
if (!fs.existsSync(emojiJsonFile)) {
- console.error(`${ emojiJsonFile } doesn't exist.`);
- console.error('Maybe you need to run \'meteor npm install emojione-assets\' or \'meteor npm install\'?');
+ console.error(`${emojiJsonFile} doesn't exist.`);
+ console.error("Maybe you need to run 'meteor npm install emojione-assets' or 'meteor npm install'?");
} else {
const emojiJson = fs.readFileSync(emojiJsonFile);
generateEmojiPicker(emojiJson);
@@ -51,7 +51,6 @@ function generateEmojiPicker(data) {
* Mapping category hashes into human readable and translated names
*/\n\n`;
-
const emojiCategoriesMapping = [
{ key: 'people', i18n: 'Smileys_and_People' },
{ key: 'nature', i18n: 'Animals_and_Nature' },
@@ -66,11 +65,11 @@ function generateEmojiPicker(data) {
// emojiCategories
output += `export const emojiCategories = [\n`;
for (let category in emojisByCategory) {
- const map = emojiCategoriesMapping.find(o => o.key === category);
+ const map = emojiCategoriesMapping.find((o) => o.key === category);
if (map) {
output += `\t{ key: '${category}', i18n: '${map.i18n}' },\n`;
} else {
- if(category !== 'modifier' || category !== 'regional'){
+ if (category !== 'modifier' || category !== 'regional') {
console.error(`No emojiCategory mapping for ${category}`);
}
}
@@ -86,7 +85,6 @@ function generateEmojiPicker(data) {
} else {
output += `\t${toneList[tone]}: 1,\n`;
}
-
}
output += `};\n`;
@@ -96,16 +94,16 @@ function generateEmojiPicker(data) {
output += `\t${category}: [\n`;
for (let emoji in emojisByCategory[category]) {
- output += `\t\t'${emojiList[emojisByCategory[category][emoji]].shortname.replace(/:/g,'')}',\n`;
+ output += `\t\t'${emojiList[emojisByCategory[category][emoji]].shortname.replace(/:/g, '')}',\n`;
}
output += `\t],\n`;
}
output += `};\n`;
- fs.writeFileSync("emojiPicker.js", output, {
+ fs.writeFileSync('emojiPicker.js', output, {
encoding: 'utf8',
- flag: 'w'
+ flag: 'w',
});
console.log('Generated emojiPicker.js!');
@@ -116,41 +114,44 @@ function generateEmojiPicker(data) {
for (let category in emojisByCategory) {
let srcList = [];
let diversityList = [];
- const emojis = _.filter(emojiList, x => x.category === category);
- const spritePath = `../../../public/packages/emojione/${ category }-sprites.png`;
+ const emojis = _.filter(emojiList, (x) => x.category === category);
+ const spritePath = `../../../public/packages/emojione/${category}-sprites.png`;
_.each(emojis, function (emoji) {
- srcList.push(`${ assetFolder }/png/64/${ emoji.code_points.base }.png`);
- if(emoji.diversity){
+ srcList.push(`${assetFolder}/png/64/${emoji.code_points.base}.png`);
+ if (emoji.diversity) {
diversityList[emoji.code_points.base] = true;
}
});
- spriteCss += `@import './${ category }-sprites.css';\n`;
-
- nsg({
- src: srcList,
- spritePath: spritePath,
- layout: 'packed',
- stylesheet: 'emojione.tpl',
- stylesheetPath: `../client/${ category }-sprites.css`,
- compositor: 'gm',
- layoutOptions: {
- scaling: 1,
+ spriteCss += `@import './${category}-sprites.css';\n`;
+
+ nsg(
+ {
+ src: srcList,
+ spritePath: spritePath,
+ layout: 'packed',
+ stylesheet: 'emojione.tpl',
+ stylesheetPath: `../client/${category}-sprites.css`,
+ compositor: 'gm',
+ layoutOptions: {
+ scaling: 1,
+ },
+ stylesheetOptions: {
+ prefix: '',
+ diversityList: diversityList,
+ category: category,
+ spritePath: `/packages/emojione/${category}-sprites.png`,
+ pixelRatio: 1,
+ },
},
- stylesheetOptions: {
- prefix: '',
- diversityList: diversityList,
- category: category,
- spritePath: `/packages/emojione/${ category }-sprites.png`,
- pixelRatio: 1
- }
- }, function (err) {
- if (err) {
- console.error(err);
- return;
- }
- console.log(`${ category }'s sprite generated!`);
- });
+ function (err) {
+ if (err) {
+ console.error(err);
+ return;
+ }
+ console.log(`${category}'s sprite generated!`);
+ },
+ );
}
spriteCss += `
@@ -173,14 +174,9 @@ function generateEmojiPicker(data) {
image-rendering: -webkit-optimize-contrast;
image-rendering: optimizeQuality;
}
-
-.emojione.big {
- width: 44px;
- height: 44px;
-}
`;
- fs.writeFileSync("../client/emojione-sprites.css", spriteCss, {
+ fs.writeFileSync('../client/emojione-sprites.css', spriteCss, {
encoding: 'utf8',
- flag: 'w'
+ flag: 'w',
});
}
diff --git a/apps/meteor/app/lib/server/functions/addUserToRoom.ts b/apps/meteor/app/lib/server/functions/addUserToRoom.ts
index 341cb60a4322..62f2cf04dece 100644
--- a/apps/meteor/app/lib/server/functions/addUserToRoom.ts
+++ b/apps/meteor/app/lib/server/functions/addUserToRoom.ts
@@ -26,6 +26,11 @@ export const addUserToRoom = async function (
const userToBeAdded = typeof user !== 'string' ? user : await Users.findOneByUsername(user.replace('@', ''));
const roomDirectives = roomCoordinator.getRoomDirectives(room.t);
+
+ if (!userToBeAdded) {
+ throw new Meteor.Error('user-not-found');
+ }
+
if (
!(await roomDirectives.allowMemberAction(room, RoomMemberActions.JOIN, userToBeAdded._id)) &&
!(await roomDirectives.allowMemberAction(room, RoomMemberActions.INVITE, userToBeAdded._id))
@@ -39,6 +44,8 @@ export const addUserToRoom = async function (
throw new Meteor.Error((error as any)?.message);
}
+ await callbacks.run('beforeAddedToRoom', { user: userToBeAdded, inviter: userToBeAdded });
+
// Check if user is already in room
const subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, userToBeAdded._id);
if (subscription || !userToBeAdded) {
diff --git a/apps/meteor/app/lib/server/functions/createRoom.ts b/apps/meteor/app/lib/server/functions/createRoom.ts
index 318aa089e124..6d0048659501 100644
--- a/apps/meteor/app/lib/server/functions/createRoom.ts
+++ b/apps/meteor/app/lib/server/functions/createRoom.ts
@@ -144,7 +144,7 @@ export const createRoom = async (
} else {
for await (const username of [...new Set(members)]) {
const member = await Users.findOneByUsername(username, {
- projection: { 'username': 1, 'settings.preferences': 1, 'federated': 1 },
+ projection: { 'username': 1, 'settings.preferences': 1, 'federated': 1, 'roles': 1 },
});
if (!member) {
continue;
@@ -152,6 +152,7 @@ export const createRoom = async (
try {
await callbacks.run('federation.beforeAddUserToARoom', { user: member, inviter: owner }, room);
+ await callbacks.run('beforeAddedToRoom', { user: member, inviter: owner });
} catch (error) {
continue;
}
diff --git a/apps/meteor/app/livechat/server/lib/Helper.js b/apps/meteor/app/livechat/server/lib/Helper.js
index d4dac0d6acf7..98a03ce3001d 100644
--- a/apps/meteor/app/livechat/server/lib/Helper.js
+++ b/apps/meteor/app/livechat/server/lib/Helper.js
@@ -382,7 +382,6 @@ export const forwardRoomToAgent = async (room, transferData) => {
if (oldServedBy && servedBy._id !== oldServedBy._id) {
await RoutingManager.removeAllRoomSubscriptions(room, servedBy);
}
- await Message.saveSystemMessage('uj', rid, servedBy.username, servedBy);
setImmediate(() => {
Apps.triggerEvent(AppEvents.IPostLivechatRoomTransferred, {
@@ -505,7 +504,7 @@ export const forwardRoomToDepartment = async (room, guest, transferData) => {
await LivechatRooms.removeAgentByRoomId(rid);
await dispatchAgentDelegated(rid, null);
const newInquiry = await LivechatInquiry.findOneById(inquiry._id);
- await queueInquiry(room, newInquiry);
+ await queueInquiry(newInquiry);
logger.debug(`Inquiry ${inquiry._id} queued succesfully`);
}
diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.js b/apps/meteor/app/livechat/server/lib/QueueManager.js
index fe44d023ebb7..644c8833cd6c 100644
--- a/apps/meteor/app/livechat/server/lib/QueueManager.js
+++ b/apps/meteor/app/livechat/server/lib/QueueManager.js
@@ -14,7 +14,7 @@ export const saveQueueInquiry = async (inquiry) => {
await callbacks.run('livechat.afterInquiryQueued', inquiry);
};
-export const queueInquiry = async (room, inquiry, defaultAgent) => {
+export const queueInquiry = async (inquiry, defaultAgent) => {
const inquiryAgent = await RoutingManager.delegateAgent(defaultAgent, inquiry);
logger.debug(`Delegating inquiry with id ${inquiry._id} to agent ${defaultAgent?.username}`);
@@ -70,7 +70,7 @@ export const QueueManager = {
await LivechatRooms.updateRoomCount();
- await queueInquiry(room, inquiry, agent);
+ await queueInquiry(inquiry, agent);
logger.debug(`Inquiry ${inquiry._id} queued`);
const newRoom = await LivechatRooms.findOneById(rid);
@@ -126,7 +126,7 @@ export const QueueManager = {
const inquiry = await LivechatInquiry.findOneById(await createLivechatInquiry({ rid, name, guest, message, extraData: { source } }));
logger.debug(`Generated inquiry for visitor ${v._id} with id ${inquiry._id} [Not queued]`);
- await queueInquiry(room, inquiry, defaultAgent);
+ await queueInquiry(inquiry, defaultAgent);
logger.debug(`Inquiry ${inquiry._id} queued`);
return room;
diff --git a/apps/meteor/app/livechat/server/lib/RoutingManager.js b/apps/meteor/app/livechat/server/lib/RoutingManager.js
index 17bb2e9f1561..1419ac73868d 100644
--- a/apps/meteor/app/livechat/server/lib/RoutingManager.js
+++ b/apps/meteor/app/livechat/server/lib/RoutingManager.js
@@ -106,7 +106,7 @@ export const RoutingManager = {
const user = await Users.findOneById(agent.agentId);
const room = await LivechatRooms.findOneById(rid);
- await Message.saveSystemMessage('command', rid, 'connected', user);
+ await Promise.all([Message.saveSystemMessage('command', rid, 'connected', user), Message.saveSystemMessage('uj', rid, '', user)]);
await dispatchAgentDelegated(rid, agent.agentId);
logger.debug(`Agent ${agent.agentId} assigned to inquriy ${inquiry._id}. Instances notified`);
@@ -176,7 +176,7 @@ export const RoutingManager = {
return room;
}
- if (room.servedBy && room.servedBy._id === agent.agentId && !room.onHold) {
+ if (room.servedBy && room.servedBy._id === agent.agentId) {
logger.debug(`Cannot take Inquiry ${inquiry._id}: Already taken by agent ${room.servedBy._id}`);
return room;
}
diff --git a/apps/meteor/app/theme/client/imports/components/emoji.css b/apps/meteor/app/theme/client/imports/components/emoji.css
index f7c641be4379..4d7f19f4acb6 100644
--- a/apps/meteor/app/theme/client/imports/components/emoji.css
+++ b/apps/meteor/app/theme/client/imports/components/emoji.css
@@ -20,8 +20,3 @@
line-height: normal;
image-rendering: auto;
}
-
-.emoji.big {
- width: 44px;
- height: 44px;
-}
diff --git a/apps/meteor/app/ui-message/client/actionButtons/messageBox.ts b/apps/meteor/app/ui-message/client/actionButtons/messageBox.ts
index 8bc1c4924bc1..828c6bcaf577 100644
--- a/apps/meteor/app/ui-message/client/actionButtons/messageBox.ts
+++ b/apps/meteor/app/ui-message/client/actionButtons/messageBox.ts
@@ -28,12 +28,13 @@ export const onAdded = (button: IUIActionButton): void =>
),
);
},
- action() {
+ action(params) {
void triggerActionButtonAction({
- rid: RoomManager.opened,
+ rid: params.rid,
+ tmid: params.tmid,
actionId: button.actionId,
appId: button.appId,
- payload: { context: button.context },
+ payload: { context: button.context, message: params.chat.composer?.text },
});
},
});
diff --git a/apps/meteor/app/ui-utils/client/lib/messageBox.ts b/apps/meteor/app/ui-utils/client/lib/messageBox.ts
index daad27f622e8..e5cd105741de 100644
--- a/apps/meteor/app/ui-utils/client/lib/messageBox.ts
+++ b/apps/meteor/app/ui-utils/client/lib/messageBox.ts
@@ -1,20 +1,13 @@
import type { IMessage, IRoom } from '@rocket.chat/core-typings';
-import type { ContextType } from 'react';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
-import type { ChatContext } from '../../../../client/views/room/contexts/ChatContext';
+import type { ChatAPI } from '../../../../client/lib/chats/ChatAPI';
type MessageBoxAction = {
label: TranslationKey;
id: string;
icon?: string;
- action: (params: {
- rid: IRoom['_id'];
- tmid?: IMessage['_id'];
- event: Event;
- messageBox: HTMLElement;
- chat: ContextType;
- }) => void;
+ action: (params: { rid: IRoom['_id']; tmid?: IMessage['_id']; event: Event; chat: ChatAPI }) => void;
condition?: () => boolean;
};
diff --git a/apps/meteor/client/components/GenericTable/hooks/usePagination.ts b/apps/meteor/client/components/GenericTable/hooks/usePagination.ts
index 31276fd57ce2..803752fda45e 100644
--- a/apps/meteor/client/components/GenericTable/hooks/usePagination.ts
+++ b/apps/meteor/client/components/GenericTable/hooks/usePagination.ts
@@ -1,4 +1,4 @@
-import { useMemo } from 'react';
+import { useEffect, useMemo } from 'react';
import { useCurrent } from './useCurrent';
import { useItemsPerPage } from './useItemsPerPage';
@@ -18,6 +18,11 @@ export const usePagination = (): {
const itemsPerPageLabel = useItemsPerPageLabel();
const showingResultsLabel = useShowingResultsLabel();
+ // Reset to first page when itemsPerPage changes
+ useEffect(() => {
+ setCurrent(0);
+ }, [itemsPerPage, setCurrent]);
+
return useMemo(
() => ({
itemsPerPage,
diff --git a/apps/meteor/client/components/message/MessageContentBody.tsx b/apps/meteor/client/components/message/MessageContentBody.tsx
index 8bfae4082d09..4674528a483f 100644
--- a/apps/meteor/client/components/message/MessageContentBody.tsx
+++ b/apps/meteor/client/components/message/MessageContentBody.tsx
@@ -1,7 +1,7 @@
import { css } from '@rocket.chat/css-in-js';
-import { MessageBody, Box, Palette } from '@rocket.chat/fuselage';
+import { MessageBody, Box, Palette, Skeleton } from '@rocket.chat/fuselage';
import { Markup } from '@rocket.chat/gazzodown';
-import React from 'react';
+import React, { Suspense } from 'react';
import type { MessageWithMdEnforced } from '../../lib/parseMessageTextToAstMarkdown';
import GazzodownText from '../GazzodownText';
@@ -55,9 +55,11 @@ const MessageContentBody = ({ mentions, channels, md, searchText }: MessageConte
return (
-
-
-
+ }>
+
+
+
+
);
diff --git a/apps/meteor/client/sidebar/search/SearchList.tsx b/apps/meteor/client/sidebar/search/SearchList.tsx
index e48c52e0b68f..300365f36449 100644
--- a/apps/meteor/client/sidebar/search/SearchList.tsx
+++ b/apps/meteor/client/sidebar/search/SearchList.tsx
@@ -101,7 +101,7 @@ const useSearchItems = (filterText: string): UseQueryResult<(ISubscription & IRo
const getSpotlight = useMethod('spotlight');
return useQuery(
- ['sidebar/search/spotlight', name, usernamesFromClient, type],
+ ['sidebar/search/spotlight', name, usernamesFromClient, type, localRooms.map(({ _id }) => _id)],
async () => {
if (localRooms.length === LIMIT) {
return localRooms;
diff --git a/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/DepartmentAgentsTable.tsx b/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/DepartmentAgentsTable.tsx
index 2f2f8d39e995..c4e4c7acb7c6 100644
--- a/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/DepartmentAgentsTable.tsx
+++ b/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/DepartmentAgentsTable.tsx
@@ -1,9 +1,11 @@
+import { Pagination } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
-import React from 'react';
+import React, { useMemo } from 'react';
import type { Control, UseFormRegister } from 'react-hook-form';
import { useWatch, useFieldArray } from 'react-hook-form';
import { GenericTable, GenericTableBody, GenericTableHeader, GenericTableHeaderCell } from '../../../../components/GenericTable';
+import { usePagination } from '../../../../components/GenericTable/hooks/usePagination';
import type { FormValues } from '../EditDepartment';
import AddAgent from './AddAgent';
import AgentRow from './AgentRow';
@@ -18,6 +20,9 @@ function DepartmentAgentsTable({ control, register }: DepartmentAgentsTableProps
const { fields, append, remove } = useFieldArray({ control, name: 'agentList' });
const agentList = useWatch({ control, name: 'agentList' });
+ const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination();
+ const page = useMemo(() => fields.slice(current, current + itemsPerPage), [current, fields, itemsPerPage]);
+
return (
<>
@@ -31,11 +36,21 @@ function DepartmentAgentsTable({ control, register }: DepartmentAgentsTableProps
- {fields.map((agent, index) => (
+ {page.map((agent, index) => (
remove(index)} />
))}
+
+
>
);
}
diff --git a/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx b/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx
index b9c701cc4428..cf43ff90d163 100644
--- a/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx
+++ b/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx
@@ -5,12 +5,12 @@ import { useSetting, useRolesDescription } from '@rocket.chat/ui-contexts';
import type { ReactElement, UIEvent } from 'react';
import React, { useMemo, useRef } from 'react';
+import { getUserDisplayName } from '../../../../lib/getUserDisplayName';
import { Backdrop } from '../../../components/Backdrop';
import LocalTime from '../../../components/LocalTime';
import UserCard from '../../../components/UserCard';
import { ReactiveUserStatus } from '../../../components/UserStatus';
-import { AsyncStatePhase } from '../../../hooks/useAsyncState';
-import { useEndpointData } from '../../../hooks/useEndpointData';
+import { useUserInfoQuery } from '../../../hooks/useUserInfoQuery';
import { useActionSpread } from '../../hooks/useActionSpread';
import { useUserInfoActions } from '../hooks/useUserInfoActions';
@@ -25,21 +25,18 @@ type UserCardWithDataProps = {
const UserCardWithData = ({ username, target, rid, open, onClose }: UserCardWithDataProps): ReactElement => {
const ref = useRef(target);
const getRoles = useRolesDescription();
- const showRealNames = useSetting('UI_Use_Real_Name');
+ const showRealNames = Boolean(useSetting('UI_Use_Real_Name'));
- const query = useMemo(() => ({ username }), [username]);
- const { value: data, phase: state } = useEndpointData('/v1/users.info', { params: query });
+ const { data, isLoading } = useUserInfoQuery({ username });
ref.current = target;
- const isLoading = state === AsyncStatePhase.LOADING;
-
const user = useMemo(() => {
const defaultValue = isLoading ? undefined : null;
const {
_id,
- name = username,
+ name,
roles = defaultValue,
statusText = defaultValue,
bio = defaultValue,
@@ -50,7 +47,7 @@ const UserCardWithData = ({ username, target, rid, open, onClose }: UserCardWith
return {
_id,
- name: showRealNames ? name : username,
+ name: getUserDisplayName(name, username, showRealNames),
username,
roles: roles && getRoles(roles).map((role, index) => {role}),
bio,
diff --git a/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/hooks/useResumeChatOnHoldMutation.ts b/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/hooks/useResumeChatOnHoldMutation.ts
index 33160291e26f..9992be969758 100644
--- a/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/hooks/useResumeChatOnHoldMutation.ts
+++ b/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/hooks/useResumeChatOnHoldMutation.ts
@@ -1,18 +1,20 @@
import type { IRoom } from '@rocket.chat/core-typings';
-import { useMethod } from '@rocket.chat/ui-contexts';
+import { useEndpoint, useToastMessageDispatch } from '@rocket.chat/ui-contexts';
import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
import { useMutation, useQueryClient } from '@tanstack/react-query';
export const useResumeChatOnHoldMutation = (
options?: Omit, 'mutationFn'>,
): UseMutationResult => {
- const resumeChatOnHold = useMethod('livechat:resumeOnHold');
+ const resumeChatOnHold = useEndpoint('POST', '/v1/livechat/room.resumeOnHold');
+
+ const dispatchToastMessage = useToastMessageDispatch();
const queryClient = useQueryClient();
return useMutation(
- async (rid) => {
- await resumeChatOnHold(rid, { clientAction: true });
+ async (roomId) => {
+ await resumeChatOnHold({ roomId });
},
{
...options,
@@ -22,6 +24,9 @@ export const useResumeChatOnHoldMutation = (
await queryClient.invalidateQueries(['subscriptions', { rid }]);
return options?.onSuccess?.(data, rid, context);
},
+ onError: (error) => {
+ dispatchToastMessage({ type: 'error', message: error });
+ },
},
);
};
diff --git a/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/ActionsToolbarDropdown.tsx b/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/ActionsToolbarDropdown.tsx
index e0b26f190757..406160124696 100644
--- a/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/ActionsToolbarDropdown.tsx
+++ b/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/ActionsToolbarDropdown.tsx
@@ -7,6 +7,7 @@ import React, { useRef, Fragment } from 'react';
import { messageBox } from '../../../../../../../../app/ui-utils/client';
import type { ChatAPI } from '../../../../../../../lib/chats/ChatAPI';
import { useDropdownVisibility } from '../../../../../../../sidebar/header/hooks/useDropdownVisibility';
+import { useChat } from '../../../../../contexts/ChatContext';
import CreateDiscussionAction from './actions/CreateDiscussionAction';
import ShareLocationAction from './actions/ShareLocationAction';
import WebdavAction from './actions/WebdavAction';
@@ -19,7 +20,13 @@ type ActionsToolbarDropdownProps = {
actions?: ReactNode[];
};
-const ActionsToolbarDropdown = ({ chatContext, isRecording, rid, tmid, actions, ...props }: ActionsToolbarDropdownProps) => {
+const ActionsToolbarDropdown = ({ isRecording, rid, tmid, actions, ...props }: ActionsToolbarDropdownProps) => {
+ const chatContext = useChat();
+
+ if (!chatContext) {
+ throw new Error('useChat must be used within a ChatProvider');
+ }
+
const t = useTranslation();
const reference = useRef(null);
const target = useRef(null);
@@ -66,7 +73,17 @@ const ActionsToolbarDropdown = ({ chatContext, isRecording, rid, tmid, actions,
{actionGroup.title}
{actionGroup.items.map((item) => (
-
diff --git a/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts
index 9a4ff6f2490f..51f424697a82 100644
--- a/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts
+++ b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts
@@ -82,8 +82,9 @@ export const useThreadMainMessageQuery = (
useEffect(() => {
return () => {
unsubscribeRef.current?.();
+ unsubscribeRef.current = undefined;
};
- }, []);
+ }, [tmid]);
return useQuery(
['rooms', room._id, 'threads', tmid, 'main-message'] as const,
@@ -96,17 +97,17 @@ export const useThreadMainMessageQuery = (
throw new Error('Invalid main message');
}
- unsubscribeRef.current?.();
-
- unsubscribeRef.current = subscribeToMessage(mainMessage, {
- onMutate: () => {
- queryClient.invalidateQueries(queryKey, { exact: true });
- },
- onDelete: () => {
- onDelete?.();
- queryClient.invalidateQueries(queryKey, { exact: true });
- },
- });
+ unsubscribeRef.current =
+ unsubscribeRef.current ||
+ subscribeToMessage(mainMessage, {
+ onMutate: () => {
+ queryClient.invalidateQueries(queryKey, { exact: true });
+ },
+ onDelete: () => {
+ onDelete?.();
+ queryClient.invalidateQueries(queryKey, { exact: true });
+ },
+ });
return mainMessage;
},
diff --git a/apps/meteor/ee/app/license/server/license.ts b/apps/meteor/ee/app/license/server/license.ts
index f8cd98dd3245..21f0b3e7b61c 100644
--- a/apps/meteor/ee/app/license/server/license.ts
+++ b/apps/meteor/ee/app/license/server/license.ts
@@ -21,6 +21,7 @@ interface IValidLicense {
}
let maxGuestUsers = 0;
+let maxRoomsPerGuest = 0;
let maxActiveUsers = 0;
class LicenseClass {
@@ -192,6 +193,10 @@ class LicenseClass {
maxGuestUsers = license.maxGuestUsers;
}
+ if (license.maxRoomsPerGuest > maxRoomsPerGuest) {
+ maxRoomsPerGuest = license.maxRoomsPerGuest;
+ }
+
if (license.maxActiveUsers > maxActiveUsers) {
maxActiveUsers = license.maxActiveUsers;
}
@@ -323,6 +328,10 @@ export function getMaxGuestUsers(): number {
return maxGuestUsers;
}
+export function getMaxRoomsPerGuest(): number {
+ return maxRoomsPerGuest;
+}
+
export function getMaxActiveUsers(): number {
return maxActiveUsers;
}
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/rooms.ts b/apps/meteor/ee/app/livechat-enterprise/server/api/rooms.ts
index 663110670d3b..97ce66d4e395 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/api/rooms.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/api/rooms.ts
@@ -1,56 +1,77 @@
-import { Meteor } from 'meteor/meteor';
-import { isPOSTLivechatRoomPriorityParams } from '@rocket.chat/rest-typings';
+import { isLivechatRoomOnHoldProps, isLivechatRoomResumeOnHoldProps, isPOSTLivechatRoomPriorityParams } from '@rocket.chat/rest-typings';
import { LivechatRooms, Subscriptions } from '@rocket.chat/models';
+import type { IOmnichannelRoom } from '@rocket.chat/core-typings';
+import { OmnichannelEEService } from '@rocket.chat/core-services';
import { API } from '../../../../../app/api/server';
import { hasPermissionAsync } from '../../../../../app/authorization/server/functions/hasPermission';
-import { LivechatEnterprise } from '../lib/LivechatEnterprise';
import { removePriorityFromRoom, updateRoomPriority } from './lib/priorities';
import { i18n } from '../../../../../server/lib/i18n';
API.v1.addRoute(
'livechat/room.onHold',
- { authRequired: true, permissionsRequired: ['on-hold-livechat-room'] },
+ { authRequired: true, permissionsRequired: ['on-hold-livechat-room'], validateParams: isLivechatRoomOnHoldProps },
{
async post() {
const { roomId } = this.bodyParams;
- if (!roomId || roomId.trim() === '') {
- return API.v1.failure('Invalid room Id');
- }
- const room = await LivechatRooms.findOneById(roomId);
- if (!room || room.t !== 'l') {
- return API.v1.failure('Invalid room Id');
- }
+ type Room = Pick;
- if (room.lastMessage?.token) {
- return API.v1.failure('You cannot place chat on-hold, when the Contact has sent the last message');
+ const room = await LivechatRooms.findOneById(roomId, {
+ projection: { _id: 1, t: 1, open: 1, onHold: 1, lastMessage: 1, servedBy: 1 },
+ });
+ if (!room) {
+ throw new Error('error-invalid-room');
}
- if (room.onHold) {
- return API.v1.failure('Room is already On-Hold');
+ const subscription = await Subscriptions.findOneByRoomIdAndUserId(roomId, this.userId, { projection: { _id: 1 } });
+ if (!subscription && !(await hasPermissionAsync(this.userId, 'on-hold-others-livechat-room'))) {
+ throw new Error('Not_authorized');
}
- if (!room.open) {
- return API.v1.failure('Room cannot be placed on hold after being closed');
+ const onHoldBy = { _id: this.userId, username: this.user.username, name: this.user.name };
+ const comment = i18n.t('Omnichannel_On_Hold_manually', {
+ user: onHoldBy.name || `@${onHoldBy.username}`,
+ });
+
+ await OmnichannelEEService.placeRoomOnHold(room, comment, this.user);
+
+ return API.v1.success();
+ },
+ },
+);
+
+API.v1.addRoute(
+ 'livechat/room.resumeOnHold',
+ { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLivechatRoomResumeOnHoldProps },
+ {
+ async post() {
+ const { roomId } = this.bodyParams;
+ if (!roomId || roomId.trim() === '') {
+ throw new Error('invalid-param');
}
- const user = await Meteor.userAsync();
- if (!user) {
- return API.v1.failure('Invalid user');
+ type Room = Pick;
+
+ const room = await LivechatRooms.findOneById(roomId, {
+ projection: { t: 1, open: 1, onHold: 1, servedBy: 1 },
+ });
+ if (!room) {
+ throw new Error('error-invalid-room');
}
- const subscription = await Subscriptions.findOneByRoomIdAndUserId(roomId, user._id, { projection: { _id: 1 } });
+ const subscription = await Subscriptions.findOneByRoomIdAndUserId(roomId, this.userId, { projection: { _id: 1 } });
if (!subscription && !(await hasPermissionAsync(this.userId, 'on-hold-others-livechat-room'))) {
- return API.v1.failure('Not authorized');
+ throw new Error('Not_authorized');
}
- const onHoldBy = { _id: user._id, username: user.username, name: (user as any).name };
+ const { name, username, _id: userId } = this.user;
+ const onHoldBy = { _id: userId, username, name };
const comment = i18n.t('Omnichannel_On_Hold_manually', {
user: onHoldBy.name || `@${onHoldBy.username}`,
});
- await LivechatEnterprise.placeRoomOnHold(room, comment, onHoldBy);
+ await OmnichannelEEService.resumeRoomOnHold(room, comment, this.user, true);
return API.v1.success();
},
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHold.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHold.ts
index bb8f45b2c65e..99c563bbdb24 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHold.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHold.ts
@@ -1,3 +1,5 @@
+import type { IOmnichannelRoom } from '@rocket.chat/core-typings';
+
import { callbacks } from '../../../../../lib/callbacks';
import { settings } from '../../../../../app/settings/server';
import { AutoCloseOnHoldScheduler } from '../lib/AutoCloseOnHoldScheduler';
@@ -6,7 +8,7 @@ import { i18n } from '../../../../../server/lib/i18n';
let autoCloseOnHoldChatTimeout = 0;
-const handleAfterOnHold = async (room: any = {}): Promise => {
+const handleAfterOnHold = async (room: Pick): Promise => {
const { _id: rid } = room;
if (!rid) {
cbLogger.debug('Skipping callback. No room provided');
@@ -24,7 +26,7 @@ const handleAfterOnHold = async (room: any = {}): Promise => {
i18n.t('Closed_automatically_because_chat_was_onhold_for_seconds', {
onHoldTime: autoCloseOnHoldChatTimeout,
});
- await AutoCloseOnHoldScheduler.scheduleRoom(room._id, autoCloseOnHoldChatTimeout, closeComment);
+ await AutoCloseOnHoldScheduler.scheduleRoom(rid, autoCloseOnHoldChatTimeout, closeComment);
};
settings.watch('Livechat_auto_close_on_hold_chats_timeout', (value) => {
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHoldChatResumed.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHoldChatResumed.ts
index b4e9b185a559..c631656a2a07 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHoldChatResumed.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHoldChatResumed.ts
@@ -1,20 +1,28 @@
+import type { IOmnichannelRoom } from '@rocket.chat/core-typings';
+
import { callbacks } from '../../../../../lib/callbacks';
-import { LivechatEnterprise } from '../lib/LivechatEnterprise';
+import { AutoCloseOnHoldScheduler } from '../lib/AutoCloseOnHoldScheduler';
import { cbLogger } from '../lib/logger';
-const handleAfterOnHoldChatResumed = async (room: any): Promise => {
- if (!room?._id || !room.onHold) {
- cbLogger.debug('Skipping callback. No room provided or room is not on hold');
- return;
+type IRoom = Pick;
+
+const handleAfterOnHoldChatResumed = async (room: IRoom): Promise => {
+ if (!room?._id) {
+ cbLogger.debug('Skipping callback. No room provided');
+ return room;
}
- cbLogger.debug(`Removing current on hold timers for room ${room._id}`);
- void LivechatEnterprise.releaseOnHoldChat(room);
+ const { _id: roomId } = room;
+
+ cbLogger.debug(`Removing current on hold timers for room ${roomId}`);
+ await AutoCloseOnHoldScheduler.unscheduleRoom(roomId);
+
+ return room;
};
callbacks.add(
'livechat:afterOnHoldChatResumed',
- (room) => handleAfterOnHoldChatResumed(room),
+ handleAfterOnHoldChatResumed,
callbacks.priority.HIGH,
'livechat-after-on-hold-chat-resumed',
);
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/onAgentAssignmentFailed.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/onAgentAssignmentFailed.ts
index 5ee6d446a449..18131d9b60d3 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/onAgentAssignmentFailed.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/onAgentAssignmentFailed.ts
@@ -1,10 +1,6 @@
-import { Subscriptions, LivechatInquiry, LivechatRooms } from '@rocket.chat/models';
-
import { callbacks } from '../../../../../lib/callbacks';
-import { queueInquiry } from '../../../../../app/livechat/server/lib/QueueManager';
import { settings } from '../../../../../app/settings/server';
import { cbLogger } from '../lib/logger';
-import { dispatchAgentDelegated } from '../../../../../app/livechat/server/lib/Helper';
const handleOnAgentAssignmentFailed = async ({
inquiry,
@@ -23,24 +19,6 @@ const handleOnAgentAssignmentFailed = async ({
return;
}
- if (room.onHold) {
- cbLogger.debug('Room is on hold. Removing current assignations before queueing again');
- const { _id: roomId } = room;
-
- const { _id: inquiryId } = inquiry;
- await LivechatInquiry.queueInquiryAndRemoveDefaultAgent(inquiryId);
- await LivechatRooms.removeAgentByRoomId(roomId);
- await Subscriptions.removeByRoomId(roomId);
- await dispatchAgentDelegated(roomId, null);
-
- const newInquiry = await LivechatInquiry.findOneById(inquiryId);
-
- await queueInquiry(room, newInquiry);
-
- cbLogger.debug('Room queued successfully');
- return;
- }
-
if (!settings.get('Livechat_waiting_queue')) {
cbLogger.debug('Skipping callback. Queue disabled by setting');
return;
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/onCloseLivechat.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/onCloseLivechat.ts
index e80445e1c057..59d96b3fac1b 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/onCloseLivechat.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/onCloseLivechat.ts
@@ -1,24 +1,46 @@
+import type { IOmnichannelRoom } from '@rocket.chat/core-typings';
+import { LivechatRooms, Subscriptions } from '@rocket.chat/models';
+
import { callbacks } from '../../../../../lib/callbacks';
import { settings } from '../../../../../app/settings/server';
import { debouncedDispatchWaitingQueueStatus } from '../lib/Helper';
-import { LivechatEnterprise } from '../lib/LivechatEnterprise';
+import { callbackLogger } from '../../../../../app/livechat/server/lib/callbackLogger';
+import { AutoCloseOnHoldScheduler } from '../lib/AutoCloseOnHoldScheduler';
-callbacks.add(
- 'livechat.closeRoom',
- async (params) => {
- const { room } = params;
+type LivechatCloseCallbackParams = {
+ room: IOmnichannelRoom;
+};
- await LivechatEnterprise.releaseOnHoldChat(room);
+const onCloseLivechat = async (params: LivechatCloseCallbackParams) => {
+ const {
+ room,
+ room: { _id: roomId },
+ } = params;
- if (!settings.get('Livechat_waiting_queue')) {
- return params;
- }
+ callbackLogger.debug(`[onCloseLivechat] clearing onHold related data for room ${roomId}`);
- const { departmentId } = room || {};
- debouncedDispatchWaitingQueueStatus(departmentId);
+ await Promise.all([
+ LivechatRooms.unsetOnHoldByRoomId(roomId),
+ Subscriptions.unsetOnHoldByRoomId(roomId),
+ AutoCloseOnHoldScheduler.unscheduleRoom(roomId),
+ ]);
+ callbackLogger.debug(`[onCloseLivechat] clearing onHold related data for room ${roomId} completed`);
+
+ if (!settings.get('Livechat_waiting_queue')) {
return params;
- },
+ }
+
+ const { departmentId } = room || {};
+ callbackLogger.debug(`[onCloseLivechat] dispatching waiting queue status for department ${departmentId}`);
+ debouncedDispatchWaitingQueueStatus(departmentId);
+
+ return params;
+};
+
+callbacks.add(
+ 'livechat.closeRoom',
+ (params: LivechatCloseCallbackParams) => onCloseLivechat(params),
callbacks.priority.HIGH,
'livechat-waiting-queue-monitor-close-room',
);
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.ts
index 9bb92947b151..8682f03852b1 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.ts
@@ -1,46 +1,68 @@
-import { Meteor } from 'meteor/meteor';
-import { isOmnichannelRoom, isEditedMessage } from '@rocket.chat/core-typings';
-import { LivechatRooms } from '@rocket.chat/models';
+import type { ILivechatVisitor, IMessage, IOmnichannelRoom, IRoom, IUser } from '@rocket.chat/core-typings';
+import { isEditedMessage, isOmnichannelRoom } from '@rocket.chat/core-typings';
+import { LivechatRooms, LivechatVisitors, Users } from '@rocket.chat/models';
+import { OmnichannelEEService } from '@rocket.chat/core-services';
import { callbacks } from '../../../../../lib/callbacks';
+import { callbackLogger } from '../../../../../app/livechat/server/lib/callbackLogger';
+import { i18n } from '../../../../../server/lib/i18n';
-callbacks.add(
- 'afterSaveMessage',
- async (message, roomParams) => {
- // skips this callback if the message was edited
- if (isEditedMessage(message)) {
- return message;
- }
+const resumeOnHoldCommentAndUser = async (room: IOmnichannelRoom): Promise<{ comment: string; resumedBy: IUser }> => {
+ const {
+ v: { _id: visitorId },
+ _id: rid,
+ } = room;
+ const visitor = await LivechatVisitors.findOneById>(visitorId, {
+ projection: { name: 1, username: 1 },
+ });
+ if (!visitor) {
+ callbackLogger.error(`[afterSaveMessage] Visitor Not found for room ${rid} while trying to resume on hold`);
+ throw new Error('Visitor not found while trying to resume on hold');
+ }
- // if the message has a type means it is a special message (like the closing comment), so skips
- if (message.t) {
- return message;
- }
+ const guest = visitor.name || visitor.username;
- if (!isOmnichannelRoom(roomParams)) {
- return message;
- }
+ const resumeChatComment = i18n.t('Omnichannel_on_hold_chat_automatically', { guest });
- const { _id: rid, t: roomType, v: roomVisitor } = roomParams;
+ const resumedBy = await Users.findOneById('rocket.cat');
+ if (!resumedBy) {
+ callbackLogger.error(`[afterSaveMessage] User Not found for room ${rid} while trying to resume on hold`);
+ throw new Error(`User not found while trying to resume on hold`);
+ }
- // message valid only if it is a livechat room
- if (!(typeof roomType !== 'undefined' && roomType === 'l' && roomVisitor && roomVisitor.token)) {
- return message;
- }
+ return { comment: resumeChatComment, resumedBy };
+};
+
+const handleAfterSaveMessage = async (message: IMessage, room: IRoom) => {
+ if (isEditedMessage(message) || message.t || !isOmnichannelRoom(room)) {
+ return message;
+ }
+
+ const { _id: rid, v: roomVisitor } = room;
- // Need to read the room every time, the room object is not updated
- const room = await LivechatRooms.findOneById(rid, { projection: { t: 1, v: 1, onHold: 1 } });
- if (!room) {
+ if (!roomVisitor?._id) {
+ return message;
+ }
+
+ // Need to read the room every time, the room object is not updated
+ const updatedRoom = await LivechatRooms.findOneById(rid);
+ if (!updatedRoom) {
+ return message;
+ }
+
+ if (message.token && room.onHold) {
+ callbackLogger.debug(`[afterSaveMessage] Room ${rid} is on hold, resuming it now since visitor sent a message`);
+
+ try {
+ const { comment: resumeChatComment, resumedBy } = await resumeOnHoldCommentAndUser(updatedRoom);
+ await OmnichannelEEService.resumeRoomOnHold(updatedRoom, resumeChatComment, resumedBy);
+ } catch (error) {
+ callbackLogger.error(`[afterSaveMessage] Error while resuming room ${rid} on hold: Error: `, error);
return message;
}
+ }
- // if a visitor sends a message in room which is On Hold
- if (message.token && room.onHold) {
- await Meteor.callAsync('livechat:resumeOnHold', rid, { clientAction: false });
- }
+ return message;
+};
- return message;
- },
- callbacks.priority.HIGH,
- 'livechat-resume-on-hold',
-);
+callbacks.add('afterSaveMessage', handleAfterSaveMessage, callbacks.priority.HIGH, 'livechat-resume-on-hold');
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts
index 831d8f3b29a6..a23e4686b438 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts
@@ -1,4 +1,5 @@
-import type { IMessage, IOmnichannelRoom } from '@rocket.chat/core-typings';
+import type { IMessage, IOmnichannelRoom, IRoom } from '@rocket.chat/core-typings';
+import { isOmnichannelRoom } from '@rocket.chat/core-typings';
import { LivechatRooms } from '@rocket.chat/models';
import { AutoTransferChatScheduler } from '../lib/AutoTransferChatScheduler';
@@ -16,7 +17,7 @@ let autoTransferTimeout = 0;
const handleAfterTakeInquiryCallback = async (inquiry: any = {}): Promise => {
const { rid } = inquiry;
- if (!rid || !rid.trim()) {
+ if (!rid?.trim()) {
cbLogger.debug('Skipping callback. Invalid room id');
return;
}
@@ -43,15 +44,25 @@ const handleAfterTakeInquiryCallback = async (inquiry: any = {}): Promise =
return inquiry;
};
-const handleAfterSaveMessage = async (message: any = {}, room: any = {}): Promise => {
- const { _id: rid, t, autoTransferredAt, autoTransferOngoing } = room;
- const { token } = message;
+const handleAfterSaveMessage = async (message: IMessage, room: IRoom | undefined): Promise => {
+ if (!room || !isOmnichannelRoom(room)) {
+ return message;
+ }
+
+ const { _id: rid, autoTransferredAt, autoTransferOngoing } = room;
+ const { token, t: messageType } = message;
+
+ if (messageType) {
+ // ignore system messages
+ return message;
+ }
if (!autoTransferTimeout || autoTransferTimeout <= 0) {
return message;
}
- if (!rid || !message || rid === '' || t !== 'l' || token) {
+ if (!message || token) {
+ // ignore messages from visitors
return message;
}
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/index.ts b/apps/meteor/ee/app/livechat-enterprise/server/index.ts
index 0cd5321b41fa..4233260aabc5 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/index.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/index.ts
@@ -17,7 +17,6 @@ import './hooks/checkAgentBeforeTakeInquiry';
import './hooks/handleNextAgentPreferredEvents';
import './hooks/onCheckRoomParamsApi';
import './hooks/onLoadConfigApi';
-import './hooks/onCloseLivechat';
import './hooks/onSaveVisitorInfo';
import './hooks/scheduleAutoTransfer';
import './hooks/resumeOnHold';
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts b/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts
index 975519e16a87..8434fcce07f0 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts
@@ -69,7 +69,7 @@ class AutoTransferChatSchedulerClass {
await this.scheduler.cancel({ name: jobName });
}
- private async transferRoom(roomId: string): Promise {
+ private async transferRoom(roomId: string): Promise {
this.logger.debug(`Transferring room ${roomId}`);
const room = await LivechatRooms.findOneById(roomId, {
_id: 1,
@@ -79,7 +79,7 @@ class AutoTransferChatSchedulerClass {
departmentId: 1,
});
if (!room?.open || !room?.servedBy?._id) {
- return false;
+ throw new Error('Room is not open or is not being served by an agent');
}
const {
@@ -91,37 +91,42 @@ class AutoTransferChatSchedulerClass {
if (!RoutingManager.getConfig().autoAssignAgent) {
this.logger.debug(`Auto-assign agent is disabled, returning room ${roomId} as inquiry`);
- return Livechat.returnRoomAsInquiry(room._id, departmentId, {
+
+ await Livechat.returnRoomAsInquiry(room._id, departmentId, {
scope: 'autoTransferUnansweredChatsToQueue',
comment: timeoutDuration,
transferredBy: await this.getSchedulerUser(),
});
+ return;
}
const agent = await RoutingManager.getNextAgent(departmentId, ignoreAgentId);
- if (agent) {
- this.logger.debug(`Transferring room ${roomId} to agent ${agent.agentId}`);
- return forwardRoomToAgent(room, {
- userId: agent.agentId,
- transferredBy: await this.getSchedulerUser(),
- transferredTo: agent,
- scope: 'autoTransferUnansweredChatsToAgent',
- comment: timeoutDuration,
- });
+ if (!agent) {
+ this.logger.error(`No agent found to transfer room ${room._id} which hasn't been answered in ${timeoutDuration} seconds`);
+ return;
}
- this.logger.debug(`No agent found to transfer room ${roomId}`);
- return false;
+ this.logger.debug(`Transferring room ${roomId} to agent ${agent.agentId}`);
+
+ await forwardRoomToAgent(room, {
+ userId: agent.agentId,
+ transferredBy: await this.getSchedulerUser(),
+ transferredTo: agent,
+ scope: 'autoTransferUnansweredChatsToAgent',
+ comment: timeoutDuration,
+ });
}
private async executeJob({ attrs: { data } }: any = {}): Promise {
const { roomId } = data;
- if (await this.transferRoom(roomId)) {
- await LivechatRooms.setAutoTransferredAtById(roomId);
- }
+ try {
+ await this.transferRoom(roomId);
- await this.unscheduleRoom(roomId);
+ await Promise.all([LivechatRooms.setAutoTransferredAtById(roomId), this.unscheduleRoom(roomId)]);
+ } catch (error) {
+ this.logger.error(`Error while executing job ${SCHEDULER_NAME} for room ${roomId}:`, error);
+ }
}
}
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/lib/LivechatEnterprise.ts b/apps/meteor/ee/app/livechat-enterprise/server/lib/LivechatEnterprise.ts
index 72534e72d021..15dd04e335eb 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/lib/LivechatEnterprise.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/lib/LivechatEnterprise.ts
@@ -3,17 +3,14 @@ import { Match, check } from 'meteor/check';
import {
LivechatInquiry,
Users,
- LivechatRooms,
LivechatDepartment as LivechatDepartmentRaw,
OmnichannelServiceLevelAgreements,
LivechatTag,
LivechatUnitMonitors,
LivechatUnit,
} from '@rocket.chat/models';
-import { Message } from '@rocket.chat/core-services';
import type {
IOmnichannelBusinessUnit,
- IOmnichannelRoom,
IOmnichannelServiceLevelAgreements,
LivechatDepartmentDTO,
InquiryWithAgentInfo,
@@ -27,9 +24,7 @@ import { processWaitingQueue, updateSLAInquiries } from './Helper';
import { removeSLAFromRooms } from './SlaHelper';
import { RoutingManager } from '../../../../../app/livechat/server/lib/RoutingManager';
import { settings } from '../../../../../app/settings/server';
-import { logger, queueLogger } from './logger';
-import { callbacks } from '../../../../../lib/callbacks';
-import { AutoCloseOnHoldScheduler } from './AutoCloseOnHoldScheduler';
+import { queueLogger } from './logger';
import { getInquirySortMechanismSetting } from '../../../../../app/livechat/server/lib/settings';
export const LivechatEnterprise = {
@@ -191,33 +186,6 @@ export const LivechatEnterprise = {
await removeSLAFromRooms(_id);
},
- async placeRoomOnHold(room: IOmnichannelRoom, comment: string, onHoldBy: { _id: string; username?: string; name?: string }) {
- logger.debug(`Attempting to place room ${room._id} on hold by user ${onHoldBy?._id}`);
- const { _id: roomId, onHold } = room;
- if (!roomId || onHold) {
- logger.debug(`Room ${roomId} invalid or already on hold. Skipping`);
- return false;
- }
- await LivechatRooms.setOnHoldByRoomId(roomId);
-
- await Message.saveSystemMessage('omnichannel_placed_chat_on_hold', roomId, '', onHoldBy, { comment });
-
- await callbacks.run('livechat:afterOnHold', room);
-
- logger.debug(`Room ${room._id} set on hold succesfully`);
- return true;
- },
-
- async releaseOnHoldChat(room: IOmnichannelRoom) {
- const { _id: roomId, onHold } = room;
- if (!roomId || !onHold) {
- return;
- }
-
- await AutoCloseOnHoldScheduler.unscheduleRoom(roomId);
- await LivechatRooms.unsetOnHoldAndPredictedVisitorAbandonmentByRoomId(roomId);
- },
-
/**
* @param {string|null} _id - The department id
* @param {Partial} departmentData
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts b/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts
index 376b0783f95b..845b52be2d16 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts
@@ -1,10 +1,10 @@
import type { IOmnichannelRoom, IUser } from '@rocket.chat/core-typings';
import { LivechatVisitors, LivechatRooms, LivechatDepartment, Users } from '@rocket.chat/models';
+import { OmnichannelEEService } from '@rocket.chat/core-services';
import { cronJobs } from '@rocket.chat/cron';
import { settings } from '../../../../../app/settings/server';
import { Livechat } from '../../../../../app/livechat/server/lib/LivechatTyped';
-import { LivechatEnterprise } from './LivechatEnterprise';
import { i18n } from '../../../../../server/lib/i18n';
import { callbacks } from '../../../../../lib/callbacks';
import { schedulerLogger } from './logger';
@@ -123,7 +123,7 @@ export class VisitorInactivityMonitor {
const comment = i18n.t('Omnichannel_On_Hold_due_to_inactivity', { guest, timeout });
const result = await Promise.allSettled([
- LivechatEnterprise.placeRoomOnHold(room, comment, this.user),
+ OmnichannelEEService.placeRoomOnHold(room, comment, this.user),
LivechatRooms.unsetPredictedVisitorAbandonmentByRoomId(room._id),
]);
this.logger.debug(`Room ${room._id} placed on hold`);
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts b/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts
index 7842dd8028fe..5a66cf219991 100644
--- a/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts
+++ b/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts
@@ -1,11 +1,13 @@
import { Meteor } from 'meteor/meteor';
-import type { ILivechatVisitor } from '@rocket.chat/core-typings';
+import type { ILivechatVisitor, IOmnichannelSystemMessage } from '@rocket.chat/core-typings';
+import { isOmnichannelRoom } from '@rocket.chat/core-typings';
import { LivechatVisitors, LivechatInquiry, LivechatRooms, Users } from '@rocket.chat/models';
-import { Message } from '@rocket.chat/core-services';
import type { ServerMethods } from '@rocket.chat/ui-contexts';
+import { Message } from '@rocket.chat/core-services';
import { RoutingManager } from '../../../../../app/livechat/server/lib/RoutingManager';
import { callbacks } from '../../../../../lib/callbacks';
+import { methodDeprecationLogger } from '../../../../../app/lib/server/lib/deprecationWarningLogger';
import { i18n } from '../../../../../server/lib/i18n';
async function resolveOnHoldCommentInfo(options: { clientAction: boolean }, room: any, onHoldChatResumedBy: any): Promise {
@@ -38,8 +40,12 @@ declare module '@rocket.chat/ui-contexts' {
Meteor.methods({
async 'livechat:resumeOnHold'(roomId, options = { clientAction: false }) {
+ methodDeprecationLogger.warn(
+ 'Method "livechat:resumeOnHold" is deprecated and will be removed in next major version. Please use "livechat/room.resumeOnHold" API instead.',
+ );
+
const room = await LivechatRooms.findOneById(roomId);
- if (!room || room.t !== 'l') {
+ if (!room || !isOmnichannelRoom(room)) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', {
method: 'livechat:resumeOnHold',
});
@@ -58,19 +64,30 @@ Meteor.methods({
});
}
- const { servedBy: { _id: agentId, username } = {} } = room;
+ if (!room.servedBy) {
+ throw new Meteor.Error('error-unserved-rooms-cannot-be-placed-onhold', 'Error! Un-served rooms cannot be placed OnHold', {
+ method: 'livechat:resumeOnHold',
+ });
+ }
+
+ const {
+ servedBy: { _id: agentId, username },
+ } = room;
await RoutingManager.takeInquiry(inquiry, { agentId, username }, options);
const onHoldChatResumedBy = options.clientAction ? await Meteor.userAsync() : await Users.findOneById('rocket.cat');
if (!onHoldChatResumedBy) {
- throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'livechat:resumeOnHold' });
+ throw new Meteor.Error('error-invalid-user', 'Invalid user', {
+ method: 'livechat:resumeOnHold',
+ });
}
const comment = await resolveOnHoldCommentInfo(options, room, onHoldChatResumedBy);
- await Message.saveSystemMessage('omnichannel_on_hold_chat_resumed', roomId, '', onHoldChatResumedBy, { comment });
+ await Message.saveSystemMessage('omnichannel_on_hold_chat_resumed', roomId, '', onHoldChatResumedBy, {
+ comment,
+ });
- const updatedRoom = await LivechatRooms.findOneById(roomId);
- updatedRoom && setImmediate(() => callbacks.run('livechat:afterOnHoldChatResumed', updatedRoom));
+ setImmediate(() => callbacks.run('livechat:afterOnHoldChatResumed', room));
},
});
diff --git a/apps/meteor/ee/app/livechat-enterprise/server/services/omnichannel.internalService.ts b/apps/meteor/ee/app/livechat-enterprise/server/services/omnichannel.internalService.ts
new file mode 100644
index 000000000000..2b099cd1aa9a
--- /dev/null
+++ b/apps/meteor/ee/app/livechat-enterprise/server/services/omnichannel.internalService.ts
@@ -0,0 +1,180 @@
+import { ServiceClassInternal, Message } from '@rocket.chat/core-services';
+import type { IOmnichannelEEService } from '@rocket.chat/core-services';
+import { isOmnichannelRoom } from '@rocket.chat/core-typings';
+import type { IOmnichannelRoom, IUser, ILivechatInquiryRecord, IOmnichannelSystemMessage } from '@rocket.chat/core-typings';
+import { LivechatRooms, Subscriptions, LivechatInquiry } from '@rocket.chat/models';
+
+import { Logger } from '../../../../../app/logger/server';
+import { callbacks } from '../../../../../lib/callbacks';
+import { RoutingManager } from '../../../../../app/livechat/server/lib/RoutingManager';
+import { dispatchAgentDelegated } from '../../../../../app/livechat/server/lib/Helper';
+import { queueInquiry } from '../../../../../app/livechat/server/lib/QueueManager';
+
+export class OmnichannelEE extends ServiceClassInternal implements IOmnichannelEEService {
+ protected name = 'omnichannel-ee';
+
+ protected internal = true;
+
+ logger: Logger;
+
+ constructor() {
+ super();
+ this.logger = new Logger('OmnichannelEE');
+ }
+
+ async placeRoomOnHold(
+ room: Pick,
+ comment: string,
+ onHoldBy: Pick,
+ ) {
+ this.logger.debug(`Attempting to place room ${room._id} on hold by user ${onHoldBy?._id}`);
+
+ const { _id: roomId } = room;
+
+ if (!room || !isOmnichannelRoom(room)) {
+ throw new Error('error-invalid-room');
+ }
+ if (!room.open) {
+ throw new Error('error-room-already-closed');
+ }
+ if (room.onHold) {
+ throw new Error('error-room-is-already-on-hold');
+ }
+ if (room.lastMessage?.token) {
+ throw new Error('error-contact-sent-last-message-so-cannot-place-on-hold');
+ }
+ if (!room.servedBy) {
+ throw new Error('error-unserved-rooms-cannot-be-placed-onhold');
+ }
+
+ await Promise.all([
+ LivechatRooms.setOnHoldByRoomId(roomId),
+ Subscriptions.setOnHoldByRoomId(roomId),
+ Message.saveSystemMessage('omnichannel_placed_chat_on_hold', roomId, '', onHoldBy, { comment }),
+ ]);
+
+ await callbacks.run('livechat:afterOnHold', room);
+
+ this.logger.debug(`Room ${room._id} set on hold successfully`);
+ }
+
+ async resumeRoomOnHold(
+ room: Pick,
+ comment: string,
+ resumeBy: Pick,
+ clientAction = false,
+ ) {
+ this.logger.debug(`Attempting to resume room ${room._id} on hold by user ${resumeBy?._id}`);
+
+ if (!room || !isOmnichannelRoom(room)) {
+ throw new Error('error-invalid-room');
+ }
+
+ if (!room.open) {
+ throw new Error('This_conversation_is_already_closed');
+ }
+
+ if (!room.onHold) {
+ throw new Error('error-room-not-on-hold');
+ }
+
+ const { _id: roomId, servedBy } = room;
+
+ if (!servedBy) {
+ this.logger.error(`No serving agent found for room ${roomId}`);
+ throw new Error('error-room-not-served');
+ }
+
+ const inquiry = await LivechatInquiry.findOneByRoomId(roomId, {});
+ if (!inquiry) {
+ this.logger.error(`No inquiry found for room ${roomId}`);
+ throw new Error('error-invalid-inquiry');
+ }
+
+ await this.attemptToAssignRoomToServingAgentElseQueueIt({
+ room,
+ inquiry,
+ servingAgent: servedBy,
+ clientAction,
+ });
+
+ await Promise.all([
+ LivechatRooms.unsetOnHoldByRoomId(roomId),
+ Subscriptions.unsetOnHoldByRoomId(roomId),
+ Message.saveSystemMessage('omnichannel_on_hold_chat_resumed', roomId, '', resumeBy, { comment }),
+ ]);
+
+ await callbacks.run('livechat:afterOnHoldChatResumed', room);
+
+ this.logger.debug(`Room ${room._id} resumed successfully`);
+ }
+
+ private async attemptToAssignRoomToServingAgentElseQueueIt({
+ room,
+ inquiry,
+ servingAgent,
+ clientAction,
+ }: {
+ room: Pick;
+ inquiry: ILivechatInquiryRecord;
+ servingAgent: NonNullable;
+ clientAction: boolean;
+ }) {
+ try {
+ const agent = {
+ agentId: servingAgent._id,
+ username: servingAgent.username,
+ };
+
+ await callbacks.run('livechat.checkAgentBeforeTakeInquiry', {
+ agent,
+ inquiry,
+ options: {},
+ });
+
+ return;
+ } catch (e) {
+ this.logger.debug(`Agent ${servingAgent._id} is not available to take the inquiry ${inquiry._id}`, e);
+ if (clientAction) {
+ // if the action was triggered by the client, we should throw the error
+ // so the client can handle it and show the error message to the user
+ throw e;
+ }
+ }
+
+ this.logger.debug(`Attempting to queue inquiry ${inquiry._id}`);
+
+ await this.removeCurrentAgentFromRoom({ room, inquiry });
+
+ const { _id: inquiryId } = inquiry;
+ const newInquiry = await LivechatInquiry.findOneById(inquiryId);
+
+ await queueInquiry(newInquiry);
+
+ this.logger.debug('Room queued successfully');
+ }
+
+ private async removeCurrentAgentFromRoom({
+ room,
+ inquiry,
+ }: {
+ room: Pick;
+ inquiry: ILivechatInquiryRecord;
+ }): Promise {
+ this.logger.debug(`Attempting to remove current agent from room ${room._id}`);
+
+ const { _id: roomId } = room;
+
+ const { _id: inquiryId } = inquiry;
+
+ await Promise.all([
+ LivechatRooms.removeAgentByRoomId(roomId),
+ LivechatInquiry.queueInquiryAndRemoveDefaultAgent(inquiryId),
+ RoutingManager.removeAllRoomSubscriptions(room),
+ ]);
+
+ await dispatchAgentDelegated(roomId, null);
+
+ this.logger.debug(`Current agent removed from room ${room._id} successfully`);
+ }
+}
diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx
index d5d79388e62d..b89dcee32315 100644
--- a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx
+++ b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx
@@ -38,13 +38,13 @@ const EngagementDashboardPage = ({ tab = 'users', onSelectTab }: EngagementDashb
-
+
{t('Users')}
-
+
{t('Messages')}
-
+
{t('Channels')}
diff --git a/apps/meteor/ee/server/apps/communication/rest.ts b/apps/meteor/ee/server/apps/communication/rest.ts
index 361865a95678..790e5a87a19d 100644
--- a/apps/meteor/ee/server/apps/communication/rest.ts
+++ b/apps/meteor/ee/server/apps/communication/rest.ts
@@ -799,7 +799,7 @@ export class AppsRestApi {
let result;
let statusCode;
try {
- const request = await fetch(`${baseUrl}/v1/apps/${this.urlParams.id}/versions`, { headers });
+ const request = await fetch(`${baseUrl}/v1/apps/${this.urlParams.id}`, { headers });
statusCode = request.status;
result = await request.json();
diff --git a/apps/meteor/ee/server/apps/communication/uikit.ts b/apps/meteor/ee/server/apps/communication/uikit.ts
index c2eb74713aae..5b760c842397 100644
--- a/apps/meteor/ee/server/apps/communication/uikit.ts
+++ b/apps/meteor/ee/server/apps/communication/uikit.ts
@@ -283,7 +283,7 @@ const appsRoutes =
triggerId,
rid,
mid,
- payload: { context },
+ payload: { context, message: msgText },
} = req.body;
const room = await orch.getConverters()?.get('rooms').convertById(rid);
@@ -300,6 +300,7 @@ const appsRoutes =
message,
payload: {
context,
+ ...(msgText && { message: msgText }),
},
};
diff --git a/apps/meteor/ee/server/lib/ldap/Manager.ts b/apps/meteor/ee/server/lib/ldap/Manager.ts
index dd107b5cf6dd..5a8a45c96a8f 100644
--- a/apps/meteor/ee/server/lib/ldap/Manager.ts
+++ b/apps/meteor/ee/server/lib/ldap/Manager.ts
@@ -254,7 +254,7 @@ export class LDAPEEManager extends LDAPManager {
const roomOwner = settings.get('LDAP_Sync_User_Data_Channels_Admin') || '';
// #ToDo: Remove typecastings when createRoom is converted to ts.
- const room = await createRoom('c', channel, roomOwner, [], false, {
+ const room = await createRoom('c', channel, roomOwner, [], false, false, {
customFields: { ldap: true },
} as any);
if (!room?.rid) {
diff --git a/apps/meteor/ee/server/lib/oauth/Manager.ts b/apps/meteor/ee/server/lib/oauth/Manager.ts
index 603490cbfe41..19dbc743595f 100644
--- a/apps/meteor/ee/server/lib/oauth/Manager.ts
+++ b/apps/meteor/ee/server/lib/oauth/Manager.ts
@@ -29,7 +29,7 @@ export class OAuthEEManager {
const name = await getValidRoomName(channel.trim(), undefined, { allowDuplicates: true });
let room = await Rooms.findOneByNonValidatedName(name);
if (!room) {
- const createdRoom = await createRoom('c', channel, channelsAdmin, [], false);
+ const createdRoom = await createRoom('c', channel, channelsAdmin, [], false, false);
if (!createdRoom?.rid) {
logger.error(`could not create channel ${channel}`);
return;
diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md
new file mode 100644
index 000000000000..c3478f72ad6d
--- /dev/null
+++ b/apps/meteor/ee/server/services/CHANGELOG.md
@@ -0,0 +1,12 @@
+# rocketchat-services
+
+## 1.0.1
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/rest-typings@6.2.6
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/models@0.0.2
diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json
index b9dc1c82e5b2..f6443e1c7755 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.0.0",
+ "version": "1.0.1",
"description": "Rocket.Chat Authorization service",
"main": "index.js",
"scripts": {
diff --git a/apps/meteor/ee/server/startup/index.ts b/apps/meteor/ee/server/startup/index.ts
index 409bc1bba597..e2f2d2d38287 100644
--- a/apps/meteor/ee/server/startup/index.ts
+++ b/apps/meteor/ee/server/startup/index.ts
@@ -3,6 +3,7 @@ import './apps';
import './audit';
import './deviceManagement';
import './engagementDashboard';
+import './maxRoomsPerGuest';
import './seatsCap';
import './services';
import './upsell';
diff --git a/apps/meteor/ee/server/startup/maxRoomsPerGuest.ts b/apps/meteor/ee/server/startup/maxRoomsPerGuest.ts
new file mode 100644
index 000000000000..3aeec09dc50e
--- /dev/null
+++ b/apps/meteor/ee/server/startup/maxRoomsPerGuest.ts
@@ -0,0 +1,21 @@
+import { Meteor } from 'meteor/meteor';
+import { Subscriptions } from '@rocket.chat/models';
+
+import { callbacks } from '../../../lib/callbacks';
+import { getMaxRoomsPerGuest } from '../../app/license/server/license';
+import { i18n } from '../../../server/lib/i18n';
+
+callbacks.add(
+ 'beforeAddedToRoom',
+ async ({ user }) => {
+ if (user.roles?.includes('guest')) {
+ const totalSubscriptions = await Subscriptions.countByUserId(user._id);
+
+ if (totalSubscriptions >= getMaxRoomsPerGuest()) {
+ throw new Meteor.Error('error-max-rooms-per-guest-reached', i18n.t('error-max-rooms-per-guest-reached'));
+ }
+ }
+ },
+ callbacks.priority.MEDIUM,
+ 'check-max-rooms-per-guest',
+);
diff --git a/apps/meteor/ee/server/startup/services.ts b/apps/meteor/ee/server/startup/services.ts
index 6aec5347f980..ba99f88a3d6e 100644
--- a/apps/meteor/ee/server/startup/services.ts
+++ b/apps/meteor/ee/server/startup/services.ts
@@ -6,6 +6,7 @@ import { MessageReadsService } from '../local-services/message-reads/service';
import { InstanceService } from '../local-services/instance/service';
import { LicenseService } from '../../app/license/server/license.internalService';
import { isRunningMs } from '../../../server/lib/isRunningMs';
+import { OmnichannelEE } from '../../app/livechat-enterprise/server/services/omnichannel.internalService';
import { FederationService } from '../../../server/services/federation/service';
import { FederationServiceEE } from '../local-services/federation/service';
import { isEnterprise, onLicense } from '../../app/license/server';
@@ -15,6 +16,7 @@ api.registerService(new EnterpriseSettings());
api.registerService(new LDAPEEService());
api.registerService(new LicenseService());
api.registerService(new MessageReadsService());
+api.registerService(new OmnichannelEE());
// when not running micro services we want to start up the instance intercom
if (!isRunningMs()) {
diff --git a/apps/meteor/lib/callbacks.ts b/apps/meteor/lib/callbacks.ts
index a1681cbaac43..8a8f1bb43842 100644
--- a/apps/meteor/lib/callbacks.ts
+++ b/apps/meteor/lib/callbacks.ts
@@ -125,8 +125,8 @@ type ChainedCallbackSignatures = {
'beforeSaveMessage': (message: IMessage, room?: IRoom) => IMessage;
'afterCreateUser': (user: IUser) => IUser;
'afterDeleteRoom': (rid: IRoom['_id']) => IRoom['_id'];
- 'livechat:afterOnHold': (room: IRoom) => IRoom;
- 'livechat:afterOnHoldChatResumed': (room: IRoom) => IRoom;
+ 'livechat:afterOnHold': (room: Pick) => Pick;
+ 'livechat:afterOnHoldChatResumed': (room: Pick) => Pick;
'livechat:onTransferFailure': (params: { room: IRoom; guest: ILivechatVisitor; transferData: { [k: string]: string | any } }) => {
room: IRoom;
guest: ILivechatVisitor;
diff --git a/apps/meteor/package.json b/apps/meteor/package.json
index 1d05041fd2c5..3f2096d37973 100644
--- a/apps/meteor/package.json
+++ b/apps/meteor/package.json
@@ -219,7 +219,7 @@
"@rocket.chat/account-utils": "workspace:^",
"@rocket.chat/agenda": "workspace:^",
"@rocket.chat/api-client": "workspace:^",
- "@rocket.chat/apps-engine": "1.40.0-alpha.266",
+ "@rocket.chat/apps-engine": "1.40.0-alpha.275",
"@rocket.chat/base64": "workspace:^",
"@rocket.chat/cas-validate": "workspace:^",
"@rocket.chat/core-services": "workspace:^",
diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
index f170ba28d02f..f4e1719ad336 100644
--- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
+++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
@@ -1993,6 +1993,7 @@
"error-max-departments-number-reached": "You reached the maximum number of departments allowed by your license. Contact sale@rocket.chat for a new license.",
"error-max-guests-number-reached": "You reached the maximum number of guest users allowed by your license. Contact sale@rocket.chat for a new license.",
"error-max-number-simultaneous-chats-reached": "The maximum number of simultaneous chats per agent has been reached.",
+ "error-max-rooms-per-guest-reached": "The maximum number of rooms per guest has been reached.",
"error-message-deleting-blocked": "Message deleting is blocked",
"error-message-editing-blocked": "Message editing is blocked",
"error-message-size-exceeded": "Message size exceeds Message_MaxAllowedSize",
@@ -2028,6 +2029,8 @@
"error-room-already-closed": "Room is already closed",
"error-room-is-not-closed": "Room is not closed",
"error-room-onHold": "Error! Room is On Hold",
+ "error-room-is-already-on-hold": "Error! Room is already On Hold",
+ "error-room-not-on-hold": "Error! Room is not On Hold",
"error-selected-agent-room-agent-are-same": "The selected agent and the room agent are the same",
"error-starring-message": "Message could not be stared",
"error-tags-must-be-assigned-before-closing-chat": "Tag(s) must be assigned before closing the chat",
@@ -2055,6 +2058,8 @@
"error-you-are-last-owner": "You are the last owner. Please set new owner before leaving the room.",
"error-saving-sla": "An error ocurred while saving the SLA",
"error-duplicated-sla": "An SLA with the same name or due time already exists",
+ "error-contact-sent-last-message-so-cannot-place-on-hold": "You cannot place chat on-hold, when the Contact has sent the last message",
+ "error-unserved-rooms-cannot-be-placed-onhold": "Room cannot be placed on hold before being served",
"You_do_not_have_permission_to_do_this": "You do not have permission to do this",
"Errors_and_Warnings": "Errors and Warnings",
"Esc_to": "Esc to",
@@ -3055,7 +3060,7 @@
"Livechat_OfflineMessageToChannel_enabled": "Send Livechat offline messages to a channel",
"Omnichannel_on_hold_chat_resumed": "On Hold Chat Resumed: {{comment}}",
"Omnichannel_on_hold_chat_automatically": "The chat was automatically resumed from On Hold upon receiving a new message from {{guest}}",
- "Omnichannel_on_hold_chat_manually": "The chat was manually resumed from On Hold by {{user}}",
+ "Omnichannel_on_hold_chat_resumed_manually": "The chat was manually resumed from On Hold by {{user}}",
"Omnichannel_On_Hold_due_to_inactivity": "The chat was automatically placed On Hold because we haven't received any reply from {{guest}} in {{timeout}} seconds",
"Omnichannel_On_Hold_manually": "The chat was manually placed On Hold by {{user}}",
"Omnichannel_onHold_Chat": "Place chat On-Hold",
diff --git a/apps/meteor/server/models/raw/Subscriptions.ts b/apps/meteor/server/models/raw/Subscriptions.ts
index 8d2fc0fbc0dc..59976dc1753c 100644
--- a/apps/meteor/server/models/raw/Subscriptions.ts
+++ b/apps/meteor/server/models/raw/Subscriptions.ts
@@ -539,6 +539,14 @@ export class SubscriptionsRaw extends BaseRaw implements ISubscri
return this.updateOne(query, { $unset: { E2ESuggestedKey: 1 } });
}
+ setOnHoldByRoomId(rid: string): Promise {
+ return this.updateOne({ rid }, { $set: { onHold: true } });
+ }
+
+ unsetOnHoldByRoomId(rid: string): Promise {
+ return this.updateOne({ rid }, { $unset: { onHold: 1 } });
+ }
+
findByRoomIds(roomIds: string[]): FindCursor {
const query = {
rid: {
@@ -945,6 +953,12 @@ export class SubscriptionsRaw extends BaseRaw implements ISubscri
return this.col.countDocuments(query);
}
+ countByUserId(userId: string): Promise {
+ const query = { 'u._id': userId };
+
+ return this.col.countDocuments(query);
+ }
+
countByRoomId(roomId: string): Promise {
const query = {
rid: roomId,
diff --git a/apps/meteor/tests/data/constants.ts b/apps/meteor/tests/data/constants.ts
new file mode 100644
index 000000000000..a7ebc76876db
--- /dev/null
+++ b/apps/meteor/tests/data/constants.ts
@@ -0,0 +1 @@
+export const CI_MAX_ROOMS_PER_GUEST = 10;
diff --git a/apps/meteor/tests/data/livechat/rooms.ts b/apps/meteor/tests/data/livechat/rooms.ts
index 429246d0189a..381f7be7120c 100644
--- a/apps/meteor/tests/data/livechat/rooms.ts
+++ b/apps/meteor/tests/data/livechat/rooms.ts
@@ -319,3 +319,11 @@ export const startANewLivechatRoomAndTakeIt = async ({
return { room, visitor };
};
+
+export const placeRoomOnHold = async (roomId: string): Promise => {
+ await request
+ .post(api('livechat/room.onHold'))
+ .set(credentials)
+ .send({ roomId })
+ .expect(200);
+}
diff --git a/apps/meteor/tests/e2e/engagement-dashboard.spec.ts b/apps/meteor/tests/e2e/engagement-dashboard.spec.ts
index 71197f0ea484..a6389e62dfa2 100644
--- a/apps/meteor/tests/e2e/engagement-dashboard.spec.ts
+++ b/apps/meteor/tests/e2e/engagement-dashboard.spec.ts
@@ -2,41 +2,34 @@ import { IS_EE } from './config/constants';
import { Users } from './fixtures/userStates';
import { test, expect } from './utils/test';
-test.skip(!IS_EE, 'Engagemente Dashboard > Enterprise Only');
+test.skip(!IS_EE, 'Engagement Dashboard > Enterprise Only');
test.use({ storageState: Users.admin.state });
test.describe('engagement-dashboard', () => {
- test.describe.parallel('expect to trigger fallback error component', () => {
- test.beforeEach(async ({ page }) => {
- await page.goto('/admin/engagement-dashboard');
- await page.route('**/api/v1/engagement-dashboard/**', (route) => route.abort());
- });
-
- test('expect to show 4 fallback errors components inside widget at Users Tab', async ({ page }) => {
- await expect(
- page.locator('[data-qa-id="EngagementDashboardPage-usersTab"][aria-selected="true"]', { hasText: 'Users' }),
- ).toBeVisible();
+ test.beforeEach(async ({ page }) => {
+ await page.goto('/admin/engagement-dashboard');
+ await page.route('**/api/v1/engagement-dashboard/**', (route) => route.abort());
+ });
+ test('expect to trigger fallback error component', async ({ page }) => {
+ await test.step('expect to show 4 fallback errors components inside widget at Users Tab', async () => {
+ await expect(page.locator('role=tab[name="Users"][selected]')).toBeVisible();
await page.waitForSelector('[data-qa="EngagementDashboardCardErrorBoundary"]');
await expect(page.locator('[data-qa="EngagementDashboardCardErrorBoundary"]')).toHaveCount(4);
});
- test('expect to show 2 fallback errors components inside widget at Messages Tab', async ({ page }) => {
- await page.locator('[data-qa-id="EngagementDashboardPage-messagesTab"]').click();
- await expect(
- page.locator('[data-qa-id="EngagementDashboardPage-messagesTab"][aria-selected="true"]', { hasText: 'Messages' }),
- ).toBeVisible();
+ await test.step('expect to show 2 fallback errors components inside widget at Messages Tab', async () => {
+ await page.locator('role=tab[name="Messages"]').click();
+ await expect(page.locator('role=tab[name="Messages"][selected]')).toBeVisible();
await page.waitForSelector('[data-qa="EngagementDashboardCardErrorBoundary"]');
await expect(page.locator('[data-qa="EngagementDashboardCardErrorBoundary"]')).toHaveCount(2);
});
- test('expect to show a fallback error component inside widget at Channels Tab', async ({ page }) => {
- await page.locator('[data-qa-id="EngagementDashboardPage-channelsTab"]').click();
- await expect(
- page.locator('[data-qa-id="EngagementDashboardPage-channelsTab"][aria-selected="true"]', { hasText: 'Channels' }),
- ).toBeVisible();
+ await test.step('expect to show a fallback error component inside widget at Channels Tab', async () => {
+ await page.locator('role=tab[name="Channels"]').click();
+ await expect(page.locator('role=tab[name="Channels"][selected]')).toBeVisible();
await page.waitForSelector('[data-qa="EngagementDashboardCardErrorBoundary"]');
await expect(page.locator('[data-qa="EngagementDashboardCardErrorBoundary"]')).toBeVisible();
diff --git a/apps/meteor/tests/e2e/message-actions.spec.ts b/apps/meteor/tests/e2e/message-actions.spec.ts
index f06b953823b3..c3d76757df74 100644
--- a/apps/meteor/tests/e2e/message-actions.spec.ts
+++ b/apps/meteor/tests/e2e/message-actions.spec.ts
@@ -96,6 +96,10 @@ test.describe.serial('message-actions', () => {
await adminPage.locator('text="Hide Contextual Bar by clicking outside of it"').click();
});
+ test.afterAll(async () => {
+ await adminPage.close();
+ });
+
test.afterAll(async ({ browser }) => {
adminPage = await browser.newPage({ storageState: Users.admin.state });
diff --git a/apps/meteor/tests/end-to-end/api/02-channels.js b/apps/meteor/tests/end-to-end/api/02-channels.js
index b3ef2e581a7a..c8cfc528cb1e 100644
--- a/apps/meteor/tests/end-to-end/api/02-channels.js
+++ b/apps/meteor/tests/end-to-end/api/02-channels.js
@@ -2,11 +2,12 @@ import { expect } from 'chai';
import { getCredentials, api, request, credentials, apiPublicChannelName, channel, reservedWords } from '../../data/api-data.js';
import { adminUsername, password } from '../../data/user';
-import { createUser, login } from '../../data/users.helper';
+import { createUser, login, deleteUser } from '../../data/users.helper';
import { updatePermission, updateSetting } from '../../data/permissions.helper';
import { createRoom } from '../../data/rooms.helper';
import { createIntegration, removeIntegration } from '../../data/integration.helper';
import { testFileUploads } from '../../data/uploads.helper';
+import { CI_MAX_ROOMS_PER_GUEST as maxRoomsPerGuest } from '../../data/constants';
function getRoomInfo(roomId) {
return new Promise((resolve /* , reject*/) => {
@@ -48,6 +49,66 @@ describe('[Channels]', function () {
.end(done);
});
+ describe('[/channels.create]', () => {
+ let guestUser;
+ let room;
+
+ before(async () => {
+ guestUser = await createUser({ roles: ['guest'] });
+ });
+ after(async () => {
+ await deleteUser(guestUser);
+ });
+
+ it('should not add guest users to more rooms than defined in the license', async function () {
+ // TODO this is not the right way to do it. We're doing this way for now just because we have separate CI jobs for EE and CE,
+ // ideally we should have a single CI job that adds a license and runs both CE and EE tests.
+ if (!process.env.IS_EE) {
+ this.skip();
+ }
+
+ const promises = [];
+ for (let i = 0; i < maxRoomsPerGuest; i++) {
+ promises.push(
+ createRoom({
+ type: 'c',
+ name: `channel.test.${Date.now()}-${Math.random()}`,
+ members: [guestUser.username],
+ }),
+ );
+ }
+ await Promise.all(promises);
+
+ request
+ .post(api('channels.create'))
+ .set(credentials)
+ .send({
+ name: `channel.test.${Date.now()}-${Math.random()}`,
+ members: [guestUser.username],
+ })
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res) => {
+ expect(res.body).to.have.property('success', true);
+ room = res.body.group;
+ })
+ .then(() => {
+ request
+ .get(api('channels.members'))
+ .set(credentials)
+ .query({
+ roomId: room._id,
+ })
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res) => {
+ expect(res.body).to.have.property('success', true);
+ expect(res.body).to.have.property('members').and.to.be.an('array');
+ expect(res.body.members).to.have.lengthOf(1);
+ });
+ });
+ });
+ });
describe('[/channels.info]', () => {
let testChannel = {};
let channelMessage = {};
diff --git a/apps/meteor/tests/end-to-end/api/03-groups.js b/apps/meteor/tests/end-to-end/api/03-groups.js
index aaa472eba45b..426f0db11b5b 100644
--- a/apps/meteor/tests/end-to-end/api/03-groups.js
+++ b/apps/meteor/tests/end-to-end/api/03-groups.js
@@ -2,11 +2,12 @@ import { expect } from 'chai';
import { getCredentials, api, request, credentials, group, apiPrivateChannelName } from '../../data/api-data.js';
import { adminUsername, password } from '../../data/user';
-import { createUser, login } from '../../data/users.helper';
+import { createUser, login, deleteUser } from '../../data/users.helper';
import { updatePermission, updateSetting } from '../../data/permissions.helper';
import { createRoom } from '../../data/rooms.helper';
import { createIntegration, removeIntegration } from '../../data/integration.helper';
import { testFileUploads } from '../../data/uploads.helper';
+import { CI_MAX_ROOMS_PER_GUEST as maxRoomsPerGuest } from '../../data/constants';
function getRoomInfo(roomId) {
return new Promise((resolve /* , reject*/) => {
@@ -47,6 +48,66 @@ describe('[Groups]', function () {
})
.end(done);
});
+ describe('[/groups.create]', () => {
+ let guestUser;
+ let room;
+
+ before(async () => {
+ guestUser = await createUser({ roles: ['guest'] });
+ });
+ after(async () => {
+ await deleteUser(guestUser);
+ });
+
+ it('should not add guest users to more rooms than defined in the license', async function () {
+ // TODO this is not the right way to do it. We're doing this way for now just because we have separate CI jobs for EE and CE,
+ // ideally we should have a single CI job that adds a license and runs both CE and EE tests.
+ if (!process.env.IS_EE) {
+ this.skip();
+ }
+ const promises = [];
+
+ for (let i = 0; i < maxRoomsPerGuest; i++) {
+ promises.push(
+ createRoom({
+ type: 'p',
+ name: `channel.test.${Date.now()}-${Math.random()}`,
+ members: [guestUser.username],
+ }),
+ );
+ }
+ await Promise.all(promises);
+
+ request
+ .post(api('groups.create'))
+ .set(credentials)
+ .send({
+ name: `channel.test.${Date.now()}-${Math.random()}`,
+ members: [guestUser.username],
+ })
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res) => {
+ expect(res.body).to.have.property('success', true);
+ room = res.body.group;
+ })
+ .then(() => {
+ request
+ .get(api('groups.members'))
+ .set(credentials)
+ .query({
+ roomId: room._id,
+ })
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res) => {
+ expect(res.body).to.have.property('success', true);
+ expect(res.body).to.have.property('members').and.to.be.an('array');
+ expect(res.body.members).to.have.lengthOf(1);
+ });
+ });
+ });
+ });
describe('/groups.create (encrypted)', () => {
it('should create a new encrypted group', async () => {
await request
diff --git a/apps/meteor/tests/end-to-end/api/24-methods.js b/apps/meteor/tests/end-to-end/api/24-methods.js
index 8ec3b2754d65..8c2a357bd007 100644
--- a/apps/meteor/tests/end-to-end/api/24-methods.js
+++ b/apps/meteor/tests/end-to-end/api/24-methods.js
@@ -1,7 +1,10 @@
import { expect } from 'chai';
import { getCredentials, request, methodCall, api, credentials } from '../../data/api-data.js';
+import { createUser, deleteUser } from '../../data/users.helper.js';
+import { createRoom } from '../../data/rooms.helper';
import { updatePermission, updateSetting } from '../../data/permissions.helper';
+import { CI_MAX_ROOMS_PER_GUEST as maxRoomsPerGuest } from '../../data/constants';
describe('Meteor.methods', function () {
this.retries(0);
@@ -2284,4 +2287,113 @@ describe('Meteor.methods', function () {
});
});
});
+
+ describe('[@addUsersToRoom]', () => {
+ let guestUser;
+ let user;
+ let room;
+
+ before(async () => {
+ guestUser = await createUser({ roles: ['guest'] });
+ user = await createUser();
+ room = (
+ await createRoom({
+ type: 'c',
+ name: `channel.test.${Date.now()}-${Math.random()}`,
+ })
+ ).body.channel;
+ });
+ after(async () => {
+ await deleteUser(user);
+ await deleteUser(guestUser);
+ user = undefined;
+ });
+
+ it('should fail if not logged in', (done) => {
+ request
+ .post(methodCall('addUsersToRoom'))
+ .expect('Content-Type', 'application/json')
+ .expect(401)
+ .expect((res) => {
+ expect(res.body).to.have.property('status', 'error');
+ expect(res.body).to.have.property('message');
+ })
+ .end(done);
+ });
+
+ it('should add a single user to a room', (done) => {
+ request
+ .post(methodCall('addUsersToRoom'))
+ .set(credentials)
+ .send({
+ message: JSON.stringify({
+ method: 'addUsersToRoom',
+ params: [{ rid: room._id, users: [user.username] }],
+ id: 'id',
+ msg: 'method',
+ }),
+ })
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res) => {
+ expect(res.body).to.have.property('success', true);
+ })
+ .then(() => {
+ request
+ .get(api('channels.members'))
+ .set(credentials)
+ .query({
+ roomId: room._id,
+ })
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res) => {
+ expect(res.body).to.have.property('success', true);
+ expect(res.body).to.have.property('members').and.to.be.an('array');
+ expect(res.body.members).to.have.lengthOf(2);
+ })
+ .end(done);
+ })
+ .catch(done);
+ });
+
+ it('should not add guest users to more rooms than defined in the license', async function () {
+ // TODO this is not the right way to do it. We're doing this way for now just because we have separate CI jobs for EE and CE,
+ // ideally we should have a single CI job that adds a license and runs both CE and EE tests.
+ if (!process.env.IS_EE) {
+ this.skip();
+ }
+ const promises = [];
+ for (let i = 0; i < maxRoomsPerGuest; i++) {
+ promises.push(
+ createRoom({
+ type: 'c',
+ name: `channel.test.${Date.now()}-${Math.random()}`,
+ members: [guestUser.username],
+ }),
+ );
+ }
+ await Promise.all(promises);
+
+ request
+ .post(methodCall('addUsersToRoom'))
+ .set(credentials)
+ .send({
+ message: JSON.stringify({
+ method: 'addUsersToRoom',
+ params: [{ rid: room._id, users: [guestUser.username] }],
+ id: 'id',
+ msg: 'method',
+ }),
+ })
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res) => {
+ expect(res.body).to.have.property('success', true);
+ const parsedBody = JSON.parse(res.body.message);
+ expect(parsedBody).to.have.property('error');
+ expect(parsedBody.error).to.have.property('error', 'error-max-rooms-per-guest-reached');
+ });
+ });
+ });
});
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 87a2a3a008d5..2a08cdc8605b 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
@@ -1152,7 +1152,7 @@ describe('LIVECHAT - rooms', function () {
expect(body).to.have.property('success', true);
expect(body).to.have.property('messages');
expect(body.messages).to.be.an('array');
- expect(body.messages.length <= 3).to.be.true;
+ expect(body.messages.length <= 4).to.be.true;
expect(body.messages[0]).to.have.property('msg', 'Hello');
expect(body.messages[1]).to.have.property('t');
});
@@ -1204,7 +1204,7 @@ describe('LIVECHAT - rooms', function () {
expect(body).to.have.property('success', true);
expect(body).to.have.property('messages').that.is.an('array');
- expect(body.messages.length <= 3).to.be.true;
+ expect(body.messages.length <= 4).to.be.true;
expect(body.messages[0]).to.have.property('msg', 'Hello');
expect(body.messages[1]).to.have.property('t');
});
diff --git a/apps/meteor/tests/end-to-end/api/livechat/18-rooms-ee.ts b/apps/meteor/tests/end-to-end/api/livechat/18-rooms-ee.ts
index 5628c3d7f381..9a3f3d37b888 100644
--- a/apps/meteor/tests/end-to-end/api/livechat/18-rooms-ee.ts
+++ b/apps/meteor/tests/end-to-end/api/livechat/18-rooms-ee.ts
@@ -1,10 +1,25 @@
/* eslint-env mocha */
+import type { IUser } from '@rocket.chat/core-typings';
import { expect } from 'chai';
import { getCredentials, api, request, credentials } from '../../../data/api-data';
-import { createVisitor, createLivechatRoom, sendMessage, closeOmnichannelRoom } from '../../../data/livechat/rooms';
+import {
+ createVisitor,
+ createLivechatRoom,
+ sendMessage,
+ sendAgentMessage,
+ placeRoomOnHold,
+ getLivechatRoomInfo,
+ startANewLivechatRoomAndTakeIt,
+ makeAgentAvailable,
+ createAgent,
+ closeOmnichannelRoom,
+} from '../../../data/livechat/rooms';
+import { sleep } from '../../../data/livechat/utils';
import { updatePermission, updateSetting } from '../../../data/permissions.helper';
+import { password } from '../../../data/user';
+import { createUser, login } from '../../../data/users.helper';
import { IS_EE } from '../../../e2e/config/constants';
(IS_EE ? describe : describe.skip)('[EE] LIVECHAT - rooms', function () {
@@ -12,8 +27,24 @@ import { IS_EE } from '../../../e2e/config/constants';
before((done) => getCredentials(done));
+ let agent2: { user: IUser; credentials: { 'X-Auth-Token': string; 'X-User-Id': string } };
+
before(async () => {
await updateSetting('Livechat_enabled', true);
+ await updateSetting('Livechat_Routing_Method', 'Manual_Selection');
+ await createAgent();
+ await makeAgentAvailable();
+ });
+
+ before(async () => {
+ const user: IUser = await createUser();
+ const userCredentials = await login(user.username, password);
+ await createAgent(user.username);
+
+ agent2 = {
+ user,
+ credentials: userCredentials,
+ };
});
describe('livechat/room.onHold', () => {
@@ -28,9 +59,10 @@ import { IS_EE } from '../../../e2e/config/constants';
.expect(403);
expect(response.body.success).to.be.false;
+
+ await updatePermission('on-hold-livechat-room', ['livechat-manager', 'livechat-monitor', 'livechat-agent', 'admin']);
});
it('should fail if roomId is invalid', async () => {
- await updatePermission('on-hold-livechat-room', ['admin']);
const response = await request
.post(api('livechat/room.onHold'))
.set(credentials)
@@ -40,6 +72,7 @@ import { IS_EE } from '../../../e2e/config/constants';
.expect(400);
expect(response.body.success).to.be.false;
+ expect(response.body.error).to.be.equal('error-invalid-room');
});
it('should fail if room is an empty string', async () => {
const response = await request
@@ -51,6 +84,7 @@ import { IS_EE } from '../../../e2e/config/constants';
.expect(400);
expect(response.body.success).to.be.false;
+ expect(response.body.error).to.be.equal('error-invalid-room');
});
it('should fail if room is not a livechat room', async () => {
const response = await request
@@ -62,6 +96,7 @@ import { IS_EE } from '../../../e2e/config/constants';
.expect(400);
expect(response.body.success).to.be.false;
+ expect(response.body.error).to.be.equal('error-invalid-room');
});
it('should fail if visitor is awaiting response (visitor sent last message)', async () => {
const visitor = await createVisitor();
@@ -77,6 +112,7 @@ import { IS_EE } from '../../../e2e/config/constants';
.expect(400);
expect(response.body.success).to.be.false;
+ expect(response.body.error).to.be.equal('error-contact-sent-last-message-so-cannot-place-on-hold');
});
it('should fail if room is closed', async () => {
const visitor = await createVisitor();
@@ -92,26 +128,26 @@ import { IS_EE } from '../../../e2e/config/constants';
.expect(400);
expect(response.body.success).to.be.false;
+ expect(response.body.error).to.be.equal('error-room-already-closed');
});
it('should fail if user is not serving the chat and doesnt have on-hold-others-livechat-room permission', async () => {
- await updatePermission('on-hold-others-livechat-room', []);
- const visitor = await createVisitor();
- const room = await createLivechatRoom(visitor.token);
+ const { room } = await startANewLivechatRoomAndTakeIt();
+ await sendAgentMessage(room._id);
const response = await request
.post(api('livechat/room.onHold'))
- .set(credentials)
+ .set(agent2.credentials)
.send({
roomId: room._id,
})
.expect(400);
expect(response.body.success).to.be.false;
+ expect(response.body.error).to.be.equal('Not_authorized');
});
it('should put room on hold', async () => {
- await updatePermission('on-hold-others-livechat-room', ['admin', 'livechat-manager']);
- const visitor = await createVisitor();
- const room = await createLivechatRoom(visitor.token);
+ const { room } = await startANewLivechatRoomAndTakeIt();
+ await sendAgentMessage(room._id);
const response = await request
.post(api('livechat/room.onHold'))
@@ -122,6 +158,97 @@ import { IS_EE } from '../../../e2e/config/constants';
.expect(200);
expect(response.body.success).to.be.true;
+
+ const updatedRoom = await getLivechatRoomInfo(room._id);
+ expect(updatedRoom.onHold).to.be.true;
+ });
+ });
+
+ describe('livechat/room.resumeOnHold', () => {
+ it('should fail if user doesnt have view-l-room permission', async () => {
+ await updatePermission('view-l-room', []);
+ const response = await request
+ .post(api('livechat/room.resumeOnHold'))
+ .set(credentials)
+ .send({
+ roomId: 'invalid-room-id',
+ })
+ .expect(403);
+
+ expect(response.body.success).to.be.false;
+ });
+ it('should fail if roomId is invalid', async () => {
+ await updatePermission('view-l-room', ['admin', 'livechat-manager', 'livechat-agent']);
+
+ const response = await request
+ .post(api('livechat/room.resumeOnHold'))
+ .set(credentials)
+ .send({
+ roomId: 'invalid-room-id',
+ })
+ .expect(400);
+
+ expect(response.body.success).to.be.false;
+ expect(response.body.error).to.be.equal('error-invalid-room');
+ });
+ it('should fail if room is not a livechat room', async () => {
+ const response = await request
+ .post(api('livechat/room.resumeOnHold'))
+ .set(credentials)
+ .send({
+ roomId: 'GENERAL',
+ })
+ .expect(400);
+
+ expect(response.body.success).to.be.false;
+ expect(response.body.error).to.be.equal('error-invalid-room');
+ });
+
+ it('should fail if room is not on hold', async () => {
+ const { room } = await startANewLivechatRoomAndTakeIt();
+
+ const response = await request
+ .post(api('livechat/room.resumeOnHold'))
+ .set(credentials)
+ .send({
+ roomId: room._id,
+ })
+ .expect(400);
+
+ expect(response.body.success).to.be.false;
+ expect(response.body.error).to.be.equal('error-room-not-on-hold');
+ });
+ it('should resume room on hold', async () => {
+ const { room } = await startANewLivechatRoomAndTakeIt();
+
+ await sendAgentMessage(room._id);
+ await placeRoomOnHold(room._id);
+
+ const response = await request
+ .post(api('livechat/room.resumeOnHold'))
+ .set(credentials)
+ .send({
+ roomId: room._id,
+ })
+ .expect(200);
+
+ expect(response.body.success).to.be.true;
+
+ const updatedRoom = await getLivechatRoomInfo(room._id);
+ expect(updatedRoom).to.not.have.property('onHold');
+ });
+ it('should resume chat automatically if visitor sent a message', async () => {
+ const { room, visitor } = await startANewLivechatRoomAndTakeIt();
+
+ await sendAgentMessage(room._id);
+ await placeRoomOnHold(room._id);
+ await sendMessage(room._id, 'test', visitor.token);
+
+ // wait for the room to be resumed since that logic is within callbacks
+ await sleep(500);
+
+ const updatedRoom = await getLivechatRoomInfo(room._id);
+ expect(updatedRoom).to.not.have.property('onHold');
});
});
});
diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md
new file mode 100644
index 000000000000..2fc7f914c256
--- /dev/null
+++ b/ee/apps/account-service/CHANGELOG.md
@@ -0,0 +1,12 @@
+# @rocket.chat/account-service
+
+## 0.1.1
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/rest-typings@6.2.6
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/models@0.0.2
diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json
index 5690f1f19784..db8b25bbecb4 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.1.0",
+ "version": "0.1.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
new file mode 100644
index 000000000000..7a41f670b511
--- /dev/null
+++ b/ee/apps/authorization-service/CHANGELOG.md
@@ -0,0 +1,12 @@
+# @rocket.chat/authorization-service
+
+## 0.1.1
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/rest-typings@6.2.6
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/models@0.0.2
diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json
index be6d452a25fe..862c228150b4 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.1.0",
+ "version": "0.1.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
new file mode 100644
index 000000000000..72bbf35e7d36
--- /dev/null
+++ b/ee/apps/ddp-streamer/CHANGELOG.md
@@ -0,0 +1,13 @@
+# @rocket.chat/ddp-streamer
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/rest-typings@6.2.6
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/models@0.0.2
+ - @rocket.chat/instance-status@0.0.2
diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json
index c8a8363c1fe1..2353c8307acc 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.0.1",
+ "version": "0.0.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
new file mode 100644
index 000000000000..5b3a2c9e84ff
--- /dev/null
+++ b/ee/apps/omnichannel-transcript/CHANGELOG.md
@@ -0,0 +1,13 @@
+# @rocket.chat/omnichannel-transcript
+
+## 0.1.1
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/omnichannel-services@0.0.2
+ - @rocket.chat/pdf-worker@0.0.2
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/models@0.0.2
diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json
index 2f69680b9ffb..c1ff5ad84142 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.1.0",
+ "version": "0.1.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
new file mode 100644
index 000000000000..18ac16d44137
--- /dev/null
+++ b/ee/apps/presence-service/CHANGELOG.md
@@ -0,0 +1,12 @@
+# @rocket.chat/presence-service
+
+## 0.1.1
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/presence@0.0.2
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/models@0.0.2
diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json
index a1866b981e40..c48b3c5b9c1e 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.1.0",
+ "version": "0.1.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
new file mode 100644
index 000000000000..2c283dd36be0
--- /dev/null
+++ b/ee/apps/queue-worker/CHANGELOG.md
@@ -0,0 +1,12 @@
+# @rocket.chat/queue-worker
+
+## 0.1.1
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/omnichannel-services@0.0.2
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/models@0.0.2
diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json
index 0a3a123f8e2c..2ecd45a5926f 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.1.0",
+ "version": "0.1.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
new file mode 100644
index 000000000000..df8798a34f8d
--- /dev/null
+++ b/ee/apps/stream-hub-service/CHANGELOG.md
@@ -0,0 +1,11 @@
+# @rocket.chat/stream-hub-service
+
+## 0.1.1
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/models@0.0.2
diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json
index 90084d14cceb..16f813601445 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.1.0",
+ "version": "0.1.1",
"description": "Rocket.Chat Stream Hub service",
"scripts": {
"build": "tsc -p tsconfig.json",
diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md
new file mode 100644
index 000000000000..d208e05c6156
--- /dev/null
+++ b/ee/packages/omnichannel-services/CHANGELOG.md
@@ -0,0 +1,13 @@
+# @rocket.chat/omnichannel-services
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/rest-typings@6.2.6
+ - @rocket.chat/pdf-worker@0.0.2
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/model-typings@0.0.2
+ - @rocket.chat/models@0.0.2
diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json
index 86cb00065b48..549ccf6ae48b 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.0.1",
+ "version": "0.0.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
new file mode 100644
index 000000000000..6eaa82ac514c
--- /dev/null
+++ b/ee/packages/pdf-worker/CHANGELOG.md
@@ -0,0 +1,8 @@
+# @rocket.chat/pdf-worker
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json
index 4006c2edd60f..3ec8a246354e 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.0.1",
+ "version": "0.0.2",
"private": true,
"devDependencies": {
"@storybook/addon-actions": "~6.5.14",
diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md
new file mode 100644
index 000000000000..a5dee9b46a83
--- /dev/null
+++ b/ee/packages/presence/CHANGELOG.md
@@ -0,0 +1,10 @@
+# @rocket.chat/presence
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/core-services@0.0.2
+ - @rocket.chat/models@0.0.2
diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json
index 1b340af4d7c2..20f57c175187 100644
--- a/ee/packages/presence/package.json
+++ b/ee/packages/presence/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/presence",
- "version": "0.0.1",
+ "version": "0.0.2",
"private": true,
"devDependencies": {
"@babel/core": "^7.20.5",
diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json
index e9208d3351f7..b688b0ce77d1 100644
--- a/ee/packages/ui-theming/package.json
+++ b/ee/packages/ui-theming/package.json
@@ -7,7 +7,7 @@
"@rocket.chat/fuselage": "next",
"@rocket.chat/fuselage-hooks": "next",
"@rocket.chat/icons": "next",
- "@rocket.chat/ui-contexts": "workspace:~",
+ "@rocket.chat/ui-contexts": "workspace:^",
"@storybook/addon-actions": "~6.5.16",
"@storybook/addon-docs": "~6.5.15",
"@storybook/addon-essentials": "~6.5.15",
diff --git a/packages/api-client/CHANGELOG.md b/packages/api-client/CHANGELOG.md
new file mode 100644
index 000000000000..2b53696dfa8a
--- /dev/null
+++ b/packages/api-client/CHANGELOG.md
@@ -0,0 +1,9 @@
+# @rocket.chat/api-client
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/rest-typings@6.2.6
diff --git a/packages/api-client/package.json b/packages/api-client/package.json
index dd907f4db973..8b39f1420440 100644
--- a/packages/api-client/package.json
+++ b/packages/api-client/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/api-client",
- "version": "0.0.1",
+ "version": "0.0.2",
"private": true,
"devDependencies": {
"@swc/core": "^1.3.60",
diff --git a/packages/base64/package.json b/packages/base64/package.json
index 49af1a9c13ec..0dbaa4ccdd1e 100644
--- a/packages/base64/package.json
+++ b/packages/base64/package.json
@@ -1,5 +1,6 @@
{
"name": "@rocket.chat/base64",
+ "private": true,
"description": "Base64 encoding and decoding; Fork of Meteor's Base64 package",
"version": "1.0.12",
"main": "./dist/base64.js",
diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md
new file mode 100644
index 000000000000..c053eb65f6df
--- /dev/null
+++ b/packages/core-services/CHANGELOG.md
@@ -0,0 +1,10 @@
+# @rocket.chat/core-services
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/rest-typings@6.2.6
+ - @rocket.chat/models@0.0.2
diff --git a/packages/core-services/package.json b/packages/core-services/package.json
index 8b6a3aac1ff9..1962ac995e26 100644
--- a/packages/core-services/package.json
+++ b/packages/core-services/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/core-services",
- "version": "0.0.1",
+ "version": "0.0.2",
"private": true,
"devDependencies": {
"@rocket.chat/eslint-config": "workspace:^",
diff --git a/packages/core-services/src/index.ts b/packages/core-services/src/index.ts
index b537b43ab0d1..22f7a82b3914 100644
--- a/packages/core-services/src/index.ts
+++ b/packages/core-services/src/index.ts
@@ -41,6 +41,7 @@ import type { IQueueWorkerService, HealthAggResult } from './types/IQueueWorkerS
import type { ITranslationService } from './types/ITranslationService';
import type { IMessageService } from './types/IMessageService';
import type { ISettingsService } from './types/ISettingsService';
+import type { IOmnichannelEEService } from './types/IOmnichannelEEService';
import type { IOmnichannelIntegrationService } from './types/IOmnichannelIntegrationService';
export { asyncLocalStorage } from './lib/asyncLocalStorage';
@@ -113,6 +114,7 @@ export {
ITranslationService,
IMessageService,
ISettingsService,
+ IOmnichannelEEService,
IOmnichannelIntegrationService,
};
@@ -146,6 +148,7 @@ export const Settings = proxifyWithWait('settings');
export const OmnichannelIntegration = proxifyWithWait('omnichannel-integration');
export const Federation = proxifyWithWait('federation');
export const FederationEE = proxifyWithWait('federation-enterprise');
+export const OmnichannelEEService = proxifyWithWait('omnichannel-ee');
// Calls without wait. Means that the service is optional and the result may be an error
// of service/method not available
diff --git a/packages/core-services/src/types/IOmnichannelEEService.ts b/packages/core-services/src/types/IOmnichannelEEService.ts
new file mode 100644
index 000000000000..8c8a4b75db1d
--- /dev/null
+++ b/packages/core-services/src/types/IOmnichannelEEService.ts
@@ -0,0 +1,18 @@
+import type { IOmnichannelRoom, IUser } from '@rocket.chat/core-typings';
+
+import type { IServiceClass } from './ServiceClass';
+
+export interface IOmnichannelEEService extends IServiceClass {
+ placeRoomOnHold(
+ room: Pick,
+ comment: string,
+ onHoldBy: Pick,
+ ): Promise;
+
+ resumeRoomOnHold(
+ room: Pick,
+ comment: string,
+ resumeBy: Pick,
+ clientAction?: boolean,
+ ): Promise;
+}
diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md
new file mode 100644
index 000000000000..da2d32d4619b
--- /dev/null
+++ b/packages/core-typings/CHANGELOG.md
@@ -0,0 +1,3 @@
+# @rocket.chat/core-typings
+
+## 6.2.6
diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json
index 74e26c32617f..0723c8bc8de5 100644
--- a/packages/core-typings/package.json
+++ b/packages/core-typings/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/core-typings",
- "version": "0.0.1",
+ "version": "6.2.6",
"private": true,
"devDependencies": {
"@rocket.chat/eslint-config": "workspace:^",
diff --git a/packages/core-typings/src/IRoom.ts b/packages/core-typings/src/IRoom.ts
index e2bf242659f7..acee191d5475 100644
--- a/packages/core-typings/src/IRoom.ts
+++ b/packages/core-typings/src/IRoom.ts
@@ -302,7 +302,7 @@ export type IOmnichannelRoomClosingInfo = Pick room.t === 'l';
+export const isOmnichannelRoom = (room: Pick): room is IOmnichannelRoom & IRoom => room.t === 'l';
export const isVoipRoom = (room: IRoom): room is IVoipRoom & IRoom => room.t === 'v';
diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json
index 2e801ea67489..1c1f5526f954 100644
--- a/packages/fuselage-ui-kit/package.json
+++ b/packages/fuselage-ui-kit/package.json
@@ -1,5 +1,6 @@
{
"name": "@rocket.chat/fuselage-ui-kit",
+ "private": true,
"version": "0.31.16",
"description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system",
"homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/",
diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md
new file mode 100644
index 000000000000..f99e52f87f34
--- /dev/null
+++ b/packages/instance-status/CHANGELOG.md
@@ -0,0 +1,8 @@
+# @rocket.chat/instance-status
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/models@0.0.2
diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json
index 0c67ef95de98..b1aeac41418d 100644
--- a/packages/instance-status/package.json
+++ b/packages/instance-status/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/instance-status",
- "version": "0.0.1",
+ "version": "0.0.2",
"private": true,
"devDependencies": {
"@rocket.chat/eslint-config": "workspace:^",
diff --git a/packages/livechat/src/components/Button/index.js b/packages/livechat/src/components/Button/index.js
deleted file mode 100644
index 472058079695..000000000000
--- a/packages/livechat/src/components/Button/index.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import { withTranslation } from 'react-i18next';
-
-import { createClassName, memo } from '../helpers';
-import styles from './styles.scss';
-
-const handleMouseUp = ({ target }) => target.blur();
-
-export const Button = withTranslation()(
- memo(
- ({
- submit,
- disabled,
- outline,
- nude,
- danger,
- secondary,
- stack,
- small,
- loading,
- badge,
- icon,
- onClick,
- className,
- style = {},
- children,
- img,
- t,
- }) => (
-
- ),
- ),
-);
diff --git a/packages/livechat/src/components/Button/index.tsx b/packages/livechat/src/components/Button/index.tsx
new file mode 100644
index 000000000000..d7d957d23acf
--- /dev/null
+++ b/packages/livechat/src/components/Button/index.tsx
@@ -0,0 +1,89 @@
+import type { CSSProperties } from 'preact/compat';
+import type { JSXInternal } from 'preact/src/jsx';
+import { useTranslation } from 'react-i18next';
+
+import { createClassName } from '../helpers';
+import styles from './styles.scss';
+
+const handleMouseUp: JSXInternal.EventHandler> = ({ target }) =>
+ (target as HTMLButtonElement)?.blur();
+
+type ButtonProps = {
+ submit?: boolean;
+ disabled?: boolean;
+ outline?: boolean;
+ nude?: boolean;
+ danger?: boolean;
+ secondary?: boolean;
+ stack?: boolean;
+ small?: boolean;
+ loading?: boolean;
+ badge?: number;
+ icon?: boolean;
+ onClick?: JSXInternal.MouseEventHandler;
+ className?: string;
+ style?: CSSProperties;
+ children?: JSXInternal.Element[];
+ img?: string;
+};
+
+export const Button = ({
+ submit,
+ disabled,
+ outline,
+ nude,
+ danger,
+ secondary,
+ stack,
+ small,
+ loading,
+ badge,
+ icon,
+ onClick,
+ className,
+ style = {},
+ children,
+ img,
+}: ButtonProps) => {
+ const { t } = useTranslation();
+ return (
+
+ );
+};
diff --git a/packages/livechat/src/scss.d.ts b/packages/livechat/src/scss.d.ts
new file mode 100644
index 000000000000..6718c3ed9812
--- /dev/null
+++ b/packages/livechat/src/scss.d.ts
@@ -0,0 +1,3 @@
+declare module '*.scss' {
+ export = undefined;
+}
diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md
new file mode 100644
index 000000000000..d23ab3911c47
--- /dev/null
+++ b/packages/model-typings/CHANGELOG.md
@@ -0,0 +1,8 @@
+# @rocket.chat/model-typings
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json
index b6d39af67951..b0aa963423e7 100644
--- a/packages/model-typings/package.json
+++ b/packages/model-typings/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/model-typings",
- "version": "0.0.1",
+ "version": "0.0.2",
"private": true,
"devDependencies": {
"@types/jest": "~29.5.0",
diff --git a/packages/model-typings/src/models/IMessagesModel.ts b/packages/model-typings/src/models/IMessagesModel.ts
index d05585fa3aa9..d87a450f7a34 100644
--- a/packages/model-typings/src/models/IMessagesModel.ts
+++ b/packages/model-typings/src/models/IMessagesModel.ts
@@ -94,6 +94,7 @@ export interface IMessagesModel extends IBaseModel {
): FindCursor;
findLivechatClosingMessage(rid: IRoom['_id'], options?: FindOptions): Promise;
+
setReactions(messageId: string, reactions: IMessage['reactions']): Promise;
keepHistoryForToken(token: string): Promise;
setRoomIdByToken(token: string, rid: string): Promise;
diff --git a/packages/model-typings/src/models/ISubscriptionsModel.ts b/packages/model-typings/src/models/ISubscriptionsModel.ts
index 49352ce6ea4f..f4dd7080597a 100644
--- a/packages/model-typings/src/models/ISubscriptionsModel.ts
+++ b/packages/model-typings/src/models/ISubscriptionsModel.ts
@@ -90,6 +90,9 @@ export interface ISubscriptionsModel extends IBaseModel {
unsetGroupE2ESuggestedKey(_id: string): Promise;
+ setOnHoldByRoomId(roomId: string): Promise;
+ unsetOnHoldByRoomId(roomId: string): Promise;
+
updateUnreadAlertById(_id: string, unreadAlert: ISubscription['unreadAlert']): Promise;
updateNotificationsPrefById(
_id: string,
@@ -229,6 +232,7 @@ export interface ISubscriptionsModel extends IBaseModel {
removeUnreadThreadsByRoomId(rid: string, tunread: string[]): Promise;
countByRoomIdAndRoles(roomId: string, roles: string[]): Promise;
countByRoomId(roomId: string): Promise;
+ countByUserId(userId: string): Promise;
openByRoomIdAndUserId(roomId: string, userId: string): Promise;
countByRoomIdAndNotUserId(rid: string, uid: string): Promise;
countByRoomIdWhenUsernameExists(rid: string): Promise;
diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md
new file mode 100644
index 000000000000..e4ce85f53cbf
--- /dev/null
+++ b/packages/models/CHANGELOG.md
@@ -0,0 +1,8 @@
+# @rocket.chat/models
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/model-typings@0.0.2
diff --git a/packages/models/package.json b/packages/models/package.json
index 44f68456a223..a46abadb67ba 100644
--- a/packages/models/package.json
+++ b/packages/models/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/models",
- "version": "0.0.1",
+ "version": "0.0.2",
"private": true,
"devDependencies": {
"@types/jest": "~29.5.0",
diff --git a/packages/random/package.json b/packages/random/package.json
index df0b6c522fbd..098750a30ae8 100644
--- a/packages/random/package.json
+++ b/packages/random/package.json
@@ -1,5 +1,6 @@
{
"name": "@rocket.chat/random",
+ "private": true,
"description": "Random number generator and utilities; Fork of Meteor's Random package",
"version": "1.2.1",
"main": "./dist/main.server.js",
diff --git a/packages/release-action/CHANGELOG.md b/packages/release-action/CHANGELOG.md
index 89b2647aa46a..dfe6a986b528 100644
--- a/packages/release-action/CHANGELOG.md
+++ b/packages/release-action/CHANGELOG.md
@@ -1 +1,7 @@
# @rocket.chat/release-action
+
+## 1.0.0
+
+### Major Changes
+
+- [#29545](https://github.com/RocketChat/Rocket.Chat/pull/29545) [`a728082848`](https://github.com/RocketChat/Rocket.Chat/commit/a72808284870af04a6457af6f2f79b0a0c38b7cb) Thanks [@github-actions](https://github.com/apps/github-actions)! - New action to publish package releases
diff --git a/packages/release-action/package.json b/packages/release-action/package.json
index 3a2263385070..72e41bb8778c 100644
--- a/packages/release-action/package.json
+++ b/packages/release-action/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/release-action",
- "version": "0.0.1",
+ "version": "1.0.0",
"private": true,
"scripts": {
"build": "tsc",
diff --git a/packages/release-action/src/bumpNextVersion.ts b/packages/release-action/src/bumpNextVersion.ts
index f4730881a1e8..00a459e917a4 100644
--- a/packages/release-action/src/bumpNextVersion.ts
+++ b/packages/release-action/src/bumpNextVersion.ts
@@ -55,6 +55,7 @@ export async function bumpNextVersion({
const newBranch = `release-${finalVersion}`;
// update root package.json
+ core.info('bump main package.json version');
updateVersionPackageJson(cwd, newVersion);
// TODO check if branch exists
@@ -63,6 +64,7 @@ export async function bumpNextVersion({
await exec('git', ['add', '.']);
await exec('git', ['commit', '-m', newVersion]);
+ core.info('fix dependencies in workspace packages');
await fixWorkspaceVersionsBeforePublish();
await exec('yarn', ['changeset', 'publish']);
@@ -80,8 +82,11 @@ export async function bumpNextVersion({
body: prBody,
...github.context.repo,
});
+ } else {
+ core.info('no pull request created: release is not the first candidate');
}
+ core.info('create release');
await octokit.rest.repos.createRelease({
name: newVersion,
tag_name: newVersion,
diff --git a/packages/release-action/src/publishRelease.ts b/packages/release-action/src/publishRelease.ts
index 8d77c6d3c96e..4c6d1618ee38 100644
--- a/packages/release-action/src/publishRelease.ts
+++ b/packages/release-action/src/publishRelease.ts
@@ -3,6 +3,7 @@ import path from 'path';
import { exec } from '@actions/exec';
import * as github from '@actions/github';
+import * as core from '@actions/core';
import { createNpmFile } from './createNpmFile';
import { setupOctokit } from './setupOctokit';
@@ -71,17 +72,20 @@ export async function publishRelease({
const releaseBody = changelogEntry.content;
// update root package.json
+ core.info('bump main package.json version');
updateVersionPackageJson(cwd, newVersion);
await exec('git', ['add', '.']);
await exec('git', ['commit', '-m', newVersion]);
+ core.info('fix dependencies in workspace packages');
await fixWorkspaceVersionsBeforePublish();
await exec('yarn', ['changeset', 'publish']);
await exec('git', ['push', '--follow-tags']);
+ core.info('create release');
await octokit.rest.repos.createRelease({
name: newVersion,
tag_name: newVersion,
diff --git a/packages/release-action/src/startPatchRelease.ts b/packages/release-action/src/startPatchRelease.ts
index 077dfc9ecb3d..320ee5e4c317 100644
--- a/packages/release-action/src/startPatchRelease.ts
+++ b/packages/release-action/src/startPatchRelease.ts
@@ -38,6 +38,7 @@ export async function startPatchRelease({
// TODO check if branch exists
await exec('git', ['checkout', '-b', newBranch]);
+ core.info('bump main package.json version');
updateVersionPackageJson(cwd, newVersion);
await exec('git', ['add', '.']);
@@ -57,5 +58,7 @@ export async function startPatchRelease({
body: '',
...github.context.repo,
});
+ } else {
+ core.info('no pull request created: patch is not for current version');
}
}
diff --git a/packages/release-action/src/utils.ts b/packages/release-action/src/utils.ts
index 8eaa86a93ed0..b8d8de9df66c 100644
--- a/packages/release-action/src/utils.ts
+++ b/packages/release-action/src/utils.ts
@@ -61,6 +61,6 @@ export function getChangelogEntry(changelog: string, version: string) {
export function updateVersionPackageJson(cwd = process.cwd(), newVersion: string) {
const rootPackageJsonPath = path.resolve(cwd, 'package.json');
const content = fs.readFileSync(rootPackageJsonPath, 'utf8');
- const updatedContent = content.replace(/'version': '.*',$/m, `'version': '${newVersion}',`);
+ const updatedContent = content.replace(/"version": ".*",$/m, `"version": "${newVersion}",`);
fs.writeFileSync(rootPackageJsonPath, updatedContent);
}
diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md
new file mode 100644
index 000000000000..52039671eb16
--- /dev/null
+++ b/packages/rest-typings/CHANGELOG.md
@@ -0,0 +1,8 @@
+# @rocket.chat/rest-typings
+
+## 6.2.6
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json
index 3803872fd005..240397446dd1 100644
--- a/packages/rest-typings/package.json
+++ b/packages/rest-typings/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/rest-typings",
- "version": "0.0.1",
+ "version": "6.2.6",
"private": true,
"devDependencies": {
"@rocket.chat/eslint-config": "workspace:^",
diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts
index 52d9b8286ca8..8423c4db1fdd 100644
--- a/packages/rest-typings/src/v1/omnichannel.ts
+++ b/packages/rest-typings/src/v1/omnichannel.ts
@@ -71,6 +71,23 @@ const LivechatRoomOnHoldSchema = {
export const isLivechatRoomOnHoldProps = ajv.compile(LivechatRoomOnHoldSchema);
+type LivechatRoomResumeOnHold = {
+ roomId: IRoom['_id'];
+};
+
+const LivechatRoomResumeOnHoldSchema = {
+ type: 'object',
+ properties: {
+ roomId: {
+ type: 'string',
+ },
+ },
+ required: ['roomId'],
+ additionalProperties: false,
+};
+
+export const isLivechatRoomResumeOnHoldProps = ajv.compile(LivechatRoomResumeOnHoldSchema);
+
type LivechatDepartmentId = {
onlyMyDepartments?: booleanString;
includeAgents?: booleanString;
@@ -2970,6 +2987,9 @@ export type OmnichannelEndpoints = {
'/v1/livechat/room.onHold': {
POST: (params: LivechatRoomOnHold) => void;
};
+ '/v1/livechat/room.resumeOnHold': {
+ POST: (params: LivechatRoomResumeOnHold) => void;
+ };
'/v1/livechat/room.join': {
GET: (params: LiveChatRoomJoin) => void;
};
diff --git a/packages/sha256/package.json b/packages/sha256/package.json
index 30e9d349e738..76dcec7e5507 100644
--- a/packages/sha256/package.json
+++ b/packages/sha256/package.json
@@ -1,5 +1,6 @@
{
"name": "@rocket.chat/sha256",
+ "private": true,
"description": "SHA256 implementation; Fork of Meteor's SHA256 package",
"version": "1.0.9",
"main": "./dist/sha256.js",
diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json
index 54cdb7fb7fe7..5df0a5f62afa 100644
--- a/packages/ui-client/package.json
+++ b/packages/ui-client/package.json
@@ -8,7 +8,7 @@
"@rocket.chat/fuselage": "next",
"@rocket.chat/fuselage-hooks": "next",
"@rocket.chat/icons": "next",
- "@rocket.chat/ui-contexts": "workspace:~",
+ "@rocket.chat/ui-contexts": "workspace:^",
"@storybook/addon-actions": "~6.5.16",
"@storybook/addon-docs": "~6.5.15",
"@storybook/addon-essentials": "~6.5.15",
diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md
new file mode 100644
index 000000000000..17d4e372f6a3
--- /dev/null
+++ b/packages/ui-contexts/CHANGELOG.md
@@ -0,0 +1,9 @@
+# @rocket.chat/ui-contexts
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @rocket.chat/core-typings@6.2.6
+ - @rocket.chat/rest-typings@6.2.6
diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json
index 821dbe55da20..bd7f461b66d4 100644
--- a/packages/ui-contexts/package.json
+++ b/packages/ui-contexts/package.json
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/ui-contexts",
- "version": "0.0.1",
+ "version": "0.0.2",
"private": true,
"devDependencies": {
"@rocket.chat/core-typings": "workspace:^",
diff --git a/yarn.lock b/yarn.lock
index f5bbf0afcc2c..eb2331071064 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3439,7 +3439,7 @@ __metadata:
"@esbuild/android-arm64@npm:0.17.18":
version: 0.17.18
resolution: "@esbuild/android-arm64@npm:0.17.18"
- conditions: os=android & cpu=arm64
+ checksum: ec47777acf96ffe5e36426e5c5715f74e154ddd2a4b2fcd12748250d7b3ded51c5a1a8a5f896f1524e52d3abf4b302aad0b2f30ac23b4efc41de2d01e359a34a
languageName: node
linkType: hard
@@ -8022,9 +8022,9 @@ __metadata:
languageName: node
linkType: hard
-"@rocket.chat/apps-engine@npm:1.40.0-alpha.266":
- version: 1.40.0-alpha.266
- resolution: "@rocket.chat/apps-engine@npm:1.40.0-alpha.266"
+"@rocket.chat/apps-engine@npm:1.40.0-alpha.275":
+ version: 1.40.0-alpha.275
+ resolution: "@rocket.chat/apps-engine@npm:1.40.0-alpha.275"
dependencies:
adm-zip: ^0.5.9
cryptiles: ^4.1.3
@@ -8036,7 +8036,7 @@ __metadata:
vm2: ^3.9.19
peerDependencies:
"@rocket.chat/ui-kit": "*"
- checksum: 5176cd8f365b0249cf9d6882e26eea0e0503d37d86d27018541ee9d34dd95feb10456192d64f2c7827c4051b651d76039c8b1a9e46e6e541f62f9991c950c5be
+ checksum: 77a4ad45c409397a7a8b1ef4ee2db67af75aa7a1f8a078cc59bc69681e8338ed90a110dfc279a46dc84d6bc93e4e43880ec1620a73837a6a9dcccbe055a51212
languageName: node
linkType: hard
@@ -8773,7 +8773,7 @@ __metadata:
"@rocket.chat/account-utils": "workspace:^"
"@rocket.chat/agenda": "workspace:^"
"@rocket.chat/api-client": "workspace:^"
- "@rocket.chat/apps-engine": 1.40.0-alpha.266
+ "@rocket.chat/apps-engine": 1.40.0-alpha.275
"@rocket.chat/base64": "workspace:^"
"@rocket.chat/cas-validate": "workspace:^"
"@rocket.chat/core-services": "workspace:^"
@@ -9577,7 +9577,7 @@ __metadata:
"@rocket.chat/fuselage": next
"@rocket.chat/fuselage-hooks": next
"@rocket.chat/icons": next
- "@rocket.chat/ui-contexts": "workspace:~"
+ "@rocket.chat/ui-contexts": "workspace:^"
"@storybook/addon-actions": ~6.5.16
"@storybook/addon-docs": ~6.5.15
"@storybook/addon-essentials": ~6.5.15
@@ -9695,7 +9695,7 @@ __metadata:
"@rocket.chat/fuselage": next
"@rocket.chat/fuselage-hooks": next
"@rocket.chat/icons": next
- "@rocket.chat/ui-contexts": "workspace:~"
+ "@rocket.chat/ui-contexts": "workspace:^"
"@storybook/addon-actions": ~6.5.16
"@storybook/addon-docs": ~6.5.15
"@storybook/addon-essentials": ~6.5.15