diff --git a/.docker/Dockerfile.rhel b/.docker/Dockerfile.rhel
index 850a879c7a89..e1dbdf4224c8 100644
--- a/.docker/Dockerfile.rhel
+++ b/.docker/Dockerfile.rhel
@@ -1,6 +1,6 @@
FROM registry.access.redhat.com/ubi8/nodejs-12
-ENV RC_VERSION 4.5.1
+ENV RC_VERSION 4.5.2
MAINTAINER buildmaster@rocket.chat
diff --git a/.github/history.json b/.github/history.json
index 6fb618dfbcc9..2380269cdb76 100644
--- a/.github/history.json
+++ b/.github/history.json
@@ -71319,6 +71319,24 @@
"'5.0'"
],
"pull_requests": [
+ {
+ "pr": "24782",
+ "title": "Release 4.5.1",
+ "userLogin": "pierre-lehnen-rc",
+ "contributors": [
+ "renatobecker",
+ "pierre-lehnen-rc",
+ "sampaiodiego",
+ "matheusbsilva137",
+ "amolghode1981",
+ "juliajforesti",
+ "tiagoevanp",
+ "KevLehman",
+ "MartinSchoeler",
+ "Aman-Maheshwari",
+ "cuonghuunguyen"
+ ]
+ },
{
"pr": "24760",
"title": "[FIX] Apple login script being loaded even when Apple Login is disabled.",
@@ -71457,6 +71475,103 @@
]
}
]
+ },
+ "4.5.2": {
+ "node_version": "14.18.3",
+ "npm_version": "6.14.15",
+ "apps_engine_version": "1.31.0",
+ "mongo_versions": [
+ "'3.6'",
+ "'4.0'",
+ "'4.2'",
+ "'4.4'",
+ "'5.0'"
+ ],
+ "pull_requests": [
+ {
+ "pr": "24812",
+ "title": "[FIX] Revert AutoComplete",
+ "userLogin": "juliajforesti",
+ "milestone": "4.5.2",
+ "contributors": [
+ "juliajforesti",
+ "ggazzo"
+ ]
+ },
+ {
+ "pr": "24809",
+ "title": "Regression: Fix ParentRoomWithEndpointData in loop",
+ "userLogin": "sampaiodiego",
+ "milestone": "4.5.2",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "24732",
+ "title": "[FIX] `PaginatedSelectFiltered` not handling changes",
+ "userLogin": "tassoevan",
+ "milestone": "4.5.2",
+ "contributors": [
+ "tassoevan"
+ ]
+ },
+ {
+ "pr": "24805",
+ "title": "[FIX] Critical: Incorrect visitor getting assigned to a chat from apps",
+ "userLogin": "murtaza98",
+ "milestone": "4.5.2",
+ "contributors": [
+ "murtaza98"
+ ]
+ },
+ {
+ "pr": "24804",
+ "title": "[FIX] \"livechat/webrtc.call\" endpoint not working",
+ "userLogin": "murtaza98",
+ "milestone": "4.5.2",
+ "contributors": [
+ "murtaza98"
+ ]
+ },
+ {
+ "pr": "24792",
+ "title": "[FIX] VoipExtensionsPage component call",
+ "userLogin": "KevLehman",
+ "milestone": "4.5.2",
+ "contributors": [
+ "KevLehman"
+ ]
+ },
+ {
+ "pr": "24705",
+ "title": "[FIX] Broken multiple OAuth integrations",
+ "userLogin": "debdutdeb",
+ "milestone": "4.5.2",
+ "contributors": [
+ "debdutdeb"
+ ]
+ },
+ {
+ "pr": "24623",
+ "title": "[FIX] Opening a new DM from user card",
+ "userLogin": "tassoevan",
+ "description": "A race condition on `useRoomIcon` -- delayed merge of rooms and subscriptions -- was causing a UI crash whenever someone tried to open a DM from the user card component.",
+ "milestone": "4.5.2",
+ "contributors": [
+ "tassoevan"
+ ]
+ },
+ {
+ "pr": "24750",
+ "title": "[IMPROVE] Voip Extensions disabled state",
+ "userLogin": "MartinSchoeler",
+ "milestone": "4.5.2",
+ "contributors": [
+ "MartinSchoeler"
+ ]
+ }
+ ]
}
}
}
\ No newline at end of file
diff --git a/.snapcraft/resources/prepareRocketChat b/.snapcraft/resources/prepareRocketChat
index 15fa6f07861d..c30d21c60ee2 100755
--- a/.snapcraft/resources/prepareRocketChat
+++ b/.snapcraft/resources/prepareRocketChat
@@ -1,6 +1,6 @@
#!/bin/bash
-curl -SLf "https://releases.rocket.chat/4.5.1/download/" -o rocket.chat.tgz
+curl -SLf "https://releases.rocket.chat/4.5.2/download/" -o rocket.chat.tgz
tar xf rocket.chat.tgz --strip 1
diff --git a/.snapcraft/snap/snapcraft.yaml b/.snapcraft/snap/snapcraft.yaml
index 92087b132cfc..5d1cc3b31d05 100644
--- a/.snapcraft/snap/snapcraft.yaml
+++ b/.snapcraft/snap/snapcraft.yaml
@@ -7,7 +7,7 @@
# 5. `snapcraft snap`
name: rocketchat-server
-version: 4.5.1
+version: 4.5.2
summary: Rocket.Chat server
description: Have your own Slack like online chat, built with Meteor. https://rocket.chat/
confinement: strict
diff --git a/HISTORY.md b/HISTORY.md
index 7de8158ee519..ce74d1516cac 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,6 +1,58 @@
+# 4.5.2
+`2022-03-12 ยท 1 ๐ ยท 7 ๐ ยท 1 ๐ ยท 8 ๐ฉโ๐ป๐จโ๐ป`
+
+### Engine versions
+- Node: `14.18.3`
+- NPM: `6.14.15`
+- MongoDB: `3.6, 4.0, 4.2, 4.4, 5.0`
+- Apps-Engine: `1.31.0`
+
+### ๐ Improvements
+
+
+- Voip Extensions disabled state ([#24750](https://github.com/RocketChat/Rocket.Chat/pull/24750))
+
+### ๐ Bug fixes
+
+
+- "livechat/webrtc.call" endpoint not working ([#24804](https://github.com/RocketChat/Rocket.Chat/pull/24804))
+
+- `PaginatedSelectFiltered` not handling changes ([#24732](https://github.com/RocketChat/Rocket.Chat/pull/24732))
+
+- Broken multiple OAuth integrations ([#24705](https://github.com/RocketChat/Rocket.Chat/pull/24705))
+
+- Critical: Incorrect visitor getting assigned to a chat from apps ([#24805](https://github.com/RocketChat/Rocket.Chat/pull/24805))
+
+- Opening a new DM from user card ([#24623](https://github.com/RocketChat/Rocket.Chat/pull/24623))
+
+ A race condition on `useRoomIcon` -- delayed merge of rooms and subscriptions -- was causing a UI crash whenever someone tried to open a DM from the user card component.
+
+- Revert AutoComplete ([#24812](https://github.com/RocketChat/Rocket.Chat/pull/24812))
+
+- VoipExtensionsPage component call ([#24792](https://github.com/RocketChat/Rocket.Chat/pull/24792))
+
+
+๐ Minor changes
+
+
+- Regression: Fix ParentRoomWithEndpointData in loop ([#24809](https://github.com/RocketChat/Rocket.Chat/pull/24809))
+
+
+
+### ๐ฉโ๐ป๐จโ๐ป Core Team ๐ค
+
+- [@KevLehman](https://github.com/KevLehman)
+- [@MartinSchoeler](https://github.com/MartinSchoeler)
+- [@debdutdeb](https://github.com/debdutdeb)
+- [@ggazzo](https://github.com/ggazzo)
+- [@juliajforesti](https://github.com/juliajforesti)
+- [@murtaza98](https://github.com/murtaza98)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+- [@tassoevan](https://github.com/tassoevan)
+
# 4.5.1
-`2022-03-09 ยท 13 ๐ ยท 1 ๐ ยท 11 ๐ฉโ๐ป๐จโ๐ป`
+`2022-03-09 ยท 13 ๐ ยท 2 ๐ ยท 12 ๐ฉโ๐ป๐จโ๐ป`
### Engine versions
- Node: `14.18.3`
@@ -54,11 +106,14 @@
- Chore: Update Livechat ([#24754](https://github.com/RocketChat/Rocket.Chat/pull/24754))
+- Release 4.5.1 ([#24782](https://github.com/RocketChat/Rocket.Chat/pull/24782) by [@Aman-Maheshwari](https://github.com/Aman-Maheshwari) & [@cuonghuunguyen](https://github.com/cuonghuunguyen))
+
### ๐ฉโ๐ป๐จโ๐ป Contributors ๐
- [@Aman-Maheshwari](https://github.com/Aman-Maheshwari)
+- [@cuonghuunguyen](https://github.com/cuonghuunguyen)
### ๐ฉโ๐ป๐จโ๐ป Core Team ๐ค
@@ -22366,4 +22421,4 @@
- [@graywolf336](https://github.com/graywolf336)
- [@marceloschmidt](https://github.com/marceloschmidt)
- [@rodrigok](https://github.com/rodrigok)
-- [@sampaiodiego](https://github.com/sampaiodiego)
\ No newline at end of file
+- [@sampaiodiego](https://github.com/sampaiodiego)
diff --git a/app/dolphin/lib/common.js b/app/dolphin/lib/common.js
index ddaacc16b2a2..d9a901cedda0 100644
--- a/app/dolphin/lib/common.js
+++ b/app/dolphin/lib/common.js
@@ -30,7 +30,7 @@ function DolphinOnCreateUser(options, user) {
if (Meteor.isServer) {
Meteor.startup(() =>
- settings.get('Accounts_OAuth_Dolphin_URL', (key, value) => {
+ settings.watch('Accounts_OAuth_Dolphin_URL', (value) => {
config.serverURL = value;
return Dolphin.configure(config);
}),
diff --git a/app/drupal/lib/common.js b/app/drupal/lib/common.js
index 4eea0cf99088..9090b3d75e2e 100644
--- a/app/drupal/lib/common.js
+++ b/app/drupal/lib/common.js
@@ -27,7 +27,7 @@ const Drupal = new CustomOAuth('drupal', config);
if (Meteor.isServer) {
Meteor.startup(function () {
- settings.get('API_Drupal_URL', function (key, value) {
+ settings.watch('API_Drupal_URL', function (value) {
config.serverURL = value;
Drupal.configure(config);
});
diff --git a/app/github-enterprise/lib/common.js b/app/github-enterprise/lib/common.js
index 5cb6ef471cfe..b1b07abc6cb8 100644
--- a/app/github-enterprise/lib/common.js
+++ b/app/github-enterprise/lib/common.js
@@ -22,7 +22,7 @@ const GitHubEnterprise = new CustomOAuth('github_enterprise', config);
if (Meteor.isServer) {
Meteor.startup(function () {
- settings.get('API_GitHub_Enterprise_URL', function (key, value) {
+ settings.watch('API_GitHub_Enterprise_URL', function (value) {
config.serverURL = value;
GitHubEnterprise.configure(config);
});
diff --git a/app/gitlab/lib/common.js b/app/gitlab/lib/common.js
index fd4520a7337d..5e3bd9941846 100644
--- a/app/gitlab/lib/common.js
+++ b/app/gitlab/lib/common.js
@@ -28,9 +28,7 @@ if (Meteor.isServer) {
Gitlab.configure(config);
}, 300);
- settings.get('API_Gitlab_URL', updateConfig);
- settings.get('Accounts_OAuth_Gitlab_identity_path', updateConfig);
- settings.get('Accounts_OAuth_Gitlab_merge_users', updateConfig);
+ settings.watchMultiple(['API_Gitlab_URL', 'Accounts_OAuth_Gitlab_identity_path', 'Accounts_OAuth_Gitlab_merge_users'], updateConfig);
});
} else {
Meteor.startup(function () {
diff --git a/app/livechat/server/api/lib/livechat.js b/app/livechat/server/api/lib/livechat.js
index d95cf802420b..d324da67fe37 100644
--- a/app/livechat/server/api/lib/livechat.js
+++ b/app/livechat/server/api/lib/livechat.js
@@ -107,7 +107,7 @@ export function normalizeHttpHeaderData(headers = {}) {
const httpHeaders = Object.assign({}, headers);
return { httpHeaders };
}
-export async function settings({ businessUnit = '' }) {
+export async function settings({ businessUnit = '' } = {}) {
const initSettings = Livechat.getInitSettings();
const triggers = await findTriggers();
const departments = findDepartments(businessUnit);
diff --git a/app/livechat/server/api/v1/videoCall.js b/app/livechat/server/api/v1/videoCall.js
index 484eb30a0ba6..8f8f74c078e5 100644
--- a/app/livechat/server/api/v1/videoCall.js
+++ b/app/livechat/server/api/v1/videoCall.js
@@ -10,6 +10,9 @@ import { findGuest, getRoom, settings } from '../lib/livechat';
import { OmnichannelSourceType } from '../../../../../definition/IRoom';
import { hasPermission, canSendMessage } from '../../../../authorization';
import { Livechat } from '../../lib/Livechat';
+import { Logger } from '../../../../logger';
+
+const logger = new Logger('LivechatVideoCallApi');
API.v1.addRoute('livechat/video.call/:token', {
get() {
@@ -62,6 +65,7 @@ API.v1.addRoute('livechat/video.call/:token', {
return API.v1.success(this.deprecationWarning({ videoCall }));
} catch (e) {
+ logger.error(e);
return API.v1.failure(e);
}
},
@@ -124,6 +128,7 @@ API.v1.addRoute(
};
return API.v1.success({ videoCall });
} catch (e) {
+ logger.error(e);
return API.v1.failure(e);
}
},
@@ -170,6 +175,7 @@ API.v1.addRoute(
return API.v1.success({ status });
} catch (e) {
+ logger.error(e);
return API.v1.failure(e);
}
},
diff --git a/app/livechat/server/lib/Livechat.js b/app/livechat/server/lib/Livechat.js
index 7a894a383d10..4ecc61e964ec 100644
--- a/app/livechat/server/lib/Livechat.js
+++ b/app/livechat/server/lib/Livechat.js
@@ -318,7 +318,7 @@ export const Livechat = {
if (user) {
Livechat.logger.debug('Found matching user by token');
userId = user._id;
- } else if (phone && (existingUser = LivechatVisitors.findOneVisitorByPhone(phone.number))) {
+ } else if (phone?.number && (existingUser = LivechatVisitors.findOneVisitorByPhone(phone.number))) {
Livechat.logger.debug('Found matching user by phone number');
userId = existingUser._id;
// Don't change token when matching by phone number, use current visitor token
diff --git a/app/tokenpass/lib/common.js b/app/tokenpass/lib/common.js
index 525aa88fcad5..0cd6868a3672 100644
--- a/app/tokenpass/lib/common.js
+++ b/app/tokenpass/lib/common.js
@@ -24,7 +24,7 @@ const Tokenpass = new CustomOAuth('tokenpass', config);
if (Meteor.isServer) {
Meteor.startup(function () {
- settings.get('API_Tokenpass_URL', function (key, value) {
+ settings.watch('API_Tokenpass_URL', function (value) {
config.serverURL = value;
Tokenpass.configure(config);
});
diff --git a/app/utils/rocketchat.info b/app/utils/rocketchat.info
index a14d9200f10d..49de4d160a25 100644
--- a/app/utils/rocketchat.info
+++ b/app/utils/rocketchat.info
@@ -1,3 +1,3 @@
{
- "version": "4.5.1"
+ "version": "4.5.2"
}
diff --git a/client/components/CreateDiscussion/CreateDiscussion.tsx b/client/components/CreateDiscussion/CreateDiscussion.tsx
index 5fe9e6c12f9a..b5f2a67ab9be 100644
--- a/client/components/CreateDiscussion/CreateDiscussion.tsx
+++ b/client/components/CreateDiscussion/CreateDiscussion.tsx
@@ -65,8 +65,14 @@ const CreateDiscussion = ({ onClose, defaultParentRoom, parentMessageId, nameSug
}
});
- const onChangeUsers = useMutableCallback((value: CreateDiscussionFormValues['usernames']) => {
- handleUsernames(value);
+ const onChangeUsers = useMutableCallback((value, action) => {
+ if (!action) {
+ if (usernames.includes(value)) {
+ return;
+ }
+ return handleUsernames([...usernames, value]);
+ }
+ handleUsernames(usernames.filter((current) => current !== value));
});
return (
diff --git a/client/components/UserAutoComplete/UserAutoComplete.js b/client/components/UserAutoComplete/UserAutoComplete.js
index d2c3c507b3b3..9653710b5df0 100644
--- a/client/components/UserAutoComplete/UserAutoComplete.js
+++ b/client/components/UserAutoComplete/UserAutoComplete.js
@@ -1,4 +1,4 @@
-import { SelectFiltered, Option, Box, Chip } from '@rocket.chat/fuselage';
+import { AutoComplete, Option, Box, Chip, Avatar } from '@rocket.chat/fuselage';
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
import React, { memo, useMemo, useState } from 'react';
@@ -17,29 +17,29 @@ const UserAutoComplete = (props) => {
useMemo(() => query(debouncedFilter, conditions), [filter]),
);
- const options = useMemo(() => (data && data.items.map((user) => [user.username, user.name])) || [], [data]);
-
- const renderSelected = ({ value, label }) =>
- value ? (
- props.onChange()} mie='x4'>
-
-
- {label}
-
-
- ) : null;
-
- const renderItem = ({ value, ...props }) => } />;
+ const options = useMemo(() => (data && data.items.map((user) => ({ value: user.username, label: user.name }))) || [], [data]);
return (
- {
+ if (!value) {
+ return '';
+ }
+
+ return (
+ props.onChange()} mie='x4'>
+
+
+ {label}
+
+
+ );
+ }}
+ renderItem={({ value, ...props }) => } />}
+ options={options}
/>
);
};
diff --git a/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.js b/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.js
index 482fd6e39fbc..dea3b0ec81c5 100644
--- a/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.js
+++ b/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.js
@@ -1,70 +1,52 @@
-import { MultiSelectFiltered, Box, Option, OptionAvatar, OptionContent, OptionDescription, Chip, CheckBox } from '@rocket.chat/fuselage';
-import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
-import React, { memo, useEffect, useMemo, useState } from 'react';
+import { AutoComplete, Box, Option, Chip } from '@rocket.chat/fuselage';
+import { useMutableCallback, useDebouncedValue } from '@rocket.chat/fuselage-hooks';
+import React, { memo, useMemo, useState } from 'react';
-import { useTranslation } from '../../contexts/TranslationContext';
import { useEndpointData } from '../../hooks/useEndpointData';
-import { AsyncStatePhase } from '../../lib/asyncState';
import UserAvatar from '../avatar/UserAvatar';
const query = (term = '') => ({ selector: JSON.stringify({ term }) });
-const UserAutoCompleteMultiple = ({ valueIsId = false, ...props }) => {
- const t = useTranslation();
+const UserAutoCompleteMultiple = (props) => {
const [filter, setFilter] = useState('');
- const [labelData, setLabelData] = useState({});
const debouncedFilter = useDebouncedValue(filter, 1000);
- const { value: data, phase } = useEndpointData(
+ const { value: data } = useEndpointData(
'users.autocomplete',
useMemo(() => query(debouncedFilter), [debouncedFilter]),
);
- const options = useMemo(
- () => (data && data.items.map((user) => [valueIsId ? user._id : user.username, user.name])) || [],
- [data, valueIsId],
- );
-
- useEffect(() => {
- const newLabelData = Object.fromEntries((data && data.items.map((user) => [user._id, user.username])) || []);
- setLabelData((labelData) => ({ ...labelData, ...newLabelData }));
- }, [data]);
-
- const renderItem = ({ value, label, selected, ...props }) => {
- const username = valueIsId ? labelData[value] : value;
- return (
-
- );
- };
-
- const renderSelected = ({ value, onMouseDown }) => {
- const username = valueIsId ? labelData[value] : value;
- return (
-
-
-
- {username}
-
-
- );
- };
+ const options = useMemo(() => (data && data.items.map((user) => ({ value: user.username, label: user.name }))) || [], [data]);
+ const onClickRemove = useMutableCallback((e) => {
+ e.stopPropagation();
+ e.preventDefault();
+ props.onChange(e.currentTarget.value, 'remove');
+ });
return (
-
+ selected?.map((value) => (
+
+
+
+ {value}
+
+
+ ))
+ }
+ renderItem={({ value, label, ...props }) => (
+
+
+
+
+ {label} ({value})
+
+
+ )}
+ options={options}
/>
);
};
diff --git a/client/hooks/usePresence.ts b/client/hooks/usePresence.ts
index e95a87059940..e02fd9c2cc32 100644
--- a/client/hooks/usePresence.ts
+++ b/client/hooks/usePresence.ts
@@ -12,7 +12,7 @@ type Presence = 'online' | 'offline' | 'busy' | 'away' | 'loading';
* @returns UserPresence
* @public
*/
-export const usePresence = (uid: string): UserPresence | undefined => {
+export const usePresence = (uid: string | undefined): UserPresence | undefined => {
const subscription = useMemo(
() => ({
getCurrentValue: (): UserPresence | undefined => (uid ? Presence.store.get(uid) : undefined),
diff --git a/client/hooks/useRoomIcon.tsx b/client/hooks/useRoomIcon.tsx
index 7bd0449e58b3..2e3510295f9e 100644
--- a/client/hooks/useRoomIcon.tsx
+++ b/client/hooks/useRoomIcon.tsx
@@ -1,6 +1,7 @@
-import React, { ReactNode } from 'react';
+import { Icon } from '@rocket.chat/fuselage';
+import React, { ComponentProps, ReactElement } from 'react';
-import { IRoom, isDirectMessageRoom } from '../../definition/IRoom';
+import { IRoom } from '../../definition/IRoom';
import { ReactiveUserStatus } from '../components/UserStatus';
export const colors = {
@@ -10,7 +11,9 @@ export const colors = {
offline: 'neutral-600',
};
-export const useRoomIcon = (room: IRoom): ReactNode | { name: string; color?: string } | null => {
+export const useRoomIcon = (
+ room: Pick,
+): ReactElement | ComponentProps | null => {
if (room.prid) {
return { name: 'baloons' };
}
@@ -19,13 +22,21 @@ export const useRoomIcon = (room: IRoom): ReactNode | { name: string; color?: st
return { name: room.t === 'p' ? 'team-lock' : 'team' };
}
- if (isDirectMessageRoom(room)) {
+ if (room.t === 'd') {
if (room.uids && room.uids.length > 2) {
return { name: 'balloon' };
}
+
if (room.uids && room.uids.length > 0) {
- return uid !== room.u._id) || room.u._id} />;
+ const uid = room.uids.find((uid) => uid !== room?.u?._id) || room?.u?._id;
+
+ if (!uid) {
+ return null;
+ }
+
+ return ;
}
+
return { name: 'at' };
}
diff --git a/client/lib/RoomManager.ts b/client/lib/RoomManager.ts
index 0d9417cace6f..a73c587473e2 100644
--- a/client/lib/RoomManager.ts
+++ b/client/lib/RoomManager.ts
@@ -149,10 +149,12 @@ export const useHandleRoom = (rid: IRoom['_id']): AsyncState
const room = uid ? subscription || _room : _room;
useEffect(() => {
- if (room) {
- update();
- resolve(room);
+ if (!room) {
+ return;
}
+
+ update();
+ resolve(room);
}, [resolve, update, room]);
return state;
diff --git a/client/sidebar/header/CreateChannelWithData.js b/client/sidebar/header/CreateChannelWithData.js
index bb5e303e95fa..e5f820126627 100644
--- a/client/sidebar/header/CreateChannelWithData.js
+++ b/client/sidebar/header/CreateChannelWithData.js
@@ -38,8 +38,14 @@ const CreateChannelWithData = ({ onClose, teamId = '', reload }) => {
const { users, name, description, type, readOnly, broadcast, encrypted } = values;
const { handleUsers, handleEncrypted, handleType, handleBroadcast, handleReadOnly } = handlers;
- const onChangeUsers = useMutableCallback((value) => {
- handleUsers(value);
+ const onChangeUsers = useMutableCallback((value, action) => {
+ if (!action) {
+ if (users.includes(value)) {
+ return;
+ }
+ return handleUsers([...users, value]);
+ }
+ handleUsers(users.filter((current) => current !== value));
});
const onChangeType = useMutableCallback((value) => {
diff --git a/client/sidebar/header/CreateDirectMessage.tsx b/client/sidebar/header/CreateDirectMessage.tsx
index 01c454ee7930..fecc80f43bd1 100644
--- a/client/sidebar/header/CreateDirectMessage.tsx
+++ b/client/sidebar/header/CreateDirectMessage.tsx
@@ -1,6 +1,6 @@
import { Box, Modal, ButtonGroup, Button } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
-import React, { ReactElement, useState, memo } from 'react';
+import React, { FC, useState, memo } from 'react';
import { IUser } from '../../../definition/IUser';
import UserAutoCompleteMultiple from '../../components/UserAutoCompleteMultiple';
@@ -8,18 +8,26 @@ import { useTranslation } from '../../contexts/TranslationContext';
import { useEndpointActionExperimental } from '../../hooks/useEndpointActionExperimental';
import { goToRoomById } from '../../lib/utils/goToRoomById';
+type Username = IUser['username'];
+
type CreateDirectMessageProps = {
onClose: () => void;
};
-const CreateDirectMessage = ({ onClose }: CreateDirectMessageProps): ReactElement => {
+const CreateDirectMessage: FC = ({ onClose }) => {
const t = useTranslation();
- const [users, setUsers] = useState>([]);
+ const [users, setUsers] = useState>([]);
const createDirect = useEndpointActionExperimental('POST', 'dm.create');
- const onChangeUsers = useMutableCallback((value: IUser['username'][]) => {
- setUsers(value);
+ const onChangeUsers = useMutableCallback((value: Username, action: string) => {
+ if (!action) {
+ if (users.includes(value)) {
+ return;
+ }
+ return setUsers([...users, value]);
+ }
+ setUsers(users.filter((current) => current !== value));
});
const onCreate = useMutableCallback(async () => {
diff --git a/client/views/admin/settings/groups/VoipGroupPage.tsx b/client/views/admin/settings/groups/VoipGroupPage.tsx
index d08316990bac..c0846e5c804c 100644
--- a/client/views/admin/settings/groups/VoipGroupPage.tsx
+++ b/client/views/admin/settings/groups/VoipGroupPage.tsx
@@ -2,8 +2,10 @@ import { Tabs, Box, Accordion } from '@rocket.chat/fuselage';
import React, { memo, useMemo, useState } from 'react';
import type { ISetting } from '../../../../../definition/ISetting';
+import NoResults from '../../../../components/GenericTable/NoResults';
import Page from '../../../../components/Page';
import { useEditableSettingsGroupSections } from '../../../../contexts/EditableSettingsContext';
+import { useSetting } from '../../../../contexts/SettingsContext';
import { useTranslation, TranslationKey } from '../../../../contexts/TranslationContext';
import GroupPage from '../GroupPage';
import Section from '../Section';
@@ -11,6 +13,7 @@ import VoipExtensionsPage from './voip/VoipExtensionsPage';
function VoipGroupPage({ _id, ...group }: ISetting): JSX.Element {
const t = useTranslation();
+ const voipEnabled = useSetting('VoIP_Enabled');
const tabs = ['Settings', 'Extensions'];
@@ -32,10 +35,20 @@ function VoipGroupPage({ _id, ...group }: ISetting): JSX.Element {
);
+ const ExtensionsPageComponent = useMemo(
+ () =>
+ voipEnabled ? (
+
+ ) : (
+
+ ),
+ [t, voipEnabled],
+ );
+
return (
{tab === 'Extensions' ? (
-
+ ExtensionsPageComponent
) : (
diff --git a/client/views/omnichannel/directory/calls/contextualBar/VoipInfo.tsx b/client/views/omnichannel/directory/calls/contextualBar/VoipInfo.tsx
index abb0db282782..e79c340f5a93 100644
--- a/client/views/omnichannel/directory/calls/contextualBar/VoipInfo.tsx
+++ b/client/views/omnichannel/directory/calls/contextualBar/VoipInfo.tsx
@@ -30,6 +30,7 @@ export const VoipInfo = ({ room, onClickClose /* , onClickReport, onClickCall */
const phoneNumber = Array.isArray(v?.phone) ? v?.phone[0]?.phoneNumber : v?.phone;
const shouldShowWrapup = useMemo(() => lastMessage?.t === 'voip-call-wrapup' && lastMessage?.msg, [lastMessage]);
const shouldShowTags = useMemo(() => tags && tags.length > 0, [tags]);
+ const _name = name || fname;
return (
<>
@@ -48,12 +49,12 @@ export const VoipInfo = ({ room, onClickClose /* , onClickReport, onClickCall */
{servedBy && }
- {v && (name || fname) && (
+ {v && _name && (
{t('Contact')}
-
- } />
+
+ } />
)}
diff --git a/client/views/room/Header/DirectRoomHeader.js b/client/views/room/Header/DirectRoomHeader.js
deleted file mode 100644
index 46895cfabb35..000000000000
--- a/client/views/room/Header/DirectRoomHeader.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-
-import { useUserId } from '../../../contexts/UserContext';
-import { usePresence } from '../../../hooks/usePresence';
-import RoomHeader from './RoomHeader';
-
-const DirectRoomHeader = ({ room, slots }) => {
- const userId = useUserId();
- const directUserId = room.uids.filter((uid) => uid !== userId).shift();
- const directUserData = usePresence(directUserId);
-
- return ;
-};
-
-export default DirectRoomHeader;
diff --git a/client/views/room/Header/DirectRoomHeader.tsx b/client/views/room/Header/DirectRoomHeader.tsx
new file mode 100644
index 000000000000..8052e71cd72d
--- /dev/null
+++ b/client/views/room/Header/DirectRoomHeader.tsx
@@ -0,0 +1,32 @@
+import React, { ReactElement } from 'react';
+
+import { IRoom } from '../../../../definition/IRoom';
+import { useUserId } from '../../../contexts/UserContext';
+import { usePresence } from '../../../hooks/usePresence';
+import RoomHeader from './RoomHeader';
+
+type DirectRoomHeaderProps = {
+ room: IRoom;
+ slots: {
+ start?: unknown;
+ preContent?: unknown;
+ insideContent?: unknown;
+ posContent?: unknown;
+ end?: unknown;
+ toolbox?: {
+ pre?: unknown;
+ content?: unknown;
+ pos?: unknown;
+ };
+ };
+};
+
+const DirectRoomHeader = ({ room, slots }: DirectRoomHeaderProps): ReactElement => {
+ const userId = useUserId();
+ const directUserId = room.uids?.filter((uid) => uid !== userId).shift();
+ const directUserData = usePresence(directUserId);
+
+ return ;
+};
+
+export default DirectRoomHeader;
diff --git a/client/views/room/Header/Header.js b/client/views/room/Header/Header.tsx
similarity index 79%
rename from client/views/room/Header/Header.js
rename to client/views/room/Header/Header.tsx
index 540682601d4d..56535ea0fa4b 100644
--- a/client/views/room/Header/Header.js
+++ b/client/views/room/Header/Header.tsx
@@ -1,5 +1,6 @@
-import React, { memo, useMemo } from 'react';
+import React, { memo, ReactElement, useMemo } from 'react';
+import { IRoom } from '../../../../definition/IRoom';
import BurgerMenu from '../../../components/BurgerMenu';
import TemplateHeader from '../../../components/Header';
import { useLayout } from '../../../contexts/LayoutContext';
@@ -8,7 +9,11 @@ import OmnichannelRoomHeader from './Omnichannel/OmnichannelRoomHeader';
import VoipRoomHeader from './Omnichannel/VoipRoomHeader';
import RoomHeader from './RoomHeader';
-const Header = ({ room }) => {
+type HeaderProps = {
+ room: IRoom;
+};
+
+const Header = ({ room }: HeaderProps): ReactElement | null => {
const { isMobile, isEmbedded, showTopNavbarEmbeddedLayout } = useLayout();
const slots = useMemo(
@@ -26,7 +31,7 @@ const Header = ({ room }) => {
return null;
}
- if (room.t === 'd' && room.uids.length < 3) {
+ if (room.t === 'd' && (room.uids?.length ?? 0) < 3) {
return ;
}
diff --git a/client/views/room/Header/HeaderIconWithRoom.js b/client/views/room/Header/HeaderIconWithRoom.tsx
similarity index 62%
rename from client/views/room/Header/HeaderIconWithRoom.js
rename to client/views/room/Header/HeaderIconWithRoom.tsx
index b52034bf121d..9fc7696f3135 100644
--- a/client/views/room/Header/HeaderIconWithRoom.js
+++ b/client/views/room/Header/HeaderIconWithRoom.tsx
@@ -1,15 +1,20 @@
-import React from 'react';
+import React, { ReactElement } from 'react';
-import { isOmnichannelRoom } from '../../../../definition/IRoom';
+import { IRoom, isOmnichannelRoom } from '../../../../definition/IRoom';
import Header from '../../../components/Header';
import { OmnichannelRoomIcon } from '../../../components/RoomIcon/OmnichannelRoomIcon';
import { useRoomIcon } from '../../../hooks/useRoomIcon';
-const HeaderIconWithRoom = ({ room }) => {
+type HeaderIconWithRoomProps = {
+ room: IRoom;
+};
+
+const HeaderIconWithRoom = ({ room }: HeaderIconWithRoomProps): ReactElement => {
const icon = useRoomIcon(room);
if (isOmnichannelRoom(room)) {
return ;
}
+
return ;
};
export default HeaderIconWithRoom;
diff --git a/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx b/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx
index f42a26371d54..6fa36eae4ec3 100644
--- a/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx
+++ b/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx
@@ -7,12 +7,27 @@ import { useCurrentRoute } from '../../../../contexts/RouterContext';
import { useOmnichannelRoom } from '../../contexts/RoomContext';
import { ToolboxActionConfig } from '../../lib/Toolbox';
import { ToolboxContext, useToolboxContext } from '../../lib/Toolbox/ToolboxContext';
-import RoomHeader, { RoomHeaderProps } from '../RoomHeader';
+import RoomHeader from '../RoomHeader';
import { BackButton } from './BackButton';
import QuickActions from './QuickActions';
import { useQuickActions } from './QuickActions/hooks/useQuickActions';
-const OmnichannelRoomHeader: FC = ({ slots: parentSlot }) => {
+type OmnichannelRoomHeaderProps = {
+ slots: {
+ start?: unknown;
+ preContent?: unknown;
+ insideContent?: unknown;
+ posContent?: unknown;
+ end?: unknown;
+ toolbox?: {
+ pre?: unknown;
+ content?: unknown;
+ pos?: unknown;
+ };
+ };
+};
+
+const OmnichannelRoomHeader: FC = ({ slots: parentSlot }) => {
const [name] = useCurrentRoute();
const { isMobile } = useLayout();
const room = useOmnichannelRoom();
diff --git a/client/views/room/Header/ParentRoom.js b/client/views/room/Header/ParentRoom.tsx
similarity index 55%
rename from client/views/room/Header/ParentRoom.js
rename to client/views/room/Header/ParentRoom.tsx
index df790cbbee6d..8cdb6d01c7c2 100644
--- a/client/views/room/Header/ParentRoom.js
+++ b/client/views/room/Header/ParentRoom.tsx
@@ -1,11 +1,16 @@
-import React from 'react';
+import React, { ReactElement } from 'react';
+import { IRoom } from '../../../../definition/IRoom';
import Header from '../../../components/Header';
import { useRoomIcon } from '../../../hooks/useRoomIcon';
import { roomCoordinator } from '../../../lib/rooms/roomCoordinator';
-const ParentRoom = ({ room }) => {
- const href = roomCoordinator.getRouteLink(room.t, room);
+type ParentRoomProps = {
+ room: Pick;
+};
+
+const ParentRoom = ({ room }: ParentRoomProps): ReactElement => {
+ const href = roomCoordinator.getRouteLink(room.t, room) || undefined;
const icon = useRoomIcon(room);
return (
diff --git a/client/views/room/Header/ParentRoomWithData.js b/client/views/room/Header/ParentRoomWithData.js
deleted file mode 100644
index 0ea0c26e2885..000000000000
--- a/client/views/room/Header/ParentRoomWithData.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-
-import { useUserSubscription } from '../../../contexts/UserContext';
-import ParentRoom from './ParentRoom';
-import ParentRoomWithEndpointData from './ParentRoomWithEndpointData';
-
-const ParentRoomWithData = ({ room }) => {
- const subscription = useUserSubscription(room.prid);
-
- if (subscription) {
- return ;
- }
-
- return ;
-};
-
-export default ParentRoomWithData;
diff --git a/client/views/room/Header/ParentRoomWithData.tsx b/client/views/room/Header/ParentRoomWithData.tsx
new file mode 100644
index 000000000000..1276d1948aa0
--- /dev/null
+++ b/client/views/room/Header/ParentRoomWithData.tsx
@@ -0,0 +1,28 @@
+import React, { ReactElement } from 'react';
+
+import { IRoom } from '../../../../definition/IRoom';
+import { useUserSubscription } from '../../../contexts/UserContext';
+import ParentRoom from './ParentRoom';
+import ParentRoomWithEndpointData from './ParentRoomWithEndpointData';
+
+type ParentRoomWithDataProps = {
+ room: IRoom;
+};
+
+const ParentRoomWithData = ({ room }: ParentRoomWithDataProps): ReactElement => {
+ const { prid } = room;
+
+ if (!prid) {
+ throw new Error('Parent room ID is missing');
+ }
+
+ const subscription = useUserSubscription(prid);
+
+ if (subscription) {
+ return ;
+ }
+
+ return ;
+};
+
+export default ParentRoomWithData;
diff --git a/client/views/room/Header/ParentRoomWithEndpointData.js b/client/views/room/Header/ParentRoomWithEndpointData.js
deleted file mode 100644
index 041e6496cee4..000000000000
--- a/client/views/room/Header/ParentRoomWithEndpointData.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React, { useEffect } from 'react';
-
-import Header from '../../../components/Header';
-import { useEndpoint } from '../../../contexts/ServerContext';
-import { AsyncStatePhase, useAsyncState } from '../../../hooks/useAsyncState';
-import ParentRoom from './ParentRoom';
-
-const ParentRoomWithEndpointData = ({ rid }) => {
- const { resolve, reject, reset, phase, value } = useAsyncState();
- const getData = useEndpoint('GET', 'rooms.info');
-
- useEffect(() => {
- (async () => {
- reset();
- getData({ roomId: rid })
- .then(resolve)
- .catch((error) => {
- reject(error);
- });
- })();
- }, [reset, getData, rid, resolve, reject]);
-
- if (AsyncStatePhase.LOADING === phase) {
- return ;
- }
-
- if (AsyncStatePhase.ERROR === phase || !value?.room) {
- return null;
- }
-
- return ;
-};
-
-export default ParentRoomWithEndpointData;
diff --git a/client/views/room/Header/ParentRoomWithEndpointData.tsx b/client/views/room/Header/ParentRoomWithEndpointData.tsx
new file mode 100644
index 000000000000..fe8fd3ac88f5
--- /dev/null
+++ b/client/views/room/Header/ParentRoomWithEndpointData.tsx
@@ -0,0 +1,30 @@
+import React, { ReactElement, useMemo } from 'react';
+
+import { IRoom } from '../../../../definition/IRoom';
+import Header from '../../../components/Header';
+import { AsyncStatePhase } from '../../../hooks/useAsyncState';
+import { useEndpointData } from '../../../hooks/useEndpointData';
+import ParentRoom from './ParentRoom';
+
+type ParentRoomWithEndpointDataProps = {
+ rid: IRoom['_id'];
+};
+
+const ParentRoomWithEndpointData = ({ rid }: ParentRoomWithEndpointDataProps): ReactElement | null => {
+ const { phase, value } = useEndpointData(
+ 'rooms.info',
+ useMemo(() => ({ roomId: rid }), [rid]),
+ );
+
+ if (AsyncStatePhase.LOADING === phase) {
+ return ;
+ }
+
+ if (AsyncStatePhase.REJECTED === phase || !value?.room) {
+ return null;
+ }
+
+ return ;
+};
+
+export default ParentRoomWithEndpointData;
diff --git a/client/views/room/Header/ParentTeam.js b/client/views/room/Header/ParentTeam.tsx
similarity index 65%
rename from client/views/room/Header/ParentTeam.js
rename to client/views/room/Header/ParentTeam.tsx
index 3cda611fa1cf..a9a6e49ced57 100644
--- a/client/views/room/Header/ParentTeam.js
+++ b/client/views/room/Header/ParentTeam.tsx
@@ -1,5 +1,6 @@
-import React, { useMemo } from 'react';
+import React, { ReactElement, useMemo } from 'react';
+import { IRoom } from '../../../../definition/IRoom';
import { TEAM_TYPE } from '../../../../definition/ITeam';
import Header from '../../../components/Header';
import { useUserId } from '../../../contexts/UserContext';
@@ -7,12 +8,25 @@ import { AsyncStatePhase } from '../../../hooks/useAsyncState';
import { useEndpointData } from '../../../hooks/useEndpointData';
import { goToRoomById } from '../../../lib/utils/goToRoomById';
-const ParentTeam = ({ room }) => {
+type ParentTeamProps = {
+ room: IRoom;
+};
+
+const ParentTeam = ({ room }: ParentTeamProps): ReactElement | null => {
+ const { teamId } = room;
const userId = useUserId();
+ if (!teamId) {
+ throw new Error('invalid rid');
+ }
+
+ if (!userId) {
+ throw new Error('invalid uid');
+ }
+
const { value, phase } = useEndpointData(
'teams.info',
- useMemo(() => ({ teamId: room.teamId }), [room.teamId]),
+ useMemo(() => ({ teamId }), [teamId]),
);
const { value: userTeams, phase: userTeamsPhase } = useEndpointData(
@@ -20,15 +34,23 @@ const ParentTeam = ({ room }) => {
useMemo(() => ({ userId }), [userId]),
);
- const belongsToTeam = userTeams?.teams?.find((team) => team._id === room.teamId) || false;
+ const belongsToTeam = userTeams?.teams?.find((team) => team._id === teamId) || false;
const isTeamPublic = value?.teamInfo.type === TEAM_TYPE.PUBLIC;
- const teamMainRoomHref = () => goToRoomById(value?.teamInfo.roomId);
+ const teamMainRoomHref = (): void => {
+ const rid = value?.teamInfo.roomId;
+
+ if (!rid) {
+ return;
+ }
+
+ goToRoomById(rid);
+ };
if (phase === AsyncStatePhase.LOADING || userTeamsPhase === AsyncStatePhase.LOADING) {
return ;
}
- if (phase === AsyncStatePhase.REJECTED || !value.teamInfo) {
+ if (phase === AsyncStatePhase.REJECTED || !value?.teamInfo) {
return null;
}
diff --git a/client/views/room/Header/RoomTitle.tsx b/client/views/room/Header/RoomTitle.tsx
index d65d40d26d4b..435537b656cd 100644
--- a/client/views/room/Header/RoomTitle.tsx
+++ b/client/views/room/Header/RoomTitle.tsx
@@ -4,7 +4,11 @@ import { IRoom } from '../../../../definition/IRoom';
import Header from '../../../components/Header';
import HeaderIconWithRoom from './HeaderIconWithRoom';
-const RoomTitle = ({ room }: { room: IRoom }): ReactElement => (
+type RoomTitleProps = {
+ room: IRoom;
+};
+
+const RoomTitle = ({ room }: RoomTitleProps): ReactElement => (
<>
{room.name}
diff --git a/client/views/room/contextualBar/ExportMessages/MailExportForm.js b/client/views/room/contextualBar/ExportMessages/MailExportForm.js
index 35d2abbf6ed1..8718dd46b9b4 100644
--- a/client/views/room/contextualBar/ExportMessages/MailExportForm.js
+++ b/client/views/room/contextualBar/ExportMessages/MailExportForm.js
@@ -68,8 +68,14 @@ const MailExportForm = ({ onCancel, rid }) => {
const { handleToUsers, handleAdditionalEmails, handleSubject } = handlers;
- const onChangeUsers = useMutableCallback((value) => {
- handleToUsers(value);
+ const onChangeUsers = useMutableCallback((value, action) => {
+ if (!action) {
+ if (toUsers.includes(value)) {
+ return;
+ }
+ return handleToUsers([...toUsers, value]);
+ }
+ handleToUsers(toUsers.filter((current) => current !== value));
});
const roomsExport = useEndpoint('POST', 'rooms.export');
diff --git a/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.js b/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.js
index ca78b64f69b8..4f435c67b9c7 100644
--- a/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.js
+++ b/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.js
@@ -65,8 +65,14 @@ const PruneMessagesWithData = ({ rid, tabBar }) => {
handleAttached,
} = handlers;
- const onChangeUsers = useMutableCallback((value) => {
- handleUsers(value);
+ const onChangeUsers = useMutableCallback((value, action) => {
+ if (!action) {
+ if (users.includes(value)) {
+ return;
+ }
+ return handleUsers([...users, value]);
+ }
+ handleUsers(users.filter((current) => current !== value));
});
const handlePrune = useMutableCallback(async () => {
diff --git a/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.js b/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.js
index f45acee96178..3383ccffbbbb 100644
--- a/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.js
+++ b/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.js
@@ -19,8 +19,14 @@ const AddUsersWithData = ({ rid, onClickBack, reload }) => {
const { users } = values;
const { handleUsers } = handlers;
- const onChangeUsers = useMutableCallback((value) => {
- handleUsers(value);
+ const onChangeUsers = useMutableCallback((value, action) => {
+ if (!action) {
+ if (users.includes(value)) {
+ return;
+ }
+ return handleUsers([...users, value]);
+ }
+ handleUsers(users.filter((current) => current !== value));
});
const handleSave = useMutableCallback(async () => {
diff --git a/client/views/room/providers/ToolboxProvider.tsx b/client/views/room/providers/ToolboxProvider.tsx
index d8e1ee41c653..650695b31268 100644
--- a/client/views/room/providers/ToolboxProvider.tsx
+++ b/client/views/room/providers/ToolboxProvider.tsx
@@ -71,7 +71,7 @@ const ToolboxProvider = ({ children, room }: { children: ReactNode; room: IRoom
open('room-info', username);
break;
case 'd':
- room.uids?.length > 2 ? open('user-info-group', username) : open('user-info', username);
+ (room.uids?.length ?? 0) > 2 ? open('user-info-group', username) : open('user-info', username);
break;
default:
open('members-list', username);
diff --git a/client/views/room/providers/VirtualAction.tsx b/client/views/room/providers/VirtualAction.tsx
index 209b3a624af2..0f4fe74b89ba 100644
--- a/client/views/room/providers/VirtualAction.tsx
+++ b/client/views/room/providers/VirtualAction.tsx
@@ -1,10 +1,11 @@
import { useLayoutEffect, memo } from 'react';
import { IRoom } from '../../../../definition/IRoom';
+import { RoomType } from '../../../../definition/RoomType';
import { Store } from '../lib/Toolbox/generator';
import { ToolboxAction } from '../lib/Toolbox/index';
-const groupsDict = {
+const groupsDict: Record = {
l: 'live',
v: 'voip',
d: 'direct',
@@ -18,7 +19,7 @@ const getGroup = (room: IRoom): string => {
return 'team';
}
- if (group === groupsDict.d && room.uids.length > 2) {
+ if (group === groupsDict.d && (room.uids?.length ?? 0) > 2) {
return 'direct_multiple';
}
diff --git a/client/views/teams/CreateTeamModal/CreateTeamModal.tsx b/client/views/teams/CreateTeamModal/CreateTeamModal.tsx
index 8da626fe91cd..ae150730e1a1 100644
--- a/client/views/teams/CreateTeamModal/CreateTeamModal.tsx
+++ b/client/views/teams/CreateTeamModal/CreateTeamModal.tsx
@@ -3,7 +3,6 @@ import { useMutableCallback, useDebouncedCallback, useAutoFocus } from '@rocket.
import React, { FC, memo, useCallback, useEffect, useMemo, useState } from 'react';
import { IUser } from '../../../../definition/IUser';
-import UserAutoCompleteMultiple from '../../../components/UserAutoCompleteMultiple';
import { usePermission } from '../../../contexts/AuthorizationContext';
import { useMethod } from '../../../contexts/ServerContext';
import { useSetting } from '../../../contexts/SettingsContext';
@@ -12,6 +11,7 @@ import { useEndpointActionExperimental } from '../../../hooks/useEndpointActionE
import { useForm } from '../../../hooks/useForm';
import { goToRoomById } from '../../../lib/utils/goToRoomById';
import TeamNameInput from './TeamNameInput';
+import UsersInput from './UsersInput';
type CreateTeamModalState = {
name: any;
@@ -82,6 +82,10 @@ const useCreateTeamModalState = (onClose: () => void): CreateTeamModalState => {
async (name: string) => {
setNameError(undefined);
+ if (!hasUnsavedChanges) {
+ return;
+ }
+
if (!name || name.length === 0) {
setNameError(t('Field_required'));
return;
@@ -132,10 +136,16 @@ const useCreateTeamModalState = (onClose: () => void): CreateTeamModalState => {
);
const onChangeMembers = useCallback(
- (value) => {
- handleMembers(value);
+ (value, action) => {
+ if (!action) {
+ if (members.includes(value)) {
+ return;
+ }
+ return handleMembers([...members, value]);
+ }
+ handleMembers(members.filter((current) => current !== value));
},
- [handleMembers],
+ [handleMembers, members],
);
const canSave = hasUnsavedChanges && !nameError;
@@ -303,7 +313,7 @@ const CreateTeamModal: FC = ({ onClose }) => {
({t('optional')})
-
+
diff --git a/client/views/teams/CreateTeamModal/UsersInput.tsx b/client/views/teams/CreateTeamModal/UsersInput.tsx
new file mode 100644
index 000000000000..339b6565d6ed
--- /dev/null
+++ b/client/views/teams/CreateTeamModal/UsersInput.tsx
@@ -0,0 +1,90 @@
+import { AutoComplete, Box, Option, Options, Chip, AutoCompleteProps } from '@rocket.chat/fuselage';
+import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
+import React, { FC, memo, useCallback, useMemo, useState } from 'react';
+
+import UserAvatar from '../../../components/avatar/UserAvatar';
+import { useEndpointData } from '../../../hooks/useEndpointData';
+
+type UsersInputProps = {
+ value: unknown[];
+ onChange: (value: unknown, action: 'remove' | undefined) => void;
+};
+
+type AutocompleteData = [AutoCompleteProps['options'], { [key: string]: string | undefined }];
+
+const useUsersAutoComplete = (term: string): AutocompleteData => {
+ const params = useMemo(
+ () => ({
+ selector: JSON.stringify({ term }),
+ }),
+ [term],
+ );
+ const { value: data } = useEndpointData('users.autocomplete', params);
+
+ return useMemo(() => {
+ if (!data) {
+ return [[], {}];
+ }
+
+ const options =
+ data.items.map((user) => ({
+ label: user.name ?? '',
+ value: user._id ?? '',
+ })) || [];
+
+ const labelData = Object.fromEntries(data.items.map((user) => [user._id, user.username]) || []);
+
+ return [options, labelData];
+ }, [data]);
+};
+
+const UsersInput: FC = ({ onChange, ...props }) => {
+ const [filter, setFilter] = useState('');
+ const [options, labelData] = useUsersAutoComplete(useDebouncedValue(filter, 1000));
+
+ const onClickSelected = useCallback(
+ (e) => {
+ e.stopPropagation();
+ e.preventDefault();
+ onChange(e.currentTarget.value, 'remove');
+ },
+ [onChange],
+ );
+
+ const renderSelected = useCallback>(
+ ({ value: selected }) => (
+ <>
+ {selected?.map((value) => (
+
+
+
+ {labelData[value]}
+
+
+ ))}
+ >
+ ),
+ [onClickSelected, props, labelData],
+ );
+
+ const renderItem = useCallback>(
+ ({ value, ...props }) => (
+ } />
+ ),
+ [labelData],
+ );
+
+ return (
+
+ );
+};
+
+export default memo(UsersInput);
diff --git a/definition/IRoom.ts b/definition/IRoom.ts
index aa5bb8bbe18c..6d266228a4cf 100644
--- a/definition/IRoom.ts
+++ b/definition/IRoom.ts
@@ -1,8 +1,8 @@
import { IRocketChatRecord } from './IRocketChatRecord';
import { IMessage } from './IMessage';
import { IUser, Username } from './IUser';
+import { RoomType } from './RoomType';
-export type RoomType = 'c' | 'd' | 'p' | 'l' | 'v';
type CallStatus = 'ringing' | 'ended' | 'declined' | 'ongoing';
export type RoomID = string;
@@ -18,7 +18,7 @@ export interface IRoom extends IRocketChatRecord {
_id: RoomID;
t: RoomType;
name?: string;
- fname: string;
+ fname?: string;
msgs: number;
default?: true;
broadcast?: true;
@@ -27,7 +27,7 @@ export interface IRoom extends IRocketChatRecord {
topic?: any;
u: Pick;
- uids: Array;
+ uids?: Array;
lastMessage?: IMessage;
lm?: Date;
@@ -229,3 +229,6 @@ export const isOmnichannelRoomFromAppSource = (room: IRoom): room is IOmnichanne
return room.source?.type === OmnichannelSourceType.APP;
};
+
+/** @deprecated */
+export { RoomType };
diff --git a/definition/ISubscription.ts b/definition/ISubscription.ts
index a528bfb3f51c..9ed8b2dc5d93 100644
--- a/definition/ISubscription.ts
+++ b/definition/ISubscription.ts
@@ -1,7 +1,6 @@
import { IRocketChatRecord } from './IRocketChatRecord';
import { IUser } from './IUser';
-
-type RoomType = 'c' | 'd' | 'p' | 'l';
+import { RoomType } from './RoomType';
type RoomID = string;
@@ -40,7 +39,7 @@ export interface ISubscription extends IRocketChatRecord {
E2EKey?: string;
unreadAlert?: 'default' | 'all' | 'mentions' | 'nothing';
- fname?: unknown;
+ fname?: string;
code?: unknown;
archived?: unknown;
diff --git a/definition/RoomType.ts b/definition/RoomType.ts
new file mode 100644
index 000000000000..9b2d3782ff47
--- /dev/null
+++ b/definition/RoomType.ts
@@ -0,0 +1 @@
+export type RoomType = 'c' | 'd' | 'p' | 'l' | 'v';
diff --git a/ee/client/audit/AuditPage.js b/ee/client/audit/AuditPage.js
index e2e33b69df0a..2a94e4242dce 100644
--- a/ee/client/audit/AuditPage.js
+++ b/ee/client/audit/AuditPage.js
@@ -38,8 +38,14 @@ const AuditPage = () => {
const { handleMsg, handleType, handleVisitor, handleAgent, handleUsers, handleRid, handleDateRange } = handlers;
- const onChangeUsers = useMutableCallback((value) => {
- handleUsers(value);
+ const onChangeUsers = useMutableCallback((value, action) => {
+ if (!action) {
+ if (users.includes(value)) {
+ return;
+ }
+ return handleUsers([...users, value]);
+ }
+ handleUsers(users.filter((current) => current !== value));
});
const apply = useMutableCallback(() => {
diff --git a/package-lock.json b/package-lock.json
index eadf333f1d12..e042f196f9f6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "Rocket.Chat",
- "version": "4.5.1",
+ "version": "4.5.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -5377,29 +5377,29 @@
}
},
"@rocket.chat/css-in-js": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.31.5.tgz",
- "integrity": "sha512-qtSJghYOrLonIdWbFl7hP9E/bUBQKpbQ2KnsP91MsbjCUwFbPdAFnl690yaxHViv1SXgxZsRRSLHKwjcqwBODw==",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.31.6.tgz",
+ "integrity": "sha512-aYUWh+41OVdFPL67nNfjkmUUEM2lgZu+9PlMQWLw+I0agLn/6IYKerPgosk4ta6l59GzfL2sccwy+UuURhPENA==",
"requires": {
"@emotion/hash": "^0.8.0",
- "@rocket.chat/css-supports": "^0.31.5",
- "@rocket.chat/memo": "^0.31.5",
- "@rocket.chat/stylis-logical-props-middleware": "^0.31.5",
+ "@rocket.chat/css-supports": "^0.31.6",
+ "@rocket.chat/memo": "^0.31.6",
+ "@rocket.chat/stylis-logical-props-middleware": "^0.31.6",
"stylis": "~4.0.13"
}
},
"@rocket.chat/css-supports": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/css-supports/-/css-supports-0.31.5.tgz",
- "integrity": "sha512-tGohngRSy/X3w/oSORAby5NQMUdE/QyxoFC5SiVtdnfOZhoVgyJIAINlYpg33aSP2SJkkr60pRm2FQx5WYtPjQ==",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/css-supports/-/css-supports-0.31.6.tgz",
+ "integrity": "sha512-TM2J19CRRNSQVhXWMglnopfaH7/qPCvbGzZcVuEKDP4gSoC5/RInGi/pOacbRAYFoFvmmxhqFgdvxueQPL4xeg==",
"requires": {
- "@rocket.chat/memo": "^0.31.5"
+ "@rocket.chat/memo": "^0.31.6"
}
},
"@rocket.chat/emitter": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/emitter/-/emitter-0.31.5.tgz",
- "integrity": "sha512-KioMqqL53CksV5aPdxJyRl8QPxiU8GcO7pSicY7y0uU8gZklbnw/Z8J0hcpQkrDh7kkh24Lk8v8NIA56ub15Xw=="
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/emitter/-/emitter-0.31.6.tgz",
+ "integrity": "sha512-7eeZFIKex1KMBoMCOM8POMs3fvorXV0gqicu+7v8sAnEnSYmYGgIN609IT7aboe8/SUvmcmcHqqF8nqOvVAJfw=="
},
"@rocket.chat/eslint-config": {
"version": "0.4.0",
@@ -5411,30 +5411,30 @@
}
},
"@rocket.chat/fuselage": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.31.5.tgz",
- "integrity": "sha512-H3FtudLb42OvZo9QyW1SqlI3a9KygzdGtv5KKqlcgPpTn1fzcKcEh01WYd9Kz9FBVXYq3qhjGnnEkSUFB8DnUw==",
- "requires": {
- "@rocket.chat/css-in-js": "^0.31.5",
- "@rocket.chat/css-supports": "^0.31.5",
- "@rocket.chat/fuselage-tokens": "^0.31.5",
- "@rocket.chat/memo": "^0.31.5",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.31.6.tgz",
+ "integrity": "sha512-cxdYx38zcvjMPOpSCK99LqzqTR8fNEW75QDSO8vY8RV0TTwHRjTGXI9B/uD3o2kC0n6tdOlCLOJajBX2yLo9rg==",
+ "requires": {
+ "@rocket.chat/css-in-js": "^0.31.6",
+ "@rocket.chat/css-supports": "^0.31.6",
+ "@rocket.chat/fuselage-tokens": "^0.31.6",
+ "@rocket.chat/memo": "^0.31.6",
"invariant": "^2.2.4",
"react-keyed-flatten-children": "^1.3.0"
}
},
"@rocket.chat/fuselage-hooks": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-hooks/-/fuselage-hooks-0.31.5.tgz",
- "integrity": "sha512-GsdEgAQycbzWo/eey0iodPMKuWClYjgBxz7BXISAXbFU8PzB4/HgVGGo/ER0SXO9pb/hDZf3pk9weW79tCai8Q==",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-hooks/-/fuselage-hooks-0.31.6.tgz",
+ "integrity": "sha512-NRAkXjjfJ43UXSSh+x3MyjiMc5pRbPe2EX4L0A1wPUH+U94nHEPNNTBio9kIqJ9TO83OEHuod+YqQ9jFfij5Vg==",
"requires": {
"@testing-library/user-event": "^13.5.0"
}
},
"@rocket.chat/fuselage-polyfills": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-polyfills/-/fuselage-polyfills-0.31.5.tgz",
- "integrity": "sha512-7dkyKHSLHKEteQrhbzr1tRfoAocG6eDfSDmaKCxm6wrwxeDvO7HDHQ2OJZOOB+Y/zbCz44k+9QOBFRXILCgDxw==",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-polyfills/-/fuselage-polyfills-0.31.6.tgz",
+ "integrity": "sha512-eYd7AVWA9j6TDU59mafQSCU1zjA/43riuCE/m3He3ZzND5BJ+x7j1NolGd28nDbSnqB0tBfmMjqIcIFwE9ermw==",
"requires": {
"@juggle/resize-observer": "^3.3.1",
"clipboard-polyfill": "^3.0.3",
@@ -5445,19 +5445,19 @@
}
},
"@rocket.chat/fuselage-tokens": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.31.5.tgz",
- "integrity": "sha512-6vYPDM2ntjz/LR/PgIW1GtEDLtDJrUXFy6QEBhfVCUjO+1zSLZ2wVv5EtRawm5QYbsZN9ZC58tBEi/ZEBvPkjA=="
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.31.6.tgz",
+ "integrity": "sha512-uHH6Bno/SnjbGAW5DzgYylfNU+bqQRZuvNxrCyUx+ScREUXL8tVNd8/ePllwPZvNFDpEuQzzF5Vx9kFV2xnXYg=="
},
"@rocket.chat/fuselage-ui-kit": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.31.5.tgz",
- "integrity": "sha512-JJx/4VlHbnPTflMLCORmFrg3haWO8cPdYSIbcVrkrESsRzGXIrPmg0XHcGS2WYdU+8BxceUyvobEXSQWjj9N4w==",
- "requires": {
- "@rocket.chat/fuselage": "^0.31.5",
- "@rocket.chat/fuselage-hooks": "^0.31.5",
- "@rocket.chat/styled": "^0.31.5",
- "@rocket.chat/ui-kit": "^0.31.5",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.31.6.tgz",
+ "integrity": "sha512-2nuIObwaw4BlMEGkLoMpHHTQI0TtkXgs9RB1HkgdE7peOFgYxbyWU0tN4I/9/mbMeQAR1AMx8Sya2zzR/DA7rg==",
+ "requires": {
+ "@rocket.chat/fuselage": "^0.31.6",
+ "@rocket.chat/fuselage-hooks": "^0.31.6",
+ "@rocket.chat/styled": "^0.31.6",
+ "@rocket.chat/ui-kit": "^0.31.6",
"tslib": "^2.3.1"
},
"dependencies": {
@@ -5469,9 +5469,9 @@
}
},
"@rocket.chat/icons": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.31.5.tgz",
- "integrity": "sha512-p67kcmnWDfV3ejRq890DmGFXWX77DfhKvBq/vC/GN5RnXAxubH7zsUqLSvPotCcvwO5pllm1CjhoVAmDrHc1FA=="
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.31.6.tgz",
+ "integrity": "sha512-wqjR7mCzmTVE/PCNZCrozab51d2VcUHu0H7gRIWIKqdnuuP9qMEvcV89uEI23hK7NIAjtS9jxdUY4pgGaV0oXw=="
},
"@rocket.chat/livechat": {
"version": "1.12.1",
@@ -5542,12 +5542,12 @@
}
},
"@rocket.chat/logo": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/logo/-/logo-0.31.5.tgz",
- "integrity": "sha512-Jdl5fmbpBZDuqgzADfbh7ZW6FqBxOc6yQkddqBviycrtRnYDSahPSVl72O4Cck26AXb623LVe7fY7oTK6+evEg==",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/logo/-/logo-0.31.6.tgz",
+ "integrity": "sha512-D+sCilG/ZHG2CAIZJsXx1saobRTm+PIbBp3wlK/brHUlmccLwcvurGoInWtaHkWkq7DjV3BbRw+/Wzu4fITMDw==",
"requires": {
- "@rocket.chat/fuselage-hooks": "^0.31.5",
- "@rocket.chat/styled": "^0.31.5",
+ "@rocket.chat/fuselage-hooks": "^0.31.6",
+ "@rocket.chat/styled": "^0.31.6",
"tslib": "^2.3.1"
},
"dependencies": {
@@ -5559,14 +5559,14 @@
}
},
"@rocket.chat/memo": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/memo/-/memo-0.31.5.tgz",
- "integrity": "sha512-wzRGQO3qZ4NvMtiC3kJsK5HDIovtZu8D4r1juK47jirxEZXB3/8uxbOk3ICQIi2tGulyVTnojV/dfolBJeY+FA=="
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/memo/-/memo-0.31.6.tgz",
+ "integrity": "sha512-llMwWrjgIAZm/1N0mhshys9b13LRqG3LAc6/8kysYFbSI6EuMD3WpzDM+xVwLYRdw5iPFShHow1atkqNFbhk8w=="
},
"@rocket.chat/message-parser": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/message-parser/-/message-parser-0.31.5.tgz",
- "integrity": "sha512-TVckPikRlPIrWqxF1OvL+YIf2Q1zgtIjDL5isWjSG4x3AVkguuT00Nm7xIAEBc/9wStyx5xHGgQaF3o0Q4AnsQ=="
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/message-parser/-/message-parser-0.31.6.tgz",
+ "integrity": "sha512-Hb07AzW9j6dN530tmJLfO/adjxBkx8ph2Id1xuRgrg63235p/YRjN+nNpX92PYXYM6MH1jhDK9VOVwnpXYx12A=="
},
"@rocket.chat/mp3-encoder": {
"version": "0.24.0",
@@ -5577,15 +5577,15 @@
}
},
"@rocket.chat/onboarding-ui": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/onboarding-ui/-/onboarding-ui-0.31.5.tgz",
- "integrity": "sha512-xbQzbq0TNijUbQC4ffR2nTrL60gt6/lsE5yzhLXfJmT5mPOf1kyM+fu+4Ork7VkD6jo3JB3cPH64dA3bIfOUUw==",
- "requires": {
- "@rocket.chat/fuselage": "^0.31.5",
- "@rocket.chat/fuselage-hooks": "^0.31.5",
- "@rocket.chat/icons": "^0.31.5",
- "@rocket.chat/logo": "^0.31.5",
- "@rocket.chat/styled": "^0.31.5",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/onboarding-ui/-/onboarding-ui-0.31.6.tgz",
+ "integrity": "sha512-U296Pl3oiQbEUCcLfR34oCDDM0PWmGPPgElrf4VwH4rh6ysJrSnKJlq1PUzd9XafKDEainH/RaVAR+puqL0bhQ==",
+ "requires": {
+ "@rocket.chat/fuselage": "^0.31.6",
+ "@rocket.chat/fuselage-hooks": "^0.31.6",
+ "@rocket.chat/icons": "^0.31.6",
+ "@rocket.chat/logo": "^0.31.6",
+ "@rocket.chat/styled": "^0.31.6",
"i18next": "~21.6.11",
"react-hook-form": "~7.27.0",
"react-i18next": "~11.15.4",
@@ -5593,9 +5593,9 @@
},
"dependencies": {
"i18next": {
- "version": "21.6.12",
- "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.12.tgz",
- "integrity": "sha512-xlGTPdu2g5PZEUIE6TA1mQ9EIAAv9nMFONzgwAIrKL/KTmYYWufQNGgOmp5Og1PvgUji+6i1whz0rMdsz1qaKw==",
+ "version": "21.6.13",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.6.13.tgz",
+ "integrity": "sha512-MVjNttw+5mIuu2/fwTpSU0EeI7iU/6pnDvGQboCzkILiv0/gD+FLZaF7qSHmUHO4ZkE6xJQ9SlBgGvMHxhC82Q==",
"requires": {
"@babel/runtime": "^7.12.0"
}
@@ -5655,9 +5655,9 @@
}
},
"@rocket.chat/string-helpers": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/string-helpers/-/string-helpers-0.31.5.tgz",
- "integrity": "sha512-MIQWeF69YF7/pazI59zZr1ZT04oHlg3oTyks2xCgh2IL3ZHAMhJcJ0yzl0GpigUbxhQ3OVI39fE7/5VanV6nhQ==",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/string-helpers/-/string-helpers-0.31.6.tgz",
+ "integrity": "sha512-Dq2EgXB5TwkO80X4qw1dpvhvtjEckM938XAKHYmxOn7KutZYIN5fUZpkcXqpnt2TqzNLElJB4tcFKie8FXwd6A==",
"requires": {
"tslib": "^2.3.1"
},
@@ -5670,11 +5670,11 @@
}
},
"@rocket.chat/styled": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/styled/-/styled-0.31.5.tgz",
- "integrity": "sha512-ai3ixlmReEEyn/VsJuoEiAXdreHlpH8sYspqeBzfR3GPrIuNGePh5a7GLgdCYh2wrsdSdB0eSBzhf0UwJsT8Vg==",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/styled/-/styled-0.31.6.tgz",
+ "integrity": "sha512-LHnQJY8Z/JESnaJJuoRRYIefhjEQMPIGAbUcafPWEojOr+0q9aXzDX7d1y9GmUPF/NnJNw6it2ptGfb0iAF2GA==",
"requires": {
- "@rocket.chat/css-in-js": "^0.31.5",
+ "@rocket.chat/css-in-js": "^0.31.6",
"tslib": "^2.3.1"
},
"dependencies": {
@@ -5686,11 +5686,11 @@
}
},
"@rocket.chat/stylis-logical-props-middleware": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/stylis-logical-props-middleware/-/stylis-logical-props-middleware-0.31.5.tgz",
- "integrity": "sha512-GhpURYo9IY9fS5UYy+tJqfcqCPeTfXVIhSJUlyIf8b8RDSUTH5u4n0Gkvm0kXMMY6vo8UGsT+HrP6CZmbstbbg==",
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/stylis-logical-props-middleware/-/stylis-logical-props-middleware-0.31.6.tgz",
+ "integrity": "sha512-IJo+MI5XKCMNs6HoOc1fipYPV+ZZz0C/vXZ5Oo6u8fhUd8lJwnwamfpaR+SJyTvXqGDvnhhT/gc3vuIC5oEomg==",
"requires": {
- "@rocket.chat/css-supports": "^0.31.5",
+ "@rocket.chat/css-supports": "^0.31.6",
"tslib": "^2.3.1"
},
"dependencies": {
@@ -5702,9 +5702,9 @@
}
},
"@rocket.chat/ui-kit": {
- "version": "0.31.5",
- "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.31.5.tgz",
- "integrity": "sha512-jmwFo//3th/VPu10qoMbL5CE8l6reaxrbo1JFoxGh+sfpBzeYmpmQ16hoLfydfRky9O+S4xBcvvZt+CIIKZ/zg=="
+ "version": "0.31.6",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.31.6.tgz",
+ "integrity": "sha512-NnJvSnqyh/hG0Ffj1MyJvMHcJWsM7IabSgllXXiJwIVKCJoLEq3DZexQosnv7FGF7i5dB6oRkC7DfemYc1hJyw=="
},
"@samverschueren/stream-to-observable": {
"version": "0.3.1",
@@ -31712,9 +31712,9 @@
"integrity": "sha512-Q2zaeQFXdVQ8l3hcywhltH+Nzj4vo50wMVujHDVN/1Xy9IOaSZJwYBXA2CYTpK6rq41fnXviw3jTLb04c7Gu9Q=="
},
"react-i18next": {
- "version": "11.15.5",
- "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.15.5.tgz",
- "integrity": "sha512-vBWuVEQgrhZrGKpyv8FmJ7Zs5jRQWl794Tte7yzJ0okZqqi3jd6j2pLYNg441WcREsbIOvWdiDXbY7W6E93p1A==",
+ "version": "11.15.6",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.15.6.tgz",
+ "integrity": "sha512-OUWcFdNgIA9swVx3JGIreuquglAinpRwB/HYrCprTN+s9BQDt9LSiY7x5DGc2JzVpwqtpoTV7oRUTOxEPNyUPw==",
"requires": {
"@babel/runtime": "^7.14.5",
"html-escaper": "^2.0.2",
diff --git a/package.json b/package.json
index c762fe2b2737..1e1ae3e518ea 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "Rocket.Chat",
"description": "The Ultimate Open Source WebChat Platform",
- "version": "4.5.1",
+ "version": "4.5.2",
"author": {
"name": "Rocket.Chat",
"url": "https://rocket.chat/"
@@ -178,21 +178,21 @@
"@nivo/line": "0.62.0",
"@nivo/pie": "0.73.0",
"@rocket.chat/apps-engine": "^1.31.0",
- "@rocket.chat/css-in-js": "^0.31.5",
- "@rocket.chat/emitter": "^0.31.5",
- "@rocket.chat/fuselage": "^0.31.5",
- "@rocket.chat/fuselage-hooks": "^0.31.5",
- "@rocket.chat/fuselage-polyfills": "^0.31.5",
- "@rocket.chat/fuselage-tokens": "^0.31.5",
- "@rocket.chat/fuselage-ui-kit": "^0.31.5",
- "@rocket.chat/icons": "^0.31.5",
- "@rocket.chat/logo": "^0.31.5",
- "@rocket.chat/memo": "^0.31.5",
- "@rocket.chat/message-parser": "^0.31.5",
+ "@rocket.chat/css-in-js": "~0.31.6",
+ "@rocket.chat/emitter": "~0.31.6",
+ "@rocket.chat/fuselage": "~0.31.6",
+ "@rocket.chat/fuselage-hooks": "~0.31.6",
+ "@rocket.chat/fuselage-polyfills": "~0.31.6",
+ "@rocket.chat/fuselage-tokens": "~0.31.6",
+ "@rocket.chat/fuselage-ui-kit": "~0.31.6",
+ "@rocket.chat/icons": "~0.31.6",
+ "@rocket.chat/logo": "~0.31.6",
+ "@rocket.chat/memo": "~0.31.6",
+ "@rocket.chat/message-parser": "~0.31.6",
"@rocket.chat/mp3-encoder": "^0.24.0",
- "@rocket.chat/onboarding-ui": "^0.31.5",
- "@rocket.chat/string-helpers": "^0.31.5",
- "@rocket.chat/ui-kit": "^0.31.5",
+ "@rocket.chat/onboarding-ui": "~0.31.6",
+ "@rocket.chat/string-helpers": "~0.31.6",
+ "@rocket.chat/ui-kit": "~0.31.6",
"@slack/client": "^4.12.0",
"@types/cookie": "^0.4.1",
"@types/lodash": "^4.14.177",
diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json
index 3f625aa1b06f..4449936d3b1a 100644
--- a/packages/rocketchat-i18n/i18n/en.i18n.json
+++ b/packages/rocketchat-i18n/i18n/en.i18n.json
@@ -4741,6 +4741,8 @@
"Voip_call_wrapup": "Call wrapup notes added: __comment__",
"VoIP_JWT_Secret": "VoIP JWT Secret",
"VoIP_JWT_Secret_description": "This allows you to set a secret key for sharing extension details from server to client as JWT instead of plain text. If you don't setup this, extension registration details will be sent as plain text",
+ "Voip_is_disabled": "VoIP is disabled",
+ "Voip_is_disabled_description": "To view the list of extensions it is necessary to activate VoIP, do so in the Settings tab.",
"Chat_opened_by_visitor": "Chat opened by the visitor",
"Wait_activation_warning": "Before you can login, your account must be manually activated by an administrator.",
"Waiting_queue": "Waiting queue",