From ccb9420189b6d3980576cf2ad4a97907c928b329 Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Fri, 2 Aug 2024 15:57:25 -0300 Subject: [PATCH 01/80] chore: update apps-engine (#32958) --- apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/ddp-streamer/package.json | 2 +- ee/packages/presence/package.json | 2 +- packages/apps/package.json | 2 +- packages/core-services/package.json | 2 +- packages/core-typings/package.json | 2 +- packages/fuselage-ui-kit/package.json | 2 +- packages/rest-typings/package.json | 2 +- yarn.lock | 26 ++++++++++----------- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index b9b1523c0c04..f28d34faa40f 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -18,7 +18,7 @@ "author": "Rocket.Chat", "license": "MIT", "dependencies": { - "@rocket.chat/apps-engine": "alpha", + "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 1e3ec0c70f0f..45bd640fed45 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -231,7 +231,7 @@ "@rocket.chat/agenda": "workspace:^", "@rocket.chat/api-client": "workspace:^", "@rocket.chat/apps": "workspace:^", - "@rocket.chat/apps-engine": "alpha", + "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/base64": "workspace:^", "@rocket.chat/cas-validate": "workspace:^", "@rocket.chat/core-services": "workspace:^", diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 42a72b165b46..562c3eca03e6 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -15,7 +15,7 @@ ], "author": "Rocket.Chat", "dependencies": { - "@rocket.chat/apps-engine": "alpha", + "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 09fd9db48b5f..83678740fc4b 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@babel/preset-env": "~7.22.20", "@babel/preset-typescript": "~7.22.15", - "@rocket.chat/apps-engine": "alpha", + "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@types/node": "^14.18.63", diff --git a/packages/apps/package.json b/packages/apps/package.json index ac0fa9589a26..9c7306d5cf79 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -22,7 +22,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "alpha", + "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/model-typings": "workspace:^" } diff --git a/packages/core-services/package.json b/packages/core-services/package.json index eb9f2fdf4c69..079cd766af3d 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -34,7 +34,7 @@ "extends": "../../package.json" }, "dependencies": { - "@rocket.chat/apps-engine": "alpha", + "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/icons": "^0.36.0", "@rocket.chat/message-parser": "workspace:^", diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 8d045fb2e4c8..4d44193ca672 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -22,7 +22,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "alpha", + "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/icons": "^0.36.0", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/ui-kit": "workspace:~" diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 001a5d08c065..f14aeb67719f 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -63,7 +63,7 @@ "@babel/preset-env": "~7.22.20", "@babel/preset-react": "~7.22.15", "@babel/preset-typescript": "~7.22.15", - "@rocket.chat/apps-engine": "alpha", + "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/fuselage": "^0.56.0", diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 3eaf55915a85..a4323af82e40 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -24,7 +24,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "alpha", + "@rocket.chat/apps-engine": "1.44.0", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/ui-kit": "workspace:~", diff --git a/yarn.lock b/yarn.lock index 4537533a7247..2e401aa7cc04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8509,9 +8509,9 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/apps-engine@npm:alpha": - version: 1.44.0-alpha.828 - resolution: "@rocket.chat/apps-engine@npm:1.44.0-alpha.828" +"@rocket.chat/apps-engine@npm:1.44.0": + version: 1.44.0 + resolution: "@rocket.chat/apps-engine@npm:1.44.0" dependencies: "@msgpack/msgpack": 3.0.0-beta2 adm-zip: ^0.5.9 @@ -8527,7 +8527,7 @@ __metadata: uuid: ~8.3.2 peerDependencies: "@rocket.chat/ui-kit": "*" - checksum: e26914b62d2e9823577fe8165a2635d65f69ddc315a880bbc417ddd674e4df487dc9bc9507bf3a0616de06cd927596872c1e90e4c29c61da8581e0a1b7c8d97d + checksum: f2b1b13c6a070c8d320a6d681ede6945a5882f9e2d42f2569bfc8c098229f761c7ef358589d3f1714d17b157fafa8e4869f28752408356f4a9286f62cb517f46 languageName: node linkType: hard @@ -8535,7 +8535,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/apps@workspace:packages/apps" dependencies: - "@rocket.chat/apps-engine": alpha + "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@types/jest": ~29.5.7 @@ -8614,7 +8614,7 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": alpha + "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/icons": ^0.36.0 @@ -8640,7 +8640,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/core-typings@workspace:packages/core-typings" dependencies: - "@rocket.chat/apps-engine": alpha + "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/icons": ^0.36.0 "@rocket.chat/message-parser": "workspace:^" @@ -8717,7 +8717,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/ddp-streamer@workspace:ee/apps/ddp-streamer" dependencies: - "@rocket.chat/apps-engine": alpha + "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/emitter": ~0.31.25 @@ -8913,7 +8913,7 @@ __metadata: "@babel/preset-env": ~7.22.20 "@babel/preset-react": ~7.22.15 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": alpha + "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/fuselage": ^0.56.0 @@ -9358,7 +9358,7 @@ __metadata: "@rocket.chat/agenda": "workspace:^" "@rocket.chat/api-client": "workspace:^" "@rocket.chat/apps": "workspace:^" - "@rocket.chat/apps-engine": alpha + "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/base64": "workspace:^" "@rocket.chat/cas-validate": "workspace:^" "@rocket.chat/core-services": "workspace:^" @@ -9997,7 +9997,7 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": alpha + "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" @@ -10112,7 +10112,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/rest-typings@workspace:packages/rest-typings" dependencies: - "@rocket.chat/apps-engine": alpha + "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/message-parser": "workspace:^" @@ -37162,7 +37162,7 @@ __metadata: version: 0.0.0-use.local resolution: "rocketchat-services@workspace:apps/meteor/ee/server/services" dependencies: - "@rocket.chat/apps-engine": alpha + "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/emitter": ~0.31.25 From 7444c3c360106b170759deaea8a9fbf00e8706be Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 2 Aug 2024 23:14:38 -0300 Subject: [PATCH 02/80] regression: fix dispatchInquiryPosition not being fired on room creation (#32972) --- .../meteor/app/livechat/server/lib/QueueManager.ts | 14 ++++++++++++++ .../app/livechat-enterprise/server/lib/Helper.ts | 6 +----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.ts b/apps/meteor/app/livechat/server/lib/QueueManager.ts index 5ae03e0ee03b..2075a5e9af97 100644 --- a/apps/meteor/app/livechat/server/lib/QueueManager.ts +++ b/apps/meteor/app/livechat/server/lib/QueueManager.ts @@ -15,6 +15,7 @@ import { Random } from '@rocket.chat/random'; import { Match, check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; +import { dispatchInquiryPosition } from '../../../../ee/app/livechat-enterprise/server/lib/Helper'; import { callbacks } from '../../../../lib/callbacks'; import { sendNotification } from '../../../lib/server'; import { @@ -27,6 +28,7 @@ import { i18n } from '../../../utils/lib/i18n'; import { createLivechatRoom, createLivechatInquiry, allowAgentSkipQueue } from './Helper'; import { Livechat } from './LivechatTyped'; import { RoutingManager } from './RoutingManager'; +import { getInquirySortMechanismSetting } from './settings'; const logger = new Logger('QueueManager'); @@ -259,6 +261,18 @@ export class QueueManager { throw new Error('room-not-found'); } + if (!newRoom.servedBy && settings.get('Omnichannel_calculate_dispatch_service_queue_statistics')) { + const [inq] = await LivechatInquiry.getCurrentSortedQueueAsync({ + inquiryId: inquiry._id, + department, + queueSortBy: getInquirySortMechanismSetting(), + }); + + if (inq) { + void dispatchInquiryPosition(inq); + } + } + return newRoom; } diff --git a/apps/meteor/ee/app/livechat-enterprise/server/lib/Helper.ts b/apps/meteor/ee/app/livechat-enterprise/server/lib/Helper.ts index 08ea48910f02..9d4b413d218a 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/lib/Helper.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/lib/Helper.ts @@ -107,15 +107,11 @@ export const dispatchInquiryPosition = async (inquiry: Omit) => { + return setTimeout(() => { void api.broadcast('omnichannel.room', inquiry.rid, { type: 'queueData', data, }); - }; - - return setTimeout(() => { - propagateInquiryPosition(inquiry); }, 1000); }; From 5ecdaff8539e15526d84268613f75fc7ac263098 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Sat, 3 Aug 2024 14:36:02 +0000 Subject: [PATCH 03/80] Release 6.11.0-rc.3 [no ci] --- .changeset/bump-patch-1722695753777.md | 5 +++ .changeset/pre.json | 1 + apps/meteor/CHANGELOG.md | 32 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 ++++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 ++++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 ++++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 15 +++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 ++++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 ++++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 ++++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 +++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/api-client/CHANGELOG.md | 10 ++++++ ee/packages/api-client/package.json | 2 +- ee/packages/ddp-client/CHANGELOG.md | 10 ++++++ ee/packages/ddp-client/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 ++++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 ++++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 ++++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 +++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/apps/CHANGELOG.md | 10 ++++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 +++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 ++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 ++++++ packages/cron/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 ++++++++ packages/fuselage-ui-kit/package.json | 8 ++--- packages/gazzodown/CHANGELOG.md | 11 +++++++ packages/gazzodown/package.json | 6 ++-- packages/instance-status/CHANGELOG.md | 9 ++++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 ++++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 ++++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 ++++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 ++++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 ++++++ packages/ui-avatar/package.json | 4 +-- packages/ui-client/CHANGELOG.md | 9 ++++++ packages/ui-client/package.json | 4 +-- packages/ui-contexts/CHANGELOG.md | 11 +++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 ++++++ packages/ui-video-conf/package.json | 6 ++-- packages/uikit-playground/CHANGELOG.md | 11 +++++++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 9 ++++++ packages/web-ui-registration/package.json | 4 +-- yarn.lock | 20 ++++++------ 69 files changed, 422 insertions(+), 54 deletions(-) create mode 100644 .changeset/bump-patch-1722695753777.md diff --git a/.changeset/bump-patch-1722695753777.md b/.changeset/bump-patch-1722695753777.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1722695753777.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/pre.json b/.changeset/pre.json index 38a7fe160e48..d4757b9380d4 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -65,6 +65,7 @@ "afraid-guests-jog", "bump-patch-1722087664914", "bump-patch-1722559871139", + "bump-patch-1722695753777", "chatty-hounds-hammer", "chilled-yaks-beg", "chilly-papayas-march", diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index c80c36bf4890..cc355a5f68a5 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,37 @@ # @rocket.chat/meteor +## 6.11.0-rc.3 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/rest-typings@6.11.0-rc.3 + - @rocket.chat/api-client@0.2.3-rc.3 + - @rocket.chat/license@0.2.3-rc.3 + - @rocket.chat/omnichannel-services@0.3.0-rc.3 + - @rocket.chat/pdf-worker@0.2.0-rc.3 + - @rocket.chat/presence@0.2.3-rc.3 + - @rocket.chat/apps@0.1.3-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/cron@0.1.3-rc.3 + - @rocket.chat/fuselage-ui-kit@9.0.0-rc.3 + - @rocket.chat/gazzodown@9.0.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/ui-contexts@9.0.0-rc.3 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.0-rc.3 + - @rocket.chat/ui-theming@0.2.0 + - @rocket.chat/ui-avatar@5.0.0-rc.3 + - @rocket.chat/ui-client@9.0.0-rc.3 + - @rocket.chat/ui-video-conf@9.0.0-rc.3 + - @rocket.chat/web-ui-registration@9.0.0-rc.3 + - @rocket.chat/instance-status@0.1.3-rc.3 +
+ ## 6.11.0-rc.2 ### Patch Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index b2dc220a6d51..976a2d1c1198 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.11.0-rc.2" + "version": "6.11.0-rc.3" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 4f5beb9327cb..d4ce5dfb6408 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.3.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/rest-typings@6.11.0-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 1.3.0-rc.2 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index f28d34faa40f..4aeb62869734 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.0-rc.2", + "version": "1.3.0-rc.3", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 45bd640fed45..7c80995a89bc 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.11.0-rc.2", + "version": "6.11.0-rc.3", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 13f5a86d0f67..f4528f2b2c98 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/rest-typings@6.11.0-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.4.3-rc.2 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index a4a29c5f7aaa..7f642163a3d2 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.3-rc.2", + "version": "0.4.3-rc.3", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index 3e65906e0c1b..ca97afb60b94 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/rest-typings@6.11.0-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.4.3-rc.2 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 043d203cca88..19c94e3a1d7f 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.3-rc.2", + "version": "0.4.3-rc.3", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index cc5d65a49914..2d5d3801320d 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/ddp-streamer +## 0.3.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/rest-typings@6.11.0-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/ui-contexts@9.0.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 + - @rocket.chat/instance-status@0.1.3-rc.3 +
+ ## 0.3.3-rc.2 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 562c3eca03e6..0b8f0993162b 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.3-rc.2", + "version": "0.3.3-rc.3", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index e9d49967c49f..4ac9716efcfb 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/omnichannel-services@0.3.0-rc.3 + - @rocket.chat/pdf-worker@0.2.0-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.4.3-rc.2 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 5976e940ea84..246623b55f4f 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.3-rc.2", + "version": "0.4.3-rc.3", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 40771ea7ca96..900e6a69120b 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/presence@0.2.3-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.4.3-rc.2 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 1153188bffe1..8e8d1a877d47 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.3-rc.2", + "version": "0.4.3-rc.3", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index bac927b65d20..6b622cbd9ee0 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/omnichannel-services@0.3.0-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.4.3-rc.2 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index c117382266a6..8d5f0f380f9e 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.3-rc.2", + "version": "0.4.3-rc.3", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 955104ad6cb3..da60a3ebf20b 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.4.3-rc.2 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index d3fb0d4b4950..0859e03ec9e5 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.3-rc.2", + "version": "0.4.3-rc.3", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/api-client/CHANGELOG.md b/ee/packages/api-client/CHANGELOG.md index 8c9a3c2b1cc6..47d4bd7668eb 100644 --- a/ee/packages/api-client/CHANGELOG.md +++ b/ee/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/rest-typings@6.11.0-rc.3 +
+ ## 0.2.3-rc.2 ### Patch Changes diff --git a/ee/packages/api-client/package.json b/ee/packages/api-client/package.json index 1bbd8d6b0b87..89c9c496463f 100644 --- a/ee/packages/api-client/package.json +++ b/ee/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.3-rc.2", + "version": "0.2.3-rc.3", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/ddp-client/CHANGELOG.md b/ee/packages/ddp-client/CHANGELOG.md index ed49a458277e..689116b0ccda 100644 --- a/ee/packages/ddp-client/CHANGELOG.md +++ b/ee/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ddp-client +## 0.3.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/rest-typings@6.11.0-rc.3 + - @rocket.chat/api-client@0.2.3-rc.3 +
+ ## 0.3.3-rc.2 ### Patch Changes diff --git a/ee/packages/ddp-client/package.json b/ee/packages/ddp-client/package.json index 2b57bb6bef78..fcd53133bc45 100644 --- a/ee/packages/ddp-client/package.json +++ b/ee/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.3-rc.2", + "version": "0.3.3-rc.3", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index e29f97b6929c..760586616052 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 +
+ ## 0.2.3-rc.2 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 87da017b63fb..0545fdadb2ec 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.3-rc.2", + "version": "0.2.3-rc.3", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 457e8d0236c5..c499efe0ea2e 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/rest-typings@6.11.0-rc.3 + - @rocket.chat/pdf-worker@0.2.0-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.3.0-rc.2 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 8729b1ac28d4..cb9fed1eced8 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.0-rc.2", + "version": "0.3.0-rc.3", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index d5e341a2360d..3afd228e31db 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 +
+ ## 0.2.0-rc.2 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 938f6bc34432..376b060af775 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.0-rc.2", + "version": "0.2.0-rc.3", "private": true, "devDependencies": { "@storybook/addon-essentials": "~6.5.16", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index d8c531e3d72d..b8bbdd1c6259 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/core-services@0.5.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.2.3-rc.2 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 83678740fc4b..281775624a9f 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.3-rc.2", + "version": "0.2.3-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index 339a74271975..fc76a3d44ca4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.11.0-rc.2", + "version": "6.11.0-rc.3", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 0c686c073432..307ade401d44 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/model-typings@0.6.0-rc.3 +
+ ## 0.1.3-rc.2 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 9c7306d5cf79..7480a03b04ac 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.3-rc.2", + "version": "0.1.3-rc.3", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index 286b003068d3..b6c09da269a1 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.5.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/rest-typings@6.11.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.5.0-rc.2 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 079cd766af3d..372232ca9d3d 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.5.0-rc.2", + "version": "0.5.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index 2d62b835be92..2051bf53528d 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.11.0-rc.3 + ## 6.11.0-rc.2 ## 6.11.0-rc.1 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 4d44193ca672..9063cf39fc06 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.11.0-rc.2", + "version": "6.11.0-rc.3", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 1fd83782f500..e94eea377caa 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.1.3-rc.2 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index 028de546744c..43c36e9c0c57 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.3-rc.2", + "version": "0.1.3-rc.3", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 0009b0237063..b44f3ff536c7 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 9.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/gazzodown@9.0.0-rc.3 + - @rocket.chat/ui-contexts@9.0.0-rc.3 + - @rocket.chat/ui-avatar@5.0.0-rc.3 + - @rocket.chat/ui-video-conf@9.0.0-rc.3 +
+ ## 9.0.0-rc.2 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index f14aeb67719f..44be4babdc34 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "9.0.0-rc.2", + "version": "9.0.0-rc.3", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.0-rc.2", - "@rocket.chat/ui-contexts": "9.0.0-rc.2", + "@rocket.chat/ui-avatar": "5.0.0-rc.3", + "@rocket.chat/ui-contexts": "9.0.0-rc.3", "@rocket.chat/ui-kit": "0.36.0-rc.0", - "@rocket.chat/ui-video-conf": "9.0.0-rc.2", + "@rocket.chat/ui-video-conf": "9.0.0-rc.3", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 7e60bdcb4e5f..e3ae037777a7 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 9.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/ui-contexts@9.0.0-rc.3 + - @rocket.chat/ui-client@9.0.0-rc.3 +
+ ## 9.0.0-rc.2 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index a90d765208ad..68fb28175c46 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "9.0.0-rc.2", + "version": "9.0.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -71,8 +71,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "9.0.0-rc.2", - "@rocket.chat/ui-contexts": "9.0.0-rc.2", + "@rocket.chat/ui-client": "9.0.0-rc.3", + "@rocket.chat/ui-contexts": "9.0.0-rc.3", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index 77382a05d6a6..5f6778ac7ebb 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.2.0-rc.3 +
+ ## 0.1.3-rc.2 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 09d81c81b1e6..978efda3228d 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.3-rc.2", + "version": "0.1.3-rc.3", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index c5e1fa9c91dc..e3b85ec2e06a 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.19.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@9.0.0-rc.3 +
+ ## 1.19.0-rc.2 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index af91b807ca2c..56bbf4c5aec2 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.0-rc.2", + "version": "1.19.0-rc.3", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 9608c678e649..0dacd0e498a2 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.6.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 +
+ ## 0.6.0-rc.2 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index ca0195079e91..e61461f13907 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.6.0-rc.2", + "version": "0.6.0-rc.3", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 375dd26f6aeb..5b6a99588bff 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.2.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.6.0-rc.3 +
+ ## 0.2.0-rc.2 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index 8a7c50d8f2d0..0443b3c39831 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.0-rc.2", + "version": "0.2.0-rc.3", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 3be5f4643578..486d5bba1313 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.11.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 +
+ ## 6.11.0-rc.2 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index a4323af82e40..a278a3a527bc 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.11.0-rc.2", + "version": "6.11.0-rc.3", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "@types/jest": "~29.5.7", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index f0b0b7b7fe99..1f19f7615382 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 5.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.0-rc.3 +
+ ## 5.0.0-rc.2 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 77d7af5288d1..0b78657b51dc 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "5.0.0-rc.2", + "version": "5.0.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "9.0.0-rc.2", + "@rocket.chat/ui-contexts": "9.0.0-rc.3", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index a08ff45507d9..ca9ab371c41a 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 9.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.0-rc.3 +
+ ## 9.0.0-rc.2 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index feb8eabcda14..ff483766daad 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "9.0.0-rc.2", + "version": "9.0.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -63,7 +63,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "9.0.0-rc.2", + "@rocket.chat/ui-contexts": "9.0.0-rc.3", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index f2bbb77a501c..9907912c5562 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 9.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.3 + - @rocket.chat/rest-typings@6.11.0-rc.3 + - @rocket.chat/ddp-client@0.3.3-rc.3 +
+ ## 9.0.0-rc.2 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index f9833521673c..4183d0a0e2fb 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "9.0.0-rc.2", + "version": "9.0.0-rc.3", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 4acd711bd304..be2e4e9444b6 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 9.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.0-rc.3 + - @rocket.chat/ui-avatar@5.0.0-rc.3 +
+ ## 9.0.0-rc.2 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 6991762ada03..f585656d72e0 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "9.0.0-rc.2", + "version": "9.0.0-rc.3", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -36,8 +36,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.0-rc.2", - "@rocket.chat/ui-contexts": "9.0.0-rc.2", + "@rocket.chat/ui-avatar": "5.0.0-rc.3", + "@rocket.chat/ui-contexts": "9.0.0-rc.3", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index d1aa257adf5c..d65421b1115b 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.3.3-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@9.0.0-rc.3 + - @rocket.chat/ui-contexts@9.0.0-rc.3 + - @rocket.chat/ui-avatar@5.0.0-rc.3 +
+ ## 0.3.3-rc.2 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 101e45a56559..bfb647c2d28e 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.3.3-rc.2", + "version": "0.3.3-rc.3", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index e6d4fa500e47..98d721324216 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 9.0.0-rc.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.0-rc.3 +
+ ## 9.0.0-rc.2 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 3144b1a58176..96479929263c 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "9.0.0-rc.2", + "version": "9.0.0-rc.3", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -51,7 +51,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2-rc.0", - "@rocket.chat/ui-contexts": "9.0.0-rc.2", + "@rocket.chat/ui-contexts": "9.0.0-rc.3", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", diff --git a/yarn.lock b/yarn.lock index 2e401aa7cc04..78f33041365c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8968,10 +8968,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0-rc.1 - "@rocket.chat/ui-contexts": 9.0.0-rc.1 + "@rocket.chat/ui-avatar": 5.0.0-rc.2 + "@rocket.chat/ui-contexts": 9.0.0-rc.2 "@rocket.chat/ui-kit": 0.36.0-rc.0 - "@rocket.chat/ui-video-conf": 9.0.0-rc.1 + "@rocket.chat/ui-video-conf": 9.0.0-rc.2 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9060,8 +9060,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 9.0.0-rc.1 - "@rocket.chat/ui-contexts": 9.0.0-rc.1 + "@rocket.chat/ui-client": 9.0.0-rc.2 + "@rocket.chat/ui-contexts": 9.0.0-rc.2 katex: "*" react: "*" languageName: unknown @@ -10281,7 +10281,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 9.0.0-rc.1 + "@rocket.chat/ui-contexts": 9.0.0-rc.2 react: ~17.0.2 languageName: unknown linkType: soft @@ -10334,7 +10334,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 9.0.0-rc.1 + "@rocket.chat/ui-contexts": 9.0.0-rc.2 react: ~17.0.2 languageName: unknown linkType: soft @@ -10510,8 +10510,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0-rc.1 - "@rocket.chat/ui-contexts": 9.0.0-rc.1 + "@rocket.chat/ui-avatar": 5.0.0-rc.2 + "@rocket.chat/ui-contexts": 9.0.0-rc.2 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10601,7 +10601,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2-rc.0 - "@rocket.chat/ui-contexts": 9.0.0-rc.1 + "@rocket.chat/ui-contexts": 9.0.0-rc.2 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From dea72b5d9febf346f060573908c9db7383ae10dc Mon Sep 17 00:00:00 2001 From: Debdut Chakraborty Date: Mon, 5 Aug 2024 19:34:05 +0530 Subject: [PATCH 04/80] regression: default to already stored value not value from code (#32870) Co-authored-by: Guilherme Gazzo Co-authored-by: Marcos Spessatto Defendi --- .../app/settings/server/SettingsRegistry.ts | 6 +- .../server/functions/settings.tests.ts | 66 +++++++++++++++++-- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/apps/meteor/app/settings/server/SettingsRegistry.ts b/apps/meteor/app/settings/server/SettingsRegistry.ts index e86a391ad8fa..d7d2fa0a79f8 100644 --- a/apps/meteor/app/settings/server/SettingsRegistry.ts +++ b/apps/meteor/app/settings/server/SettingsRegistry.ts @@ -139,6 +139,7 @@ export class SettingsRegistry { const settingFromCodeOverwritten = overwriteSetting(settingFromCode); const settingStored = this.store.getSetting(_id); + const settingStoredOverwritten = settingStored && overwriteSetting(settingStored); try { @@ -166,7 +167,10 @@ export class SettingsRegistry { })(); await this.saveUpdatedSetting(_id, updatedProps, removedKeys); - this.store.set(settingFromCodeOverwritten); + if ('value' in updatedProps) { + this.store.set(updatedProps as ISetting); + } + return; } diff --git a/apps/meteor/tests/unit/app/settings/server/functions/settings.tests.ts b/apps/meteor/tests/unit/app/settings/server/functions/settings.tests.ts index 3f409881b259..5f5001c0251d 100644 --- a/apps/meteor/tests/unit/app/settings/server/functions/settings.tests.ts +++ b/apps/meteor/tests/unit/app/settings/server/functions/settings.tests.ts @@ -448,7 +448,7 @@ describe('Settings', () => { .to.not.have.any.keys('section'); }); - it('should ignore setting object from code if only value changes and setting already stored', async () => { + it('should ignore setting object from code if only value changes in code and setting already stored', async () => { const settings = new CachedSettings(); Settings.settings = settings; settings.initialized(); @@ -467,7 +467,60 @@ describe('Settings', () => { expect(Settings.upsertCalls).to.be.equal(0); }); - it('should ignore value from environment if setting is already stored', async () => { + it('should not update (reset) cached setting with value in code if some prop in code changes (including value)', async () => { + Settings.setDelay(1000); + const settings = new CachedSettings(); + process.env[`OVERWRITE_SETTING_${testSetting._id}`] = 'false'; + const storedSetting = { ...testSetting, value: true, packageValue: true }; + settings.set(storedSetting); + + Settings.settings = settings; + + settings.initialized(); + + expect(settings.get(storedSetting._id)).to.be.equal(true); + + const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any }); + + const settingFromCodeFaked = { + ...storedSetting, + value: true, + enterprise: true, + invalidValue: '', + }; + + await settingsRegistry.add(settingFromCodeFaked._id, settingFromCodeFaked.value, settingFromCodeFaked); + + expect(Settings.insertCalls).to.be.equal(0); + expect(Settings.upsertCalls).to.be.equal(1); + + expect(settings.get(storedSetting._id)).to.be.equal(false); + }); + + it('should update cached setting with value from environment if some prop including value in code changes', async () => { + const settings = new CachedSettings(); + Settings.settings = settings; + settings.initialized(); + const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any }); + + await settingsRegistry.add(testSetting._id, testSetting.value, testSetting); + + expect(Settings.insertCalls).to.be.equal(1); + Settings.insertCalls = 0; + + const settingFromCodeFaked = { ...testSetting, value: Date.now().toString(), enterprise: true, invalidValue: '' }; + + process.env[`OVERWRITE_SETTING_${testSetting._id}`] = Date.now().toString(); + + await settingsRegistry.add(settingFromCodeFaked._id, settingFromCodeFaked.value, settingFromCodeFaked); + + expect(Settings.insertCalls).to.be.equal(0); + expect(Settings.upsertCalls).to.be.equal(1); + + expect(settings.get(testSetting._id)).to.be.equal(process.env[`OVERWRITE_SETTING_${testSetting._id}`]); + }); + + it('should ignore default value from environment if setting is already stored', async () => { const settings = new CachedSettings(); Settings.settings = settings; settings.initialized(); @@ -482,12 +535,14 @@ describe('Settings', () => { expect(Settings.findOne({ _id: testSetting._id }).value).to.be.equal(testSetting.value); }); - it('should update setting cache synchronously if overwrite is available in enviornment', async () => { + it('should update setting cache synchronously if overwrite is available in environment', async () => { const settings = new CachedSettings(); Settings.settings = settings; settings.initialized(); const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any }); + settings.set(testSetting); + process.env[`OVERWRITE_SETTING_${testSetting._id}`] = Date.now().toString(); await settingsRegistry.add(testSetting._id, testSetting.value, testSetting); @@ -495,7 +550,7 @@ describe('Settings', () => { expect(settings.get(testSetting._id)).to.be.equal(process.env[`OVERWRITE_SETTING_${testSetting._id}`]); }); - it('should update cached value with OVERWRITE_SETTING value even if both with-prefixed and without-prefixed variables exist', async () => { + it('should update cached value with OVERWRITE_SETTING value even if both overwrite and default overwrite variables both exist', async () => { const settings = new CachedSettings(); Settings.settings = settings; settings.initialized(); @@ -506,7 +561,8 @@ describe('Settings', () => { await settingsRegistry.add(testSetting._id, testSetting.value, testSetting); - expect(Settings.findOne({ _id: testSetting._id }).value).to.be.equal(process.env[`OVERWRITE_SETTING_${testSetting._id}`]); + expect(Settings.insertCalls).to.be.equal(1); + expect(settings.get(testSetting._id)).to.be.equal(process.env[`OVERWRITE_SETTING_${testSetting._id}`]); }); it('should call `settings.get` callback on setting added', async () => { From 2db5155c045dae7d5aefd83db3dbbba022fbe0bf Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Mon, 5 Aug 2024 13:10:13 -0300 Subject: [PATCH 05/80] feat: Upgrade `fuselage-toastbar` adding pause on hover (#32969) --- .changeset/strong-swans-double.md | 6 ++++++ apps/meteor/package.json | 2 +- packages/uikit-playground/package.json | 2 +- yarn.lock | 23 +++++++++++++++++------ 4 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 .changeset/strong-swans-double.md diff --git a/.changeset/strong-swans-double.md b/.changeset/strong-swans-double.md new file mode 100644 index 000000000000..db521aeeef0f --- /dev/null +++ b/.changeset/strong-swans-double.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/uikit-playground': minor +'@rocket.chat/meteor': minor +--- + +Upgrades fuselage-toastbar version in order to add pause on hover functionality diff --git a/apps/meteor/package.json b/apps/meteor/package.json index a712ac548e36..5e5c0cc6877e 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -246,7 +246,7 @@ "@rocket.chat/fuselage": "^0.57.0", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", - "@rocket.chat/fuselage-toastbar": "^0.32.0", + "@rocket.chat/fuselage-toastbar": "^0.33.0", "@rocket.chat/fuselage-tokens": "^0.33.1", "@rocket.chat/fuselage-ui-kit": "workspace:^", "@rocket.chat/gazzodown": "workspace:^", diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 3c3c6405a75d..7ffc102699bc 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -18,7 +18,7 @@ "@rocket.chat/fuselage": "^0.57.0", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", - "@rocket.chat/fuselage-toastbar": "^0.32.0", + "@rocket.chat/fuselage-toastbar": "^0.33.0", "@rocket.chat/fuselage-tokens": "^0.33.1", "@rocket.chat/fuselage-ui-kit": "workspace:~", "@rocket.chat/icons": "^0.36.0", diff --git a/yarn.lock b/yarn.lock index cbaed225e131..56da32a6f5ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8876,9 +8876,11 @@ __metadata: languageName: node linkType: hard -"@rocket.chat/fuselage-toastbar@npm:^0.32.0": - version: 0.32.0 - resolution: "@rocket.chat/fuselage-toastbar@npm:0.32.0" +"@rocket.chat/fuselage-toastbar@npm:^0.33.0": + version: 0.33.0 + resolution: "@rocket.chat/fuselage-toastbar@npm:0.33.0" + dependencies: + react-timing-hooks: ~4.0.2 peerDependencies: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" @@ -8886,7 +8888,7 @@ __metadata: "@rocket.chat/styled": "*" react: ^17.0.2 react-dom: ^17.0.2 - checksum: 5e78516aee6446da4c76dac10ff83adb4deeb86d6111c42419f0629c35ec64b19ae6ab563f20b5efa2600c9c723b9096edc3c166e960fd25cfda1f07c4df3f3f + checksum: 97993ad2acdc5a742b71c94f9d321e090769c4116ab52208c2103ca41d4455bc4cd15c0cd0a1f8545144910a8c7f7de645ee150c0d8fc6b746001244690de2ed languageName: node linkType: hard @@ -9385,7 +9387,7 @@ __metadata: "@rocket.chat/fuselage": ^0.57.0 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 - "@rocket.chat/fuselage-toastbar": ^0.32.0 + "@rocket.chat/fuselage-toastbar": ^0.33.0 "@rocket.chat/fuselage-tokens": ^0.33.1 "@rocket.chat/fuselage-ui-kit": "workspace:^" "@rocket.chat/gazzodown": "workspace:^" @@ -10547,7 +10549,7 @@ __metadata: "@rocket.chat/fuselage": ^0.57.0 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/fuselage-polyfills": ~0.31.25 - "@rocket.chat/fuselage-toastbar": ^0.32.0 + "@rocket.chat/fuselage-toastbar": ^0.33.0 "@rocket.chat/fuselage-tokens": ^0.33.1 "@rocket.chat/fuselage-ui-kit": "workspace:~" "@rocket.chat/icons": ^0.36.0 @@ -35804,6 +35806,15 @@ __metadata: languageName: node linkType: hard +"react-timing-hooks@npm:~4.0.2": + version: 4.0.2 + resolution: "react-timing-hooks@npm:4.0.2" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 95ebcaffe400f3e1af32bd82eb92258c5e1473e43a7edf65879692117946105bb21f4e91046fdc85c8c737997be1d8148bffacfde8a8a9ee835d81415048119e + languageName: node + linkType: hard + "react-virtuoso@npm:^4.7.1": version: 4.7.1 resolution: "react-virtuoso@npm:4.7.1" From e2a750f316d72d8a7e6f33af195faa009bba8078 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Mon, 5 Aug 2024 15:19:28 -0300 Subject: [PATCH 06/80] chore: move afterOmnichannelSaveMessage hook to work with updater (#32978) Co-authored-by: Guilherme Gazzo --- .../server/hooks/afterSaveOmnichannelMessage.ts | 12 ++++++++++-- .../app/livechat/server/hooks/saveAnalyticsData.ts | 10 ++-------- apps/meteor/lib/callbacks.ts | 3 ++- apps/meteor/server/models/raw/LivechatRooms.ts | 10 +++++++--- .../model-typings/src/models/ILivechatRoomsModel.ts | 2 ++ 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts b/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts index 8badfb07177e..372704d339bb 100644 --- a/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts +++ b/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts @@ -1,15 +1,23 @@ import { isOmnichannelRoom } from '@rocket.chat/core-typings'; +import { LivechatRooms } from '@rocket.chat/models'; import { callbacks } from '../../../../lib/callbacks'; callbacks.add( 'afterSaveMessage', async (message, room) => { - // only call webhook if it is a livechat room if (!isOmnichannelRoom(room)) { return message; } - return callbacks.run('afterOmnichannelSaveMessage', message, { room }); + + const updater = LivechatRooms.getUpdater(); + const result = await callbacks.run('afterOmnichannelSaveMessage', message, { room, roomUpdater: updater }); + + if (updater.hasChanges()) { + await updater.persist({ _id: room._id }); + } + + return result; }, callbacks.priority.MEDIUM, 'after-omnichannel-save-message', diff --git a/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.ts b/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.ts index 07802b75553c..fef6ad0936f8 100644 --- a/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.ts +++ b/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.ts @@ -61,7 +61,7 @@ const getAnalyticsData = (room: IOmnichannelRoom, now: Date): Record { + async (message, { room, roomUpdater }) => { if (!message || isEditedMessage(message)) { return message; } @@ -71,13 +71,7 @@ callbacks.add( } const analyticsData = getAnalyticsData(room, new Date()); - const updater = await LivechatRooms.getAnalyticsUpdateQueryByRoomId(room, message, analyticsData); - - if (updater.hasChanges()) { - await updater.persist({ - _id: room._id, - }); - } + await LivechatRooms.getAnalyticsUpdateQueryByRoomId(room, message, analyticsData, roomUpdater); return message; }, diff --git a/apps/meteor/lib/callbacks.ts b/apps/meteor/lib/callbacks.ts index 044e70580e5b..eb8e032804f7 100644 --- a/apps/meteor/lib/callbacks.ts +++ b/apps/meteor/lib/callbacks.ts @@ -23,6 +23,7 @@ import type { MessageMention, OmnichannelSourceType, } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/models'; import type { FilterOperators } from 'mongodb'; import type { ILoginAttempt } from '../app/authentication/server/ILoginAttempt'; @@ -50,7 +51,7 @@ interface EventLikeCallbackSignatures { 'afterFileUpload': (params: { user: IUser; room: IRoom; message: IMessage }) => void; 'afterRoomNameChange': (params: { rid: string; name: string; oldName: string }) => void; 'afterSaveMessage': (message: IMessage, room: IRoom, uid?: string) => void; - 'afterOmnichannelSaveMessage': (message: IMessage, constant: { room: IOmnichannelRoom }) => void; + 'afterOmnichannelSaveMessage': (message: IMessage, constant: { room: IOmnichannelRoom; roomUpdater: Updater }) => void; 'livechat.removeAgentDepartment': (params: { departmentId: ILivechatDepartmentRecord['_id']; agentsId: ILivechatAgent['_id'][] }) => void; 'livechat.saveAgentDepartment': (params: { departmentId: ILivechatDepartmentRecord['_id']; agentsId: ILivechatAgent['_id'][] }) => void; 'livechat.closeRoom': (params: { room: IOmnichannelRoom; options: CloseRoomParams['options'] }) => void; diff --git a/apps/meteor/server/models/raw/LivechatRooms.ts b/apps/meteor/server/models/raw/LivechatRooms.ts index dfb0143cb984..d6a6711d06c9 100644 --- a/apps/meteor/server/models/raw/LivechatRooms.ts +++ b/apps/meteor/server/models/raw/LivechatRooms.ts @@ -78,6 +78,10 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive ]; } + getUpdater(): Updater { + return super.getUpdater(); + } + getQueueMetrics({ departmentId, agentId, @@ -2056,7 +2060,7 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive return this.getAnalyticsUpdateQuery(analyticsData, updater).set('metrics.servedBy.lr', message.ts); } - return updater; + return this.getAnalyticsUpdateQuery(analyticsData, updater); } private getAnalyticsUpdateQueryBySentByVisitor( @@ -2071,10 +2075,10 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive // update visitor timestamp, only if its new inquiry and not continuing message if (agentLastReply >= visitorLastQuery) { - return this.getAnalyticsUpdateQuery(analyticsData).set('metrics.v.lq', message.ts); + return this.getAnalyticsUpdateQuery(analyticsData, updater).set('metrics.v.lq', message.ts); } - return updater; + return this.getAnalyticsUpdateQuery(analyticsData, updater); } async getAnalyticsUpdateQueryByRoomId( diff --git a/packages/model-typings/src/models/ILivechatRoomsModel.ts b/packages/model-typings/src/models/ILivechatRoomsModel.ts index 8f364ad66a89..32238ccb5602 100644 --- a/packages/model-typings/src/models/ILivechatRoomsModel.ts +++ b/packages/model-typings/src/models/ILivechatRoomsModel.ts @@ -31,6 +31,8 @@ type WithOptions = { // TODO: Fix types of model export interface ILivechatRoomsModel extends IBaseModel { + getUpdater(): Updater; + getQueueMetrics(params: { departmentId: any; agentId: any; includeOfflineAgents: any; options?: any }): any; findAllNumberOfAbandonedRooms(params: Period & WithDepartment & WithOnlyCount & WithOptions): Promise; From cf778f1651c2f8498abe821cba5208ca571ff4fb Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Mon, 5 Aug 2024 18:26:49 -0300 Subject: [PATCH 07/80] chore: add updater on afterOmnichannelSaveMessage (save-last-visitor-message-timestamp) hook (#32977) --- .../server/hooks/saveLastVisitorMessageTs.ts | 11 +++++------ apps/meteor/server/models/raw/LivechatRooms.ts | 13 ++----------- .../model-typings/src/models/ILivechatRoomsModel.ts | 2 +- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/apps/meteor/app/livechat/server/hooks/saveLastVisitorMessageTs.ts b/apps/meteor/app/livechat/server/hooks/saveLastVisitorMessageTs.ts index bdaedfed19f2..03dcfdbf81bd 100644 --- a/apps/meteor/app/livechat/server/hooks/saveLastVisitorMessageTs.ts +++ b/apps/meteor/app/livechat/server/hooks/saveLastVisitorMessageTs.ts @@ -5,15 +5,14 @@ import { callbacks } from '../../../../lib/callbacks'; callbacks.add( 'afterOmnichannelSaveMessage', - async (message, { room }) => { - if (message.t) { - return message; - } - if (!isMessageFromVisitor(message)) { + async (message, { roomUpdater }) => { + if (message.t || !isMessageFromVisitor(message)) { return message; } - await LivechatRooms.setVisitorLastMessageTimestampByRoomId(room._id, message.ts); + await LivechatRooms.getVisitorLastMessageTsUpdateQueryByRoomId(message.ts, roomUpdater); + + return message; }, callbacks.priority.HIGH, 'save-last-visitor-message-timestamp', diff --git a/apps/meteor/server/models/raw/LivechatRooms.ts b/apps/meteor/server/models/raw/LivechatRooms.ts index d6a6711d06c9..b88ae1eb767a 100644 --- a/apps/meteor/server/models/raw/LivechatRooms.ts +++ b/apps/meteor/server/models/raw/LivechatRooms.ts @@ -2403,17 +2403,8 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive return this.deleteOne(query); } - setVisitorLastMessageTimestampByRoomId(roomId: string, lastMessageTs: Date) { - const query = { - _id: roomId, - }; - const update = { - $set: { - 'v.lastMessageTs': lastMessageTs, - }, - }; - - return this.updateOne(query, update); + getVisitorLastMessageTsUpdateQueryByRoomId(lastMessageTs: Date, updater: Updater = this.getUpdater()) { + return updater.set('v.lastMessageTs', lastMessageTs); } setVisitorInactivityInSecondsById(roomId: string, visitorInactivity: number) { diff --git a/packages/model-typings/src/models/ILivechatRoomsModel.ts b/packages/model-typings/src/models/ILivechatRoomsModel.ts index 32238ccb5602..345ecb2d768d 100644 --- a/packages/model-typings/src/models/ILivechatRoomsModel.ts +++ b/packages/model-typings/src/models/ILivechatRoomsModel.ts @@ -244,7 +244,7 @@ export interface ILivechatRoomsModel extends IBaseModel { removeAgentByRoomId(roomId: string): Promise; removeByVisitorToken(token: string): Promise; removeById(_id: string): Promise; - setVisitorLastMessageTimestampByRoomId(roomId: string, lastMessageTs: Date): Promise; + getVisitorLastMessageTsUpdateQueryByRoomId(lastMessageTs: Date, updater?: Updater): Updater; setVisitorInactivityInSecondsById(roomId: string, visitorInactivity: any): Promise; changeVisitorByRoomId(roomId: string, visitor: { _id: string; username: string; token: string }): Promise; unarchiveOneById(roomId: string): Promise; From 05de4ba54f2c5b7ad2308439478b47d5dd5146ae Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 6 Aug 2024 07:50:50 +0000 Subject: [PATCH 08/80] Release 6.11.0-rc.4 [no ci] --- .changeset/bump-patch-1722930641296.md | 5 +++ .changeset/pre.json | 1 + apps/meteor/CHANGELOG.md | 32 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 ++++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 ++++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 ++++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 15 +++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 ++++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 ++++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 ++++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 +++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/api-client/CHANGELOG.md | 10 ++++++ ee/packages/api-client/package.json | 2 +- ee/packages/ddp-client/CHANGELOG.md | 10 ++++++ ee/packages/ddp-client/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 ++++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 ++++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 ++++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 +++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/apps/CHANGELOG.md | 10 ++++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 +++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 ++ packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 ++++++ packages/cron/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 ++++++++ packages/fuselage-ui-kit/package.json | 8 ++--- packages/gazzodown/CHANGELOG.md | 11 +++++++ packages/gazzodown/package.json | 6 ++-- packages/instance-status/CHANGELOG.md | 9 ++++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 ++++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 ++++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 ++++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 ++++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 ++++++ packages/ui-avatar/package.json | 4 +-- packages/ui-client/CHANGELOG.md | 9 ++++++ packages/ui-client/package.json | 4 +-- packages/ui-contexts/CHANGELOG.md | 11 +++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 ++++++ packages/ui-video-conf/package.json | 6 ++-- packages/uikit-playground/CHANGELOG.md | 11 +++++++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 9 ++++++ packages/web-ui-registration/package.json | 4 +-- yarn.lock | 20 ++++++------ 69 files changed, 422 insertions(+), 54 deletions(-) create mode 100644 .changeset/bump-patch-1722930641296.md diff --git a/.changeset/bump-patch-1722930641296.md b/.changeset/bump-patch-1722930641296.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1722930641296.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/.changeset/pre.json b/.changeset/pre.json index d4757b9380d4..aafa9a312133 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -66,6 +66,7 @@ "bump-patch-1722087664914", "bump-patch-1722559871139", "bump-patch-1722695753777", + "bump-patch-1722930641296", "chatty-hounds-hammer", "chilled-yaks-beg", "chilly-papayas-march", diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index cc355a5f68a5..078f9815d55a 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,37 @@ # @rocket.chat/meteor +## 6.11.0-rc.4 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/rest-typings@6.11.0-rc.4 + - @rocket.chat/api-client@0.2.3-rc.4 + - @rocket.chat/license@0.2.3-rc.4 + - @rocket.chat/omnichannel-services@0.3.0-rc.4 + - @rocket.chat/pdf-worker@0.2.0-rc.4 + - @rocket.chat/presence@0.2.3-rc.4 + - @rocket.chat/apps@0.1.3-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/cron@0.1.3-rc.4 + - @rocket.chat/fuselage-ui-kit@9.0.0-rc.4 + - @rocket.chat/gazzodown@9.0.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/ui-contexts@9.0.0-rc.4 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.2.0-rc.4 + - @rocket.chat/ui-theming@0.2.0 + - @rocket.chat/ui-avatar@5.0.0-rc.4 + - @rocket.chat/ui-client@9.0.0-rc.4 + - @rocket.chat/ui-video-conf@9.0.0-rc.4 + - @rocket.chat/web-ui-registration@9.0.0-rc.4 + - @rocket.chat/instance-status@0.1.3-rc.4 +
+ ## 6.11.0-rc.3 ### Patch Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index 976a2d1c1198..2153c14b3a8b 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.11.0-rc.3" + "version": "6.11.0-rc.4" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index d4ce5dfb6408..ca444eaa3555 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.3.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/rest-typings@6.11.0-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 1.3.0-rc.3 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index 4aeb62869734..8c6a4ac724a1 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.3.0-rc.3", + "version": "1.3.0-rc.4", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 7c80995a89bc..09d90f4d913c 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.11.0-rc.3", + "version": "6.11.0-rc.4", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index f4528f2b2c98..330f4216c603 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/rest-typings@6.11.0-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.4.3-rc.3 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 7f642163a3d2..56bf0835b59c 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.3-rc.3", + "version": "0.4.3-rc.4", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index ca97afb60b94..643e846b41b6 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/rest-typings@6.11.0-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.4.3-rc.3 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 19c94e3a1d7f..58c4721655fc 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.3-rc.3", + "version": "0.4.3-rc.4", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 2d5d3801320d..c67f72caeb1d 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/ddp-streamer +## 0.3.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/rest-typings@6.11.0-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/ui-contexts@9.0.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 + - @rocket.chat/instance-status@0.1.3-rc.4 +
+ ## 0.3.3-rc.3 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 0b8f0993162b..c84454c7b60c 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.3-rc.3", + "version": "0.3.3-rc.4", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 4ac9716efcfb..fb9b79136b49 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/omnichannel-services@0.3.0-rc.4 + - @rocket.chat/pdf-worker@0.2.0-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.4.3-rc.3 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 246623b55f4f..c5f3d25fb306 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.3-rc.3", + "version": "0.4.3-rc.4", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 900e6a69120b..e0122ec3a194 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/presence@0.2.3-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.4.3-rc.3 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 8e8d1a877d47..3764076bf94c 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.3-rc.3", + "version": "0.4.3-rc.4", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 6b622cbd9ee0..9ca974747a19 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/omnichannel-services@0.3.0-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.4.3-rc.3 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 8d5f0f380f9e..4bf292e31590 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.3-rc.3", + "version": "0.4.3-rc.4", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index da60a3ebf20b..78b7c955c562 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.4.3-rc.3 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 0859e03ec9e5..17fb792a1775 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.3-rc.3", + "version": "0.4.3-rc.4", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/api-client/CHANGELOG.md b/ee/packages/api-client/CHANGELOG.md index 47d4bd7668eb..6a287f1ff106 100644 --- a/ee/packages/api-client/CHANGELOG.md +++ b/ee/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/rest-typings@6.11.0-rc.4 +
+ ## 0.2.3-rc.3 ### Patch Changes diff --git a/ee/packages/api-client/package.json b/ee/packages/api-client/package.json index 89c9c496463f..86ffc389412b 100644 --- a/ee/packages/api-client/package.json +++ b/ee/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.3-rc.3", + "version": "0.2.3-rc.4", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/ddp-client/CHANGELOG.md b/ee/packages/ddp-client/CHANGELOG.md index 689116b0ccda..521c7783a3b4 100644 --- a/ee/packages/ddp-client/CHANGELOG.md +++ b/ee/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ddp-client +## 0.3.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/rest-typings@6.11.0-rc.4 + - @rocket.chat/api-client@0.2.3-rc.4 +
+ ## 0.3.3-rc.3 ### Patch Changes diff --git a/ee/packages/ddp-client/package.json b/ee/packages/ddp-client/package.json index fcd53133bc45..86e982665438 100644 --- a/ee/packages/ddp-client/package.json +++ b/ee/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.3-rc.3", + "version": "0.3.3-rc.4", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 760586616052..97e9aa3ae9fe 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 +
+ ## 0.2.3-rc.3 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 0545fdadb2ec..e4af3354f806 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.3-rc.3", + "version": "0.2.3-rc.4", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index c499efe0ea2e..7a40ba9b076c 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.3.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/rest-typings@6.11.0-rc.4 + - @rocket.chat/pdf-worker@0.2.0-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.3.0-rc.3 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index cb9fed1eced8..4206404d1658 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.3.0-rc.3", + "version": "0.3.0-rc.4", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index 3afd228e31db..98fbca3ceccd 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.2.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 +
+ ## 0.2.0-rc.3 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 376b060af775..3ea9b604a246 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.2.0-rc.3", + "version": "0.2.0-rc.4", "private": true, "devDependencies": { "@storybook/addon-essentials": "~6.5.16", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index b8bbdd1c6259..4c6471b6f9b0 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/core-services@0.5.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.2.3-rc.3 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 281775624a9f..41b728e53a8d 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.3-rc.3", + "version": "0.2.3-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index fc76a3d44ca4..262d59132d5f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.11.0-rc.3", + "version": "6.11.0-rc.4", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 307ade401d44..bf0477edaa36 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/model-typings@0.6.0-rc.4 +
+ ## 0.1.3-rc.3 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 7480a03b04ac..c36b17380d96 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.3-rc.3", + "version": "0.1.3-rc.4", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index b6c09da269a1..de4b332aa791 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.5.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/rest-typings@6.11.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.5.0-rc.3 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 372232ca9d3d..2c9bfed68b8d 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.5.0-rc.3", + "version": "0.5.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index 2051bf53528d..0babf61dace8 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.11.0-rc.4 + ## 6.11.0-rc.3 ## 6.11.0-rc.2 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 9063cf39fc06..1c3fb9446a71 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.11.0-rc.3", + "version": "6.11.0-rc.4", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index e94eea377caa..8f40c8b0b134 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.1.3-rc.3 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index 43c36e9c0c57..5b9939747c3f 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.3-rc.3", + "version": "0.1.3-rc.4", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index b44f3ff536c7..6921e780af1a 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 9.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/gazzodown@9.0.0-rc.4 + - @rocket.chat/ui-contexts@9.0.0-rc.4 + - @rocket.chat/ui-avatar@5.0.0-rc.4 + - @rocket.chat/ui-video-conf@9.0.0-rc.4 +
+ ## 9.0.0-rc.3 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 44be4babdc34..94ea8ef1b3b3 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "9.0.0-rc.3", + "version": "9.0.0-rc.4", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.0-rc.3", - "@rocket.chat/ui-contexts": "9.0.0-rc.3", + "@rocket.chat/ui-avatar": "5.0.0-rc.4", + "@rocket.chat/ui-contexts": "9.0.0-rc.4", "@rocket.chat/ui-kit": "0.36.0-rc.0", - "@rocket.chat/ui-video-conf": "9.0.0-rc.3", + "@rocket.chat/ui-video-conf": "9.0.0-rc.4", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index e3ae037777a7..31b1f94d4a7f 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 9.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/ui-contexts@9.0.0-rc.4 + - @rocket.chat/ui-client@9.0.0-rc.4 +
+ ## 9.0.0-rc.3 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 68fb28175c46..a87e4cbcd5b9 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "9.0.0-rc.3", + "version": "9.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -71,8 +71,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "9.0.0-rc.3", - "@rocket.chat/ui-contexts": "9.0.0-rc.3", + "@rocket.chat/ui-client": "9.0.0-rc.4", + "@rocket.chat/ui-contexts": "9.0.0-rc.4", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index 5f6778ac7ebb..682dbcea8eb1 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.2.0-rc.4 +
+ ## 0.1.3-rc.3 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 978efda3228d..7179d7d1796b 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.3-rc.3", + "version": "0.1.3-rc.4", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index e3b85ec2e06a..7c585e147359 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.19.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@9.0.0-rc.4 +
+ ## 1.19.0-rc.3 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 56bbf4c5aec2..41d38e6615d5 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.19.0-rc.3", + "version": "1.19.0-rc.4", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 0dacd0e498a2..b3d90db0f34e 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.6.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 +
+ ## 0.6.0-rc.3 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index e61461f13907..6fe12d7a71bd 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.6.0-rc.3", + "version": "0.6.0-rc.4", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 5b6a99588bff..aa5a88d88981 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.2.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.6.0-rc.4 +
+ ## 0.2.0-rc.3 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index 0443b3c39831..3f1fd66b47d7 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.2.0-rc.3", + "version": "0.2.0-rc.4", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 486d5bba1313..6297a58a39ca 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.11.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 +
+ ## 6.11.0-rc.3 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index a278a3a527bc..5c53c581b326 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.11.0-rc.3", + "version": "6.11.0-rc.4", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "@types/jest": "~29.5.7", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index 1f19f7615382..99914f95c887 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 5.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.0-rc.4 +
+ ## 5.0.0-rc.3 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 0b78657b51dc..4d14b0db6476 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "5.0.0-rc.3", + "version": "5.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "9.0.0-rc.3", + "@rocket.chat/ui-contexts": "9.0.0-rc.4", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index ca9ab371c41a..c30f8b47d1e2 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 9.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.0-rc.4 +
+ ## 9.0.0-rc.3 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index ff483766daad..8c11835c701a 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "9.0.0-rc.3", + "version": "9.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -63,7 +63,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "9.0.0-rc.3", + "@rocket.chat/ui-contexts": "9.0.0-rc.4", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index 9907912c5562..7046c428ea3f 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 9.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.11.0-rc.4 + - @rocket.chat/rest-typings@6.11.0-rc.4 + - @rocket.chat/ddp-client@0.3.3-rc.4 +
+ ## 9.0.0-rc.3 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 4183d0a0e2fb..e6f1f2cfb35d 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "9.0.0-rc.3", + "version": "9.0.0-rc.4", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index be2e4e9444b6..adc27e661575 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 9.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.0-rc.4 + - @rocket.chat/ui-avatar@5.0.0-rc.4 +
+ ## 9.0.0-rc.3 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index f585656d72e0..d6552cffc0db 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "9.0.0-rc.3", + "version": "9.0.0-rc.4", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -36,8 +36,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "5.0.0-rc.3", - "@rocket.chat/ui-contexts": "9.0.0-rc.3", + "@rocket.chat/ui-avatar": "5.0.0-rc.4", + "@rocket.chat/ui-contexts": "9.0.0-rc.4", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index d65421b1115b..582f6170dab8 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.3.3-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@9.0.0-rc.4 + - @rocket.chat/ui-contexts@9.0.0-rc.4 + - @rocket.chat/ui-avatar@5.0.0-rc.4 +
+ ## 0.3.3-rc.3 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index bfb647c2d28e..3eb07bae7902 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.3.3-rc.3", + "version": "0.3.3-rc.4", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 98d721324216..4f59a6ee8db4 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 9.0.0-rc.4 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@9.0.0-rc.4 +
+ ## 9.0.0-rc.3 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 96479929263c..31f47e77466e 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "9.0.0-rc.3", + "version": "9.0.0-rc.4", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -51,7 +51,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.2-rc.0", - "@rocket.chat/ui-contexts": "9.0.0-rc.3", + "@rocket.chat/ui-contexts": "9.0.0-rc.4", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", diff --git a/yarn.lock b/yarn.lock index 78f33041365c..fd83eccadf8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8968,10 +8968,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0-rc.2 - "@rocket.chat/ui-contexts": 9.0.0-rc.2 + "@rocket.chat/ui-avatar": 5.0.0-rc.3 + "@rocket.chat/ui-contexts": 9.0.0-rc.3 "@rocket.chat/ui-kit": 0.36.0-rc.0 - "@rocket.chat/ui-video-conf": 9.0.0-rc.2 + "@rocket.chat/ui-video-conf": 9.0.0-rc.3 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9060,8 +9060,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 9.0.0-rc.2 - "@rocket.chat/ui-contexts": 9.0.0-rc.2 + "@rocket.chat/ui-client": 9.0.0-rc.3 + "@rocket.chat/ui-contexts": 9.0.0-rc.3 katex: "*" react: "*" languageName: unknown @@ -10281,7 +10281,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 9.0.0-rc.2 + "@rocket.chat/ui-contexts": 9.0.0-rc.3 react: ~17.0.2 languageName: unknown linkType: soft @@ -10334,7 +10334,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 9.0.0-rc.2 + "@rocket.chat/ui-contexts": 9.0.0-rc.3 react: ~17.0.2 languageName: unknown linkType: soft @@ -10510,8 +10510,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 5.0.0-rc.2 - "@rocket.chat/ui-contexts": 9.0.0-rc.2 + "@rocket.chat/ui-avatar": 5.0.0-rc.3 + "@rocket.chat/ui-contexts": 9.0.0-rc.3 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10601,7 +10601,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.2-rc.0 - "@rocket.chat/ui-contexts": 9.0.0-rc.2 + "@rocket.chat/ui-contexts": 9.0.0-rc.3 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From b4d8c14a3ee68c832359d3826fa2bc3d9f0cef00 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 6 Aug 2024 11:25:52 -0300 Subject: [PATCH 09/80] =?UTF-8?q?chore:=20replace=20`dtinth/setup-github-a?= =?UTF-8?q?ctions-caching-for-turbo`=20to=20use=20`rhark=E2=80=A6=20(#3299?= =?UTF-8?q?0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/build-docker/action.yml | 2 +- .github/actions/meteor-build/action.yml | 2 +- .github/workflows/ci-code-check.yml | 2 +- .github/workflows/ci-test-e2e.yml | 2 +- .github/workflows/ci-test-unit.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/new-release.yml | 2 +- .github/workflows/pr-update-description.yml | 3 +- .github/workflows/publish-release.yml | 2 +- package.json | 2 +- yarn.lock | 60 ++++++++++----------- 11 files changed, 40 insertions(+), 41 deletions(-) diff --git a/.github/actions/build-docker/action.yml b/.github/actions/build-docker/action.yml index 364957ecdf01..dbc615da889a 100644 --- a/.github/actions/build-docker/action.yml +++ b/.github/actions/build-docker/action.yml @@ -43,7 +43,7 @@ runs: tar xzf Rocket.Chat.tar.gz rm Rocket.Chat.tar.gz - - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - uses: rharkor/caching-for-turbo@v1.5 - name: Setup NodeJS uses: ./.github/actions/setup-node diff --git a/.github/actions/meteor-build/action.yml b/.github/actions/meteor-build/action.yml index d261000ceb87..c13703aeea46 100644 --- a/.github/actions/meteor-build/action.yml +++ b/.github/actions/meteor-build/action.yml @@ -91,7 +91,7 @@ runs: meteor node -v git version - - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - uses: rharkor/caching-for-turbo@v1.5 - name: Translation check shell: bash diff --git a/.github/workflows/ci-code-check.yml b/.github/workflows/ci-code-check.yml index 75deb399d2f2..fd214bc39488 100644 --- a/.github/workflows/ci-code-check.yml +++ b/.github/workflows/ci-code-check.yml @@ -42,7 +42,7 @@ jobs: # docker rmi $(docker image ls -aq) # df -h - - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - uses: rharkor/caching-for-turbo@v1.5 - name: Cache TypeCheck uses: actions/cache@v3 diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index 6ac9d751fc7a..b31f56c7a7de 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -139,7 +139,7 @@ jobs: CR_PAT: ${{ secrets.CR_PAT }} node-version: ${{ inputs.node-version }} - - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - uses: rharkor/caching-for-turbo@v1.5 - name: Start httpbin container and wait for it to be ready if: inputs.type == 'api' diff --git a/.github/workflows/ci-test-unit.yml b/.github/workflows/ci-test-unit.yml index bfb22ffa4e73..a32c1e575b8f 100644 --- a/.github/workflows/ci-test-unit.yml +++ b/.github/workflows/ci-test-unit.yml @@ -40,7 +40,7 @@ jobs: cache-modules: true install: true - - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - uses: rharkor/caching-for-turbo@v1.5 - name: Unit Test run: yarn testunit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 411aa2cc5b1a..77a8d648ae61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -161,7 +161,7 @@ jobs: restore-keys: | vite-local-cache-${{ runner.os }}- - - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - uses: rharkor/caching-for-turbo@v1.5 - name: Build Rocket.Chat Packages run: yarn build diff --git a/.github/workflows/new-release.yml b/.github/workflows/new-release.yml index f10578d5879f..5ef8027b1467 100644 --- a/.github/workflows/new-release.yml +++ b/.github/workflows/new-release.yml @@ -38,7 +38,7 @@ jobs: cache-modules: true install: true - - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - uses: rharkor/caching-for-turbo@v1.5 - name: Build packages run: yarn build diff --git a/.github/workflows/pr-update-description.yml b/.github/workflows/pr-update-description.yml index 71b4ffeda801..e792127eac9d 100644 --- a/.github/workflows/pr-update-description.yml +++ b/.github/workflows/pr-update-description.yml @@ -25,7 +25,7 @@ jobs: cache-modules: true install: true - - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - uses: rharkor/caching-for-turbo@v1.5 - name: Build packages run: yarn build @@ -36,4 +36,3 @@ jobs: action: update-pr-description env: GITHUB_TOKEN: ${{ secrets.CI_PAT }} - diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index e133a3153722..ccc3408e194e 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -28,7 +28,7 @@ jobs: cache-modules: true install: true - - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + - uses: rharkor/caching-for-turbo@v1.5 - name: Build packages run: yarn build diff --git a/package.json b/package.json index 741623a582b7..6f7980d8bfc9 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "@types/chart.js": "^2.9.39", "@types/js-yaml": "^4.0.8", "ts-node": "^10.9.2", - "turbo": "^2.0.9" + "turbo": "latest" }, "workspaces": [ "apps/*", diff --git a/yarn.lock b/yarn.lock index 56da32a6f5ed..41752957bbfe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -36860,7 +36860,7 @@ __metadata: "@types/js-yaml": ^4.0.8 node-gyp: ^9.4.1 ts-node: ^10.9.2 - turbo: ^2.0.9 + turbo: latest languageName: unknown linkType: soft @@ -40393,58 +40393,58 @@ __metadata: languageName: node linkType: hard -"turbo-darwin-64@npm:2.0.9": - version: 2.0.9 - resolution: "turbo-darwin-64@npm:2.0.9" +"turbo-darwin-64@npm:2.0.11": + version: 2.0.11 + resolution: "turbo-darwin-64@npm:2.0.11" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"turbo-darwin-arm64@npm:2.0.9": - version: 2.0.9 - resolution: "turbo-darwin-arm64@npm:2.0.9" +"turbo-darwin-arm64@npm:2.0.11": + version: 2.0.11 + resolution: "turbo-darwin-arm64@npm:2.0.11" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"turbo-linux-64@npm:2.0.9": - version: 2.0.9 - resolution: "turbo-linux-64@npm:2.0.9" +"turbo-linux-64@npm:2.0.11": + version: 2.0.11 + resolution: "turbo-linux-64@npm:2.0.11" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"turbo-linux-arm64@npm:2.0.9": - version: 2.0.9 - resolution: "turbo-linux-arm64@npm:2.0.9" +"turbo-linux-arm64@npm:2.0.11": + version: 2.0.11 + resolution: "turbo-linux-arm64@npm:2.0.11" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"turbo-windows-64@npm:2.0.9": - version: 2.0.9 - resolution: "turbo-windows-64@npm:2.0.9" +"turbo-windows-64@npm:2.0.11": + version: 2.0.11 + resolution: "turbo-windows-64@npm:2.0.11" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"turbo-windows-arm64@npm:2.0.9": - version: 2.0.9 - resolution: "turbo-windows-arm64@npm:2.0.9" +"turbo-windows-arm64@npm:2.0.11": + version: 2.0.11 + resolution: "turbo-windows-arm64@npm:2.0.11" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"turbo@npm:^2.0.9": - version: 2.0.9 - resolution: "turbo@npm:2.0.9" - dependencies: - turbo-darwin-64: 2.0.9 - turbo-darwin-arm64: 2.0.9 - turbo-linux-64: 2.0.9 - turbo-linux-arm64: 2.0.9 - turbo-windows-64: 2.0.9 - turbo-windows-arm64: 2.0.9 +"turbo@npm:latest": + version: 2.0.11 + resolution: "turbo@npm:2.0.11" + dependencies: + turbo-darwin-64: 2.0.11 + turbo-darwin-arm64: 2.0.11 + turbo-linux-64: 2.0.11 + turbo-linux-arm64: 2.0.11 + turbo-windows-64: 2.0.11 + turbo-windows-arm64: 2.0.11 dependenciesMeta: turbo-darwin-64: optional: true @@ -40460,7 +40460,7 @@ __metadata: optional: true bin: turbo: bin/turbo - checksum: 11896c5ede91c081161cc481effb922733dbae234277345144e4f9f069aeed0f2c38f9f9d25116773c348ebfe149631374e204f256a8d74486943be983547214 + checksum: a2fcb17b2549102dcd912799319a5c31cbabc3fcb76241bac1d2231ee4e1911789cd4e6b4eb050f9e8548ef89143ee77be59eb35b1843cf12b42f136ef176a0c languageName: node linkType: hard From 9939508bb379063bd772a00f01d65d1ec32c4be6 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 6 Aug 2024 12:07:20 -0300 Subject: [PATCH 10/80] chore: don't mark room as read after sending message (#32941) --- .../client/lib/chats/flows/sendMessage.ts | 1 - .../tests/end-to-end/api/subscriptions.ts | 78 ++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/apps/meteor/client/lib/chats/flows/sendMessage.ts b/apps/meteor/client/lib/chats/flows/sendMessage.ts index dbac8d808e4f..e025730682d5 100644 --- a/apps/meteor/client/lib/chats/flows/sendMessage.ts +++ b/apps/meteor/client/lib/chats/flows/sendMessage.ts @@ -57,7 +57,6 @@ export const sendMessage = async ( } chat.readStateManager.clearUnreadMark(); - await chat.readStateManager.debouncedMarkAsRead(); text = text.trim(); diff --git a/apps/meteor/tests/end-to-end/api/subscriptions.ts b/apps/meteor/tests/end-to-end/api/subscriptions.ts index c1df85bafccd..a03179569615 100644 --- a/apps/meteor/tests/end-to-end/api/subscriptions.ts +++ b/apps/meteor/tests/end-to-end/api/subscriptions.ts @@ -50,8 +50,36 @@ describe('[Subscriptions]', () => { .end(done); }); - it('/subscriptions.getOne:', () => { - it('subscriptions.getOne', (done) => { + describe('/subscriptions.getOne', () => { + it('should fail if no roomId provided', (done) => { + void request + .get(api('subscriptions.getOne')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', "must have required property 'roomId' [invalid-params]"); + }) + .end(done); + }); + + it('should fail if not logged in', (done) => { + void request + .get(api('subscriptions.getOne')) + .query({ + roomId: testChannel._id, + }) + .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 return the subscription with success', (done) => { void request .get(api('subscriptions.getOne')) .set(credentials) @@ -66,6 +94,52 @@ describe('[Subscriptions]', () => { }) .end(done); }); + + it('should keep subscription as read after sending a message', async () => { + await request + .get(api('subscriptions.getOne')) + .set(credentials) + .query({ + roomId: testChannel._id, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('subscription').and.to.be.an('object'); + expect(res.body.subscription).to.have.property('alert', false); + }); + + await request + .post(api('chat.sendMessage')) + .set(credentials) + .send({ + message: { + rid: testChannel._id, + msg: 'Sample message', + }, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('message').and.to.be.an('object'); + }); + + await request + .get(api('subscriptions.getOne')) + .set(credentials) + .query({ + roomId: testChannel._id, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('subscription').and.to.be.an('object'); + expect(res.body.subscription).to.have.property('alert', false); + }); + }); }); describe('[/subscriptions.read]', () => { From e28be46db7f70652f04a80b0422ed5acc1fd98c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?= <60678893+juliajforesti@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:22:55 -0300 Subject: [PATCH 11/80] feat: add `sidepanel` to teams api (#32868) --- .changeset/swift-maps-tickle.md | 9 +++ apps/meteor/app/api/server/v1/teams.ts | 9 ++- .../server/methods/saveRoomSettings.ts | 27 ++++++- .../app/lib/server/functions/createRoom.ts | 2 + apps/meteor/server/models/raw/Rooms.ts | 4 + apps/meteor/server/services/room/service.ts | 4 +- apps/meteor/server/services/team/service.ts | 6 +- apps/meteor/tests/end-to-end/api/rooms.ts | 70 ++++++++++++++++- apps/meteor/tests/end-to-end/api/teams.ts | 78 +++++++++++++++++++ .../core-services/src/types/IRoomService.ts | 1 + .../core-services/src/types/ITeamService.ts | 1 + packages/core-typings/src/IRoom.ts | 22 ++++++ .../model-typings/src/models/IRoomsModel.ts | 2 + packages/rest-typings/src/v1/teams/index.ts | 1 + 14 files changed, 229 insertions(+), 7 deletions(-) create mode 100644 .changeset/swift-maps-tickle.md diff --git a/.changeset/swift-maps-tickle.md b/.changeset/swift-maps-tickle.md new file mode 100644 index 000000000000..076ead1cea4c --- /dev/null +++ b/.changeset/swift-maps-tickle.md @@ -0,0 +1,9 @@ +--- +'@rocket.chat/core-services': minor +'@rocket.chat/model-typings': minor +'@rocket.chat/core-typings': minor +'@rocket.chat/rest-typings': minor +'@rocket.chat/meteor': minor +--- + +Added `sidepanel` field to `teams.create` and `rooms.saveRoomSettings` endpoints diff --git a/apps/meteor/app/api/server/v1/teams.ts b/apps/meteor/app/api/server/v1/teams.ts index 4ea8f2a48f38..f64f8c820575 100644 --- a/apps/meteor/app/api/server/v1/teams.ts +++ b/apps/meteor/app/api/server/v1/teams.ts @@ -1,6 +1,6 @@ import { Team } from '@rocket.chat/core-services'; import type { ITeam, UserStatus } from '@rocket.chat/core-typings'; -import { TEAM_TYPE } from '@rocket.chat/core-typings'; +import { TEAM_TYPE, isValidSidepanel } from '@rocket.chat/core-typings'; import { Users, Rooms } from '@rocket.chat/models'; import { isTeamsConvertToChannelProps, @@ -85,7 +85,11 @@ API.v1.addRoute( }), ); - const { name, type, members, room, owner } = this.bodyParams; + const { name, type, members, room, owner, sidepanel } = this.bodyParams; + + if (sidepanel?.items && !isValidSidepanel(sidepanel)) { + throw new Error('error-invalid-sidepanel'); + } const team = await Team.create(this.userId, { team: { @@ -95,6 +99,7 @@ API.v1.addRoute( room, members, owner, + sidepanel, }); return API.v1.success({ team }); diff --git a/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts b/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts index e3f45daa5b18..44ad253d83ef 100644 --- a/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts +++ b/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts @@ -1,6 +1,6 @@ import { Team } from '@rocket.chat/core-services'; import type { IRoom, IRoomWithRetentionPolicy, IUser, MessageTypesValues } from '@rocket.chat/core-typings'; -import { TEAM_TYPE } from '@rocket.chat/core-typings'; +import { TEAM_TYPE, isValidSidepanel } from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Rooms, Users } from '@rocket.chat/models'; import { Match } from 'meteor/check'; @@ -49,6 +49,7 @@ type RoomSettings = { favorite: boolean; defaultValue: boolean; }; + sidepanel?: IRoom['sidepanel']; }; type RoomSettingsValidators = { @@ -80,6 +81,24 @@ const validators: RoomSettingsValidators = { }); } }, + async sidepanel({ room, userId, value }) { + if (!room.teamMain) { + throw new Meteor.Error('error-action-not-allowed', 'Invalid room', { + method: 'saveRoomSettings', + }); + } + + if (!(await hasPermissionAsync(userId, 'edit-team', room._id))) { + throw new Meteor.Error('error-action-not-allowed', 'You do not have permission to change sidepanel items', { + method: 'saveRoomSettings', + }); + } + + if (!isValidSidepanel(value)) { + throw new Meteor.Error('error-invalid-sidepanel'); + } + }, + async roomType({ userId, room, value }) { if (value === room.t) { return; @@ -213,6 +232,11 @@ const settingSavers: RoomSettingsSavers = { await saveRoomTopic(rid, value, user); } }, + async sidepanel({ value, rid, room }) { + if (JSON.stringify(value) !== JSON.stringify(room.sidepanel)) { + await Rooms.setSidepanelById(rid, value); + } + }, async roomAnnouncement({ value, room, rid, user }) { if (!value && !room.announcement) { return; @@ -339,6 +363,7 @@ const fields: (keyof RoomSettings)[] = [ 'retentionOverrideGlobal', 'encrypted', 'favorite', + 'sidepanel', ]; const validate = ( diff --git a/apps/meteor/app/lib/server/functions/createRoom.ts b/apps/meteor/app/lib/server/functions/createRoom.ts index 19e5fb2f9489..183cb789051f 100644 --- a/apps/meteor/app/lib/server/functions/createRoom.ts +++ b/apps/meteor/app/lib/server/functions/createRoom.ts @@ -112,6 +112,7 @@ export const createRoom = async ( readOnly?: boolean, roomExtraData?: Partial, options?: ICreateRoomParams['options'], + sidepanel?: ICreateRoomParams['sidepanel'], ): Promise< ICreatedRoom & { rid: string; @@ -187,6 +188,7 @@ export const createRoom = async ( }, ts: now, ro: readOnly === true, + sidepanel, }; if (teamId) { diff --git a/apps/meteor/server/models/raw/Rooms.ts b/apps/meteor/server/models/raw/Rooms.ts index a4cd19a1c30a..f967068158f9 100644 --- a/apps/meteor/server/models/raw/Rooms.ts +++ b/apps/meteor/server/models/raw/Rooms.ts @@ -662,6 +662,10 @@ export class RoomsRaw extends BaseRaw implements IRoomsModel { return this.updateOne({ _id: roomId }, { $set: { name } }); } + setSidepanelById(roomId: IRoom['_id'], sidepanel: IRoom['sidepanel']): Promise { + return this.updateOne({ _id: roomId }, { $set: { sidepanel } }); + } + setFnameById(_id: IRoom['_id'], fname: IRoom['fname']): Promise { const query: Filter = { _id }; diff --git a/apps/meteor/server/services/room/service.ts b/apps/meteor/server/services/room/service.ts index b09dc865f928..3ba47284ddee 100644 --- a/apps/meteor/server/services/room/service.ts +++ b/apps/meteor/server/services/room/service.ts @@ -16,7 +16,7 @@ export class RoomService extends ServiceClassInternal implements IRoomService { protected name = 'room'; async create(uid: string, params: ICreateRoomParams): Promise { - const { type, name, members = [], readOnly, extraData, options } = params; + const { type, name, members = [], readOnly, extraData, options, sidepanel } = params; const hasPermission = await Authorization.hasPermission(uid, `create-${type}`); if (!hasPermission) { @@ -29,7 +29,7 @@ export class RoomService extends ServiceClassInternal implements IRoomService { } // TODO convert `createRoom` function to "raw" and move to here - return createRoom(type, name, user, members, false, readOnly, extraData, options) as unknown as IRoom; + return createRoom(type, name, user, members, false, readOnly, extraData, options, sidepanel) as unknown as IRoom; } async createDirectMessage({ to, from }: { to: string; from: string }): Promise<{ rid: string }> { diff --git a/apps/meteor/server/services/team/service.ts b/apps/meteor/server/services/team/service.ts index f898b1775ae9..bc4211322b66 100644 --- a/apps/meteor/server/services/team/service.ts +++ b/apps/meteor/server/services/team/service.ts @@ -37,7 +37,10 @@ import { settings } from '../../../app/settings/server'; export class TeamService extends ServiceClassInternal implements ITeamService { protected name = 'team'; - async create(uid: string, { team, room = { name: team.name, extraData: {} }, members, owner }: ITeamCreateParams): Promise { + async create( + uid: string, + { team, room = { name: team.name, extraData: {} }, members, owner, sidepanel }: ITeamCreateParams, + ): Promise { if (!(await checkUsernameAvailability(team.name))) { throw new Error('team-name-already-exists'); } @@ -120,6 +123,7 @@ export class TeamService extends ServiceClassInternal implements ITeamService { teamId, teamMain: true, }, + sidepanel, }; const createdRoom = await Room.create(owner || uid, newRoom); diff --git a/apps/meteor/tests/end-to-end/api/rooms.ts b/apps/meteor/tests/end-to-end/api/rooms.ts index a8d64b1f4c7d..d59d3722f1a4 100644 --- a/apps/meteor/tests/end-to-end/api/rooms.ts +++ b/apps/meteor/tests/end-to-end/api/rooms.ts @@ -2129,12 +2129,15 @@ describe('[Rooms]', () => { describe('rooms.saveRoomSettings', () => { let testChannel: IRoom; const randomString = `randomString${Date.now()}`; + const teamName = `team-${Date.now()}`; let discussion: IRoom; + let testTeam: ITeam; before(async () => { const result = await createRoom({ type: 'c', name: `channel.test.${Date.now()}-${Math.random()}` }); testChannel = result.body.channel; + const resTeam = await request.post(api('teams.create')).set(credentials).send({ name: teamName, type: 0 }); const resDiscussion = await request .post(api('rooms.createDiscussion')) .set(credentials) @@ -2143,10 +2146,17 @@ describe('[Rooms]', () => { t_name: `discussion-create-from-tests-${testChannel.name}`, }); + testTeam = resTeam.body.team; discussion = resDiscussion.body.discussion; }); - after(() => Promise.all([deleteRoom({ type: 'p', roomId: discussion._id }), deleteRoom({ type: 'p', roomId: testChannel._id })])); + after(() => + Promise.all([ + deleteRoom({ type: 'p', roomId: discussion._id }), + deleteTeam(credentials, testTeam.name), + deleteRoom({ type: 'p', roomId: testChannel._id }), + ]), + ); it('should update the room settings', (done) => { const imageDataUri = `data:image/png;base64,${fs.readFileSync(path.join(process.cwd(), imgURL)).toString('base64')}`; @@ -2290,6 +2300,64 @@ describe('[Rooms]', () => { expect(res.body.room).to.not.have.property('favorite'); }); }); + it('should update the team sidepanel items to channels and discussions', async () => { + const sidepanelItems = ['channels', 'discussions']; + const response = await request + .post(api('rooms.saveRoomSettings')) + .set(credentials) + .send({ + rid: testTeam.roomId, + sidepanel: { items: sidepanelItems }, + }) + .expect('Content-Type', 'application/json') + .expect(200); + + expect(response.body).to.have.property('success', true); + + const channelInfoResponse = await request + .get(api('channels.info')) + .set(credentials) + .query({ roomId: response.body.rid }) + .expect('Content-Type', 'application/json') + .expect(200); + + expect(channelInfoResponse.body).to.have.property('success', true); + expect(channelInfoResponse.body.channel).to.have.property('sidepanel'); + expect(channelInfoResponse.body.channel.sidepanel).to.have.property('items').that.is.an('array').to.have.deep.members(sidepanelItems); + }); + it('should throw error when updating team sidepanel with incorrect items', async () => { + const sidepanelItems = ['wrong']; + await request + .post(api('rooms.saveRoomSettings')) + .set(credentials) + .send({ + rid: testTeam.roomId, + sidepanel: { items: sidepanelItems }, + }) + .expect(400); + }); + it('should throw error when updating team sidepanel with more than 2 items', async () => { + const sidepanelItems = ['channels', 'discussions', 'extra']; + await request + .post(api('rooms.saveRoomSettings')) + .set(credentials) + .send({ + rid: testTeam.roomId, + sidepanel: { items: sidepanelItems }, + }) + .expect(400); + }); + it('should throw error when updating team sidepanel with duplicated items', async () => { + const sidepanelItems = ['channels', 'channels']; + await request + .post(api('rooms.saveRoomSettings')) + .set(credentials) + .send({ + rid: testTeam.roomId, + sidepanel: { items: sidepanelItems }, + }) + .expect(400); + }); }); describe('rooms.images', () => { diff --git a/apps/meteor/tests/end-to-end/api/teams.ts b/apps/meteor/tests/end-to-end/api/teams.ts index 99689650384d..425d0039e502 100644 --- a/apps/meteor/tests/end-to-end/api/teams.ts +++ b/apps/meteor/tests/end-to-end/api/teams.ts @@ -172,6 +172,84 @@ describe('[Teams]', () => { }) .end(done); }); + + it('should create a team with sidepanel items containing channels', async () => { + const teamName = `test-team-with-sidepanel-${Date.now()}`; + const sidepanelItems = ['channels']; + + const response = await request + .post(api('teams.create')) + .set(credentials) + .send({ + name: teamName, + type: 0, + sidepanel: { + items: sidepanelItems, + }, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }); + + await request + .get(api('channels.info')) + .set(credentials) + .query({ roomId: response.body.team.roomId }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((response) => { + expect(response.body).to.have.property('success', true); + expect(response.body.channel).to.have.property('sidepanel'); + expect(response.body.channel.sidepanel).to.have.property('items').that.is.an('array').to.have.deep.members(sidepanelItems); + }); + await deleteTeam(credentials, teamName); + }); + + it('should throw error when creating a team with sidepanel with more than 2 items', async () => { + await request + .post(api('teams.create')) + .set(credentials) + .send({ + name: `test-team-with-sidepanel-error-${Date.now()}`, + type: 0, + sidepanel: { + items: ['channels', 'discussion', 'other'], + }, + }) + .expect('Content-Type', 'application/json') + .expect(400); + }); + + it('should throw error when creating a team with sidepanel with incorrect items', async () => { + await request + .post(api('teams.create')) + .set(credentials) + .send({ + name: `test-team-with-sidepanel-error-${Date.now()}`, + type: 0, + sidepanel: { + items: ['other'], + }, + }) + .expect('Content-Type', 'application/json') + .expect(400); + }); + it('should throw error when creating a team with sidepanel with duplicated items', async () => { + await request + .post(api('teams.create')) + .set(credentials) + .send({ + name: `test-team-with-sidepanel-error-${Date.now()}`, + type: 0, + sidepanel: { + items: ['channels', 'channels'], + }, + }) + .expect('Content-Type', 'application/json') + .expect(400); + }); }); describe('/teams.convertToChannel', () => { diff --git a/packages/core-services/src/types/IRoomService.ts b/packages/core-services/src/types/IRoomService.ts index 3acb7edbfcbe..23186590af50 100644 --- a/packages/core-services/src/types/IRoomService.ts +++ b/packages/core-services/src/types/IRoomService.ts @@ -24,6 +24,7 @@ export interface ICreateRoomParams { readOnly?: boolean; extraData?: Partial; options?: ICreateRoomOptions; + sidepanel?: IRoom['sidepanel']; } export interface IRoomService { addMember(uid: string, rid: string): Promise; diff --git a/packages/core-services/src/types/ITeamService.ts b/packages/core-services/src/types/ITeamService.ts index 98747a385b59..2d67bf515fca 100644 --- a/packages/core-services/src/types/ITeamService.ts +++ b/packages/core-services/src/types/ITeamService.ts @@ -23,6 +23,7 @@ export interface ITeamCreateParams { room: ITeamCreateRoom; members?: Array | null; // list of user _ids owner?: string | null; // the team owner. If not present, owner = requester + sidepanel?: IRoom['sidepanel']; } export interface ITeamMemberParams { diff --git a/packages/core-typings/src/IRoom.ts b/packages/core-typings/src/IRoom.ts index 4bc07c5a8ad4..442cac45fada 100644 --- a/packages/core-typings/src/IRoom.ts +++ b/packages/core-typings/src/IRoom.ts @@ -7,6 +7,8 @@ import type { IUser, Username } from './IUser'; import type { RoomType } from './RoomType'; type CallStatus = 'ringing' | 'ended' | 'declined' | 'ongoing'; +const sidepanelItemValues = ['channels', 'discussions'] as const; +export type SidepanelItem = (typeof sidepanelItemValues)[number]; export type RoomID = string; export type ChannelName = string; @@ -95,8 +97,28 @@ export interface IRoom extends IRocketChatRecord { customFields?: Record; usersWaitingForE2EKeys?: { userId: IUser['_id']; ts: Date }[]; + + sidepanel?: { + items: [SidepanelItem, SidepanelItem?]; + }; } +export const isSidepanelItem = (item: any): item is SidepanelItem => { + return sidepanelItemValues.includes(item); +}; + +export const isValidSidepanel = (sidepanel: IRoom['sidepanel']) => { + if (!sidepanel?.items) { + return false; + } + return ( + Array.isArray(sidepanel.items) && + sidepanel.items.length && + sidepanel.items.every(isSidepanelItem) && + sidepanel.items.length === new Set(sidepanel.items).size + ); +}; + export const isRoomWithJoinCode = (room: Partial): room is IRoomWithJoinCode => 'joinCodeRequired' in room && (room as any).joinCodeRequired === true; diff --git a/packages/model-typings/src/models/IRoomsModel.ts b/packages/model-typings/src/models/IRoomsModel.ts index f9daef91dece..a88a5bde7f4e 100644 --- a/packages/model-typings/src/models/IRoomsModel.ts +++ b/packages/model-typings/src/models/IRoomsModel.ts @@ -119,6 +119,8 @@ export interface IRoomsModel extends IBaseModel { setRoomNameById(roomId: IRoom['_id'], name: IRoom['name']): Promise; + setSidepanelById(roomId: IRoom['_id'], sidepanel: IRoom['sidepanel']): Promise; + setFnameById(_id: IRoom['_id'], fname: IRoom['fname']): Promise; setRoomTopicById(roomId: IRoom['_id'], topic: IRoom['description']): Promise; diff --git a/packages/rest-typings/src/v1/teams/index.ts b/packages/rest-typings/src/v1/teams/index.ts index 0a1583b66474..d63e6da8bd8a 100644 --- a/packages/rest-typings/src/v1/teams/index.ts +++ b/packages/rest-typings/src/v1/teams/index.ts @@ -89,6 +89,7 @@ export type TeamsEndpoints = { }; }; owner?: IUser['_id']; + sidepanel?: IRoom['sidepanel']; }) => { team: ITeam; }; From 5660be253d204401ff1c80b65625f12376385f3e Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Tue, 6 Aug 2024 16:32:21 -0300 Subject: [PATCH 12/80] chore: Renders back button through prop in admin settings (#32987) --- .../client/views/admin/settings/GroupPage.tsx | 15 +++--- .../views/admin/settings/GroupSelector.tsx | 13 ++--- .../views/admin/settings/SettingsRoute.tsx | 5 +- .../admin/settings/groups/AssetsGroupPage.tsx | 8 +-- .../settings/groups/GenericGroupPage.tsx | 8 +-- .../admin/settings/groups/LDAPGroupPage.tsx | 7 ++- .../admin/settings/groups/OAuthGroupPage.tsx | 7 ++- .../admin/settings/groups/TabbedGroupPage.tsx | 7 +-- .../admin/settings/groups/VoipGroupPage.tsx | 8 ++- .../tests/e2e/administration-settings.spec.ts | 52 +++++++++++++++++++ apps/meteor/tests/e2e/administration.spec.ts | 30 ----------- 11 files changed, 100 insertions(+), 60 deletions(-) create mode 100644 apps/meteor/tests/e2e/administration-settings.spec.ts diff --git a/apps/meteor/client/views/admin/settings/GroupPage.tsx b/apps/meteor/client/views/admin/settings/GroupPage.tsx index a68daff979c9..5946805a497e 100644 --- a/apps/meteor/client/views/admin/settings/GroupPage.tsx +++ b/apps/meteor/client/views/admin/settings/GroupPage.tsx @@ -1,8 +1,8 @@ import type { ISetting, ISettingColor } from '@rocket.chat/core-typings'; import { Accordion, Box, Button, ButtonGroup } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import { useToastMessageDispatch, useSettingsDispatch, useSettings, useTranslation, useRoute } from '@rocket.chat/ui-contexts'; +import { useToastMessageDispatch, useSettingsDispatch, useSettings, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactNode, FormEvent, MouseEvent } from 'react'; import React, { useMemo, memo } from 'react'; @@ -14,6 +14,7 @@ import GroupPageSkeleton from './GroupPageSkeleton'; type GroupPageProps = { children: ReactNode; headerButtons?: ReactNode; + onClickBack?: () => void; _id: string; i18nLabel: string; i18nDescription?: string; @@ -24,6 +25,7 @@ type GroupPageProps = { const GroupPage = ({ children = undefined, headerButtons = undefined, + onClickBack, _id, i18nLabel, i18nDescription = undefined, @@ -31,7 +33,6 @@ const GroupPage = ({ isCustom = false, }: GroupPageProps) => { const t = useTranslation(); - const router = useRoute('admin-settings'); const dispatch = useSettingsDispatch(); const dispatchToastMessage = useToastMessageDispatch(); @@ -56,7 +57,7 @@ const GroupPage = ({ const isColorSetting = (setting: ISetting): setting is ISettingColor => setting.type === 'color'; - const save = useMutableCallback(async () => { + const save = useEffectEvent(async () => { const changes = changedEditableSettings.map((setting) => { if (isColorSetting(setting)) { return { @@ -86,7 +87,7 @@ const GroupPage = ({ const dispatchToEditing = useEditableSettingsDispatch(); - const cancel = useMutableCallback(() => { + const cancel = useEffectEvent(() => { const settingsToDispatch = changedEditableSettings .map(({ _id }) => originalSettings.find((setting) => setting._id === _id)) .map((setting) => { @@ -118,8 +119,6 @@ const GroupPage = ({ save(); }; - const handleBack = useMutableCallback(() => router.push({})); - const handleCancelClick = (event: MouseEvent): void => { event.preventDefault(); cancel(); @@ -139,7 +138,7 @@ const GroupPage = ({ return ( - + {headerButtons} {tabs} diff --git a/apps/meteor/client/views/admin/settings/GroupSelector.tsx b/apps/meteor/client/views/admin/settings/GroupSelector.tsx index defe2a0a9a45..6d6d90a566eb 100644 --- a/apps/meteor/client/views/admin/settings/GroupSelector.tsx +++ b/apps/meteor/client/views/admin/settings/GroupSelector.tsx @@ -11,9 +11,10 @@ import VoipGroupPage from './groups/VoipGroupPage'; type GroupSelectorProps = { groupId: GroupId; + onClickBack?: () => void; }; -const GroupSelector = ({ groupId }: GroupSelectorProps) => { +const GroupSelector = ({ groupId, onClickBack }: GroupSelectorProps) => { const group = useSettingStructure(groupId); if (!group) { @@ -21,22 +22,22 @@ const GroupSelector = ({ groupId }: GroupSelectorProps) => { } if (groupId === 'Assets') { - return ; + return ; } if (groupId === 'OAuth') { - return ; + return ; } if (groupId === 'LDAP') { - return ; + return ; } if (groupId === 'Call_Center') { - return ; + return ; } - return ; + return ; }; export default GroupSelector; diff --git a/apps/meteor/client/views/admin/settings/SettingsRoute.tsx b/apps/meteor/client/views/admin/settings/SettingsRoute.tsx index d0c0c0003778..c03aced8b5a0 100644 --- a/apps/meteor/client/views/admin/settings/SettingsRoute.tsx +++ b/apps/meteor/client/views/admin/settings/SettingsRoute.tsx @@ -1,4 +1,4 @@ -import { useRouteParameter, useIsPrivilegedSettingsContext } from '@rocket.chat/ui-contexts'; +import { useRouteParameter, useIsPrivilegedSettingsContext, useRouter } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; @@ -10,6 +10,7 @@ import SettingsPage from './SettingsPage'; export const SettingsRoute = (): ReactElement => { const hasPermission = useIsPrivilegedSettingsContext(); const groupId = useRouteParameter('group'); + const router = useRouter(); if (!hasPermission) { return ; @@ -21,7 +22,7 @@ export const SettingsRoute = (): ReactElement => { return ( - + router.navigate('/admin/settings')} /> ); }; diff --git a/apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx b/apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx index 6d4bb90e3d12..a5935eb47bc8 100644 --- a/apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx +++ b/apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx @@ -6,14 +6,16 @@ import { useEditableSettingsGroupSections } from '../../EditableSettingsContext' import GroupPage from '../GroupPage'; import Section from '../Section'; -type AssetsGroupPageProps = ISetting; +type AssetsGroupPageProps = ISetting & { + onClickBack?: () => void; +}; -function AssetsGroupPage({ _id, ...group }: AssetsGroupPageProps): ReactElement { +function AssetsGroupPage({ _id, onClickBack, ...group }: AssetsGroupPageProps): ReactElement { const sections = useEditableSettingsGroupSections(_id); const solo = sections.length === 1; return ( - + {sections.map((sectionName) => (
))} diff --git a/apps/meteor/client/views/admin/settings/groups/GenericGroupPage.tsx b/apps/meteor/client/views/admin/settings/groups/GenericGroupPage.tsx index 6f71ec9c1333..c9148547b955 100644 --- a/apps/meteor/client/views/admin/settings/groups/GenericGroupPage.tsx +++ b/apps/meteor/client/views/admin/settings/groups/GenericGroupPage.tsx @@ -6,14 +6,16 @@ import { useEditableSettingsGroupSections } from '../../EditableSettingsContext' import GroupPage from '../GroupPage'; import Section from '../Section'; -type GenericGroupPageProps = ISetting; +type GenericGroupPageProps = ISetting & { + onClickBack?: () => void; +}; -function GenericGroupPage({ _id, ...props }: GenericGroupPageProps): ReactElement { +function GenericGroupPage({ _id, onClickBack, ...props }: GenericGroupPageProps): ReactElement { const sections = useEditableSettingsGroupSections(_id); const solo = sections.length === 1; return ( - + {sections.map((sectionName) => (
))} diff --git a/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx b/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx index bea9ccd76222..a497738b9541 100644 --- a/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx +++ b/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx @@ -10,7 +10,11 @@ import { useExternalLink } from '../../../../hooks/useExternalLink'; import { useEditableSettings } from '../../EditableSettingsContext'; import TabbedGroupPage from './TabbedGroupPage'; -function LDAPGroupPage({ _id, ...group }: ISetting): JSX.Element { +type LDAPGroupPageProps = ISetting & { + onClickBack?: () => void; +}; + +function LDAPGroupPage({ _id, onClickBack, ...group }: LDAPGroupPageProps) { const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); const testConnection = useEndpoint('POST', '/v1/ldap.testConnection'); @@ -127,6 +131,7 @@ function LDAPGroupPage({ _id, ...group }: ISetting): JSX.Element { return ( diff --git a/apps/meteor/client/views/admin/settings/groups/OAuthGroupPage.tsx b/apps/meteor/client/views/admin/settings/groups/OAuthGroupPage.tsx index 0bd65a3ad533..713a26935994 100644 --- a/apps/meteor/client/views/admin/settings/groups/OAuthGroupPage.tsx +++ b/apps/meteor/client/views/admin/settings/groups/OAuthGroupPage.tsx @@ -12,9 +12,11 @@ import GroupPage from '../GroupPage'; import Section from '../Section'; import CreateOAuthModal from './CreateOAuthModal'; -type OAuthGroupPageProps = ISetting; +type OAuthGroupPageProps = ISetting & { + onClickBack?: () => void; +}; -function OAuthGroupPage({ _id, ...group }: OAuthGroupPageProps): ReactElement { +function OAuthGroupPage({ _id, onClickBack, ...group }: OAuthGroupPageProps): ReactElement { const sections = useEditableSettingsGroupSections(_id); const solo = sections.length === 1; const t = useTranslation(); @@ -95,6 +97,7 @@ function OAuthGroupPage({ _id, ...group }: OAuthGroupPageProps): ReactElement { diff --git a/apps/meteor/client/views/admin/settings/groups/TabbedGroupPage.tsx b/apps/meteor/client/views/admin/settings/groups/TabbedGroupPage.tsx index f3546f13d758..eeecf9cc3800 100644 --- a/apps/meteor/client/views/admin/settings/groups/TabbedGroupPage.tsx +++ b/apps/meteor/client/views/admin/settings/groups/TabbedGroupPage.tsx @@ -12,9 +12,10 @@ import GenericGroupPage from './GenericGroupPage'; type TabbedGroupPageProps = ISetting & { headerButtons?: ReactElement; + onClickBack?: () => void; }; -function TabbedGroupPage({ _id, ...props }: TabbedGroupPageProps): JSX.Element { +function TabbedGroupPage({ _id, onClickBack, ...props }: TabbedGroupPageProps): JSX.Element { const t = useTranslation(); const tabs = useEditableSettingsGroupTabs(_id); @@ -25,7 +26,7 @@ function TabbedGroupPage({ _id, ...props }: TabbedGroupPageProps): JSX.Element { const solo = sections.length === 1; if (!tabs.length || (tabs.length === 1 && !tabs[0])) { - return ; + return ; } if (!tab && tabs[0]) { @@ -43,7 +44,7 @@ function TabbedGroupPage({ _id, ...props }: TabbedGroupPageProps): JSX.Element { ); return ( - + {sections.map((sectionName) => (
))} diff --git a/apps/meteor/client/views/admin/settings/groups/VoipGroupPage.tsx b/apps/meteor/client/views/admin/settings/groups/VoipGroupPage.tsx index 82b55a152563..3b7c873f2268 100644 --- a/apps/meteor/client/views/admin/settings/groups/VoipGroupPage.tsx +++ b/apps/meteor/client/views/admin/settings/groups/VoipGroupPage.tsx @@ -11,7 +11,11 @@ import GroupPage from '../GroupPage'; import Section from '../Section'; import VoipExtensionsPage from './voip/VoipExtensionsPage'; -function VoipGroupPage({ _id, ...group }: ISetting): JSX.Element { +type VoipGroupPageProps = ISetting & { + onClickBack?: () => void; +}; + +function VoipGroupPage({ _id, onClickBack, ...group }: VoipGroupPageProps) { const t = useTranslation(); const voipEnabled = useSetting('VoIP_Enabled'); @@ -46,7 +50,7 @@ function VoipGroupPage({ _id, ...group }: ISetting): JSX.Element { ); return ( - + {tab === 'Extensions' ? ( ExtensionsPageComponent ) : ( diff --git a/apps/meteor/tests/e2e/administration-settings.spec.ts b/apps/meteor/tests/e2e/administration-settings.spec.ts new file mode 100644 index 000000000000..d2996d6eac88 --- /dev/null +++ b/apps/meteor/tests/e2e/administration-settings.spec.ts @@ -0,0 +1,52 @@ +import { Users } from './fixtures/userStates'; +import { Admin } from './page-objects'; +import { getSettingValueById } from './utils'; +import { test, expect } from './utils/test'; + +test.use({ storageState: Users.admin.state }); + +test.describe.parallel('administration-settings', () => { + let poAdmin: Admin; + + test.beforeEach(async ({ page }) => { + poAdmin = new Admin(page); + }); + + test.describe('General', () => { + let inputSiteURLSetting: string; + + test.beforeAll(async ({ api }) => { + inputSiteURLSetting = (await getSettingValueById(api, 'Site_Url')) as string; + }); + + test.beforeEach(async ({ page }) => { + await page.goto('/admin/settings/General'); + }); + + test('should be able to reset a setting after a change', async () => { + await poAdmin.inputSiteURL.fill('any_text'); + await poAdmin.btnResetSiteURL.click(); + + await expect(poAdmin.inputSiteURL).toHaveValue(inputSiteURLSetting); + }); + + test('should be able to go back to the settings page', async ({ page }) => { + await poAdmin.btnBack.click(); + + await expect(page).toHaveURL('/admin/settings'); + }); + }); + + test.describe('Layout', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/admin/settings/Layout'); + }); + + test('should code mirror full screen be displayed correctly', async ({ page }) => { + await poAdmin.getAccordionBtnByName('Custom CSS').click(); + await poAdmin.btnFullScreen.click(); + + await expect(page.getByRole('code')).toHaveCSS('width', '920px'); + }); + }); +}); diff --git a/apps/meteor/tests/e2e/administration.spec.ts b/apps/meteor/tests/e2e/administration.spec.ts index 703c4a4bd8b1..45fee011efc3 100644 --- a/apps/meteor/tests/e2e/administration.spec.ts +++ b/apps/meteor/tests/e2e/administration.spec.ts @@ -319,34 +319,4 @@ test.describe.parallel('administration', () => { await expect(poAdmin.getIntegrationByName(incomingIntegrationName)).not.toBeVisible(); }); }); - - test.describe('Settings', () => { - test.describe('General', () => { - test.beforeEach(async ({ page }) => { - await page.goto('/admin/settings/General'); - }); - - test.afterAll(async ({ api }) => { - await setSettingValueById(api, 'Language', 'en'); - }); - - test('expect be able to reset a setting after a change', async () => { - await poAdmin.inputSiteURL.type('any_text'); - await poAdmin.btnResetSiteURL.click(); - }); - }); - - test.describe('Layout', () => { - test.beforeEach(async ({ page }) => { - await page.goto('/admin/settings/Layout'); - }); - - test('should code mirror full screen be displayed correctly', async ({ page }) => { - await poAdmin.getAccordionBtnByName('Custom CSS').click(); - await poAdmin.btnFullScreen.click(); - - await expect(page.getByRole('code')).toHaveCSS('width', '920px'); - }); - }); - }); }); From 2c72a26a6250d0d2c7cf653a80a16c22e6c17a11 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Tue, 6 Aug 2024 18:01:09 -0300 Subject: [PATCH 13/80] chore: `FilterByText` component sanitization (#32957) --- .../meteor/client/components/FilterByText.tsx | 43 +++++-------------- .../businessHours/BusinessHoursTable.tsx | 2 +- .../omnichannel/monitors/MonitorsTable.tsx | 2 +- .../omnichannel/slaPolicies/SlaTable.tsx | 2 +- .../client/omnichannel/tags/TagsTable.tsx | 2 +- .../client/omnichannel/units/UnitsTable.tsx | 2 +- .../views/admin/customEmoji/CustomEmoji.tsx | 2 +- .../CustomSoundsTable/CustomSoundsTable.tsx | 2 +- .../CustomUserStatusTable.tsx | 2 +- .../DeviceManagementAdminTable.tsx | 2 +- .../admin/integrations/IntegrationsTable.tsx | 2 +- .../moderation/helpers/ModerationFilter.tsx | 6 +-- .../users/UsersTable/UsersTableFilters.tsx | 2 +- .../channels/ChannelsTable/ChannelsTable.tsx | 2 +- .../tabs/teams/TeamsTable/TeamsTable.tsx | 2 +- .../tabs/users/UsersTable/UsersTable.tsx | 2 +- .../marketplace/AppsPage/AppsFilters.tsx | 4 +- .../components/CategoryFilter/TagList.tsx | 24 +++++++---- .../agents/AgentsTable/AgentsTable.tsx | 2 +- .../customFields/CustomFieldsTable.tsx | 2 +- .../DepartmentsTable/DepartmentsTable.tsx | 2 +- .../omnichannel/directory/calls/CallTable.tsx | 2 +- .../omnichannel/directory/chats/ChatTable.tsx | 2 +- .../directory/contacts/ContactTable.tsx | 13 +++--- .../omnichannel/managers/ManagersTable.tsx | 2 +- .../WebdavFilePickerModal.tsx | 2 +- 26 files changed, 57 insertions(+), 75 deletions(-) diff --git a/apps/meteor/client/components/FilterByText.tsx b/apps/meteor/client/components/FilterByText.tsx index 1aeeb29a0a57..5c5a3d599e2f 100644 --- a/apps/meteor/client/components/FilterByText.tsx +++ b/apps/meteor/client/components/FilterByText.tsx @@ -1,26 +1,13 @@ -import { Box, Icon, TextInput, Button, Margins } from '@rocket.chat/fuselage'; +import { Box, Icon, TextInput, Margins } from '@rocket.chat/fuselage'; import { useAutoFocus, useMergedRefs } from '@rocket.chat/fuselage-hooks'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import type { ReactNode, ChangeEvent, FormEvent } from 'react'; -import React, { forwardRef, memo, useCallback, useEffect, useState } from 'react'; +import type { ChangeEvent, FormEvent, HTMLAttributes } from 'react'; +import React, { forwardRef, memo, useCallback, useState } from 'react'; -type FilterByTextCommonProps = { - children?: ReactNode | undefined; - placeholder?: string; - onChange: (filter: { text: string }) => void; +type FilterByTextProps = { + onChange: (filter: string) => void; shouldAutoFocus?: boolean; -}; - -type FilterByTextPropsWithButton = FilterByTextCommonProps & { - displayButton: true; - textButton: string; - onButtonClick: () => void; -}; - -type FilterByTextProps = FilterByTextCommonProps | FilterByTextPropsWithButton; - -const isFilterByTextPropsWithButton = (props: any): props is FilterByTextPropsWithButton => - 'displayButton' in props && props.displayButton === true; +} & Omit, 'is' | 'onChange'>; const FilterByText = forwardRef(function FilterByText( { placeholder, onChange: setFilter, shouldAutoFocus = false, children, ...props }, @@ -31,13 +18,10 @@ const FilterByText = forwardRef(function Fi const autoFocusRef = useAutoFocus(shouldAutoFocus); const mergedRefs = useMergedRefs(ref, autoFocusRef); - const handleInputChange = useCallback((event: ChangeEvent) => { + const handleInputChange = (event: ChangeEvent) => { setText(event.currentTarget.value); - }, []); - - useEffect(() => { - setFilter({ text }); - }, [setFilter, text]); + setFilter(event.currentTarget.value); + }; const handleFormSubmit = useCallback((event: FormEvent) => { event.preventDefault(); @@ -47,6 +31,7 @@ const FilterByText = forwardRef(function Fi } @@ -57,13 +42,7 @@ const FilterByText = forwardRef(function Fi aria-label={placeholder ?? t('Search')} /> - {isFilterByTextPropsWithButton(props) ? ( - - ) : ( - children && {children} - )} + {children && {children}} ); }); diff --git a/apps/meteor/client/omnichannel/businessHours/BusinessHoursTable.tsx b/apps/meteor/client/omnichannel/businessHours/BusinessHoursTable.tsx index 6fddd95859d8..b4220e420a9a 100644 --- a/apps/meteor/client/omnichannel/businessHours/BusinessHoursTable.tsx +++ b/apps/meteor/client/omnichannel/businessHours/BusinessHoursTable.tsx @@ -47,7 +47,7 @@ const BusinessHoursTable = () => { return ( <> - setText(text)} /> + {isLoading && ( {headers} diff --git a/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx b/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx index a67057b9add1..62adc2a0405f 100644 --- a/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx +++ b/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx @@ -144,7 +144,7 @@ const MonitorsTable = () => { - {((isSuccess && data?.monitors.length > 0) || queryHasChanged) && setText(text)} />} + {((isSuccess && data?.monitors.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/omnichannel/slaPolicies/SlaTable.tsx b/apps/meteor/client/omnichannel/slaPolicies/SlaTable.tsx index d550118a5017..01b4bfe90374 100644 --- a/apps/meteor/client/omnichannel/slaPolicies/SlaTable.tsx +++ b/apps/meteor/client/omnichannel/slaPolicies/SlaTable.tsx @@ -84,7 +84,7 @@ const SlaTable = ({ reload }: { reload: MutableRefObject<() => void> }) => { return ( <> - {((isSuccess && data?.sla.length > 0) || queryHasChanged) && setFilter(text)} />} + {((isSuccess && data?.sla.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/omnichannel/tags/TagsTable.tsx b/apps/meteor/client/omnichannel/tags/TagsTable.tsx index 3b9757134bed..a4b31cd4755c 100644 --- a/apps/meteor/client/omnichannel/tags/TagsTable.tsx +++ b/apps/meteor/client/omnichannel/tags/TagsTable.tsx @@ -70,7 +70,7 @@ const TagsTable = () => { return ( <> - {((isSuccess && data?.tags.length > 0) || queryHasChanged) && setFilter(text)} />} + {((isSuccess && data?.tags.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/omnichannel/units/UnitsTable.tsx b/apps/meteor/client/omnichannel/units/UnitsTable.tsx index fe95bc90d8a2..93734acb8de0 100644 --- a/apps/meteor/client/omnichannel/units/UnitsTable.tsx +++ b/apps/meteor/client/omnichannel/units/UnitsTable.tsx @@ -69,7 +69,7 @@ const UnitsTable = () => { return ( <> - {((isSuccess && data?.units.length > 0) || queryHasChanged) && setFilter(text)} />} + {((isSuccess && data?.units.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx index abfa438d9ced..2bd795c3ccab 100644 --- a/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx @@ -66,7 +66,7 @@ const CustomEmoji = ({ onClick, reload }: CustomEmojiProps) => { return ( <> - setText(text)} /> + {isLoading && ( {headers} diff --git a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx index 58b1c4ea7b8a..5e8bd0c0fac9 100644 --- a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx +++ b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx @@ -64,7 +64,7 @@ const CustomSoundsTable = ({ reload, onClick }: CustomSoundsTableProps) => { return ( <> - setParams(text)} /> + {isLoading && ( {headers} diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx index 59c4cdd74eb3..d18fc4a706a8 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx @@ -70,7 +70,7 @@ const CustomUserStatus = ({ reload, onClick }: CustomUserStatusProps): ReactElem return ( <> - setText(text)} /> + {data.length === 0 && } {data && data.length > 0 && ( <> diff --git a/apps/meteor/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminTable.tsx b/apps/meteor/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminTable.tsx index 026f1cb0de30..ebd1e762ff80 100644 --- a/apps/meteor/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminTable.tsx +++ b/apps/meteor/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminTable.tsx @@ -76,7 +76,7 @@ const DeviceManagementAdminTable = ({ reloadRef }: { reloadRef: MutableRefObject return ( <> - setText(text)} /> + { return ( <> - setText(text)} /> + {isLoading && ( {headers} diff --git a/apps/meteor/client/views/admin/moderation/helpers/ModerationFilter.tsx b/apps/meteor/client/views/admin/moderation/helpers/ModerationFilter.tsx index 4fde3568b2aa..5414e3d06aa5 100644 --- a/apps/meteor/client/views/admin/moderation/helpers/ModerationFilter.tsx +++ b/apps/meteor/client/views/admin/moderation/helpers/ModerationFilter.tsx @@ -1,5 +1,5 @@ import { useTranslation } from '@rocket.chat/ui-contexts'; -import React, { useCallback } from 'react'; +import React from 'react'; import FilterByText from '../../../../components/FilterByText'; import DateRangePicker from './DateRangePicker'; @@ -12,10 +12,8 @@ type ModerationFilterProps = { const ModerationFilter = ({ setText, setDateRange }: ModerationFilterProps) => { const t = useTranslation(); - const handleChange = useCallback(({ text }): void => setText(text), [setText]); - return ( - + ); diff --git a/apps/meteor/client/views/admin/users/UsersTable/UsersTableFilters.tsx b/apps/meteor/client/views/admin/users/UsersTable/UsersTableFilters.tsx index 28508ac94ac5..e3b919ae4a02 100644 --- a/apps/meteor/client/views/admin/users/UsersTable/UsersTableFilters.tsx +++ b/apps/meteor/client/views/admin/users/UsersTable/UsersTableFilters.tsx @@ -20,7 +20,7 @@ const UsersTableFilters = ({ roleData, setUsersFilters }: UsersTableFiltersProps const [text, setText] = useState(''); const handleSearchTextChange = useCallback( - ({ text }) => { + (text) => { setUsersFilters({ text, roles: selectedRoles }); setText(text); }, diff --git a/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx b/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx index 8ec510eed76d..cbd4671bc076 100644 --- a/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx +++ b/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx @@ -96,7 +96,7 @@ const ChannelsTable = () => { return ( <> - setText(text)} /> + {isLoading && ( {headers} diff --git a/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx b/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx index f33b359e4b07..43e6e0e6cdf6 100644 --- a/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx +++ b/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx @@ -73,7 +73,7 @@ const TeamsTable = () => { return ( <> - setText(text)} /> + {isLoading && ( {headers} diff --git a/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx b/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx index 5b69a59909ca..db01bdf59201 100644 --- a/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx +++ b/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx @@ -95,7 +95,7 @@ const UsersTable = ({ workspace = 'local' }): ReactElement => { return ( <> - setText(text)} /> + {isLoading && ( {headers} diff --git a/apps/meteor/client/views/marketplace/AppsPage/AppsFilters.tsx b/apps/meteor/client/views/marketplace/AppsPage/AppsFilters.tsx index f1332284c97f..a1f486395dbb 100644 --- a/apps/meteor/client/views/marketplace/AppsPage/AppsFilters.tsx +++ b/apps/meteor/client/views/marketplace/AppsPage/AppsFilters.tsx @@ -59,8 +59,8 @@ const AppsFilters = ({ const fixFiltersSize = breakpoints.includes('lg') ? { maxWidth: 'x200', minWidth: 'x200' } : null; return ( - - setText(text)}> + + {!isPrivateAppsPage && ( )} diff --git a/apps/meteor/client/views/marketplace/components/CategoryFilter/TagList.tsx b/apps/meteor/client/views/marketplace/components/CategoryFilter/TagList.tsx index ec5fb13f0fab..3cba9e81b357 100644 --- a/apps/meteor/client/views/marketplace/components/CategoryFilter/TagList.tsx +++ b/apps/meteor/client/views/marketplace/components/CategoryFilter/TagList.tsx @@ -8,14 +8,20 @@ type TagListProps = { onClick: CategoryDropDownListProps['onSelected']; }; -const TagList = ({ categories, onClick }: TagListProps) => ( - - {categories.map((category) => ( - onClick(category)} disabled={undefined} mbe={8}> - {category.label} - - ))} - -); +const TagList = ({ categories, onClick }: TagListProps) => { + if (!categories.length) { + return null; + } + + return ( + + {categories.map((category) => ( + onClick(category)}> + {category.label} + + ))} + + ); +}; export default TagList; diff --git a/apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx b/apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx index 5d0e89e1008a..13e1498d7422 100644 --- a/apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx +++ b/apps/meteor/client/views/omnichannel/agents/AgentsTable/AgentsTable.tsx @@ -73,7 +73,7 @@ const AgentsTable = () => { return ( <> - {((isSuccess && data?.users.length > 0) || queryHasChanged) && setFilter(text)} />} + {((isSuccess && data?.users.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/views/omnichannel/customFields/CustomFieldsTable.tsx b/apps/meteor/client/views/omnichannel/customFields/CustomFieldsTable.tsx index d8609293c2c5..f8043a178857 100644 --- a/apps/meteor/client/views/omnichannel/customFields/CustomFieldsTable.tsx +++ b/apps/meteor/client/views/omnichannel/customFields/CustomFieldsTable.tsx @@ -75,7 +75,7 @@ const CustomFieldsTable = () => { return ( <> - {((isSuccess && data?.customFields.length > 0) || queryHasChanged) && setFilter(text)} />} + {((isSuccess && data?.customFields.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/views/omnichannel/departments/DepartmentsTable/DepartmentsTable.tsx b/apps/meteor/client/views/omnichannel/departments/DepartmentsTable/DepartmentsTable.tsx index 7aee3f534d42..46ef80d5b0e3 100644 --- a/apps/meteor/client/views/omnichannel/departments/DepartmentsTable/DepartmentsTable.tsx +++ b/apps/meteor/client/views/omnichannel/departments/DepartmentsTable/DepartmentsTable.tsx @@ -91,7 +91,7 @@ const DepartmentsTable = ({ archived }: { archived: boolean }) => { return ( <> - {((isSuccess && data?.departments.length > 0) || queryHasChanged) && setText(text)} />} + {((isSuccess && data?.departments.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx b/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx index 916a866b0431..2b529999fea1 100644 --- a/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx +++ b/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx @@ -95,7 +95,7 @@ const CallTable = () => { return ( <> - {((isSuccess && data?.rooms.length > 0) || queryHasChanged) && setText(text)} />} + {((isSuccess && data?.rooms.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx b/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx index e11a1c332066..c6d090c7547c 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx +++ b/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx @@ -134,7 +134,7 @@ const ChatTable = () => { return ( <> - {((isSuccess && data?.rooms.length > 0) || queryHasChanged) && setText(text)} />} + {((isSuccess && data?.rooms.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx b/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx index 76fdce05c9bb..09ec19e6a2fe 100644 --- a/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx +++ b/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx @@ -1,4 +1,4 @@ -import { Pagination, States, StatesAction, StatesActions, StatesIcon, StatesTitle, Box } from '@rocket.chat/fuselage'; +import { Pagination, States, StatesAction, StatesActions, StatesIcon, StatesTitle, Box, Button } from '@rocket.chat/fuselage'; import { useDebouncedState, useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useRoute, useTranslation } from '@rocket.chat/ui-contexts'; import { hashQueryKey } from '@tanstack/react-query'; @@ -106,12 +106,11 @@ function ContactTable(): ReactElement { return ( <> {((isSuccess && data?.visitors.length > 0) || queryHasChanged) && ( - setTerm(text)} - /> + + + )} {isLoading && ( diff --git a/apps/meteor/client/views/omnichannel/managers/ManagersTable.tsx b/apps/meteor/client/views/omnichannel/managers/ManagersTable.tsx index afb2ae8f351b..a60d41c0c3aa 100644 --- a/apps/meteor/client/views/omnichannel/managers/ManagersTable.tsx +++ b/apps/meteor/client/views/omnichannel/managers/ManagersTable.tsx @@ -80,7 +80,7 @@ const ManagersTable = () => { return ( <> - {((isSuccess && data?.users.length > 0) || queryHasChanged) && setText(text)} />} + {((isSuccess && data?.users.length > 0) || queryHasChanged) && } {isLoading && ( {headers} diff --git a/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerModal.tsx b/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerModal.tsx index 4b75e496cefe..38895d4c211e 100644 --- a/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerModal.tsx +++ b/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerModal.tsx @@ -196,7 +196,7 @@ const WebdavFilePickerModal = ({ onUpload, onClose, account }: WebdavFilePickerM - setFilterText(text)}> + {typeView === 'grid' && ( setServerName(String(value))} /> - ) => setRoomName(e.currentTarget.value)} /> - + {t('Manage_server_list')} diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationItems.spec.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationItems.spec.tsx index d2a94e3ab501..4e68fc0c9e4f 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationItems.spec.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useAdministrationItems.spec.tsx @@ -1,10 +1,11 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useAdministrationItems } from './useAdministrationItems'; it('should return omnichannel item if has `view-livechat-manager` permission ', async () => { - const { result, waitFor } = renderHook(() => useAdministrationItems(), { + const { result } = renderHook(() => useAdministrationItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/v1/licenses.info', () => ({ // @ts-expect-error this is a mock @@ -29,7 +30,8 @@ it('should return omnichannel item if has `view-livechat-manager` permission ', }); it('should show administration item if has at least one admin permission', async () => { - const { result, waitFor } = renderHook(() => useAdministrationItems(), { + const { result } = renderHook(() => useAdministrationItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/v1/licenses.info', () => ({ // @ts-expect-error this is a mock diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useAppsItems.spec.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useAppsItems.spec.tsx index ac3479dcde63..f7b77c013235 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useAppsItems.spec.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useAppsItems.spec.tsx @@ -1,21 +1,23 @@ import { UIActionButtonContext } from '@rocket.chat/apps-engine/definition/ui'; import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useAppsItems } from './useAppsItems'; it('should return and empty array if the user does not have `manage-apps` and `access-marketplace` permission', () => { const { result } = renderHook(() => useAppsItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/apps/actionButtons', () => []) .build(), }); - expect(result.all[0]).toEqual([]); + expect(result.current).toEqual([]); }); it('should return `marketplace` and `installed` items if the user has `access-marketplace` permission', () => { const { result } = renderHook(() => useAppsItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/apps/actionButtons', () => []) .withPermission('access-marketplace') @@ -37,6 +39,7 @@ it('should return `marketplace` and `installed` items if the user has `access-ma it('should return `marketplace` and `installed` items if the user has `manage-apps` permission', () => { const { result } = renderHook(() => useAppsItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/apps/actionButtons', () => []) .withEndpoint('GET', '/apps/app-request/stats', () => ({ @@ -69,7 +72,8 @@ it('should return `marketplace` and `installed` items if the user has `manage-ap }); it('should return one action from the server with no conditions', async () => { - const { result, waitForValueToChange } = renderHook(() => useAppsItems(), { + const { result } = renderHook(() => useAppsItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/apps/actionButtons', () => [ { @@ -101,18 +105,19 @@ it('should return one action from the server with no conditions', async () => { }), ); - await waitForValueToChange(() => result.current[3]); - - expect(result.current[3]).toEqual( - expect.objectContaining({ - id: 'APP_ID_ACTION_ID', - }), + await waitFor(() => + expect(result.current[3]).toEqual( + expect.objectContaining({ + id: 'APP_ID_ACTION_ID', + }), + ), ); }); describe('User Dropdown actions with role conditions', () => { it('should return the action if the user has admin role', async () => { - const { result, waitForValueToChange } = renderHook(() => useAppsItems(), { + const { result } = renderHook(() => useAppsItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/apps/actionButtons', () => [ { @@ -149,17 +154,18 @@ describe('User Dropdown actions with role conditions', () => { }), ); - await waitForValueToChange(() => result.current[3]); - - expect(result.current[3]).toEqual( - expect.objectContaining({ - id: 'APP_ID_ACTION_ID', - }), + await waitFor(() => + expect(result.current[3]).toEqual( + expect.objectContaining({ + id: 'APP_ID_ACTION_ID', + }), + ), ); }); it('should return filter the action if the user doesn`t have admin role', async () => { const { result } = renderHook(() => useAppsItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/apps/actionButtons', () => [ { @@ -206,7 +212,8 @@ describe('User Dropdown actions with role conditions', () => { describe('User Dropdown actions with permission conditions', () => { it('should return the action if the user has manage-apps permission', async () => { - const { result, waitForValueToChange } = renderHook(() => useAppsItems(), { + const { result } = renderHook(() => useAppsItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/apps/actionButtons', () => [ { @@ -241,17 +248,18 @@ describe('User Dropdown actions with permission conditions', () => { }), ); - await waitForValueToChange(() => result.current[3]); - - expect(result.current[3]).toEqual( - expect.objectContaining({ - id: 'APP_ID_ACTION_ID', - }), + await waitFor(() => + expect(result.current[3]).toEqual( + expect.objectContaining({ + id: 'APP_ID_ACTION_ID', + }), + ), ); }); it('should return filter the action if the user doesn`t have `any` permission', async () => { const { result } = renderHook(() => useAppsItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/apps/actionButtons', () => [ { diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useAuditItems.spec.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useAuditItems.spec.tsx index 95d2d219bc14..66eae7369a3c 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useAuditItems.spec.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useAuditItems.spec.tsx @@ -1,10 +1,11 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useAuditItems } from './useAuditItems'; it('should return an empty array if doesn`t have license', async () => { - const { result, waitFor } = renderHook(() => useAuditItems(), { + const { result } = renderHook(() => useAuditItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/v1/licenses.info', () => ({ // @ts-expect-error: just for testing @@ -18,13 +19,12 @@ it('should return an empty array if doesn`t have license', async () => { .build(), }); - await waitFor(() => result.all.length > 1); - expect(result.current).toEqual([]); }); it('should return an empty array if have license and not have permissions', async () => { - const { result, waitFor } = renderHook(() => useAuditItems(), { + const { result } = renderHook(() => useAuditItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/v1/licenses.info', () => ({ license: { @@ -41,13 +41,12 @@ it('should return an empty array if have license and not have permissions', asyn .build(), }); - await waitFor(() => result.all.length > 1); - expect(result.current).toEqual([]); }); it('should return auditItems if have license and permissions', async () => { - const { result, waitFor } = renderHook(() => useAuditItems(), { + const { result } = renderHook(() => useAuditItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/v1/licenses.info', () => ({ license: { @@ -65,12 +64,12 @@ it('should return auditItems if have license and permissions', async () => { .build(), }); - await waitFor(() => result.current.length > 0); - - expect(result.current[0]).toEqual( - expect.objectContaining({ - id: 'messages', - }), + await waitFor(() => + expect(result.current[0]).toEqual( + expect.objectContaining({ + id: 'messages', + }), + ), ); expect(result.current[1]).toEqual( @@ -81,7 +80,8 @@ it('should return auditItems if have license and permissions', async () => { }); it('should return auditMessages item if have license and can-audit permission', async () => { - const { result, waitFor } = renderHook(() => useAuditItems(), { + const { result } = renderHook(() => useAuditItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/v1/licenses.info', () => ({ license: { @@ -98,17 +98,18 @@ it('should return auditMessages item if have license and can-audit permission', .build(), }); - await waitFor(() => result.current.length > 0); - - expect(result.current[0]).toEqual( - expect.objectContaining({ - id: 'messages', - }), + await waitFor(() => + expect(result.current[0]).toEqual( + expect.objectContaining({ + id: 'messages', + }), + ), ); }); it('should return audiLogs item if have license and can-audit-log permission', async () => { - const { result, waitFor } = renderHook(() => useAuditItems(), { + const { result } = renderHook(() => useAuditItems(), { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/v1/licenses.info', () => ({ license: { @@ -125,11 +126,11 @@ it('should return audiLogs item if have license and can-audit-log permission', a .build(), }); - await waitFor(() => result.current.length > 0); - - expect(result.current[0]).toEqual( - expect.objectContaining({ - id: 'auditLog', - }), + await waitFor(() => + expect(result.current[0]).toEqual( + expect.objectContaining({ + id: 'auditLog', + }), + ), ); }); diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useGroupingListItems.spec.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useGroupingListItems.spec.tsx index b5779d825202..08363b0ee036 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useGroupingListItems.spec.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useGroupingListItems.spec.tsx @@ -1,9 +1,9 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useGroupingListItems } from './useGroupingListItems'; it('should render groupingList items', async () => { - const { result } = renderHook(() => useGroupingListItems()); + const { result } = renderHook(() => useGroupingListItems(), { legacyRoot: true }); expect(result.current[0]).toEqual( expect.objectContaining({ diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useSortModeItems.spec.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useSortModeItems.spec.tsx index 143d228fe7ca..46d5aab37321 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useSortModeItems.spec.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useSortModeItems.spec.tsx @@ -1,9 +1,9 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useSortModeItems } from './useSortModeItems'; it('should render sortMode items', async () => { - const { result } = renderHook(() => useSortModeItems()); + const { result } = renderHook(() => useSortModeItems(), { legacyRoot: true }); expect(result.current[0]).toEqual( expect.objectContaining({ diff --git a/apps/meteor/client/sidebar/header/actions/hooks/useViewModeItems.spec.tsx b/apps/meteor/client/sidebar/header/actions/hooks/useViewModeItems.spec.tsx index 6c6dd7532e7e..7cdc6ff7bce8 100644 --- a/apps/meteor/client/sidebar/header/actions/hooks/useViewModeItems.spec.tsx +++ b/apps/meteor/client/sidebar/header/actions/hooks/useViewModeItems.spec.tsx @@ -1,9 +1,9 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useViewModeItems } from './useViewModeItems'; it('should render viewMode items', async () => { - const { result } = renderHook(() => useViewModeItems()); + const { result } = renderHook(() => useViewModeItems(), { legacyRoot: true }); expect(result.current[0]).toEqual( expect.objectContaining({ diff --git a/apps/meteor/client/sidebarv2/header/actions/hooks/useGroupingListItems.spec.tsx b/apps/meteor/client/sidebarv2/header/actions/hooks/useGroupingListItems.spec.tsx index b5779d825202..08363b0ee036 100644 --- a/apps/meteor/client/sidebarv2/header/actions/hooks/useGroupingListItems.spec.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/hooks/useGroupingListItems.spec.tsx @@ -1,9 +1,9 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useGroupingListItems } from './useGroupingListItems'; it('should render groupingList items', async () => { - const { result } = renderHook(() => useGroupingListItems()); + const { result } = renderHook(() => useGroupingListItems(), { legacyRoot: true }); expect(result.current[0]).toEqual( expect.objectContaining({ diff --git a/apps/meteor/client/sidebarv2/header/actions/hooks/useSortModeItems.spec.tsx b/apps/meteor/client/sidebarv2/header/actions/hooks/useSortModeItems.spec.tsx index 143d228fe7ca..46d5aab37321 100644 --- a/apps/meteor/client/sidebarv2/header/actions/hooks/useSortModeItems.spec.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/hooks/useSortModeItems.spec.tsx @@ -1,9 +1,9 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useSortModeItems } from './useSortModeItems'; it('should render sortMode items', async () => { - const { result } = renderHook(() => useSortModeItems()); + const { result } = renderHook(() => useSortModeItems(), { legacyRoot: true }); expect(result.current[0]).toEqual( expect.objectContaining({ diff --git a/apps/meteor/client/sidebarv2/header/actions/hooks/useViewModeItems.spec.tsx b/apps/meteor/client/sidebarv2/header/actions/hooks/useViewModeItems.spec.tsx index 6c6dd7532e7e..7cdc6ff7bce8 100644 --- a/apps/meteor/client/sidebarv2/header/actions/hooks/useViewModeItems.spec.tsx +++ b/apps/meteor/client/sidebarv2/header/actions/hooks/useViewModeItems.spec.tsx @@ -1,9 +1,9 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useViewModeItems } from './useViewModeItems'; it('should render viewMode items', async () => { - const { result } = renderHook(() => useViewModeItems()); + const { result } = renderHook(() => useViewModeItems(), { legacyRoot: true }); expect(result.current[0]).toEqual( expect.objectContaining({ diff --git a/apps/meteor/client/views/admin/settings/inputs/TimespanSettingInput.spec.tsx b/apps/meteor/client/views/admin/settings/inputs/TimespanSettingInput.spec.tsx index cd345b0f1ede..ee42bc8387f9 100644 --- a/apps/meteor/client/views/admin/settings/inputs/TimespanSettingInput.spec.tsx +++ b/apps/meteor/client/views/admin/settings/inputs/TimespanSettingInput.spec.tsx @@ -40,7 +40,7 @@ describe('TimespanSettingInput component', () => { jest.clearAllMocks(); }); - it('should call onChangeValue with the correct value when inputting a value and changing time unit', () => { + it('should call onChangeValue with the correct value when inputting a value and changing time unit', async () => { render( { placeholder='Enter timespan' onChangeValue={onChangeValueMock} />, + { legacyRoot: true }, ); const numberInput = screen.getByRole('spinbutton'); - userEvent.clear(numberInput); // Change value to 2 - userEvent.type(numberInput, '2'); + await userEvent.clear(numberInput); // Change value to 2 + await userEvent.type(numberInput, '2'); expect(onChangeValueMock).toHaveBeenCalledWith(2 * 24 * 60 * 60 * 1000); // 2 days in milliseconds }); - it('should update value to minutes when changing time unit to minutes', () => { + it('should update value to minutes when changing time unit to minutes', async () => { render( { placeholder='Enter timespan' onChangeValue={onChangeValueMock} />, + { legacyRoot: true }, ); const selectInput = screen.getByRole('button', { name: 'hours' }); - userEvent.click(selectInput); + await userEvent.click(selectInput); const minutesOption = screen.getByRole('option', { name: 'minutes' }); - userEvent.click(minutesOption); + await userEvent.click(minutesOption); expect(onChangeValueMock).toHaveBeenCalledWith(60000); // 1 min in milliseconds expect(screen.getByDisplayValue('1')).toBeTruthy(); }); - it('should update value to hours when changing time unit to hours', () => { + it('should update value to hours when changing time unit to hours', async () => { render( { placeholder='Enter timespan' onChangeValue={onChangeValueMock} />, + { legacyRoot: true }, ); const selectInput = screen.getByRole('button', { name: 'days' }); - userEvent.click(selectInput); + await userEvent.click(selectInput); const hoursOption = screen.getByRole('option', { name: 'hours' }); - userEvent.click(hoursOption); + await userEvent.click(hoursOption); expect(onChangeValueMock).toHaveBeenCalledWith(3600000); // 1 hour in milliseconds expect(screen.getByDisplayValue('1')).toBeTruthy(); }); - it('should update value to days when changing time unit to days', () => { + it('should update value to days when changing time unit to days', async () => { render( { placeholder='Enter timespan' onChangeValue={onChangeValueMock} />, + { legacyRoot: true }, ); const selectInput = screen.getByRole('button', { name: 'hours' }); - userEvent.click(selectInput); + await userEvent.click(selectInput); const daysOption = screen.getByRole('option', { name: 'days' }); - userEvent.click(daysOption); + await userEvent.click(daysOption); expect(onChangeValueMock).toHaveBeenCalledWith(1036800000); // 12 days in milliseconds expect(screen.getByDisplayValue('12')).toBeTruthy(); }); - it('should call onResetButtonClick when reset button is clicked', () => { + it('should call onResetButtonClick when reset button is clicked', async () => { render( { hasResetButton onResetButtonClick={onResetButtonClickMock} />, + { legacyRoot: true }, ); const resetButton = screen.getByTitle('Reset'); - userEvent.click(resetButton); + await userEvent.click(resetButton); expect(onResetButtonClickMock).toHaveBeenCalled(); expect(screen.getByDisplayValue('30')).toBeTruthy(); diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx index 3d9db6163cf4..3d48bb398e26 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx @@ -1,8 +1,8 @@ import { faker } from '@faker-js/faker'; import { mockAppRoot } from '@rocket.chat/mock-providers'; import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import React from 'react'; -import '@testing-library/jest-dom'; import { mockedAppsContext } from '../../../../../../tests/mocks/client/marketplace'; import { createFakeApp, createFakeLicenseInfo } from '../../../../../../tests/mocks/data'; @@ -12,6 +12,7 @@ it('should look good', async () => { const app = createFakeApp(); render(, { + legacyRoot: true, wrapper: mockAppRoot() .withJohnDoe() .withEndpoint('GET', '/apps/count', async () => ({ @@ -28,5 +29,5 @@ it('should look good', async () => { .build(), }); - screen.getByRole('button', { name: 'Request' }).click(); + await userEvent.click(screen.getByRole('button', { name: 'Request' })); }); diff --git a/apps/meteor/client/views/marketplace/AppMenu.spec.tsx b/apps/meteor/client/views/marketplace/AppMenu.spec.tsx index 8eea5386b3b7..00316b193014 100644 --- a/apps/meteor/client/views/marketplace/AppMenu.spec.tsx +++ b/apps/meteor/client/views/marketplace/AppMenu.spec.tsx @@ -2,7 +2,6 @@ import { faker } from '@faker-js/faker'; import { mockAppRoot } from '@rocket.chat/mock-providers'; import { render, screen } from '@testing-library/react'; import React from 'react'; -import '@testing-library/jest-dom'; import { mockedAppsContext } from '../../../tests/mocks/client/marketplace'; import { createFakeApp } from '../../../tests/mocks/data'; @@ -13,6 +12,7 @@ describe('without app details', () => { const app = createFakeApp(); render(, { + legacyRoot: true, wrapper: mockAppRoot() .withEndpoint('GET', '/apps/count', async () => ({ maxMarketplaceApps: faker.number.int({ min: 0 }), diff --git a/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByCategories.test.ts b/apps/meteor/client/views/marketplace/helpers/filterAppsByCategories.spec.ts similarity index 62% rename from apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByCategories.test.ts rename to apps/meteor/client/views/marketplace/helpers/filterAppsByCategories.spec.ts index 975e45532e54..8b43d0cb3c4c 100644 --- a/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByCategories.test.ts +++ b/apps/meteor/client/views/marketplace/helpers/filterAppsByCategories.spec.ts @@ -1,8 +1,5 @@ -/* eslint-env mocha */ -import { expect } from 'chai'; - -import { filterAppsByCategories } from '../../../../../../../client/views/marketplace/helpers/filterAppsByCategories'; -import type { App } from '../../../../../../../client/views/marketplace/types'; +import type { App } from '../types'; +import { filterAppsByCategories } from './filterAppsByCategories'; describe('filterAppsByCategories', () => { it('should return true if the app is in the categories', () => { @@ -11,14 +8,15 @@ describe('filterAppsByCategories', () => { }; const categories = ['category1']; const result = filterAppsByCategories(app as App, categories); - expect(result).to.be.true; + expect(result).toBe(true); }); + it('should return false if the app is not in the categories', () => { const app = { categories: ['category1', 'category2'], }; const categories = ['category3']; const result = filterAppsByCategories(app as App, categories); - expect(result).to.be.false; + expect(result).toBe(false); }); }); diff --git a/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByFree.test.ts b/apps/meteor/client/views/marketplace/helpers/filterAppsByFree.spec.ts similarity index 78% rename from apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByFree.test.ts rename to apps/meteor/client/views/marketplace/helpers/filterAppsByFree.spec.ts index 49d1de3fd527..839659bc5f68 100644 --- a/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByFree.test.ts +++ b/apps/meteor/client/views/marketplace/helpers/filterAppsByFree.spec.ts @@ -1,8 +1,6 @@ -/* eslint-env mocha */ import type { PurchaseType } from '@rocket.chat/core-typings'; -import { expect } from 'chai'; -import { filterAppsByFree } from '../../../../../../../client/views/marketplace/helpers/filterAppsByFree'; +import { filterAppsByFree } from './filterAppsByFree'; describe('filterAppsByFree', () => { it('should return true if app purchase type is buy and price does not exist or is 0', () => { @@ -12,8 +10,9 @@ describe('filterAppsByFree', () => { price: 0, }; const result = filterAppsByFree(app); - expect(result).to.be.true; + expect(result).toBe(true); }); + it('should return false if app purchase type is not buy', () => { const purchaseType: PurchaseType = 'subscription'; const app = { @@ -21,8 +20,9 @@ describe('filterAppsByFree', () => { price: 0, }; const result = filterAppsByFree(app); - expect(result).to.be.false; + expect(result).toBe(false); }); + it('should return false if app price exists and is different than 0', () => { const purchaseType: PurchaseType = 'buy'; const app = { @@ -30,8 +30,9 @@ describe('filterAppsByFree', () => { price: 5, }; const result = filterAppsByFree(app); - expect(result).to.be.false; + expect(result).toBe(false); }); + it('should return false if both app purchase type is different than buy and price exists and is different than 0', () => { const purchaseType: PurchaseType = 'subscription'; const app = { @@ -39,6 +40,6 @@ describe('filterAppsByFree', () => { price: 5, }; const result = filterAppsByFree(app); - expect(result).to.be.false; + expect(result).toBe(false); }); }); diff --git a/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByPaid.test.ts b/apps/meteor/client/views/marketplace/helpers/filterAppsByPaid.spec.ts similarity index 79% rename from apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByPaid.test.ts rename to apps/meteor/client/views/marketplace/helpers/filterAppsByPaid.spec.ts index 860f67464ff9..b0cc4492ef4a 100644 --- a/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByPaid.test.ts +++ b/apps/meteor/client/views/marketplace/helpers/filterAppsByPaid.spec.ts @@ -1,8 +1,6 @@ -/* eslint-env mocha */ import type { PurchaseType } from '@rocket.chat/core-typings'; -import { expect } from 'chai'; -import { filterAppsByPaid } from '../../../../../../../client/views/marketplace/helpers/filterAppsByPaid'; +import { filterAppsByPaid } from './filterAppsByPaid'; describe('filterAppsByPaid', () => { it('should return true if both app purchase type is subscription and app price exists and is not 0', () => { @@ -12,8 +10,9 @@ describe('filterAppsByPaid', () => { price: 5, }; const result = filterAppsByPaid(app); - expect(result).to.be.true; + expect(result).toBe(true); }); + it('should return true if app purchase type is subscription', () => { const purchaseType: PurchaseType = 'subscription'; const app = { @@ -21,8 +20,9 @@ describe('filterAppsByPaid', () => { price: 0, }; const result = filterAppsByPaid(app); - expect(result).to.be.true; + expect(result).toBe(true); }); + it('should return true if app price exists and is not 0', () => { const purchaseType: PurchaseType = 'buy'; const app = { @@ -30,8 +30,9 @@ describe('filterAppsByPaid', () => { price: 5, }; const result = filterAppsByPaid(app); - expect(result).to.be.true; + expect(result).toBe(true); }); + it('should return false if both app price does not exist or is 0 and app purchase type is not subscription', () => { const purchaseType: PurchaseType = 'buy'; const app = { @@ -39,6 +40,6 @@ describe('filterAppsByPaid', () => { price: 0, }; const result = filterAppsByPaid(app); - expect(result).to.be.false; + expect(result).toBe(false); }); }); diff --git a/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByText.test.ts b/apps/meteor/client/views/marketplace/helpers/filterAppsByText.spec.ts similarity index 65% rename from apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByText.test.ts rename to apps/meteor/client/views/marketplace/helpers/filterAppsByText.spec.ts index bda40e034e19..55623505f5e5 100644 --- a/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByText.test.ts +++ b/apps/meteor/client/views/marketplace/helpers/filterAppsByText.spec.ts @@ -1,7 +1,4 @@ -/* eslint-env mocha */ -import { expect } from 'chai'; - -import { filterAppsByText } from '../../../../../../../client/views/marketplace/helpers/filterAppsByText'; +import { filterAppsByText } from './filterAppsByText'; describe('filterAppsByText', () => { it('should return true if the text is the name of an app', () => { @@ -10,14 +7,15 @@ describe('filterAppsByText', () => { }; const text = 'name1'; const result = filterAppsByText(app.name, text); - expect(result).to.be.true; + expect(result).toBe(true); }); + it('should return false if the text is not the name of an app', () => { const app = { name: 'name1', }; const text = 'name2'; const result = filterAppsByText(app.name, text); - expect(result).to.be.false; + expect(result).toBe(false); }); }); diff --git a/apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByAlphabeticalOrInverseOrder.test.ts b/apps/meteor/client/views/marketplace/helpers/sortAppsByAlphabeticalOrInverseOrder.spec.ts similarity index 71% rename from apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByAlphabeticalOrInverseOrder.test.ts rename to apps/meteor/client/views/marketplace/helpers/sortAppsByAlphabeticalOrInverseOrder.spec.ts index 37e766491b63..5eaf1f7ed1d6 100644 --- a/apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByAlphabeticalOrInverseOrder.test.ts +++ b/apps/meteor/client/views/marketplace/helpers/sortAppsByAlphabeticalOrInverseOrder.spec.ts @@ -1,7 +1,4 @@ -/* eslint-env mocha */ -import { expect } from 'chai'; - -import { sortAppsByAlphabeticalOrInverseOrder } from '../../../../../../../client/views/marketplace/helpers/sortAppsByAlphabeticalOrInverseOrder'; +import { sortAppsByAlphabeticalOrInverseOrder } from './sortAppsByAlphabeticalOrInverseOrder'; describe('sortAppsByAlphabeticalOrder', () => { it.skip('should return a positive number if first word is, alphabetically, after second word', () => { @@ -10,22 +7,24 @@ describe('sortAppsByAlphabeticalOrder', () => { const result = sortAppsByAlphabeticalOrInverseOrder(firstWord, secondWord); - expect(result).to.be.above(0); + expect(result).toBeGreaterThan(0); }); + it.skip('should return a negative number if first word is, alphabetically, before second word', () => { const firstWord = 'Bravo'; const secondWord = 'Alfa'; const result = sortAppsByAlphabeticalOrInverseOrder(firstWord, secondWord); - expect(result).to.be.below(0); + expect(result).toBeLessThan(0); }); + it('should return 0 if the words are the equivalent', () => { const firstWord = 'Alfa'; const secondWord = 'Alfa'; const result = sortAppsByAlphabeticalOrInverseOrder(firstWord, secondWord); - expect(result).to.be.equal(0); + expect(result).toBe(0); }); }); diff --git a/apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByClosestOrFarthestModificationDate.test.ts b/apps/meteor/client/views/marketplace/helpers/sortAppsByClosestOrFarthestModificationDate.spec.ts similarity index 73% rename from apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByClosestOrFarthestModificationDate.test.ts rename to apps/meteor/client/views/marketplace/helpers/sortAppsByClosestOrFarthestModificationDate.spec.ts index 842a728db242..f0e0dc73389c 100644 --- a/apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByClosestOrFarthestModificationDate.test.ts +++ b/apps/meteor/client/views/marketplace/helpers/sortAppsByClosestOrFarthestModificationDate.spec.ts @@ -1,7 +1,4 @@ -/* eslint-env mocha */ -import { expect } from 'chai'; - -import { sortAppsByClosestOrFarthestModificationDate } from '../../../../../../../client/views/marketplace/helpers/sortAppsByClosestOrFarthestModificationDate'; +import { sortAppsByClosestOrFarthestModificationDate } from './sortAppsByClosestOrFarthestModificationDate'; describe('sortAppsByClosestOrFarthestModificationDate', () => { it('should return a positive number if firstDate is before secondDate', () => { @@ -10,22 +7,24 @@ describe('sortAppsByClosestOrFarthestModificationDate', () => { const result = sortAppsByClosestOrFarthestModificationDate(firstDate, secondDate); - expect(result).to.be.above(0); + expect(result).toBeGreaterThan(0); }); + it('should return a negative number if firstDate is after secondDate', () => { const firstDate = '2022-02-21T13:00:00'; const secondDate = '2000-04-01T07:00:00'; const result = sortAppsByClosestOrFarthestModificationDate(firstDate, secondDate); - expect(result).to.be.below(0); + expect(result).toBeLessThan(0); }); + it.skip('should return zero if firstDate and secondDate are equivalent', () => { const firstDate = '2000-04-01T07:00:00'; const secondDate = '2000-04-01T07:00:00'; const result = sortAppsByClosestOrFarthestModificationDate(firstDate, secondDate); - expect(result).to.be.below(0); + expect(result).toBeLessThan(0); }); }); diff --git a/apps/meteor/client/views/notFound/NotFoundPage.spec.tsx b/apps/meteor/client/views/notFound/NotFoundPage.spec.tsx new file mode 100644 index 000000000000..19d2238cefc4 --- /dev/null +++ b/apps/meteor/client/views/notFound/NotFoundPage.spec.tsx @@ -0,0 +1,49 @@ +import { render, waitFor, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import type { MutableRefObject } from 'react'; +import React from 'react'; + +import RouterContextMock from '../../../tests/mocks/client/RouterContextMock'; +import NotFoundPage from './NotFoundPage'; + +it('should look good', async () => { + render(, { legacyRoot: true }); + + await expect(screen.findByRole('heading')).resolves.toHaveTextContent('Page_not_found'); + + expect(screen.getByRole('button', { name: 'Homepage' })).not.toBeDisabled(); +}); + +it('should have correct tab order', async () => { + render(, { legacyRoot: true }); + + expect(document.body).toHaveFocus(); + + await userEvent.tab(); + + expect(screen.getByRole('button', { name: 'Homepage' })).toHaveFocus(); + + await userEvent.tab(); + + expect(document.body).toHaveFocus(); +}); + +describe('"Return to home" button', () => { + describe('when clicked', () => { + it('should go back on history', async () => { + const currentPath: MutableRefObject = { current: undefined }; + + render( + + + , + { legacyRoot: true }, + ); + const button = screen.getByRole('button', { name: 'Homepage' }); + + await userEvent.click(button); + + await waitFor(() => expect(currentPath.current).toBe('/home')); + }); + }); +}); diff --git a/apps/meteor/client/views/room/MessageList/hooks/useKatex.spec.ts b/apps/meteor/client/views/room/MessageList/hooks/useKatex.spec.ts new file mode 100644 index 000000000000..d601ff8ab58d --- /dev/null +++ b/apps/meteor/client/views/room/MessageList/hooks/useKatex.spec.ts @@ -0,0 +1,64 @@ +import { mockAppRoot } from '@rocket.chat/mock-providers'; +import { renderHook } from '@testing-library/react'; + +import { useKatex } from './useKatex'; + +it('should return enabled true dollar syntax true and parenthesis syntax true if all settings is enabled', () => { + const { result } = renderHook(() => useKatex(), { + legacyRoot: true, + wrapper: mockAppRoot() + .withSetting('Katex_Enabled', true) + .withSetting('Katex_Dollar_Syntax', true) + .withSetting('Katex_Parenthesis_Syntax', true) + .build(), + }); + + expect(result.current.katexEnabled).toBe(true); + expect(result.current.katexDollarSyntaxEnabled).toBe(true); + expect(result.current.katexParenthesisSyntaxEnabled).toBe(true); +}); + +it('should return enabled false dollar syntax false and parenthesis syntax false if all settings is disabled', () => { + const { result } = renderHook(() => useKatex(), { + legacyRoot: true, + wrapper: mockAppRoot() + .withSetting('Katex_Enabled', false) + .withSetting('Katex_Dollar_Syntax', false) + .withSetting('Katex_Parenthesis_Syntax', false) + .build(), + }); + + expect(result.current.katexEnabled).toBe(false); + expect(result.current.katexDollarSyntaxEnabled).toBe(false); + expect(result.current.katexParenthesisSyntaxEnabled).toBe(false); +}); + +it('should return enabled true dollar syntax false and parenthesis syntax false if Katex_Enabled settings is enable', () => { + const { result } = renderHook(() => useKatex(), { + legacyRoot: true, + wrapper: mockAppRoot() + .withSetting('Katex_Enabled', true) + .withSetting('Katex_Dollar_Syntax', false) + .withSetting('Katex_Parenthesis_Syntax', false) + .build(), + }); + + expect(result.current.katexEnabled).toBe(true); + expect(result.current.katexDollarSyntaxEnabled).toBe(false); + expect(result.current.katexParenthesisSyntaxEnabled).toBe(false); +}); + +it('should return enabled false dollar syntax false and parenthesis syntax false if DollarSyntaxEnabled and ParenthesisSyntaxEnabled settings is enable', () => { + const { result } = renderHook(() => useKatex(), { + legacyRoot: true, + wrapper: mockAppRoot() + .withSetting('Katex_Enabled', false) + .withSetting('Katex_Dollar_Syntax', true) + .withSetting('Katex_Parenthesis_Syntax', true) + .build(), + }); + + expect(result.current.katexEnabled).toBe(false); + expect(result.current.katexDollarSyntaxEnabled).toBe(false); + expect(result.current.katexParenthesisSyntaxEnabled).toBe(false); +}); diff --git a/apps/meteor/client/views/room/MessageList/lib/autoTranslate.spec.ts b/apps/meteor/client/views/room/MessageList/lib/autoTranslate.spec.ts new file mode 100644 index 000000000000..048716c7f711 --- /dev/null +++ b/apps/meteor/client/views/room/MessageList/lib/autoTranslate.spec.ts @@ -0,0 +1,37 @@ +import type { IMessage, MessageAttachment } from '@rocket.chat/core-typings'; + +import { hasTranslationLanguageInAttachments, hasTranslationLanguageInMessage } from './autoTranslate'; + +describe('hasTranslationLanguageInMessage', () => { + const testCases = [ + [{}, '', false], + [{ translations: { en: 'bah' } }, '', false], + [{ translations: { en: 'bah' } }, 'pt', false], + [{ translations: { en: 'bah' } }, 'en', true], + ] as const; + + testCases.forEach(([message, language, expectedResult]) => { + it(`should return ${JSON.stringify(expectedResult)} for ${JSON.stringify(message)} with ${JSON.stringify(language)}`, () => { + const result = hasTranslationLanguageInMessage(message as unknown as IMessage, language); + expect(result).toBe(expectedResult); + }); + }); +}); + +describe('hasTranslationLanguageInAttachments', () => { + const testCases = [ + [[{}], '', false], + [undefined, '', false], + [[{ translations: { en: 'bah' } }], '', false], + [[{ translations: { en: 'bah' } }], 'pt', false], + [[{ translations: { en: 'bah' } }], 'pt', false], + [[{ translations: { en: 'bah' } }], 'en', true], + ] as const; + + testCases.forEach(([attachment, language, expectedResult]) => { + it(`should return ${JSON.stringify(expectedResult)} for ${JSON.stringify(attachment)} with ${JSON.stringify(language)}`, () => { + const result = hasTranslationLanguageInAttachments(attachment as unknown as MessageAttachment[], language); + expect(result).toBe(expectedResult); + }); + }); +}); diff --git a/apps/meteor/client/views/room/MessageList/lib/isMessageNewDay.spec.ts b/apps/meteor/client/views/room/MessageList/lib/isMessageNewDay.spec.ts new file mode 100644 index 000000000000..542b739efbc4 --- /dev/null +++ b/apps/meteor/client/views/room/MessageList/lib/isMessageNewDay.spec.ts @@ -0,0 +1,59 @@ +import type { IMessage } from '@rocket.chat/core-typings'; + +import { isMessageNewDay } from './isMessageNewDay'; + +const date = new Date('2021-10-27T00:00:00.000Z'); + +const baseMessage: IMessage = { + ts: date, + u: { + _id: 'userId', + name: 'userName', + username: 'userName', + }, + msg: 'message', + rid: 'roomId', + _id: 'messageId', + _updatedAt: date, + urls: [], +}; + +it('should return true if the message is from a different day', () => { + const message = { + ...baseMessage, + }; + const message2 = { + ...baseMessage, + ts: new Date('2021-10-28T00:00:00.000Z'), + }; + expect(isMessageNewDay(message, message2)).toBe(true); +}); + +it('should return false if the message is from the same day', () => { + const message = { + ...baseMessage, + }; + const message2 = { + ...baseMessage, + }; + expect(isMessageNewDay(message, message2)).toBe(false); +}); + +it('should return true if there is no previous message', () => { + const message = { + ...baseMessage, + }; + expect(isMessageNewDay(message, undefined)).toBe(true); +}); + +it('should return true for different days even if the range is on second', () => { + const previous: IMessage = { + ...baseMessage, + ts: new Date(2022, 0, 1, 23, 59, 59, 999), + }; + const current: IMessage = { + ...baseMessage, + ts: new Date(2022, 0, 2, 0, 0, 0, 0), + }; + expect(isMessageNewDay(current, previous)).toBe(true); +}); diff --git a/apps/meteor/client/views/room/MessageList/lib/isMessageSequential.spec.ts b/apps/meteor/client/views/room/MessageList/lib/isMessageSequential.spec.ts new file mode 100644 index 000000000000..d3da6c88fd5b --- /dev/null +++ b/apps/meteor/client/views/room/MessageList/lib/isMessageSequential.spec.ts @@ -0,0 +1,164 @@ +import type { IMessage } from '@rocket.chat/core-typings'; + +import { MessageTypes } from '../../../../../app/ui-utils/lib/MessageTypes'; +import { isMessageSequential } from './isMessageSequential'; + +const TIME_RANGE_IN_SECONDS = 300; + +const date = new Date('2021-10-27T00:00:00.000Z'); +const baseMessage: IMessage = { + ts: date, + u: { + _id: 'userId', + name: 'userName', + username: 'userName', + }, + msg: 'message', + rid: 'roomId', + _id: 'messageId', + _updatedAt: date, + urls: [], +}; + +it('should return false if no previous message', () => { + const current: IMessage = { + ...baseMessage, + }; + expect(isMessageSequential(current, undefined, TIME_RANGE_IN_SECONDS)).toBe(false); +}); + +it("should return false if both messages doesn't belong to the same user", () => { + const previous: IMessage = { + ...baseMessage, + }; + const current: IMessage = { + ...baseMessage, + u: { + _id: 'userId2', + name: 'userName2', + username: 'userName2', + }, + }; + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(false); +}); + +it('should return false if both messages belongs to the same user but have more than five minutes of difference', () => { + const previous: IMessage = { + ...baseMessage, + }; + + const current: IMessage = { + ...previous, + ts: new Date('2021-10-27T00:05:00.001Z'), + }; + + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(false); +}); +it('should return true if both messages belongs to the same user and have less than five minutes of difference', () => { + const previous: IMessage = { + ...baseMessage, + }; + const current: IMessage = { + ...previous, + ts: new Date('2021-10-27T00:04:59.999Z'), + }; + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(true); +}); +it('should return false if message are not groupable', () => { + const previous: IMessage = { + ...baseMessage, + groupable: false, + }; + const current: IMessage = { + ...previous, + groupable: false, + }; + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(false); +}); +it('should return false if both messages are not from the same thread', () => { + const previous: IMessage = { + ...baseMessage, + tmid: 'threadId', + }; + const current: IMessage = { + ...previous, + tmid: 'threadId2', + }; + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(false); +}); + +it('should return true if both messages are from the same thread same user and bellow the time range', () => { + const previous: IMessage = { + ...baseMessage, + tmid: 'threadId', + }; + const current: IMessage = { + ...previous, + tmid: 'threadId', + }; + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(true); +}); + +it('should return false if previous message is thread message but the current is a regular one', () => { + const previous: IMessage = { + tmid: 'threadId', + ...baseMessage, + }; + const current: IMessage = { + ...baseMessage, + }; + + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(false); +}); + +it('should return true if message is a reply from a previous message', () => { + const previous: IMessage = { + ...baseMessage, + _id: 'threadId', + }; + const current: IMessage = { + ...previous, + tmid: 'threadId', + }; + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(true); +}); +it("should return false if both messages don't have the same alias", () => { + const previous: IMessage = { + ...baseMessage, + alias: 'alias', + }; + const current: IMessage = { + ...previous, + alias: 'alias2', + }; + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(false); +}); + +it('should return false if message is from system', () => { + MessageTypes.registerType({ + id: 'au', + system: true, + message: 'User_added_by', + }); + const previous: IMessage = { + ...baseMessage, + }; + const current: IMessage = { + ...previous, + ts: new Date('2021-10-27T00:04:59.999Z'), + t: 'au', + }; + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(false); +}); + +it('should return false even if messages should be sequential, but they are from a different day', () => { + const previous: IMessage = { + ...baseMessage, + ts: new Date(2022, 0, 1, 23, 59, 59, 999), + }; + const current: IMessage = { + ...baseMessage, + ts: new Date(2022, 0, 2, 0, 0, 0, 0), + }; + expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).toBe(false); +}); diff --git a/apps/meteor/client/views/room/MessageList/lib/isOwnUserMessage.spec.ts b/apps/meteor/client/views/room/MessageList/lib/isOwnUserMessage.spec.ts new file mode 100644 index 000000000000..c819a864bd9a --- /dev/null +++ b/apps/meteor/client/views/room/MessageList/lib/isOwnUserMessage.spec.ts @@ -0,0 +1,63 @@ +import type { IMessage, ISubscription } from '@rocket.chat/core-typings'; + +import { MessageTypes } from '../../../../../app/ui-utils/lib/MessageTypes'; +import { isOwnUserMessage } from './isOwnUserMessage'; + +const date = new Date('2021-10-27T00:00:00.000Z'); + +const baseMessage: IMessage = { + ts: date, + u: { + _id: 'userId', + name: 'userName', + username: 'userName', + }, + msg: 'message', + rid: 'roomId', + _id: 'messageId', + _updatedAt: date, + urls: [], +}; + +// Register a system message +MessageTypes.registerType({ + id: 'au', + system: true, + message: 'User_added_to', +}); + +it('should return true if the message is from user', () => { + const message: IMessage = { + ...baseMessage, + }; + + const subscription: ISubscription = { + u: { + _id: 'userId', + }, + } as ISubscription; + + expect(isOwnUserMessage(message, subscription)).toBe(true); +}); + +it('should return false if the message is not from user', () => { + const message: IMessage = { + ...baseMessage, + }; + + const subscription: ISubscription = { + u: { + _id: 'otherUser', + }, + } as ISubscription; + + expect(isOwnUserMessage(message, subscription)).toBe(false); +}); + +it('should return false if there is no subscription', () => { + const message: IMessage = { + ...baseMessage, + }; + + expect(isOwnUserMessage(message, undefined)).toBe(false); +}); diff --git a/apps/meteor/client/views/room/MessageList/lib/isParsedMessage.spec.ts b/apps/meteor/client/views/room/MessageList/lib/isParsedMessage.spec.ts new file mode 100644 index 000000000000..46e20c60e37e --- /dev/null +++ b/apps/meteor/client/views/room/MessageList/lib/isParsedMessage.spec.ts @@ -0,0 +1,47 @@ +import type { IMessage } from '@rocket.chat/core-typings'; +import type { Root } from '@rocket.chat/message-parser'; + +import { isParsedMessage } from './isParsedMessage'; + +const date = new Date('2021-10-27T00:00:00.000Z'); + +const baseMessage: IMessage = { + ts: date, + u: { + _id: 'userId', + name: 'userName', + username: 'userName', + }, + msg: 'message', + md: [ + { + type: 'PARAGRAPH', + value: [ + { + type: 'PLAIN_TEXT', + value: 'message', + }, + ], + }, + ], + rid: 'roomId', + _id: 'messageId', + _updatedAt: date, + urls: [], +}; + +it('should return true if the message parsed', () => { + const message: IMessage = { + ...baseMessage, + }; + + expect(isParsedMessage(message.md as Root)).toBe(true); +}); + +it('should return false if the message is not parsed', () => { + const message: IMessage = { + ...baseMessage, + }; + + expect(isParsedMessage(message.msg as string)).toBe(false); +}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isValidLink.spec.ts b/apps/meteor/client/views/room/MessageList/lib/isValidLink.spec.ts similarity index 74% rename from apps/meteor/tests/unit/client/views/room/MessageList/lib/isValidLink.spec.ts rename to apps/meteor/client/views/room/MessageList/lib/isValidLink.spec.ts index b114fef2851a..6f1278024ab3 100644 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isValidLink.spec.ts +++ b/apps/meteor/client/views/room/MessageList/lib/isValidLink.spec.ts @@ -1,6 +1,4 @@ -import { expect } from 'chai'; - -import { isValidLink } from '../../../../../../../client/views/room/MessageList/lib/isValidLink'; +import { isValidLink } from './isValidLink'; describe('isValidLink', () => { const testCases = [ @@ -17,7 +15,7 @@ describe('isValidLink', () => { testCases.forEach(([parameter, expectedResult]) => { it(`should return ${JSON.stringify(expectedResult)} for ${JSON.stringify(parameter)}`, () => { const result = isValidLink(parameter); - expect(result).to.be.equal(expectedResult); + expect(result).toBe(expectedResult); }); }); }); diff --git a/apps/meteor/client/views/room/body/RetentionPolicyWarning.spec.tsx b/apps/meteor/client/views/room/body/RetentionPolicyWarning.spec.tsx index a6c49c5537de..712a2b9850cc 100644 --- a/apps/meteor/client/views/room/body/RetentionPolicyWarning.spec.tsx +++ b/apps/meteor/client/views/room/body/RetentionPolicyWarning.spec.tsx @@ -1,6 +1,5 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; -import '@testing-library/jest-dom/extend-expect'; import { createRenteionPolicySettingsMock as createMock } from '../../../../tests/mocks/client/mockRetentionPolicySettings'; import { createFakeRoom } from '../../../../tests/mocks/data'; @@ -15,13 +14,17 @@ beforeEach(() => { describe('RetentionPolicyWarning', () => { it('Should render callout if settings are valid', () => { const fakeRoom = createFakeRoom({ t: 'c' }); - render(, { wrapper: createMock({ appliesToChannels: true, TTLChannels: 60000 }) }); + render(, { + legacyRoot: true, + wrapper: createMock({ appliesToChannels: true, TTLChannels: 60000 }), + }); expect(screen.getByRole('alert')).toHaveTextContent('a minute June 1, 2024, 12:30 AM'); }); it('Should not render callout if settings are invalid', () => { const fakeRoom = createFakeRoom({ t: 'c' }); render(, { + legacyRoot: true, wrapper: createMock({ appliesToChannels: true, TTLChannels: 60000, advancedPrecisionCron: '* * * 12 *', advancedPrecision: true }), }); expect(screen.queryByRole('alert')).not.toBeInTheDocument(); diff --git a/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfBlockModal.tsx b/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfBlockModal.tsx index d16d00ab4c49..f362aac89cc8 100644 --- a/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfBlockModal.tsx +++ b/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfBlockModal.tsx @@ -23,6 +23,7 @@ const VideoConfBlockModal = ({ onClose, onConfirm }: { onClose: () => void; onCo return ( { - const wrapper = ({ children }: { children: ReactNode }) => ( - null, - }, - currentModal: { component: null }, - }} - /> - ); beforeEach(() => { window.RocketChatDesktop = { openInternalVideoChatWindow: jest.fn(), @@ -29,20 +16,26 @@ describe('with window.RocketChatDesktop set', () => { }); it('should pass to videoConfOpenCall the url', async () => { - const { result } = renderHook(() => useVideoConfOpenCall(), { wrapper }); + const { result } = renderHook(() => useVideoConfOpenCall(), { legacyRoot: true, wrapper: mockAppRoot().build() }); + const url = faker.internet.url(); - result.current(url); + act(() => { + result.current(url); + }); expect(window.RocketChatDesktop?.openInternalVideoChatWindow).toHaveBeenCalledWith(url, { providerName: undefined }); }); it('should pass to videoConfOpenCall the url and the providerName', async () => { - const { result } = renderHook(() => useVideoConfOpenCall(), { wrapper }); + const { result } = renderHook(() => useVideoConfOpenCall(), { legacyRoot: true, wrapper: mockAppRoot().build() }); + const url = faker.internet.url(); const providerName = faker.lorem.word(); - result.current(url, providerName); + act(() => { + result.current(url, providerName); + }); expect(window.RocketChatDesktop?.openInternalVideoChatWindow).toHaveBeenCalledWith(url, { providerName, @@ -50,43 +43,45 @@ describe('with window.RocketChatDesktop set', () => { }); }); -describe('with window.RocketChatDesktop unset', () => { - const setModal = jest.fn(); - - const wrapper = ({ children }: { children: ReactNode }) => ( - - ); +describe('without window.RocketChatDesktop set', () => { + const previousWindowOpen = window.open; + + afterAll(() => { + window.open = previousWindowOpen; + }); it('should open window', async () => { - const { result } = renderHook(() => useVideoConfOpenCall(), { wrapper }); - const url = faker.internet.url(); + window.open = jest.fn(() => ({} as Window)); - window.open = jest.fn(); + const { result } = renderHook(() => useVideoConfOpenCall(), { + legacyRoot: true, + wrapper: mockAppRoot().build(), + }); - result.current(url); + const url = faker.internet.url(); + act(() => { + result.current(url); + }); expect(window.open).toHaveBeenCalledWith(url); - expect(setModal).not.toBeCalled(); + expect(screen.queryByRole('dialog', { name: 'Open_call_in_new_tab' })).not.toBeInTheDocument(); }); - it('should NOT open window AND open modal', async () => { - const { result } = renderHook(() => useVideoConfOpenCall(), { wrapper }); - const url = faker.internet.url(); - + it('should NOT open window, AND open modal instead', async () => { window.open = jest.fn(() => null); - result.current(url); + const { result } = renderHook(() => useVideoConfOpenCall(), { + legacyRoot: true, + wrapper: mockAppRoot().build(), + }); + + const url = faker.internet.url(); + act(() => { + result.current(url); + }); expect(window.open).toHaveBeenCalledWith(url); - expect(window.open).toReturnWith(null); - expect(setModal).toBeCalled(); + expect(window.open).toHaveReturnedWith(null); + expect(await screen.findByRole('dialog', { name: 'Open_call_in_new_tab' })).toBeInTheDocument(); }); }); diff --git a/apps/meteor/client/views/room/lib/getRoomGroup.spec.ts b/apps/meteor/client/views/room/lib/getRoomGroup.spec.ts new file mode 100644 index 000000000000..676f212f607a --- /dev/null +++ b/apps/meteor/client/views/room/lib/getRoomGroup.spec.ts @@ -0,0 +1,21 @@ +import type { IRoom } from '@rocket.chat/core-typings'; + +import { getRoomGroup } from './getRoomGroup'; + +it('should return "direct" for direct message rooms', () => { + const result = getRoomGroup({ t: 'd' } as IRoom); + + expect(result).toBe('direct'); +}); + +it('should return "team" for team rooms', () => { + const result = getRoomGroup({ teamMain: true } as IRoom); + + expect(result).toBe('team'); +}); + +it('should return "direct_multiple" for direct message room with many users', () => { + const result = getRoomGroup({ uids: ['id1', 'id2', 'id3'], t: 'd' } as IRoom); + + expect(result).toBe('direct_multiple'); +}); diff --git a/apps/meteor/client/views/root/MainLayout/MainLayoutStyleTags.spec.tsx b/apps/meteor/client/views/root/MainLayout/MainLayoutStyleTags.spec.tsx index 535ed378cec3..ad7159ab7d8e 100644 --- a/apps/meteor/client/views/root/MainLayout/MainLayoutStyleTags.spec.tsx +++ b/apps/meteor/client/views/root/MainLayout/MainLayoutStyleTags.spec.tsx @@ -7,6 +7,7 @@ import { MainLayoutStyleTags } from './MainLayoutStyleTags'; describe('MainLayout style tags', () => { it('should create the Light theme style tag', () => { render(, { + legacyRoot: true, wrapper: mockAppRoot().withUserPreference('themeAppearence', 'light').build(), }); const tagLight = queryByAttribute('id', document.head, 'main-palette-light'); @@ -15,6 +16,7 @@ describe('MainLayout style tags', () => { it('should create the Dark theme style tag', () => { render(, { + legacyRoot: true, wrapper: mockAppRoot().withUserPreference('themeAppearence', 'dark').build(), }); const tagDark = queryByAttribute('id', document.head, 'main-palette-dark'); @@ -23,9 +25,28 @@ describe('MainLayout style tags', () => { it('should create the codeBlock style tag when in dark mode', () => { render(, { + legacyRoot: true, wrapper: mockAppRoot().withUserPreference('themeAppearence', 'dark').build(), }); const style = queryByAttribute('id', document.head, 'codeBlock-palette'); expect(style).not.toBeNull(); }); }); + +it('should create the Dark theme style tag', () => { + render(, { + legacyRoot: true, + wrapper: mockAppRoot().withUserPreference('themeAppearence', 'dark').build(), + }); + const tagDark = queryByAttribute('id', document.head, 'main-palette-dark'); + expect(tagDark).not.toBeNull(); +}); + +it('should create the codeBlock style tag when in dark mode', () => { + render(, { + legacyRoot: true, + wrapper: mockAppRoot().withUserPreference('themeAppearence', 'dark').build(), + }); + const style = queryByAttribute('id', document.head, 'codeBlock-palette'); + expect(style).not.toBeNull(); +}); diff --git a/apps/meteor/client/views/root/SAMLLoginRoute.spec.tsx b/apps/meteor/client/views/root/SAMLLoginRoute.spec.tsx new file mode 100644 index 000000000000..e642e7851707 --- /dev/null +++ b/apps/meteor/client/views/root/SAMLLoginRoute.spec.tsx @@ -0,0 +1,107 @@ +import { MockedServerContext, MockedUserContext } from '@rocket.chat/mock-providers'; +import { render } from '@testing-library/react'; +import { Meteor } from 'meteor/meteor'; +import React from 'react'; + +import RouterContextMock from '../../../tests/mocks/client/RouterContextMock'; +import SAMLLoginRoute from './SAMLLoginRoute'; + +const navigateStub = jest.fn(); + +beforeEach(() => { + jest.clearAllMocks(); + navigateStub.mockClear(); + (Meteor.loginWithSamlToken as jest.Mock).mockClear(); +}); + +it('should redirect to /home', async () => { + render( + + + + + + + , + { legacyRoot: true }, + ); + + expect(navigateStub).toHaveBeenCalledTimes(1); + expect(navigateStub).toHaveBeenLastCalledWith(expect.objectContaining({ pathname: '/home' }), expect.anything()); +}); + +it('should redirect to /home when userId is not null', async () => { + render( + + + + + + + , + { legacyRoot: true }, + ); + + expect(navigateStub).toHaveBeenCalledTimes(1); + expect(navigateStub).toHaveBeenLastCalledWith(expect.objectContaining({ pathname: '/home' }), expect.anything()); +}); + +it('should redirect to /home when userId is null and redirectUrl is not within the workspace domain', async () => { + render( + + + + + , + { legacyRoot: true }, + ); + + expect(navigateStub).toHaveBeenCalledTimes(1); + expect(navigateStub).toHaveBeenLastCalledWith(expect.objectContaining({ pathname: '/home' }), expect.anything()); +}); + +it('should redirect to the provided redirectUrl when userId is null and redirectUrl is within the workspace domain', async () => { + render( + + + + + , + { legacyRoot: true }, + ); + + expect(navigateStub).toHaveBeenCalledTimes(1); + expect(navigateStub).toHaveBeenLastCalledWith(expect.objectContaining({ pathname: '/invite/test' }), expect.anything()); +}); + +it('should call loginWithSamlToken when component is mounted', async () => { + render( + + + + + , + { legacyRoot: true }, + ); + + expect(Meteor.loginWithSamlToken).toHaveBeenCalledTimes(1); + expect(Meteor.loginWithSamlToken).toHaveBeenLastCalledWith(undefined, expect.any(Function)); +}); + +it('should call loginWithSamlToken with the token when it is present', async () => { + render( + + + + + , + { legacyRoot: true }, + ); + + expect(Meteor.loginWithSamlToken).toHaveBeenCalledTimes(1); + expect(Meteor.loginWithSamlToken).toHaveBeenLastCalledWith('testToken', expect.any(Function)); +}); diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 03d3d2553e95..5addaf756f8a 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -31,25 +31,25 @@ "stylelint": "stylelint \"app/**/*.css\" \"client/**/*.css\" \"app/**/*.less\" \"client/**/*.less\" \"ee/**/*.less\"", "stylelint:fix": "stylelint --fix \"app/**/*.css\" \"client/**/*.css\" \"app/**/*.less\" \"client/**/*.less\" \"ee/**/*.less\"", "typecheck": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" tsc -p tsconfig.typecheck.json", - "deploy": "npm run build && pm2 startOrRestart pm2.json", + "deploy": "yarn build && pm2 startOrRestart pm2.json", "coverage": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' nyc -r html mocha --config ./.mocharc.js", "test:e2e": "playwright test", "test:e2e:federation": "playwright test --config=playwright-federation.config.ts", "test:e2e:nyc": "nyc report --reporter=lcov", "testapi": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' mocha --config ./.mocharc.api.js", - "testunit": "npm run .testunit:definition && npm run .testunit:client && npm run .testunit:server:cov", + "testunit": "yarn .testunit:definition && yarn .testunit:client && yarn .testunit:server:cov", ".testunit:server": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' mocha --config ./.mocharc.js", ".testunit:server:cov": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' nyc -r text -r lcov mocha --config ./.mocharc.js", - ".testunit:client": "jest --silent && TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' mocha --config ./.mocharc.client.js --exit", + ".testunit:client": "jest", ".testunit:definition": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' mocha --config ./.mocharc.definition.js", "testunit-watch": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' mocha --watch --config ./.mocharc.js", - "test": "npm run testapi && npm run testui", + "test": "yarn testunit && yarn testapi", "translation-diff": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' ts-node .scripts/translation-diff.ts", "translation-check": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' ts-node .scripts/translation-check.ts", "translation-fix-order": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' ts-node .scripts/translation-fix-order.ts", "version": "node .scripts/version.js", "set-version": "node .scripts/set-version.js", - "release": "meteor npm run set-version --silent", + "release": "meteor yarn set-version --silent", "storybook": "cross-env NODE_OPTIONS=--max-old-space-size=8192 start-storybook -p 6006 --no-version-updates", "prepare": "node playwright.prepare.mjs", "docker:start": "docker-compose up" @@ -86,12 +86,9 @@ "@storybook/addons": "~6.5.16", "@storybook/react": "~6.5.16", "@storybook/testing-library": "0.0.13", - "@swc/core": "^1.3.95", - "@swc/jest": "^0.2.29", "@tanstack/react-query-devtools": "^4.19.1", - "@testing-library/react": "~12.1.5", - "@testing-library/react-hooks": "^8.0.1", - "@testing-library/user-event": "~13.5.0", + "@testing-library/react": "~16.0.0", + "@testing-library/user-event": "~14.5.2", "@types/adm-zip": "^0.5.3", "@types/archiver": "^5.3.4", "@types/bad-words": "^3.0.2", @@ -117,6 +114,7 @@ "@types/he": "^1.1.2", "@types/i18next-sprintf-postprocessor": "^0.2.2", "@types/imap": "^0.8.39", + "@types/jest": "~29.5.12", "@types/jsdom": "^16.2.15", "@types/jsdom-global": "^3.0.6", "@types/jsrsasign": "^10.5.11", @@ -182,7 +180,7 @@ "eslint-plugin-prettier": "~4.2.1", "eslint-plugin-react": "~7.32.2", "eslint-plugin-react-hooks": "~4.6.0", - "eslint-plugin-testing-library": "~5.11.1", + "eslint-plugin-testing-library": "~6.2.2", "eslint-plugin-you-dont-need-lodash-underscore": "~6.12.0", "fast-glob": "^3.2.12", "i18next": "~23.4.9", 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 15f983927cf3..9f0427ec2d8e 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 @@ -982,7 +982,6 @@ describe('LIVECHAT - rooms', () => { .expect('Content-Type', 'application/json') .expect(200) .expect((res: Response) => { - console.log({ res: res.body }); expect(res.body).to.have.property('success', true); }); diff --git a/apps/meteor/tests/mocks/client/ServerProviderMock.tsx b/apps/meteor/tests/mocks/client/ServerProviderMock.tsx index 6c07573f05b2..b661fea54379 100644 --- a/apps/meteor/tests/mocks/client/ServerProviderMock.tsx +++ b/apps/meteor/tests/mocks/client/ServerProviderMock.tsx @@ -69,14 +69,14 @@ const contextValue = { getStream, }; -type ServerProviderProps = { +type ServerProviderMockProps = { children?: ReactNode; callEndpoint?: ContextType['callEndpoint']; }; -const ServerProvider = ({ children, callEndpoint }: ServerProviderProps) => { +const ServerProviderMock = ({ children, callEndpoint }: ServerProviderMockProps) => { const value = useMemo(() => ({ ...contextValue, callEndpoint: callEndpoint ?? contextValue.callEndpoint }), [callEndpoint]); return ; }; -export default ServerProvider; +export default ServerProviderMock; diff --git a/apps/meteor/tests/mocks/client/blobUrls.ts b/apps/meteor/tests/mocks/client/blobUrls.ts deleted file mode 100644 index d56164c027ff..000000000000 --- a/apps/meteor/tests/mocks/client/blobUrls.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { v4 } from 'uuid'; - -export const enableBlobUrlsMock = (): void => { - const urlByBlob = new WeakMap(); - const blobByUrl = new Map(); - - window.URL.createObjectURL = (blob: Blob): string => { - const url = urlByBlob.get(blob) ?? `blob://${v4()}`; - urlByBlob.set(blob, url); - blobByUrl.set(url, blob); - return url; - }; - - window.URL.revokeObjectURL = (url: string): void => { - const blob = blobByUrl.get(url); - if (!blob) { - return; - } - - urlByBlob.delete(blob); - blobByUrl.delete(url); - }; -}; diff --git a/apps/meteor/tests/mocks/client/jsdom.ts b/apps/meteor/tests/mocks/client/jsdom.ts deleted file mode 100644 index 3398a619a932..000000000000 --- a/apps/meteor/tests/mocks/client/jsdom.ts +++ /dev/null @@ -1,9 +0,0 @@ -import globalJsdom from 'jsdom-global'; - -const testUrl = process.env.TEST_API_URL || 'http://localhost:3000'; - -export const enableJsdom = (): void => { - globalJsdom('', { - url: testUrl, - }); -}; diff --git a/apps/meteor/tests/setup/cleanupTestingLibrary.ts b/apps/meteor/tests/setup/cleanupTestingLibrary.ts deleted file mode 100644 index 663890796ac8..000000000000 --- a/apps/meteor/tests/setup/cleanupTestingLibrary.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { cleanup } from '@testing-library/react'; - -/** - * Usually the testing library attachs its `cleanup` function by itself when an `afterEach` function is present at the - * global scope. It provides a simple mechanism for, e.g., unmounting React components after tests to avoid leaking - * memory and breaking the idempotence of subsequent tests. Despite working fine at a single run, when Mocha is run in - * _watch mode_ all hooks previously attached are discarded and reloaded from **tests files only**, and its supposed to - * work that way. - * - * See https://testing-library.com/docs/react-testing-library/setup#auto-cleanup-in-mochas-watch-mode - */ - -export const mochaHooks = { - afterEach(): void { - cleanup(); - }, -}; diff --git a/apps/meteor/tests/setup/hoistedReact.ts b/apps/meteor/tests/setup/hoistedReact.ts deleted file mode 100644 index 47a42b21fd95..000000000000 --- a/apps/meteor/tests/setup/hoistedReact.ts +++ /dev/null @@ -1,15 +0,0 @@ -// A UNINTENDED LOL-ZONE: SORRY FOR THIS -// ------------+----------+------------- -// /\O | _O | O -// /\/ | //|_ | /_ -// /\ | | | |\ -// / \ | /| | / | -// LOL LOL | LLOL | LOLLOL -// ------------+----------+------------- -// BLACK MAGIC FULL FEATURED ENABLED - -// As Meteor requires a disabled hoisting of dependencies, we end up with multiple React instances, -// despite having the same version. - -// eslint-disable-next-line @typescript-eslint/no-var-requires -Object.assign(require('../../node_modules/react'), require('../../../../node_modules/react')); diff --git a/apps/meteor/tests/setup/registerWebApiMocks.ts b/apps/meteor/tests/setup/registerWebApiMocks.ts deleted file mode 100644 index 83bf826fa0d0..000000000000 --- a/apps/meteor/tests/setup/registerWebApiMocks.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { enableBlobUrlsMock } from '../mocks/client/blobUrls'; -import { enableJsdom } from '../mocks/client/jsdom'; - -enableJsdom(); -enableBlobUrlsMock(); diff --git a/apps/meteor/tests/unit/app/ui-utils/client.tests.ts b/apps/meteor/tests/unit/app/ui-utils/client.tests.ts deleted file mode 100644 index 5de4d53e2003..000000000000 --- a/apps/meteor/tests/unit/app/ui-utils/client.tests.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* eslint-env mocha */ -import { expect } from 'chai'; -import { JSDOM } from 'jsdom'; - -import { waitForElement } from '../../../../client/lib/utils/waitForElement'; - -describe('waitUntilWrapperExists', () => { - const globalDocument = global.document; - const mutationObserver = global.MutationObserver; - - beforeEach(() => { - const dom = new JSDOM( - ` - - - - `, - { url: 'http://localhost' }, - ); - global.document = dom.window.document; - global.MutationObserver = dom.window.MutationObserver; - }); - - afterEach(() => { - global.document = globalDocument; - global.MutationObserver = mutationObserver; - }); - - it('should return the element when it is already in the dom', async () => { - expect(await waitForElement('.ready')).to.be.equal(document.querySelector('.ready')); - }); - - it('should await until the element be in the dom and return it', async () => { - setTimeout(() => { - const element = document.createElement('div'); - element.setAttribute('class', 'not-ready'); - document.body.appendChild(element); - }, 5); - expect(await waitForElement('.not-ready')).to.be.equal(document.querySelector('.not-ready')); - }); -}); diff --git a/apps/meteor/tests/unit/client/components/Omnichannel/modals/TranscriptModal.spec.tsx b/apps/meteor/tests/unit/client/components/Omnichannel/modals/TranscriptModal.spec.tsx deleted file mode 100644 index 517253afd087..000000000000 --- a/apps/meteor/tests/unit/client/components/Omnichannel/modals/TranscriptModal.spec.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import type { IOmnichannelRoom } from '@rocket.chat/core-typings'; -import { userEvent } from '@storybook/testing-library'; -import { render, screen } from '@testing-library/react'; -import { expect, spy } from 'chai'; -import React from 'react'; - -import TranscriptModal from '../../../../../../client/components/Omnichannel/modals/TranscriptModal'; - -const room = { - open: true, - v: { token: '1234567890' }, - transcriptRequest: { - email: 'example@example.com', - subject: 'Transcript of livechat conversation', - }, -} as IOmnichannelRoom; - -const defaultProps = { - room, - email: 'test@example.com', - onRequest: () => null, - onSend: () => null, - onCancel: () => null, - onDiscard: () => null, -}; - -describe('components/Omnichannel/TranscriptModal', () => { - it('should show Undo request button when roomOpen is true and transcriptRequest exist', () => { - const onDiscardMock = spy(); - render(); - const undoRequestButton = screen.getByText('Undo_request'); - - userEvent.click(undoRequestButton); - - expect(onDiscardMock).to.have.been.called(); - }); - - it('should show Request button when roomOpen is true and transcriptRequest not exist', async () => { - render(); - - const requestBtn = await screen.findByRole('button', { name: 'request-button' }); - expect(requestBtn).to.be.visible; - }); - - it('should show Send button when roomOpen is false', async () => { - render(); - - const sendBtn = await screen.findByRole('button', { name: 'send-button' }); - expect(sendBtn).to.be.visible; - }); -}); diff --git a/apps/meteor/tests/unit/client/lib/federation/Federation.test.ts b/apps/meteor/tests/unit/client/lib/federation/Federation.test.ts deleted file mode 100644 index dff34d739258..000000000000 --- a/apps/meteor/tests/unit/client/lib/federation/Federation.test.ts +++ /dev/null @@ -1,489 +0,0 @@ -import { expect } from 'chai'; -import proxyquire from 'proxyquire'; -import sinon from 'sinon'; - -import { RoomMemberActions, RoomSettingsEnum } from '../../../../../definition/IRoomTypeConfig'; - -const findOneStub = sinon.stub(); - -const Federation = proxyquire.noCallThru().load('../../../../../client/lib/federation/Federation', { - '../../../app/models/client': { - RoomRoles: { - findOne: findOneStub, - }, - }, -}); - -describe('Federation[Client] - Federation', () => { - afterEach(() => findOneStub.reset()); - - describe('#actionAllowed()', () => { - const me = 'user-id'; - const them = 'other-user-id'; - - it('should return false if the room is not federated', () => { - expect(Federation.actionAllowed({ federated: false } as any, RoomMemberActions.REMOVE_USER, 'user-id', { roles: ['owner'] } as any)) - .to.be.false; - }); - - it('should return false if the room is a direct message', () => { - expect( - Federation.actionAllowed({ federated: true, t: 'd' } as any, RoomMemberActions.REMOVE_USER, 'user-id', { roles: ['owner'] } as any), - ).to.be.false; - }); - - it('should return false if the user is not subscribed to the room', () => { - expect(Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, 'user-id', undefined)).to.be.false; - }); - - it('should return false if the user is trying to remove himself', () => { - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, 'user-id', { - u: { _id: 'user-id' }, - roles: ['owner'], - } as any), - ).to.be.false; - }); - - describe('Owners', () => { - const myRole = ['owner']; - - describe('Seeing another owners', () => { - const theirRole = ['owner']; - it('should return true if the user want to remove himself as an owner', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: me }, - roles: myRole, - } as any), - ).to.be.true; - }); - it('should return true if the user want to add himself as a moderator (Demoting himself to moderator)', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: me }, - roles: myRole, - } as any), - ).to.be.true; - }); - it('should return false if the user want to remove another owners as an owner', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.false; - }); - it('should return false if the user want to remove another owners from the room', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.false; - }); - }); - describe('Seeing moderators', () => { - const theirRole = ['moderator']; - - it('should return true if the user want to add/remove moderators as an owner', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.true; - }); - it('should return true if the user want to remove moderators as a moderator', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.true; - }); - it('should return true if the user want to remove moderators from the room', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.true; - }); - }); - describe('Seeing normal users', () => { - it('should return true if the user want to add/remove normal users as an owner', () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.true; - }); - it('should return true if the user want to add/remove normal users as a moderator', () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.true; - }); - it('should return true if the user want to remove normal users from the room', () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.true; - }); - }); - }); - - describe('Moderators', () => { - const myRole = ['moderator']; - describe('Seeing owners', () => { - const theirRole = ['owner']; - it('should return false if the user want to add/remove owners as a moderator', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: me }, - roles: myRole, - } as any), - ).to.be.false; - }); - it('should return false if the user want to add/remove owners as a moderator', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: me }, - roles: myRole, - } as any), - ).to.be.false; - }); - it('should return false if the user want to add/remove owners as a moderator', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: me }, - roles: myRole, - } as any), - ).to.be.false; - }); - it('should return false if the user want to remove owners from the room', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, me, { - u: { _id: me }, - roles: myRole, - } as any), - ).to.be.false; - }); - }); - describe('Seeing another moderators', () => { - const theirRole = ['moderator']; - it('should return false if the user want to add/remove moderator as an owner', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.false; - }); - it('should return true if the user want to remove himself as a moderator (Demoting himself)', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: me }, - roles: myRole, - } as any), - ).to.be.true; - }); - it('should return false if the user want to promote himself as an owner', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: me }, - roles: myRole, - } as any), - ).to.be.false; - }); - it('should return false if the user want to remove another moderator from their role', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.false; - }); - it('should return false if the user want to remove another moderator from the room', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.false; - }); - }); - describe('Seeing normal users', () => { - it('should return false if the user want to add/remove normal users as an owner', () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.false; - }); - it('should return true if the user want to add/remove normal users as a moderator', () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.true; - }); - it('should return true if the user want to remove normal users from the room', () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, me, { - u: { _id: them }, - roles: myRole, - } as any), - ).to.be.true; - }); - }); - }); - - describe('Normal user', () => { - describe('Seeing owners', () => { - const theirRole = ['owner']; - it('should return false if the user want to add/remove owners as a normal user', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: them }, - } as any), - ).to.be.false; - }); - it('should return false if the user want to add/remove moderators as a normal user', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: them }, - } as any), - ).to.be.false; - }); - it('should return false if the user want to remove owners from the room', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, me, { - u: { _id: them }, - } as any), - ).to.be.false; - }); - }); - describe('Seeing moderators', () => { - const theirRole = ['owner']; - it('should return false if the user want to add/remove owner as a normal user', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: them }, - } as any), - ).to.be.false; - }); - it('should return false if the user want to remove a moderator from their role', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_MODERATOR, me, { - u: { _id: them }, - } as any), - ).to.be.false; - }); - it('should return false if the user want to remove a moderator from the room', () => { - findOneStub.returns({ roles: theirRole }); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, me, { - u: { _id: them }, - } as any), - ).to.be.false; - }); - }); - describe('Seeing another normal users', () => { - it('should return false if the user want to add/remove owner as a normal user', () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: them }, - } as any), - ).to.be.false; - }); - it('should return false if the user want to add/remove moderator as a normal user', () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.SET_AS_OWNER, me, { - u: { _id: them }, - } as any), - ).to.be.false; - }); - it('should return false if the user want to remove normal users from the room', () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, RoomMemberActions.REMOVE_USER, me, { - u: { _id: them }, - } as any), - ).to.be.false; - }); - - [RoomMemberActions.SET_AS_MODERATOR, RoomMemberActions.SET_AS_OWNER, RoomMemberActions.REMOVE_USER].forEach((action) => { - it(`should return false if the user want to ${action} for himself`, () => { - findOneStub.returns(undefined); - expect( - Federation.actionAllowed({ federated: true } as any, action, me, { - u: { _id: me }, - } as any), - ).to.be.false; - }); - }); - }); - }); - }); - - describe('#isEditableByTheUser()', () => { - it('should return false if the user is null', () => { - expect(Federation.isEditableByTheUser(undefined, { u: { _id: 'id' } } as any, {} as any)).to.be.false; - }); - - it('should return false if the room is null', () => { - expect(Federation.isEditableByTheUser({} as any, undefined, {} as any)).to.be.false; - }); - - it('should return false if the subscription is null', () => { - expect(Federation.isEditableByTheUser({} as any, {} as any, undefined)).to.be.false; - }); - - it('should return false if the current room is NOT a federated one', () => { - expect(Federation.isEditableByTheUser({ _id: 'differentId' } as any, { u: { _id: 'id' } } as any, {} as any)).to.be.false; - }); - - it('should return false if the current user is NOT the room owner nor moderator', () => { - expect(Federation.isEditableByTheUser({ _id: 'differentId' } as any, { federated: true, u: { _id: 'id' } } as any, {} as any)).to.be - .false; - }); - - it('should return true if the current user is a room owner', () => { - expect( - Federation.isEditableByTheUser( - { _id: 'differentId' } as any, - { federated: true, u: { _id: 'id' } } as any, - { roles: ['owner'] } as any, - ), - ).to.be.true; - }); - - it('should return true if the current user is a room moderator', () => { - expect( - Federation.isEditableByTheUser( - { _id: 'differentId' } as any, - { federated: true, u: { _id: 'id' } } as any, - { roles: ['moderator'] } as any, - ), - ).to.be.true; - }); - }); - describe('#canCreateInviteLinks()', () => { - it('should return false if the user is null', () => { - expect(Federation.canCreateInviteLinks(undefined, { u: { _id: 'id' } } as any, {} as any)).to.be.false; - }); - - it('should return false if the room is null', () => { - expect(Federation.canCreateInviteLinks({} as any, undefined, {} as any)).to.be.false; - }); - - it('should return false if the subscription is null', () => { - expect(Federation.canCreateInviteLinks({} as any, {} as any, undefined)).to.be.false; - }); - - it('should return false if the current room is NOT a federated one', () => { - expect(Federation.canCreateInviteLinks({ _id: 'differentId' } as any, { u: { _id: 'id' } } as any, {} as any)).to.be.false; - }); - - it('should return false if the current room is federated one but NOT a public one', () => { - expect(Federation.canCreateInviteLinks({ _id: 'differentId' } as any, { federated: true, u: { _id: 'id' } } as any, {} as any)).to.be - .false; - }); - - it('should return false if the current room is federated one, a public one but the user is NOT an owner nor moderator', () => { - expect( - Federation.canCreateInviteLinks({ _id: 'differentId' } as any, { federated: true, t: 'c', u: { _id: 'id' } } as any, {} as any), - ).to.be.false; - }); - - it('should return false if the current room is federated one, a public one but the user is NOT an owner nor moderator', () => { - expect( - Federation.canCreateInviteLinks({ _id: 'differentId' } as any, { federated: true, t: 'c', u: { _id: 'id' } } as any, {} as any), - ).to.be.false; - }); - - it('should return true if the current room is federated one, a public one but the user is an owner', () => { - expect( - Federation.canCreateInviteLinks( - { _id: 'differentId' } as any, - { federated: true, t: 'c', u: { _id: 'id' } } as any, - { roles: ['owner'] } as any, - ), - ).to.be.true; - }); - - it('should return true if the current room is federated one, a public one but the user is an moderator', () => { - expect( - Federation.canCreateInviteLinks( - { _id: 'differentId' } as any, - { federated: true, t: 'c', u: { _id: 'id' } } as any, - { roles: ['moderator'] } as any, - ), - ).to.be.true; - }); - }); - - describe('#isRoomSettingAllowed()', () => { - it('should return false if the room is NOT federated', () => { - expect(Federation.isRoomSettingAllowed({ t: 'c' } as any, RoomSettingsEnum.NAME)).to.be.false; - }); - - it('should return false if the room is a DM one', () => { - expect(Federation.isRoomSettingAllowed({ t: 'd', federated: true } as any, RoomSettingsEnum.NAME)).to.be.false; - }); - - const allowedSettingsChanges = [RoomSettingsEnum.NAME, RoomSettingsEnum.TOPIC]; - - Object.values(RoomSettingsEnum) - .filter((setting) => !allowedSettingsChanges.includes(setting as any)) - .forEach((setting) => { - it('should return false if the setting change is NOT allowed within the federation context for regular channels', () => { - expect(Federation.isRoomSettingAllowed({ t: 'c', federated: true } as any, setting)).to.be.false; - }); - }); - - allowedSettingsChanges.forEach((setting) => { - it('should return true if the setting change is allowed within the federation context for regular channels', () => { - expect(Federation.isRoomSettingAllowed({ t: 'c', federated: true } as any, setting)).to.be.true; - }); - }); - }); -}); diff --git a/apps/meteor/tests/unit/client/lib/getRoomGroup.spec.ts b/apps/meteor/tests/unit/client/lib/getRoomGroup.spec.ts deleted file mode 100644 index 0c2a1e53dc8e..000000000000 --- a/apps/meteor/tests/unit/client/lib/getRoomGroup.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { IRoom } from '@rocket.chat/core-typings'; -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { getRoomGroup } from '../../../../client/views/room/lib/getRoomGroup'; - -describe('getRoomGroup', () => { - it('should return "direct" for direct message rooms', () => { - const result = getRoomGroup({ t: 'd' } as IRoom); - - expect(result).to.be.equal('direct'); - }); - - it('should return "team" for team rooms', () => { - const result = getRoomGroup({ teamMain: true } as IRoom); - - expect(result).to.be.equal('team'); - }); - - it('should return "direct_multiple" for direct message room with many users', () => { - const result = getRoomGroup({ uids: ['id1', 'id2', 'id3'], t: 'd' } as IRoom); - - expect(result).to.be.equal('direct_multiple'); - }); -}); diff --git a/apps/meteor/tests/unit/client/lib/minimongo/bson.spec.ts b/apps/meteor/tests/unit/client/lib/minimongo/bson.spec.ts deleted file mode 100644 index 9f177a90079e..000000000000 --- a/apps/meteor/tests/unit/client/lib/minimongo/bson.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { getBSONType, compareBSONValues } from '../../../../../client/lib/minimongo/bson'; -import { BSONType } from '../../../../../client/lib/minimongo/types'; - -describe('getBSONType', () => { - it('should work', () => { - expect(getBSONType(1)).to.be.equals(BSONType.Double); - expect(getBSONType('xyz')).to.be.equals(BSONType.String); - expect(getBSONType({})).to.be.equals(BSONType.Object); - expect(getBSONType([])).to.be.equals(BSONType.Array); - expect(getBSONType(new Uint8Array())).to.be.equals(BSONType.BinData); - expect(getBSONType(undefined)).to.be.equals(BSONType.Object); - expect(getBSONType(null)).to.be.equals(BSONType.Null); - expect(getBSONType(false)).to.be.equals(BSONType.Boolean); - expect(getBSONType(/.*/)).to.be.equals(BSONType.Regex); - expect(getBSONType(() => true)).to.be.equals(BSONType.JavaScript); - expect(getBSONType(new Date(0))).to.be.equals(BSONType.Date); - }); -}); - -describe('compareBSONValues', () => { - it('should work for the same types', () => { - expect(compareBSONValues(2, 3)).to.be.equals(-1); - expect(compareBSONValues('xyz', 'abc')).to.be.equals(1); - expect(compareBSONValues({}, {})).to.be.equals(0); - expect(compareBSONValues(true, false)).to.be.equals(1); - expect(compareBSONValues(new Date(0), new Date(1))).to.be.equals(-1); - }); - - it('should work for different types', () => { - expect(compareBSONValues(2, null)).to.be.equals(1); - expect(compareBSONValues('xyz', {})).to.be.equals(-1); - expect(compareBSONValues(false, 3)).to.be.equals(1); - }); -}); diff --git a/apps/meteor/tests/unit/client/lib/minimongo/comparisons.spec.ts b/apps/meteor/tests/unit/client/lib/minimongo/comparisons.spec.ts deleted file mode 100644 index 04163469e7e8..000000000000 --- a/apps/meteor/tests/unit/client/lib/minimongo/comparisons.spec.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { equals, isObject, flatSome, some, isEmptyArray } from '../../../../../client/lib/minimongo/comparisons'; - -describe('Comparisons service', () => { - describe('equals', () => { - it('should return true if two numbers are equal', () => { - expect(equals(1, 1)).to.be.equal(true); - }); - - it('should return false if arguments are null or undefined', () => { - expect(equals(undefined, null)).to.be.equal(false); - expect(equals(null, undefined)).to.be.equal(false); - }); - - it('should return false if arguments arent objects and they are not the same', () => { - expect(equals('not', 'thesame')).to.be.equal(false); - }); - - it('should return true if date objects provided have the same value', () => { - const currentDate = new Date(); - - expect(equals(currentDate, currentDate)).to.be.equal(true); - }); - - it('should return true if 2 equal UInt8Array are provided', () => { - const arr1 = new Uint8Array([1, 2]); - const arr2 = new Uint8Array([1, 2]); - - expect(equals(arr1, arr2)).to.be.equal(true); - }); - - it('should return true if 2 equal arrays are provided', () => { - const arr1 = [1, 2, 4]; - const arr2 = [1, 2, 4]; - - expect(equals(arr1, arr2)).to.be.equal(true); - }); - - it('should return false if 2 arrays with different length are provided', () => { - const arr1 = [1, 4, 5]; - const arr2 = [1, 4, 5, 7]; - - expect(equals(arr1, arr2)).to.be.equal(false); - }); - - it('should return true if the objects provided are "equal"', () => { - const obj = { a: 1 }; - const obj2 = obj; - - expect(equals(obj, obj2)).to.be.equal(true); - }); - - it('should return true if both objects have the same keys', () => { - const obj = { a: 1 }; - const obj2 = { a: 1 }; - - expect(equals(obj, obj2)).to.be.equal(true); - }); - }); - - describe('isObject', () => { - it('should return true if value is an object or function', () => { - const obj = {}; - const func = (a: any): any => a; - - expect(isObject(obj)).to.be.equal(true); - expect(isObject(func)).to.be.equal(true); - }); - - it('should return false for other data types', () => { - expect(isObject(1)).to.be.equal(false); - expect(isObject(true)).to.be.equal(false); - expect(isObject('212')).to.be.equal(false); - }); - }); - - describe('flatSome', () => { - it('should run .some on array', () => { - const arr = [1, 2, 4, 6, 9]; - const isEven = (v: number): boolean => v % 2 === 0; - - expect(flatSome(arr, isEven)).to.be.equal(true); - }); - - it('should run the function on the value when its not an array', () => { - const val = 1; - const isEven = (v: number): boolean => v % 2 === 0; - - expect(flatSome(val, isEven)).to.be.equal(false); - }); - }); - - describe('some', () => { - it('should run .some on array', () => { - const arr = [1, 2, 4, 6, 9]; - const isEven = (v: number | number[]): boolean => { - if (Array.isArray(v)) { - return false; - } - return v % 2 === 0; - }; - - expect(some(arr, isEven)).to.be.equal(true); - }); - - it('should run the function on the value when its not an array', () => { - const val = 1; - const isEven = (v: number | number[]): boolean => { - if (Array.isArray(v)) { - return false; - } - return v % 2 === 0; - }; - - expect(some(val, isEven)).to.be.equal(false); - }); - }); - - describe('isEmptyArray', () => { - it('should return true if array is empty', () => { - expect(isEmptyArray([])).to.be.equal(true); - }); - - it('should return false if value is not an array', () => { - expect(isEmptyArray(1)).to.be.equal(false); - }); - - it('should return false if array is not empty', () => { - expect(isEmptyArray([1, 2])).to.be.equal(false); - }); - }); -}); diff --git a/apps/meteor/tests/unit/client/lib/minimongo/lookups.spec.ts b/apps/meteor/tests/unit/client/lib/minimongo/lookups.spec.ts deleted file mode 100644 index f2117f6eaa96..000000000000 --- a/apps/meteor/tests/unit/client/lib/minimongo/lookups.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { createLookupFunction } from '../../../../../client/lib/minimongo/lookups'; - -describe('createLookupFunction', () => { - it('should work', () => { - expect(createLookupFunction('a.x')({ a: { x: 1 } })).to.be.deep.equals([1]); - expect(createLookupFunction('a.x')({ a: { x: [1] } })).to.be.deep.equals([[1]]); - expect(createLookupFunction('a.x')({ a: 5 })).to.be.deep.equals([undefined]); - expect(createLookupFunction('a.x')({ a: [{ x: 1 }, { x: [2] }, { y: 3 }] })).to.be.deep.equals([1, [2], undefined]); - }); -}); diff --git a/apps/meteor/tests/unit/client/lib/utils/isRTLScriptLanguage.spec.ts b/apps/meteor/tests/unit/client/lib/utils/isRTLScriptLanguage.spec.ts deleted file mode 100644 index bcf610b7bfbc..000000000000 --- a/apps/meteor/tests/unit/client/lib/utils/isRTLScriptLanguage.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { expect } from 'chai'; - -import { isRTLScriptLanguage } from '../../../../../client/lib/utils/isRTLScriptLanguage'; - -describe('isRTLScriptLanguage', () => { - const testCases = [ - ['en', false], - ['ar', true], - ['dv', true], - ['fa', true], - ['he', true], - ['ku', true], - ['ps', true], - ['sd', true], - ['ug', true], - ['ur', true], - ['yi', true], - ['ar', true], - ['ar-LY', true], - ['dv-MV', true], - ['', false], - ] as const; - - testCases.forEach(([parameter, expectedResult]) => { - it(`should return ${JSON.stringify(expectedResult)} for ${JSON.stringify(parameter)}`, () => { - const result = isRTLScriptLanguage(parameter); - expect(result).to.be.equal(expectedResult); - }); - }); -}); diff --git a/apps/meteor/tests/unit/client/sidebar/header/MatrixFederationSearch/MatrixFederationSearch.spec.tsx b/apps/meteor/tests/unit/client/sidebar/header/MatrixFederationSearch/MatrixFederationSearch.spec.tsx deleted file mode 100644 index a5d7a250b722..000000000000 --- a/apps/meteor/tests/unit/client/sidebar/header/MatrixFederationSearch/MatrixFederationSearch.spec.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import { cleanup, render, screen, within } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { expect } from 'chai'; -import proxyquire from 'proxyquire'; -import type { ReactElement } from 'react'; -import React from 'react'; - -const fetchRoomList = async ({ serverName, roomName, count }: any): Promise => { - return new Promise((resolve) => - resolve({ - rooms: Array.from({ length: count || 100 }).map((index) => ({ - id: `Matrix${index}`, - name: `${roomName}${index}` || `Matrix${index}`, - canJoin: true, - canonicalAlias: `#${serverName}:matrix.org`, - joinedMembers: 44461, - topic: - 'The Official Matrix HQ - chat about Matrix here! | https://matrix.org | https://spec.matrix.org | To support Matrix.org development: https://patreon.com/matrixdotorg | Code of Conduct: https://matrix.org/legal/code-of-conduct/ | This is an English speaking room | The Official Matrix HQ - chat about Matrix here! | https://matrix.org | https://spec.matrix.org | To support Matrix.org development: https://patreon.com/matrixdotorg | Code of Conduct: https://matrix.org/legal/code-of-conduct/ | This is an English speaking room The Official Matrix HQ - chat about Matrix here! | https://matrix.org | https://spec.matrix.org | To support Matrix.org development: https://patreon.com/matrixdotorg | Code of Conduct: https://matrix.org/legal/code-of-conduct/ | This is an English speaking room | The Official Matrix HQ - chat about Matrix here! | https://matrix.org | https://spec.matrix.org | To support Matrix.org development: https://patreon.com/matrixdotorg | Code of Conduct: https://matrix.org/legal/code-of-conduct/ | This is an English speaking room', - })), - count: 1, - total: 73080, - nextPageToken: 'g6FtzZa3oXK+IUpkemFiTlVQUFh6bENKQWhFbDpmYWJyaWMucHVioWTD', - prevPageToken: 'g6FtzYqIoXK+IWNOd2pkUXdWcFJNc0lNa1VweDptYXRyaXgub3JnoWTC', - success: true, - }), - ); -}; - -const joinExternalPublicRoom: any = async () => ({ success: true }); - -let serverList = [ - { name: `server-1`, default: true, local: false }, - { name: `server-2`, default: false, local: false }, - { name: `server-3`, default: false, local: false }, -]; - -const fetchServerList = async () => ({ - servers: serverList, -}); - -const removeMatrixServer: any = async ({ serverName }: any) => { - serverList = serverList.filter((server) => server.name !== serverName); -}; -const addMatrixServer: any = async ({ serverName }: any) => serverList.push({ name: serverName, default: false, local: false }); - -const COMPONENT_PATH = '../../../../../../client/sidebar/header/MatrixFederationSearch'; - -const defaultConfig = { - '@rocket.chat/ui-contexts': { - 'useSetModal': () => (modal: ReactElement) => { - cleanup(); - if (!modal) { - return; - } - render(modal); - }, - '@global': true, - }, - '../../../lib/rooms/roomCoordinator': { - '@noCallThru': true, - '@global': true, - 'roomCoordinator': { - openRouteLink: () => null, - }, - }, -}; -const { makeCallEndpoint } = proxyquire.load('../../../../../mocks/client/ServerProviderMock', defaultConfig); - -const [callEndpoint, registerEndpoint] = makeCallEndpoint(); - -registerEndpoint('GET', '/v1/federation/listServersByUser', fetchServerList); -registerEndpoint('GET', '/v1/federation/searchPublicRooms', fetchRoomList); -registerEndpoint('GET', '/v1/federation/joinExternalPublicRoom', joinExternalPublicRoom); -registerEndpoint('POST', '/v1/federation/addServerByUser', addMatrixServer); -registerEndpoint('POST', '/v1/federation/removeServerByUser', removeMatrixServer); - -const openManageServers = () => { - const manageServerLink = screen.getByRole('a'); - expect(manageServerLink).to.exist; - userEvent.click(manageServerLink); - expect(screen.getByRole('dialog')).to.exist; - expect(screen.getByText('Manage servers')).to.exist; -}; - -const renderMatrixFederationSearch = () => { - const MatrixFederationSearch = proxyquire.load(COMPONENT_PATH, defaultConfig).default; - const ServerProviderMock = proxyquire.load('../../../../../mocks/client/ServerProviderMock', defaultConfig).default; - const QueryClientProviderMock = proxyquire.load( - '../../../../../../client/stories/contexts/QueryClientProviderMock', - defaultConfig, - ).default; - - render( - - - - - , - ); -}; - -describe.skip('sidebar/header/MatrixFederationSearch', () => { - it('should render Federated Room search modal', async () => { - renderMatrixFederationSearch(); - - expect(screen.getByRole('dialog')).to.exist; - expect(screen.getByText('Federated room search')).to.exist; - expect(screen.getByText('Matrix1')).to.exist; - expect(screen.getByText('Matrix2')).to.exist; - }); - - it('should search for rooms', async () => { - renderMatrixFederationSearch(); - - const input = screen.getByPlaceholderText('Search rooms'); - expect(input).to.exist; - userEvent.type(input, 'NotMatrix'); - expect(screen.getByText('NotMatrix1')).to.exist; - expect(screen.getByText('NotMatrix2')).to.exist; - }); - - it('should close the modal when joining a room', async () => { - renderMatrixFederationSearch(); - - const firstListItem = screen.getByRole('li', { name: 'Matrix1' }); - expect(firstListItem).to.exist; - const joinButton = within(firstListItem).getByRole('button'); - expect(joinButton).to.exist; - userEvent.click(joinButton); - expect(screen.getByRole('dialog')).to.not.exist; - }); - - it('should open the manage server modal', async () => { - renderMatrixFederationSearch(); - - openManageServers(); - serverList.forEach((server) => { - expect(screen.getByText(server.name)).to.exist; - }); - }); - - it('should return to the Search modal when clicking cancel', async () => { - renderMatrixFederationSearch(); - - openManageServers(); - - const cancelButton = screen.getByText('Cancel'); - expect(cancelButton).to.exist; - userEvent.click(cancelButton); - - expect(screen.getByRole('dialog')).to.exist; - expect(screen.getByText('Federated room search')).to.exist; - }); - - it('should return to the Search modal with the new server selected', async () => { - renderMatrixFederationSearch(); - - openManageServers(); - - const input = screen.getByRole('input'); - expect(input).to.exist; - userEvent.type(input, 'server-4'); - - const addButton = screen.getByText('Add'); - expect(addButton).to.exist; - userEvent.click(addButton); - - expect(screen.getByRole('dialog')).to.exist; - expect(screen.getByText('Federated room search')).to.exist; - expect(screen.getByText('server-4')).to.be.visible; - }); - - it('should remove servers from the list', async () => { - renderMatrixFederationSearch(); - - openManageServers(); - - const defaultItem = screen.getByTitle('server-1'); - expect(defaultItem).to.exist; - userEvent.hover(defaultItem); - expect(within(defaultItem).getByRole('i')).to.not.exist; - - const lastItem = screen.getByTitle('server-4'); - expect(lastItem).to.exist; - userEvent.hover(lastItem); - const removeButton = within(lastItem).getByRole('i'); - expect(removeButton).to.be.visible; - userEvent.click(removeButton); - - expect(screen.getByText('server-4')).to.not.exist; - }); -}); diff --git a/apps/meteor/tests/unit/client/views/notFound/NotFoundPage.spec.tsx b/apps/meteor/tests/unit/client/views/notFound/NotFoundPage.spec.tsx deleted file mode 100644 index d188202c503a..000000000000 --- a/apps/meteor/tests/unit/client/views/notFound/NotFoundPage.spec.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { render, waitFor, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import '@testing-library/jest-dom'; -import type { MutableRefObject } from 'react'; -import React from 'react'; - -import NotFoundPage from '../../../../../client/views/notFound/NotFoundPage'; -import RouterContextMock from '../../../../mocks/client/RouterContextMock'; - -describe('views/notFound/NotFoundPage', () => { - it('should look good', async () => { - render(); - - await screen.findByRole('heading'); - - expect(screen.getByRole('heading')).toHaveTextContent('Page_not_found'); - - expect(screen.getByRole('button', { name: 'Homepage' })).not.toBeDisabled(); - }); - - it('should have correct tab order', () => { - render(); - // eslint-disable-next-line testing-library/no-node-access - expect(document.activeElement).toBe(document.body); - userEvent.tab(); - // eslint-disable-next-line testing-library/no-node-access - expect(document.activeElement).toBe(screen.getByRole('button', { name: 'Homepage' })); - userEvent.tab(); - // eslint-disable-next-line testing-library/no-node-access - expect(document.activeElement).toBe(document.body); - }); - - describe('"Return to home" button', () => { - describe('when clicked', () => { - it('should go back on history', async () => { - const currentPath: MutableRefObject = { current: undefined }; - - render( - - - , - ); - const button = screen.getByRole('button', { name: 'Homepage' }); - - userEvent.click(button); - - await waitFor(() => expect(currentPath.current).toBe('/home')); - }); - }); - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/Message.test.tsx b/apps/meteor/tests/unit/client/views/room/MessageList/Message.test.tsx deleted file mode 100644 index b6a0f9ecd957..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/Message.test.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import type { IMessage } from '@rocket.chat/core-typings'; -import { render, screen } from '@testing-library/react'; -import { expect } from 'chai'; -import proxyquire from 'proxyquire'; -import React from 'react'; - -import type { default as _RoomMessage } from '../../../../../../client/components/message/variants/RoomMessage'; - -const date = new Date('2021-10-27T00:00:00.000Z'); -const baseMessage: IMessage = { - ts: date, - u: { - _id: 'userId', - name: 'userName', - username: 'userName', - }, - msg: 'message', - md: [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'message', - }, - ], - }, - ], - rid: 'roomId', - _id: 'messageId', - _updatedAt: date, - urls: [], -}; - -const RoomMessage = proxyquire.noCallThru().load('../../../../../../client/components/message/variants/RoomMessage.tsx', { - '../../avatar/UserAvatar': () =>

user avatar

, - '../../../views/room/MessageList/contexts/MessageHighlightContext': { - useIsMessageHighlight: () => false, - }, - '../../../views/room/MessageList/contexts/SelectedMessagesContext': { - useIsSelecting: () => '', - useToggleSelect: () => '', - useIsSelectedMessage: () => '', - useCountSelected: () => '', - }, - '../IgnoredContent': () =>

message ignored

, - './room/RoomMessageContent': () => baseMessage.msg, - '../MessageHeader': () =>

message header

, - '../StatusIndicators': { MessageIndicators: () =>

message indicators

}, - '../MessageToolboxHolder': () =>

toolbox

, -}).default as typeof _RoomMessage; - -describe('Message', () => { - it('should show normal message', () => { - render( - , - ); - - expect(screen.getByText(baseMessage.msg)).to.exist; - }); - - it('should show ignored message', () => { - render( - , - ); - - expect(screen.getByText('message ignored')).to.exist; - }); - - it('should show ignored message', () => { - render( - , - ); - - expect(screen.getByText('message ignored')).to.exist; - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/hooks/useKatex.test.ts b/apps/meteor/tests/unit/client/views/room/MessageList/hooks/useKatex.test.ts deleted file mode 100644 index 1739f070e32a..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/hooks/useKatex.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { renderHook } from '@testing-library/react-hooks'; -import { expect } from 'chai'; -import proxyquire from 'proxyquire'; - -const COMPONENT_PATH = '../../../../../../../client/views/room/MessageList/hooks/useKatex'; -const defaultConfig = { - '@rocket.chat/ui-contexts': { - useSetting: () => true, - }, -}; - -describe('room/MessageList/hooks/useKatex', () => { - it('should return enabled true dollar syntax true and parenthesis syntax true if all settings is enabled', () => { - const { useKatex } = proxyquire.load(COMPONENT_PATH, defaultConfig); - - const { result } = renderHook(() => useKatex()); - - expect(result.current.katexEnabled).to.be.equal(true); - expect(result.current.katexDollarSyntaxEnabled).to.be.equal(true); - expect(result.current.katexParenthesisSyntaxEnabled).to.be.equal(true); - }); - - it('should return enabled false dollar syntax false and parenthesis syntax false if all settings is disabled', () => { - const { useKatex } = proxyquire.load(COMPONENT_PATH, { - ...defaultConfig, - '@rocket.chat/ui-contexts': { - useSetting: () => false, - }, - }); - - const { result } = renderHook(() => useKatex()); - - expect(result.current.katexEnabled).to.be.equal(false); - expect(result.current.katexDollarSyntaxEnabled).to.be.equal(false); - expect(result.current.katexParenthesisSyntaxEnabled).to.be.equal(false); - }); - - it('should return enabled true dollar syntax false and parenthesis syntax false if Katex_Enabled settings is enable', () => { - const { useKatex } = proxyquire.load(COMPONENT_PATH, { - ...defaultConfig, - '@rocket.chat/ui-contexts': { - useSetting: (str: string) => str === 'Katex_Enabled', - }, - }); - - const { result } = renderHook(() => useKatex()); - - expect(result.current.katexEnabled).to.be.equal(true); - expect(result.current.katexDollarSyntaxEnabled).to.be.equal(false); - expect(result.current.katexParenthesisSyntaxEnabled).to.be.equal(false); - }); - - it('should return enabled false dollar syntax false and parenthesis syntax false if DollarSyntaxEnabled and ParenthesisSyntaxEnabled settings is enable', () => { - const { useKatex } = proxyquire.load(COMPONENT_PATH, { - ...defaultConfig, - '@rocket.chat/ui-contexts': { - useSetting: (str: string) => str === 'DollarSyntaxEnabled' || str === 'ParenthesisSyntaxEnabled', - }, - }); - - const { result } = renderHook(() => useKatex()); - - expect(result.current.katexEnabled).to.be.equal(false); - expect(result.current.katexDollarSyntaxEnabled).to.be.equal(false); - expect(result.current.katexParenthesisSyntaxEnabled).to.be.equal(false); - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/autoTranslate.spec.ts b/apps/meteor/tests/unit/client/views/room/MessageList/lib/autoTranslate.spec.ts deleted file mode 100644 index bbf6f10cc7ef..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/autoTranslate.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { IMessage, MessageAttachment } from '@rocket.chat/core-typings'; -import { expect } from 'chai'; - -import { - hasTranslationLanguageInAttachments, - hasTranslationLanguageInMessage, -} from '../../../../../../../client/views/room/MessageList/lib/autoTranslate'; - -describe('autoTranslate', () => { - describe('hasTranslationLanguageInMessage', () => { - const testCases = [ - [{}, '', false], - [{ translations: { en: 'bah' } }, '', false], - [{ translations: { en: 'bah' } }, 'pt', false], - [{ translations: { en: 'bah' } }, 'en', true], - ] as const; - - testCases.forEach(([message, language, expectedResult]) => { - it(`should return ${JSON.stringify(expectedResult)} for ${JSON.stringify(message)} with ${JSON.stringify(language)}`, () => { - const result = hasTranslationLanguageInMessage(message as unknown as IMessage, language); - expect(result).to.be.equal(expectedResult); - }); - }); - }); - - describe('hasTranslationLanguageInAttachments', () => { - const testCases = [ - [[{}], '', false], - [undefined, '', false], - [[{ translations: { en: 'bah' } }], '', false], - [[{ translations: { en: 'bah' } }], 'pt', false], - [[{ translations: { en: 'bah' } }], 'pt', false], - [[{ translations: { en: 'bah' } }], 'en', true], - ] as const; - - testCases.forEach(([attachment, language, expectedResult]) => { - it(`should return ${JSON.stringify(expectedResult)} for ${JSON.stringify(attachment)} with ${JSON.stringify(language)}`, () => { - const result = hasTranslationLanguageInAttachments(attachment as unknown as MessageAttachment[], language); - expect(result).to.be.equal(expectedResult); - }); - }); - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/buildImageURL.spec.ts b/apps/meteor/tests/unit/client/views/room/MessageList/lib/buildImageURL.spec.ts deleted file mode 100644 index 83d90f90e4c6..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/buildImageURL.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { expect } from 'chai'; - -import { buildImageURL } from '../../../../../../../client/components/message/content/urlPreviews/buildImageURL'; - -describe('buildImageURL', () => { - const testCases = [ - [ - 'https://g1.globo.com/mundo/video/misseis-atingem-ponte-de-vidro-em-kiev-11012523.ghtml', - 'https://s2.glbimg.com/fXQKM_UZjF6I_3APIbPJzJTOUvw=/1200x/smart/filters:cover():strip_icc()/s04.video.glbimg.com/x720/11012523.jpg', - 'https://s2.glbimg.com/fXQKM_UZjF6I_3APIbPJzJTOUvw=/1200x/smart/filters:cover():strip_icc()/s04.video.glbimg.com/x720/11012523.jpg', - ], - ['https://open.rocket.chat/channel/general', 'assets/favicon_512.png', 'https://open.rocket.chat/assets/favicon_512.png'], - ['https://open.rocket.chat/channel/general', '/assets/favicon_512.png', 'https://open.rocket.chat/assets/favicon_512.png'], - ['https://open.rocket.chat/channel/general/', '/assets/favicon_512.png', 'https://open.rocket.chat/assets/favicon_512.png'], - ] as const; - - testCases.forEach(([linkUrl, metaImgUrl, expectedResult]) => { - it(`should return ${expectedResult} for ${metaImgUrl}`, () => { - const result = buildImageURL(linkUrl, metaImgUrl); - - expect(result).to.equal(JSON.stringify(expectedResult)); - }); - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageNewDay.spec.ts b/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageNewDay.spec.ts deleted file mode 100644 index 27af3d4c6de9..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageNewDay.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-env mocha */ -import type { IMessage } from '@rocket.chat/core-typings'; -import { expect } from 'chai'; - -import { isMessageNewDay } from '../../../../../../../client/views/room/MessageList/lib/isMessageNewDay'; - -const date = new Date('2021-10-27T00:00:00.000Z'); - -const baseMessage: IMessage = { - ts: date, - u: { - _id: 'userId', - name: 'userName', - username: 'userName', - }, - msg: 'message', - rid: 'roomId', - _id: 'messageId', - _updatedAt: date, - urls: [], -}; - -describe('isMessageNewDay', () => { - it('should return true if the message is from a different day', () => { - const message = { - ...baseMessage, - }; - const message2 = { - ...baseMessage, - ts: new Date('2021-10-28T00:00:00.000Z'), - }; - expect(isMessageNewDay(message, message2)).to.be.true; - }); - it('should return false if the message is from the same day', () => { - const message = { - ...baseMessage, - }; - const message2 = { - ...baseMessage, - }; - expect(isMessageNewDay(message, message2)).to.be.false; - }); - it('should return true if there is no previous message', () => { - const message = { - ...baseMessage, - }; - expect(isMessageNewDay(message, undefined)).to.be.true; - }); - - it('should return true for different days even if the range is on second', () => { - const previous: IMessage = { - ...baseMessage, - ts: new Date(2022, 0, 1, 23, 59, 59, 999), - }; - const current: IMessage = { - ...baseMessage, - ts: new Date(2022, 0, 2, 0, 0, 0, 0), - }; - expect(isMessageNewDay(current, previous)).to.be.true; - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageSequential.spec.ts b/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageSequential.spec.ts deleted file mode 100644 index aa74388f04f6..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageSequential.spec.ts +++ /dev/null @@ -1,168 +0,0 @@ -/* eslint-env mocha */ -import type { IMessage } from '@rocket.chat/core-typings'; -import { expect } from 'chai'; - -import { MessageTypes } from '../../../../../../../app/ui-utils/lib/MessageTypes'; -import { isMessageSequential } from '../../../../../../../client/views/room/MessageList/lib/isMessageSequential'; - -const TIME_RANGE_IN_SECONDS = 300; - -const date = new Date('2021-10-27T00:00:00.000Z'); -const baseMessage: IMessage = { - ts: date, - u: { - _id: 'userId', - name: 'userName', - username: 'userName', - }, - msg: 'message', - rid: 'roomId', - _id: 'messageId', - _updatedAt: date, - urls: [], -}; - -describe('isMessageSequential', () => { - it('should return false if no previous message', () => { - const current: IMessage = { - ...baseMessage, - }; - expect(isMessageSequential(current, undefined, TIME_RANGE_IN_SECONDS)).to.be.false; - }); - - it("should return false if both messages doesn't belong to the same user", () => { - const previous: IMessage = { - ...baseMessage, - }; - const current: IMessage = { - ...baseMessage, - u: { - _id: 'userId2', - name: 'userName2', - username: 'userName2', - }, - }; - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.false; - }); - - it('should return false if both messages belongs to the same user but have more than five minutes of difference', () => { - const previous: IMessage = { - ...baseMessage, - }; - - const current: IMessage = { - ...previous, - ts: new Date('2021-10-27T00:05:00.001Z'), - }; - - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.false; - }); - it('should return true if both messages belongs to the same user and have less than five minutes of difference', () => { - const previous: IMessage = { - ...baseMessage, - }; - const current: IMessage = { - ...previous, - ts: new Date('2021-10-27T00:04:59.999Z'), - }; - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.true; - }); - it('should return false if message are not groupable', () => { - const previous: IMessage = { - ...baseMessage, - groupable: false, - }; - const current: IMessage = { - ...previous, - groupable: false, - }; - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.false; - }); - it('should return false if both messages are not from the same thread', () => { - const previous: IMessage = { - ...baseMessage, - tmid: 'threadId', - }; - const current: IMessage = { - ...previous, - tmid: 'threadId2', - }; - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.false; - }); - - it('should return true if both messages are from the same thread same user and bellow the time range', () => { - const previous: IMessage = { - ...baseMessage, - tmid: 'threadId', - }; - const current: IMessage = { - ...previous, - tmid: 'threadId', - }; - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.true; - }); - - it('should return false if previous message is thread message but the current is a regular one', () => { - const previous: IMessage = { - tmid: 'threadId', - ...baseMessage, - }; - const current: IMessage = { - ...baseMessage, - }; - - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.false; - }); - - it('should return true if message is a reply from a previous message', () => { - const previous: IMessage = { - ...baseMessage, - _id: 'threadId', - }; - const current: IMessage = { - ...previous, - tmid: 'threadId', - }; - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.true; - }); - it("should return false if both messages don't have the same alias", () => { - const previous: IMessage = { - ...baseMessage, - alias: 'alias', - }; - const current: IMessage = { - ...previous, - alias: 'alias2', - }; - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.false; - }); - - it('should return false if message is from system', () => { - MessageTypes.registerType({ - id: 'au', - system: true, - message: 'User_added_by', - }); - const previous: IMessage = { - ...baseMessage, - }; - const current: IMessage = { - ...previous, - ts: new Date('2021-10-27T00:04:59.999Z'), - t: 'au', - }; - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.false; - }); - - it('should return false even if messages should be sequential, but they are from a different day', () => { - const previous: IMessage = { - ...baseMessage, - ts: new Date(2022, 0, 1, 23, 59, 59, 999), - }; - const current: IMessage = { - ...baseMessage, - ts: new Date(2022, 0, 2, 0, 0, 0, 0), - }; - expect(isMessageSequential(current, previous, TIME_RANGE_IN_SECONDS)).to.be.false; - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isOwnUserMessage.spec.ts b/apps/meteor/tests/unit/client/views/room/MessageList/lib/isOwnUserMessage.spec.ts deleted file mode 100644 index cc98cdce6647..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isOwnUserMessage.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* eslint-env mocha */ -import type { IMessage, ISubscription } from '@rocket.chat/core-typings'; -import { expect } from 'chai'; - -import { MessageTypes } from '../../../../../../../app/ui-utils/lib/MessageTypes'; -import { isOwnUserMessage } from '../../../../../../../client/views/room/MessageList/lib/isOwnUserMessage'; - -const date = new Date('2021-10-27T00:00:00.000Z'); - -const baseMessage: IMessage = { - ts: date, - u: { - _id: 'userId', - name: 'userName', - username: 'userName', - }, - msg: 'message', - rid: 'roomId', - _id: 'messageId', - _updatedAt: date, - urls: [], -}; - -// Register a system message -MessageTypes.registerType({ - id: 'au', - system: true, - message: 'User_added_to', -}); - -describe('isUserMessage', () => { - it('should return true if the message is from user', () => { - const message: IMessage = { - ...baseMessage, - }; - - const subscription: ISubscription = { - u: { - _id: 'userId', - }, - } as ISubscription; - - expect(isOwnUserMessage(message, subscription)).to.be.true; - }); - - it('should return false if the message is not from user', () => { - const message: IMessage = { - ...baseMessage, - }; - - const subscription: ISubscription = { - u: { - _id: 'otherUser', - }, - } as ISubscription; - - expect(isOwnUserMessage(message, subscription)).to.be.false; - }); - - it('should return false if there is no subscription', () => { - const message: IMessage = { - ...baseMessage, - }; - - expect(isOwnUserMessage(message, undefined)).to.be.false; - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isParsedMessage.spec.ts b/apps/meteor/tests/unit/client/views/room/MessageList/lib/isParsedMessage.spec.ts deleted file mode 100644 index e2e2a57377f2..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/isParsedMessage.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { IMessage } from '@rocket.chat/core-typings'; -import type { Root } from '@rocket.chat/message-parser'; -/* eslint-env mocha */ -import { expect } from 'chai'; - -import { isParsedMessage } from '../../../../../../../client/views/room/MessageList/lib/isParsedMessage'; - -const date = new Date('2021-10-27T00:00:00.000Z'); - -const baseMessage: IMessage = { - ts: date, - u: { - _id: 'userId', - name: 'userName', - username: 'userName', - }, - msg: 'message', - md: [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'message', - }, - ], - }, - ], - rid: 'roomId', - _id: 'messageId', - _updatedAt: date, - urls: [], -}; - -describe('isParsedMessage', () => { - it('should return true if the message parsed', () => { - const message: IMessage = { - ...baseMessage, - }; - - expect(isParsedMessage(message.md as Root)).to.be.true; - }); - - it('should return false if the message is not parsed', () => { - const message: IMessage = { - ...baseMessage, - }; - - expect(isParsedMessage(message.msg as string)).to.be.false; - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessage.spec.ts b/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessage.spec.ts deleted file mode 100644 index eeca03982132..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessage.spec.ts +++ /dev/null @@ -1,317 +0,0 @@ -/* eslint-env mocha */ -import type { IMessage, ITranslatedMessage } from '@rocket.chat/core-typings'; -import type { Options, Root } from '@rocket.chat/message-parser'; -import { expect } from 'chai'; - -import { parseMessageTextToAstMarkdown } from '../../../../../../../client/lib/parseMessageTextToAstMarkdown'; - -const date = new Date('2021-10-27T00:00:00.000Z'); - -const parseOptions: Options = { - colors: true, - emoticons: true, - katex: { - dollarSyntax: true, - parenthesisSyntax: true, - }, -}; - -const messageParserTokenMessageWithWrongData: Root = [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'message', - }, - { - type: 'BOLD', - value: [ - { - type: 'PLAIN_TEXT', - value: 'bold', - }, - ], - }, - { - type: 'PLAIN_TEXT', - value: ' ', - }, - { - type: 'ITALIC', - value: [ - { - type: 'PLAIN_TEXT', - value: 'italic', - }, - ], - }, - { - type: 'PLAIN_TEXT', - value: ' and ', - }, - { - type: 'STRIKE', - value: [ - { - type: 'PLAIN_TEXT', - value: 'strike', - }, - ], - }, - ], - }, -]; - -const messageParserTokenMessage: Root = [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'message ', - }, - { - type: 'BOLD', - value: [ - { - type: 'PLAIN_TEXT', - value: 'bold', - }, - ], - }, - { - type: 'PLAIN_TEXT', - value: ' ', - }, - { - type: 'ITALIC', - value: [ - { - type: 'PLAIN_TEXT', - value: 'italic', - }, - ], - }, - { - type: 'PLAIN_TEXT', - value: ' and ', - }, - { - type: 'STRIKE', - value: [ - { - type: 'PLAIN_TEXT', - value: 'strike', - }, - ], - }, - ], - }, -]; - -const baseMessage: IMessage = { - ts: date, - u: { - _id: 'userId', - name: 'userName', - username: 'userName', - }, - msg: 'message **bold** _italic_ and ~strike~', - rid: 'roomId', - _id: 'messageId', - _updatedAt: date, - urls: [], -}; - -const autoTranslateOptions = { - autoTranslateEnabled: false, - showAutoTranslate: () => false, -}; - -const quoteMessage = { - author_name: 'authorName', - author_link: 'link', - author_icon: 'icon', - md: [], -}; - -describe('parseMessage', () => { - it('should return md property populated if the message is parsed', () => { - expect(parseMessageTextToAstMarkdown(baseMessage, parseOptions, autoTranslateOptions).md).to.deep.equal(messageParserTokenMessage); - }); - - it('should return correct parsed md property populated and fail in comparison with different Root element', () => { - expect(parseMessageTextToAstMarkdown(baseMessage, parseOptions, autoTranslateOptions).md).to.not.deep.equal( - messageParserTokenMessageWithWrongData, - ); - }); - - describe('translated', () => { - const translatedMessage: ITranslatedMessage = { - ...baseMessage, - msg: 'message not translated', - translationProvider: 'provider', - translations: { - en: 'message translated', - }, - }; - const translatedMessageParsed: Root = [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'message translated', - }, - ], - }, - ]; - - const enabledAutoTranslatedOptions = { - autoTranslateEnabled: true, - autoTranslateLanguage: 'en', - showAutoTranslate: () => true, - }; - it('should return correct translated parsed md when translate is active', () => { - expect(parseMessageTextToAstMarkdown(translatedMessage, parseOptions, enabledAutoTranslatedOptions).md).to.deep.equal( - translatedMessageParsed, - ); - }); - - it('should return correct attachment translated parsed md when translate is active', () => { - const attachmentTranslatedMessage = { - ...translatedMessage, - attachments: [ - { - description: 'description', - translations: { - en: 'description translated', - }, - }, - ], - }; - const attachmentTranslatedMessageParsed = { - ...translatedMessage, - md: translatedMessageParsed, - attachments: [ - { - description: 'description', - translations: { - en: 'description translated', - }, - md: [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'description translated', - }, - ], - }, - ], - }, - ], - }; - - expect(parseMessageTextToAstMarkdown(attachmentTranslatedMessage, parseOptions, enabledAutoTranslatedOptions)).to.deep.equal( - attachmentTranslatedMessageParsed, - ); - }); - - it('should return correct attachment quote translated parsed md when translate is active', () => { - const attachmentTranslatedMessage = { - ...translatedMessage, - attachments: [ - { - text: 'text', - translations: { - en: 'text translated', - }, - }, - ], - }; - const attachmentTranslatedMessageParsed = { - ...translatedMessage, - md: translatedMessageParsed, - attachments: [ - { - text: 'text', - translations: { - en: 'text translated', - }, - md: [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'text translated', - }, - ], - }, - ], - }, - ], - }; - - expect(parseMessageTextToAstMarkdown(attachmentTranslatedMessage, parseOptions, enabledAutoTranslatedOptions)).to.deep.equal( - attachmentTranslatedMessageParsed, - ); - }); - - it('should return correct multiple attachment quote translated parsed md when translate is active', () => { - const attachmentTranslatedMessage = { - ...translatedMessage, - attachments: [ - { - text: 'text', - translations: { - en: 'text translated', - }, - attachments: [{ ...quoteMessage, text: 'text level 2', translations: { en: 'text level 2 translated' } }], - }, - ], - }; - const attachmentTranslatedMessageParsed = { - ...translatedMessage, - md: translatedMessageParsed, - attachments: [ - { - text: 'text', - translations: { - en: 'text translated', - }, - md: [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'text translated', - }, - ], - }, - ], - attachments: [ - { - ...quoteMessage, - text: 'text level 2', - translations: { - en: 'text level 2 translated', - }, - }, - ], - }, - ], - }; - - expect(parseMessageTextToAstMarkdown(attachmentTranslatedMessage, parseOptions, enabledAutoTranslatedOptions)).to.deep.equal( - attachmentTranslatedMessageParsed, - ); - }); - }); - - // TODO: Add more tests for each type of message and for each type of token -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageAttachment.spec.ts b/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageAttachment.spec.ts deleted file mode 100644 index 7b94a3cfdef3..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageAttachment.spec.ts +++ /dev/null @@ -1,191 +0,0 @@ -/* eslint-env mocha */ -import type { MessageQuoteAttachment } from '@rocket.chat/core-typings'; -import type { Options, Root } from '@rocket.chat/message-parser'; -import { expect } from 'chai'; - -import { parseMessageAttachment } from '../../../../../../../client/lib/parseMessageTextToAstMarkdown'; - -const parseOptions: Options = { - colors: true, - emoticons: true, - katex: { - dollarSyntax: true, - parenthesisSyntax: true, - }, -}; - -const messageParserTokenMessage: Root = [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'message ', - }, - { - type: 'BOLD', - value: [ - { - type: 'PLAIN_TEXT', - value: 'bold', - }, - ], - }, - { - type: 'PLAIN_TEXT', - value: ' ', - }, - { - type: 'ITALIC', - value: [ - { - type: 'PLAIN_TEXT', - value: 'italic', - }, - ], - }, - { - type: 'PLAIN_TEXT', - value: ' and ', - }, - { - type: 'STRIKE', - value: [ - { - type: 'PLAIN_TEXT', - value: 'strike', - }, - ], - }, - ], - }, -]; - -const autoTranslateOptions = { - autoTranslateEnabled: false, - translated: false, -}; - -const quoteMessage = { - author_name: 'authorName', - author_link: 'link', - author_icon: 'icon', - message_link: 'http://localhost/any_link', - text: 'message **bold** _italic_ and ~strike~', - md: messageParserTokenMessage, -}; - -describe('parseMessageAttachment', () => { - it('should return md property populated if the quote is parsed', () => { - expect(parseMessageAttachment(quoteMessage, parseOptions, autoTranslateOptions).md).to.deep.equal(messageParserTokenMessage); - }); - - it('should return md property populated if the quote is not parsed', () => { - expect( - parseMessageAttachment({ ...quoteMessage, md: undefined } as unknown as MessageQuoteAttachment, parseOptions, autoTranslateOptions) - .md, - ).to.deep.equal(messageParserTokenMessage); - }); - - describe('translated', () => { - const translatedQuote = { - ...quoteMessage, - text: 'quote not translated', - translationProvider: 'provider', - translations: { - en: 'quote translated', - }, - }; - const translatedMessageParsed: Root = [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'quote translated', - }, - ], - }, - ]; - - const enabledAutoTranslatedOptions = { - translated: true, - autoTranslateLanguage: 'en', - }; - it('should return correct quote translated parsed md when translate is active', () => { - expect(parseMessageAttachment(translatedQuote, parseOptions, enabledAutoTranslatedOptions).md).to.deep.equal(translatedMessageParsed); - }); - - it('should return text parsed md when translate is active and autoTranslateLanguage is undefined', () => { - expect( - parseMessageAttachment(translatedQuote, parseOptions, { ...enabledAutoTranslatedOptions, autoTranslateLanguage: undefined }).md, - ).to.deep.equal([ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'quote not translated', - }, - ], - }, - ]); - }); - - it('should return correct multiple attachment quote translated parsed md when translate is active', () => { - const quote = { ...quoteMessage, text: 'text level 2', translations: { en: 'text level 2 translated' } }; - - const multipleQuotes = { - ...translatedQuote, - attachments: [ - { - ...translatedQuote, - text: 'text', - translations: { - en: 'text translated', - }, - attachments: [quote], - }, - ], - }; - const multipleQuotesParsed = { - ...translatedQuote, - md: translatedMessageParsed, - attachments: [ - { - ...multipleQuotes.attachments[0], - md: [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'text translated', - }, - ], - }, - ], - attachments: [ - { - ...quote, - md: [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'text level 2 translated', - }, - ], - }, - ], - }, - ], - }, - ], - }; - - expect(parseMessageAttachment(multipleQuotes, parseOptions, enabledAutoTranslatedOptions)).to.deep.equal(multipleQuotesParsed); - }); - }); -}); diff --git a/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageAttachments.spec.ts b/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageAttachments.spec.ts deleted file mode 100644 index 23d6944f99f2..000000000000 --- a/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageAttachments.spec.ts +++ /dev/null @@ -1,236 +0,0 @@ -/* eslint-env mocha */ -import type { Options, Root } from '@rocket.chat/message-parser'; -import { expect } from 'chai'; - -import { parseMessageAttachments } from '../../../../../../../client/lib/parseMessageTextToAstMarkdown'; - -const parseOptions: Options = { - colors: true, - emoticons: true, - katex: { - dollarSyntax: true, - parenthesisSyntax: true, - }, -}; - -const messageParserTokenMessage: Root = [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'message ', - }, - { - type: 'BOLD', - value: [ - { - type: 'PLAIN_TEXT', - value: 'bold', - }, - ], - }, - { - type: 'PLAIN_TEXT', - value: ' ', - }, - { - type: 'ITALIC', - value: [ - { - type: 'PLAIN_TEXT', - value: 'italic', - }, - ], - }, - { - type: 'PLAIN_TEXT', - value: ' and ', - }, - { - type: 'STRIKE', - value: [ - { - type: 'PLAIN_TEXT', - value: 'strike', - }, - ], - }, - ], - }, -]; - -const autoTranslateOptions = { - autoTranslateEnabled: false, - translated: false, -}; - -const attachmentMessage = [ - { - description: 'message **bold** _italic_ and ~strike~', - md: messageParserTokenMessage, - }, -]; - -describe('parseMessageAttachments', () => { - it('should return md property populated if the message is parsed', () => { - expect(parseMessageAttachments(attachmentMessage, parseOptions, autoTranslateOptions)[0].md).to.deep.equal(messageParserTokenMessage); - }); - - it('should return md property populated if the attachment is not parsed', () => { - expect(parseMessageAttachments([{ ...attachmentMessage[0], md: undefined }], parseOptions, autoTranslateOptions)[0].md).to.deep.equal( - messageParserTokenMessage, - ); - }); - - describe('translated', () => { - const enabledAutoTranslatedOptions = { - translated: true, - autoTranslateLanguage: 'en', - }; - - it('should return correct attachment description translated parsed md when translate is active', () => { - const descriptionAttachment = [ - { - ...attachmentMessage[0], - description: 'attachment not translated', - translationProvider: 'provider', - translations: { - en: 'attachment translated', - }, - }, - ]; - const descriptionAttachmentParsed: Root = [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'attachment translated', - }, - ], - }, - ]; - - expect(parseMessageAttachments(descriptionAttachment, parseOptions, enabledAutoTranslatedOptions)[0].md).to.deep.equal( - descriptionAttachmentParsed, - ); - }); - - it('should return correct attachment description parsed md when translate is active and auto translate language is undefined', () => { - const descriptionAttachment = [ - { - ...attachmentMessage[0], - description: 'attachment not translated', - translationProvider: 'provider', - translations: { - en: 'attachment translated', - }, - }, - ]; - const descriptionAttachmentParsed: Root = [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'attachment not translated', - }, - ], - }, - ]; - - expect( - parseMessageAttachments(descriptionAttachment, parseOptions, { - ...enabledAutoTranslatedOptions, - autoTranslateLanguage: undefined, - })[0].md, - ).to.deep.equal(descriptionAttachmentParsed); - }); - - it('should return correct attachment text translated parsed md when translate is active', () => { - const textAttachment = [ - { - ...attachmentMessage[0], - text: 'attachment not translated', - translationProvider: 'provider', - translations: { - en: 'attachment translated', - }, - }, - ]; - const textAttachmentParsed: Root = [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'attachment translated', - }, - ], - }, - ]; - - expect(parseMessageAttachments(textAttachment, parseOptions, enabledAutoTranslatedOptions)[0].md).to.deep.equal(textAttachmentParsed); - }); - - it('should return correct attachment text translated parsed md when translate is active and has multiple texts', () => { - const quote = { - author_name: 'authorName', - author_link: 'link', - author_icon: 'icon', - message_link: 'messageLink', - md: [], - text: 'text level 2', - translations: { en: 'text level 2 translated' }, - }; - const textAttachment = [ - { - ...quote, - text: 'attachment not translated', - translationProvider: 'provider', - translations: { - en: 'attachment translated', - }, - attachments: [quote], - }, - ]; - const textAttachmentParsed = { - ...textAttachment[0], - md: [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'attachment translated', - }, - ], - }, - ], - attachments: [ - { - ...quote, - text: 'text level 2', - translations: { - en: 'text level 2 translated', - }, - md: [ - { - type: 'PARAGRAPH', - value: [ - { - type: 'PLAIN_TEXT', - value: 'text level 2 translated', - }, - ], - }, - ], - }, - ], - }; - - expect(parseMessageAttachments(textAttachment, parseOptions, enabledAutoTranslatedOptions)[0]).to.deep.equal(textAttachmentParsed); - }); - }); -}); diff --git a/apps/meteor/tests/unit/client/views/root/SAMLLoginRoute.spec.tsx b/apps/meteor/tests/unit/client/views/root/SAMLLoginRoute.spec.tsx deleted file mode 100644 index 9b81f192b595..000000000000 --- a/apps/meteor/tests/unit/client/views/root/SAMLLoginRoute.spec.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { MockedServerContext, MockedUserContext } from '@rocket.chat/mock-providers'; -import { render } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import { Meteor } from 'meteor/meteor'; -import React from 'react'; - -import SAMLLoginRoute from '../../../../../client/views/root/SAMLLoginRoute'; -import RouterContextMock from '../../../../mocks/client/RouterContextMock'; - -const navigateStub = jest.fn(); - -describe('views/root/SAMLLoginRoute', () => { - beforeEach(() => { - jest.clearAllMocks(); - navigateStub.mockClear(); - (Meteor.loginWithSamlToken as jest.Mock).mockClear(); - }); - - it('should redirect to /home', async () => { - render( - - - - - - - , - ); - - expect(navigateStub).toHaveBeenCalledTimes(1); - expect(navigateStub).toHaveBeenLastCalledWith(expect.objectContaining({ pathname: '/home' }), expect.anything()); - }); - - it('should redirect to /home when redirectUrl is not within the workspace domain', async () => { - render( - - - - - , - ); - - expect(navigateStub).toHaveBeenCalledTimes(1); - expect(navigateStub).toHaveBeenLastCalledWith(expect.objectContaining({ pathname: '/home' }), expect.anything()); - }); - - it('should redirect to the provided redirectUrl when redirectUrl is within the workspace domain', async () => { - render( - - - - - , - ); - - expect(navigateStub).toHaveBeenCalledTimes(1); - expect(navigateStub).toHaveBeenLastCalledWith(expect.objectContaining({ pathname: '/invite/test' }), expect.anything()); - }); - - it('should call loginWithSamlToken when component is mounted', async () => { - render( - - - - - , - ); - - expect(Meteor.loginWithSamlToken).toHaveBeenCalledTimes(1); - expect(Meteor.loginWithSamlToken).toHaveBeenLastCalledWith(undefined, expect.any(Function)); - }); - - it('should call loginWithSamlToken with the token when it is present', async () => { - render( - - - - - , - ); - - expect(Meteor.loginWithSamlToken).toHaveBeenCalledTimes(1); - expect(Meteor.loginWithSamlToken).toHaveBeenLastCalledWith('testToken', expect.any(Function)); - }); -}); diff --git a/ee/packages/api-client/jest.config.ts b/ee/packages/api-client/jest.config.ts index 455fa3a054f2..2905f298e766 100644 --- a/ee/packages/api-client/jest.config.ts +++ b/ee/packages/api-client/jest.config.ts @@ -1,13 +1,7 @@ +import client from '@rocket.chat/jest-presets/client'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', - errorOnDeprecated: true, - testEnvironment: 'jsdom', - modulePathIgnorePatterns: ['/dist/'], - transform: { - '^.+\\.(t|j)sx?$': '@swc/jest', - }, - moduleNameMapper: { - '\\.css$': 'identity-obj-proxy', - }, - collectCoverage: true, -}; + preset: client.preset, + setupFilesAfterEnv: [...client.setupFilesAfterEnv], +} satisfies Config; diff --git a/ee/packages/api-client/package.json b/ee/packages/api-client/package.json index 7b20963145c8..43de20583d47 100644 --- a/ee/packages/api-client/package.json +++ b/ee/packages/api-client/package.json @@ -2,22 +2,21 @@ "name": "@rocket.chat/api-client", "version": "0.2.3", "devDependencies": { - "@swc/core": "^1.3.95", - "@swc/jest": "^0.2.29", + "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", "@types/strict-uri-encode": "^2.0.1", "eslint": "~8.45.0", "jest": "~29.7.0", "jest-fetch-mock": "^3.0.3", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { + "build": "tsc", + "dev": "tsc --watch --preserveWatchOutput", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "testunit": "jest", - "build": "tsc -p tsconfig.json", - "dev": "tsc --watch --preserveWatchOutput -p tsconfig.json" + "test": "jest", + "testunit": "jest" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", @@ -31,5 +30,8 @@ "query-string": "^7.1.3", "split-on-first": "^3.0.0", "strict-uri-encode": "^2.0.0" + }, + "volta": { + "extends": "../../../package.json" } } diff --git a/ee/packages/ddp-client/jest.config.ts b/ee/packages/ddp-client/jest.config.ts index eb3f38119a73..513d37db1e9c 100644 --- a/ee/packages/ddp-client/jest.config.ts +++ b/ee/packages/ddp-client/jest.config.ts @@ -1,14 +1,7 @@ +import client from '@rocket.chat/jest-presets/client'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', - errorOnDeprecated: true, - testEnvironment: 'jsdom', - modulePathIgnorePatterns: ['/dist/'], - testMatch: ['**/**.spec.ts'], - transform: { - '^.+\\.(t|j)sx?$': '@swc/jest', - }, - moduleNameMapper: { - '\\.css$': 'identity-obj-proxy', - }, - collectCoverage: true, -}; + preset: client.preset, + modulePathIgnorePatterns: ['/__tests__/helpers'], +} satisfies Config; diff --git a/ee/packages/ddp-client/package.json b/ee/packages/ddp-client/package.json index d4cce6a377e3..9e4fdfd85910 100644 --- a/ee/packages/ddp-client/package.json +++ b/ee/packages/ddp-client/package.json @@ -2,15 +2,12 @@ "name": "@rocket.chat/ddp-client", "version": "0.3.3", "devDependencies": { - "@swc/core": "^1.3.95", - "@swc/jest": "^0.2.29", + "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", "@types/ws": "^8.5.8", "eslint": "~8.45.0", "jest": "~29.7.0", - "jest-environment-jsdom": "~29.7.0", - "jest-websocket-mock": "^2.4.0", - "ts-jest": "^29.1.2", + "jest-websocket-mock": "~2.5.0", "typescript": "~5.3.3", "ws": "^8.13.0" }, @@ -18,12 +15,12 @@ "@rocket.chat/emitter": "*" }, "scripts": { + "build": "tsc", + "dev": "tsc --watch --preserveWatchOutput", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "unit": "jest", - "testunit": "jest", - "build": "rm -rf dist && tsc -p tsconfig.json", - "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" + "test": "jest", + "testunit": "jest" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/ee/packages/license/jest.config.ts b/ee/packages/license/jest.config.ts index 21121603f6e0..a89df51443e5 100644 --- a/ee/packages/license/jest.config.ts +++ b/ee/packages/license/jest.config.ts @@ -1,16 +1,7 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', - errorOnDeprecated: true, - modulePathIgnorePatterns: ['/dist/'], - testMatch: ['**/**.spec.ts'], - transform: { - '^.+\\.(t|j)sx?$': '@swc/jest', - }, - // transformIgnorePatterns: ['!node_modules/jose'], - moduleNameMapper: { - '\\.css$': 'identity-obj-proxy', - '^jose$': require.resolve('jose'), - }, - collectCoverage: true, - collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}'], -}; + preset: server.preset, + modulePathIgnorePatterns: ['/__tests__/MockedLicenseBuilder'], +} satisfies Config; diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index adb79a565418..1c746514d443 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -3,27 +3,22 @@ "version": "0.2.3", "private": true, "devDependencies": { - "@swc/core": "^1.3.95", - "@swc/jest": "^0.2.29", + "@rocket.chat/jest-presets": "workspace:~", "@types/bcrypt": "^5.0.1", "@types/jest": "~29.5.12", "@types/ws": "^8.5.8", "eslint": "~8.45.0", "jest": "~29.7.0", - "jest-environment-jsdom": "~29.7.0", - "jest-websocket-mock": "^2.4.0", - "ts-jest": "~29.1.1", + "jest-websocket-mock": "~2.5.0", "typescript": "~5.3.3" }, "scripts": { + "build": "tsc", + "dev": "tsc --watch --preserveWatchOutput", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", "test": "jest", - "testunit": "jest", - "build": "npm run build:types && npm run build:js", - "build:types": "tsc --emitDeclarationOnly", - "build:js": "rm -rf dist && tsc -p tsconfig.json", - "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" + "testunit": "jest" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/ee/packages/omnichannel-services/jest.config.ts b/ee/packages/omnichannel-services/jest.config.ts index 4f4e7697b108..c18c8ae02465 100644 --- a/ee/packages/omnichannel-services/jest.config.ts +++ b/ee/packages/omnichannel-services/jest.config.ts @@ -1,9 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', - errorOnDeprecated: true, - testEnvironment: 'jsdom', - modulePathIgnorePatterns: ['/dist/'], - moduleNameMapper: { - '\\.css$': 'identity-obj-proxy', - }, -}; + preset: server.preset, +} satisfies Config; diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 1962badbf929..f520d82bd7d3 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -4,10 +4,10 @@ "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", + "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "dependencies": { diff --git a/ee/packages/omnichannel-services/src/OmnichannelTranscript.spec.ts b/ee/packages/omnichannel-services/src/OmnichannelTranscript.spec.ts index 789cd9341690..569e0b4eefe5 100644 --- a/ee/packages/omnichannel-services/src/OmnichannelTranscript.spec.ts +++ b/ee/packages/omnichannel-services/src/OmnichannelTranscript.spec.ts @@ -1,4 +1,3 @@ -import '@testing-library/jest-dom'; import type { IMessage } from '@rocket.chat/core-typings'; import { Logger } from '@rocket.chat/logger'; diff --git a/ee/packages/pdf-worker/jest.config.ts b/ee/packages/pdf-worker/jest.config.ts index acf158bdd7d8..b8f99e5482c0 100644 --- a/ee/packages/pdf-worker/jest.config.ts +++ b/ee/packages/pdf-worker/jest.config.ts @@ -1,9 +1,22 @@ +import client from '@rocket.chat/jest-presets/client'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', - errorOnDeprecated: true, - testEnvironment: 'jsdom', - modulePathIgnorePatterns: ['/dist/', '/src/worker.spec.ts'], - moduleNameMapper: { - '\\.css$': 'identity-obj-proxy', - }, -}; + projects: [ + { + displayName: 'client', + preset: client.preset, + setupFilesAfterEnv: [...client.setupFilesAfterEnv], + modulePathIgnorePatterns: ['/src/worker.spec.ts'], + }, + { + displayName: 'worker', + preset: client.preset, + setupFilesAfterEnv: [...client.setupFilesAfterEnv], + moduleNameMapper: { + '^fontkit($|/.+)': '/../../../node_modules/fontkit$1', // needed to a weird bug related to module resolution in SWC + }, + modulePathIgnorePatterns: ['/src/strategies/', '/src/templates/'], + }, + ], +} satisfies Config; diff --git a/ee/packages/pdf-worker/jest.worker.config.ts b/ee/packages/pdf-worker/jest.worker.config.ts deleted file mode 100644 index 83706fdd37ec..000000000000 --- a/ee/packages/pdf-worker/jest.worker.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default { - preset: 'ts-jest', - errorOnDeprecated: true, - modulePathIgnorePatterns: ['/dist/', '/src/strategies/', '/src/templates/'], -}; diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 454592182db1..749d48ccc9c2 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -3,29 +3,27 @@ "version": "0.2.0", "private": true, "devDependencies": { + "@rocket.chat/jest-presets": "workspace:~", "@storybook/addon-essentials": "~6.5.16", "@storybook/react": "~6.5.16", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "~13.4.0", + "@testing-library/react": "~16.0.0", "@types/emojione": "^2.2.8", "@types/jest": "~29.5.12", + "@types/react": "~17.0.69", "@types/react-dom": "~17.0.22", - "@types/testing-library__jest-dom": "~5.14.9", "eslint": "~8.45.0", "jest": "~29.7.0", - "jest-environment-jsdom": "~29.7.0", - "react-dom": "^18.2.0", - "ts-jest": "~29.1.1", + "react-dom": "~18.3.1", "typescript": "~5.3.3" }, "scripts": { + "build": "tsc -p tsconfig.build.json && cp -r src/public dist/public", + "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", "test": "jest", - "test:worker": "jest --config ./jest.worker.config.ts", - "testunit": "yarn run test && yarn run test:worker", - "build": "rm -rf dist && tsc -p tsconfig.json && cp -r src/public dist/public", - "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput", + "testunit": "jest", "storybook": "start-storybook -p 6006" }, "main": "./dist/index.js", @@ -37,12 +35,11 @@ "@react-pdf/renderer": "^3.1.14", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/fuselage-tokens": "^0.33.1", - "@types/react": "~17.0.69", "emoji-assets": "^7.0.1", "emoji-toolkit": "^7.0.1", "moment": "^2.29.4", "moment-timezone": "^0.5.43", - "react": "^18.2.0" + "react": "~18.3.1" }, "volta": { "extends": "../../../package.json" diff --git a/ee/packages/pdf-worker/src/strategies/ChatTranscript.spec.ts b/ee/packages/pdf-worker/src/strategies/ChatTranscript.spec.ts index 280c5e9de2f0..8e425c014ec7 100644 --- a/ee/packages/pdf-worker/src/strategies/ChatTranscript.spec.ts +++ b/ee/packages/pdf-worker/src/strategies/ChatTranscript.spec.ts @@ -1,6 +1,5 @@ import moment from 'moment-timezone'; -import '@testing-library/jest-dom'; import { invalidData, validData, newDayData, sameDayData, translationsData } from '../templates/ChatTranscript/ChatTranscript.fixtures'; import { ChatTranscript } from './ChatTranscript'; diff --git a/ee/packages/pdf-worker/src/templates/ChatTranscript/components/Files.spec.tsx b/ee/packages/pdf-worker/src/templates/ChatTranscript/components/Files.spec.tsx index 16b5b92c5de9..4a2273ac65e5 100644 --- a/ee/packages/pdf-worker/src/templates/ChatTranscript/components/Files.spec.tsx +++ b/ee/packages/pdf-worker/src/templates/ChatTranscript/components/Files.spec.tsx @@ -1,7 +1,6 @@ import { render } from '@testing-library/react'; import type { ReactNode } from 'react'; -import '@testing-library/jest-dom'; import { invalidFile, validFile } from '../ChatTranscript.fixtures'; import { Files } from './Files'; diff --git a/ee/packages/pdf-worker/src/templates/ChatTranscript/components/MessageList.spec.tsx b/ee/packages/pdf-worker/src/templates/ChatTranscript/components/MessageList.spec.tsx index 0fb01f87d6da..49994e1c69fe 100644 --- a/ee/packages/pdf-worker/src/templates/ChatTranscript/components/MessageList.spec.tsx +++ b/ee/packages/pdf-worker/src/templates/ChatTranscript/components/MessageList.spec.tsx @@ -1,6 +1,5 @@ import { render } from '@testing-library/react'; -import '@testing-library/jest-dom'; import { invalidFile, validFile, validMessage, validSystemMessage } from '../ChatTranscript.fixtures'; import { MessageList } from './MessageList'; diff --git a/ee/packages/pdf-worker/src/worker.spec.ts b/ee/packages/pdf-worker/src/worker.spec.ts index 8dc197d79588..d880700194be 100644 --- a/ee/packages/pdf-worker/src/worker.spec.ts +++ b/ee/packages/pdf-worker/src/worker.spec.ts @@ -1,4 +1,6 @@ -import fs from 'fs'; +import { mkdtemp, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; import { PdfWorker } from './index'; import { @@ -18,70 +20,71 @@ const streamToBuffer = async (stream: NodeJS.ReadableStream) => { return Buffer.concat(chunks as Buffer[]); }; -jest.mock('@rocket.chat/core-services', () => ({ - Translation: { - translateToServerLanguage: (e: string) => e, - }, -})); - const pdfWorker = new PdfWorker('chat-transcript'); -describe('PdfWorker', () => { - it('should fail to instantiate if no mode is provided', () => { - // @ts-expect-error - testing - expect(() => new PdfWorker('')).toThrow(); - }); - it('should fail to instantiate if mode is invalid', () => { - // @ts-expect-error - testing - expect(() => new PdfWorker('invalid')).toThrow(); - }); - it('should properly instantiate', () => { - const newWorker = new PdfWorker('chat-transcript'); +it('should fail to instantiate if no mode is provided', () => { + // @ts-expect-error - testing + expect(() => new PdfWorker('')).toThrow(); +}); - expect(newWorker).toBeInstanceOf(PdfWorker); - expect(newWorker.mode).toBe('chat-transcript'); - }); - it('should generate a pdf transcript for a big bunch of messages', async () => { - const stream = await pdfWorker.renderToStream({ data: bigConversationData }); - const buffer = await streamToBuffer(stream); +it('should fail to instantiate if mode is invalid', () => { + // @ts-expect-error - testing + expect(() => new PdfWorker('invalid')).toThrow(); +}); - expect(buffer).toBeTruthy(); - }); - it('should generate a pdf transcript for a single message, but a really long message', async () => { - const stream = await pdfWorker.renderToStream({ data: dataWithASingleMessageButAReallyLongMessage }); - const buffer = await streamToBuffer(stream); +it('should properly instantiate', () => { + const newWorker = new PdfWorker('chat-transcript'); - expect(buffer).toBeTruthy(); - }); + expect(newWorker).toBeInstanceOf(PdfWorker); + expect(newWorker.mode).toBe('chat-transcript'); +}); - it('should generate a pdf transcript of a single message with an image', async () => { - const stream = await pdfWorker.renderToStream({ data: dataWithASingleMessageAndAnImage }); - const buffer = await streamToBuffer(stream); +it('should generate a pdf transcript for a big bunch of messages', async () => { + const stream = await pdfWorker.renderToStream({ data: bigConversationData }); + const buffer = await streamToBuffer(stream); - fs.writeFileSync('test.pdf', buffer); - expect(buffer).toBeTruthy(); - }); + expect(buffer).toBeTruthy(); +}, 10000); - it('should generate a pdf transcript for multiple messages, one big message and 2 small messages', async () => { - const stream = await pdfWorker.renderToStream({ data: dataWithMultipleMessagesAndABigMessage }); - const buffer = await streamToBuffer(stream); +it('should generate a pdf transcript for a single message, but a really long message', async () => { + const stream = await pdfWorker.renderToStream({ data: dataWithASingleMessageButAReallyLongMessage }); + const buffer = await streamToBuffer(stream); - expect(buffer).toBeTruthy(); - }); + expect(buffer).toBeTruthy(); +}, 10000); + +it('should generate a pdf transcript of a single message with an image', async () => { + const stream = await pdfWorker.renderToStream({ data: dataWithASingleMessageAndAnImage }); + const buffer = await streamToBuffer(stream); + + expect(buffer).toBeTruthy(); + + const tempDir = await mkdtemp(join(tmpdir(), 'pdf-worker')); + const tempFile = join(tempDir, 'test.pdf'); + // console.log(tempFile); + await writeFile(tempFile, buffer); +}, 10000); - it('should generate a pdf transcript for a single system message', async () => { - const stream = await pdfWorker.renderToStream({ data: dataWithASingleSystemMessage }); - const buffer = await streamToBuffer(stream); +it('should generate a pdf transcript for multiple messages, one big message and 2 small messages', async () => { + const stream = await pdfWorker.renderToStream({ data: dataWithMultipleMessagesAndABigMessage }); + const buffer = await streamToBuffer(stream); + + expect(buffer).toBeTruthy(); +}, 10000); + +it('should generate a pdf transcript for a single system message', async () => { + const stream = await pdfWorker.renderToStream({ data: dataWithASingleSystemMessage }); + const buffer = await streamToBuffer(stream); + + expect(buffer).toBeTruthy(); +}); - expect(buffer).toBeTruthy(); +describe('isMimeTypeValid', () => { + it('should return true if mimeType is valid', () => { + expect(pdfWorker.isMimeTypeValid('image/png')).toBe(true); }); - describe('isMimeTypeValid', () => { - it('should return true if mimeType is valid', () => { - expect(pdfWorker.isMimeTypeValid('image/png')).toBe(true); - }); - it('should return false if mimeType is not valid', () => { - expect(pdfWorker.isMimeTypeValid('image/svg')).toBe(false); - }); + it('should return false if mimeType is not valid', () => { + expect(pdfWorker.isMimeTypeValid('image/svg')).toBe(false); }); }); diff --git a/ee/packages/pdf-worker/tsconfig.build.json b/ee/packages/pdf-worker/tsconfig.build.json new file mode 100644 index 000000000000..3c11f201b746 --- /dev/null +++ b/ee/packages/pdf-worker/tsconfig.build.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "declaration": true, + "declarationMap": true + }, + "include": ["./src/**/*"], + "exclude": ["./src/**/*.spec.ts", "./src/**/*.spec.tsx"], +} diff --git a/ee/packages/pdf-worker/tsconfig.json b/ee/packages/pdf-worker/tsconfig.json index 64ec0d793b2f..a59de9bb7935 100644 --- a/ee/packages/pdf-worker/tsconfig.json +++ b/ee/packages/pdf-worker/tsconfig.json @@ -1,10 +1,6 @@ { "extends": "../../../tsconfig.base.server.json", "compilerOptions": { - "declaration": true, - "rootDir": "./src", - "outDir": "./dist", - "jsx": "react-jsx", - }, - "include": ["./src/**/*"] + "jsx": "react-jsx" + } } diff --git a/ee/packages/presence/jest.config.ts b/ee/packages/presence/jest.config.ts new file mode 100644 index 000000000000..c18c8ae02465 --- /dev/null +++ b/ee/packages/presence/jest.config.ts @@ -0,0 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + +export default { + preset: server.preset, +} satisfies Config; diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index b76cc8d69dba..21f1883b6704 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -19,9 +19,9 @@ "lint": "eslint src", "lint:fix": "eslint src --fix", "test": "jest", - "build": "tsc -p tsconfig.json", - "testunit": "jest tests/**/*.test.ts", - "typecheck": "tsc --noEmit --skipLibCheck -p tsconfig.json" + "build": "tsc", + "testunit": "jest", + "typecheck": "tsc --noEmit --skipLibCheck" }, "main": "./dist/Presence.js", "typings": "./dist/Presence.d.ts", diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json index a1e7925968fb..d1929c8b93f0 100644 --- a/ee/packages/ui-theming/package.json +++ b/ee/packages/ui-theming/package.json @@ -8,33 +8,19 @@ "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "^0.36.0", "@rocket.chat/ui-contexts": "workspace:~", - "@storybook/addon-actions": "~6.5.16", - "@storybook/addon-docs": "~6.5.16", - "@storybook/addon-essentials": "~6.5.16", - "@storybook/addon-interactions": "~6.5.16", - "@storybook/addon-links": "~6.5.16", - "@storybook/addon-postcss": "~2.0.0", - "@storybook/builder-webpack4": "~6.5.16", - "@storybook/manager-webpack4": "~6.5.16", - "@storybook/react": "~6.5.16", - "@storybook/testing-library": "~0.0.13", - "@types/jest": "~29.5.12", "@types/react": "~17.0.69", "eslint": "~8.45.0", "eslint-plugin-anti-trojan-source": "~1.1.1", "eslint-plugin-react": "~7.32.2", "eslint-plugin-react-hooks": "~4.6.0", "eslint-plugin-testing-library": "^5.11.1", - "jest": "~29.7.0", "react": "~17.0.2", "react-docgen-typescript-plugin": "~1.0.5", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig-build.json", "dev": "tsc -p tsconfig-build.json --watch --preserveWatchOutput" }, diff --git a/packages/account-utils/package.json b/packages/account-utils/package.json index 4f0fb62744e8..e33876a02d28 100644 --- a/packages/account-utils/package.json +++ b/packages/account-utils/package.json @@ -3,16 +3,12 @@ "version": "0.0.2", "private": true, "devDependencies": { - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, diff --git a/packages/agenda/package.json b/packages/agenda/package.json index 26f3e4866e3f..71b8b01bd6b0 100644 --- a/packages/agenda/package.json +++ b/packages/agenda/package.json @@ -13,16 +13,12 @@ }, "devDependencies": { "@types/debug": "^4.1.10", - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json" }, "main": "./dist/index.js", diff --git a/packages/apps/package.json b/packages/apps/package.json index ebf4b67725cf..15289501be4c 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -3,16 +3,12 @@ "version": "0.1.3", "private": true, "devDependencies": { - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, diff --git a/packages/base64/jest.config.ts b/packages/base64/jest.config.ts index 959a31a7c6bf..c18c8ae02465 100644 --- a/packages/base64/jest.config.ts +++ b/packages/base64/jest.config.ts @@ -1,3 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', -}; + preset: server.preset, +} satisfies Config; diff --git a/packages/base64/package.json b/packages/base64/package.json index 555128281d5f..c58a652877a3 100644 --- a/packages/base64/package.json +++ b/packages/base64/package.json @@ -16,11 +16,11 @@ "@babel/core": "~7.22.20", "@babel/preset-env": "~7.22.20", "@rocket.chat/eslint-config": "workspace:^", + "@rocket.chat/jest-presets": "workspace:~", "@typescript-eslint/eslint-plugin": "~5.60.1", "@typescript-eslint/parser": "~5.60.1", "eslint": "~8.45.0", "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "volta": { diff --git a/packages/cas-validate/package.json b/packages/cas-validate/package.json index f626cecfb48e..769b74d38e56 100644 --- a/packages/cas-validate/package.json +++ b/packages/cas-validate/package.json @@ -4,16 +4,12 @@ "version": "0.0.2", "private": true, "devDependencies": { - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, diff --git a/packages/core-services/jest.config.ts b/packages/core-services/jest.config.ts new file mode 100644 index 000000000000..c18c8ae02465 --- /dev/null +++ b/packages/core-services/jest.config.ts @@ -0,0 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + +export default { + preset: server.preset, +} satisfies Config; diff --git a/packages/core-services/package.json b/packages/core-services/package.json index bb080133de03..d576f87bef27 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -7,6 +7,7 @@ "@babel/preset-env": "~7.22.20", "@babel/preset-typescript": "~7.22.15", "@rocket.chat/eslint-config": "workspace:^", + "@rocket.chat/jest-presets": "workspace:~", "@types/babel__core": "^7.20.3", "@types/babel__preset-env": "^7.9.4", "@types/jest": "~29.5.12", @@ -20,10 +21,9 @@ "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "jest": "jest", - "testunit": "jest --verbose tests/**/*.test.ts", - "dev": "tsc --watch --preserveWatchOutput -p tsconfig.json", - "build": "rm -rf dist && tsc -p tsconfig.json" + "testunit": "jest", + "dev": "tsc --watch --preserveWatchOutput", + "build": "rm -rf dist && tsc" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/cron/package.json b/packages/cron/package.json index c68629f75129..a6484224ded5 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -3,16 +3,12 @@ "version": "0.1.3", "private": true, "devDependencies": { - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, diff --git a/packages/fuselage-ui-kit/jest.config.ts b/packages/fuselage-ui-kit/jest.config.ts index 070e217dc457..5c3180dfe83f 100644 --- a/packages/fuselage-ui-kit/jest.config.ts +++ b/packages/fuselage-ui-kit/jest.config.ts @@ -1,35 +1,13 @@ +import client from '@rocket.chat/jest-presets/client'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', - errorOnDeprecated: true, - testEnvironment: 'jsdom', - modulePathIgnorePatterns: ['/dist/'], - transform: { - '^.+\\.(t|j)sx?$': [ - '@swc/jest', - { - sourceMaps: true, - jsc: { - parser: { - syntax: 'typescript', - tsx: true, - decorators: false, - dynamicImport: true, - }, - transform: { - react: { - runtime: 'automatic', - }, - }, - }, - }, - ], - }, + preset: client.preset, + setupFilesAfterEnv: [...client.setupFilesAfterEnv], moduleNameMapper: { - '\\.css$': 'identity-obj-proxy', '^react($|/.+)': '/../../node_modules/react$1', + '^react-dom/client$': '/../../node_modules/react-dom$1', + '^react-dom($|/.+)': '/../../node_modules/react-dom$1', + '^react-i18next($|/.+)': '/../../node_modules/react-i18next$1', }, - setupFilesAfterEnv: [ - '@testing-library/jest-dom/extend-expect', - '/jest.setup.ts', - ], -}; +} satisfies Config; diff --git a/packages/fuselage-ui-kit/jest.setup.ts b/packages/fuselage-ui-kit/jest.setup.ts deleted file mode 100644 index 657e42bbdea1..000000000000 --- a/packages/fuselage-ui-kit/jest.setup.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { TextEncoder, TextDecoder } from 'util'; - -global.TextEncoder = TextEncoder; -// @ts-ignore -global.TextDecoder = TextDecoder; - -global.ResizeObserver = jest.fn().mockImplementation(() => ({ - observe: jest.fn(), - unobserve: jest.fn(), - disconnect: jest.fn(), -})); diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 723c7e44edbb..6d6b882c89d2 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -30,8 +30,8 @@ "dev": "tsc --watch --preserveWatchOutput -p tsconfig-esm.json", "build": "run-s .:build:clean .:build:esm .:build:cjs", ".:build:clean": "rimraf dist", - ".:build:esm": "tsc -p tsconfig-esm.json", - ".:build:cjs": "tsc -p tsconfig-cjs.json", + ".:build:esm": "tsc -p tsconfig.esm.json", + ".:build:cjs": "tsc -p tsconfig.cjs.json", "test": "jest", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "testunit": "jest", @@ -70,6 +70,7 @@ "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/icons": "^0.36.0", + "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/mock-providers": "workspace:^", "@rocket.chat/prettier-config": "~0.31.25", "@rocket.chat/styled": "~0.31.25", @@ -85,9 +86,8 @@ "@storybook/source-loader": "~6.5.16", "@storybook/theming": "~6.5.16", "@tanstack/react-query": "^4.16.1", - "@testing-library/react": "^12.1.4", - "@testing-library/react-hooks": "^8.0.1", - "@testing-library/user-event": "^14.5.2", + "@testing-library/react": "~16.0.0", + "@testing-library/user-event": "~14.5.2", "@types/babel__core": "^7.20.3", "@types/babel__preset-env": "^7.9.4", "@types/react": "~17.0.69", @@ -105,7 +105,6 @@ "react-i18next": "^14.1.0", "rimraf": "^3.0.2", "storybook-dark-mode": "~3.0.1", - "ts-jest": "^29.1.2", "tslib": "^2.5.3", "typescript": "~5.3.3" }, diff --git a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.spec.tsx b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.spec.tsx index 6af59dba4f63..a1a1f93dd1cd 100644 --- a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.spec.tsx +++ b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.spec.tsx @@ -66,7 +66,10 @@ describe('UiKit ChannelsSelect Element', () => { context={BlockContext.FORM} surfaceRenderer={contextualBarParser} /> - + , + { + legacyRoot: true, + } ); }); diff --git a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/MultiChannelsSelectElement.spec.tsx b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/MultiChannelsSelectElement.spec.tsx index 774f7652a3c9..304a1a442d69 100644 --- a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/MultiChannelsSelectElement.spec.tsx +++ b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/MultiChannelsSelectElement.spec.tsx @@ -65,7 +65,8 @@ describe('UiKit MultiChannelsSelect Element', () => { context={BlockContext.FORM} surfaceRenderer={contextualBarParser} /> - + , + { legacyRoot: true } ); }); diff --git a/packages/fuselage-ui-kit/src/elements/UsersSelectElement/MultiUsersSelectElement.spec.tsx b/packages/fuselage-ui-kit/src/elements/UsersSelectElement/MultiUsersSelectElement.spec.tsx index 1a6afad6c614..eea4f509fed0 100644 --- a/packages/fuselage-ui-kit/src/elements/UsersSelectElement/MultiUsersSelectElement.spec.tsx +++ b/packages/fuselage-ui-kit/src/elements/UsersSelectElement/MultiUsersSelectElement.spec.tsx @@ -53,7 +53,8 @@ describe('UiKit MultiUsersSelect Element', () => { context={BlockContext.FORM} surfaceRenderer={contextualBarParser} /> - + , + { legacyRoot: true } ); }); diff --git a/packages/fuselage-ui-kit/src/elements/UsersSelectElement/UserSelectElement.spec.tsx b/packages/fuselage-ui-kit/src/elements/UsersSelectElement/UserSelectElement.spec.tsx index 02f11d50951b..6e92a85d1656 100644 --- a/packages/fuselage-ui-kit/src/elements/UsersSelectElement/UserSelectElement.spec.tsx +++ b/packages/fuselage-ui-kit/src/elements/UsersSelectElement/UserSelectElement.spec.tsx @@ -53,7 +53,8 @@ describe('UiKit UserSelect Element', () => { context={BlockContext.FORM} surfaceRenderer={contextualBarParser} /> - + , + { legacyRoot: true } ); }); diff --git a/packages/fuselage-ui-kit/src/hooks/useAppTranslation.spec.tsx b/packages/fuselage-ui-kit/src/hooks/useAppTranslation.spec.tsx index e32dff123c1a..46314982aed8 100644 --- a/packages/fuselage-ui-kit/src/hooks/useAppTranslation.spec.tsx +++ b/packages/fuselage-ui-kit/src/hooks/useAppTranslation.spec.tsx @@ -1,5 +1,6 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import * as i18next from 'i18next'; +import { Suspense } from 'react'; import { I18nextProvider, initReactI18next } from 'react-i18next'; import { AppIdProvider } from '../contexts/AppIdContext'; @@ -30,6 +31,7 @@ beforeEach(async () => { it('should work with normal app ID (`test`)', async () => { const { result } = renderHook(() => useAppTranslation().t('test'), { + legacyRoot: true, wrapper: ({ children }) => ( {children} @@ -42,6 +44,7 @@ it('should work with normal app ID (`test`)', async () => { it('should work with core app ID (`test-core`)', async () => { const { result } = renderHook(() => useAppTranslation().t('test'), { + legacyRoot: true, wrapper: ({ children }) => ( {children} @@ -57,7 +60,14 @@ describe('with suspense', () => { beforeEach(async () => { i18n = i18next - .createInstance() + .createInstance({ + lng: 'en', + defaultNS: 'core', + partialBundledLanguages: true, + react: { + useSuspense: true, + }, + }) .use({ type: 'backend', init: () => undefined, @@ -81,27 +91,20 @@ describe('with suspense', () => { } satisfies i18next.BackendModule) .use(initReactI18next); - await i18n.init({ - lng: 'en', - defaultNS: 'core', - partialBundledLanguages: true, - react: { - useSuspense: true, - }, - }); + await i18n.init(); }); it('should work with normal app ID (`test`)', async () => { - const { result, waitFor } = renderHook( - () => useAppTranslation().t('test'), - { - wrapper: ({ children }) => ( - - {children} - - ), - } - ); + const { result } = renderHook(() => useAppTranslation().t('test'), { + legacyRoot: true, + wrapper: ({ children }) => ( + + + {children} + + + ), + }); await waitFor(() => expect(result.current).toBe('jumped over the lazy dog') @@ -109,16 +112,16 @@ describe('with suspense', () => { }); it('should work with core app ID (`test-core`)', async () => { - const { result, waitFor } = renderHook( - () => useAppTranslation().t('test'), - { - wrapper: ({ children }) => ( - - {children} - - ), - } - ); + const { result } = renderHook(() => useAppTranslation().t('test'), { + legacyRoot: true, + wrapper: ({ children }) => ( + + + {children} + + + ), + }); await waitFor(() => expect(result.current).toBe('a quick brown fox')); }); diff --git a/packages/fuselage-ui-kit/tsconfig-cjs.json b/packages/fuselage-ui-kit/tsconfig.cjs.json similarity index 78% rename from packages/fuselage-ui-kit/tsconfig-cjs.json rename to packages/fuselage-ui-kit/tsconfig.cjs.json index d4ac04a4fbc0..baae5231fec4 100644 --- a/packages/fuselage-ui-kit/tsconfig-cjs.json +++ b/packages/fuselage-ui-kit/tsconfig.cjs.json @@ -6,5 +6,5 @@ "outDir": "./dist/cjs" }, "include": ["src"], - "exclude": ["node_modules", "dist", "src/**/*.stories.tsx", ".storybook/**/*"] + "exclude": ["node_modules", "dist", "src/**/*.stories.tsx", ".storybook/**/*", "./src/**/*.spec.ts", "./src/**/*.spec.tsx"] } diff --git a/packages/fuselage-ui-kit/tsconfig-esm.json b/packages/fuselage-ui-kit/tsconfig.esm.json similarity index 78% rename from packages/fuselage-ui-kit/tsconfig-esm.json rename to packages/fuselage-ui-kit/tsconfig.esm.json index e7628b7b0174..017766f03607 100644 --- a/packages/fuselage-ui-kit/tsconfig-esm.json +++ b/packages/fuselage-ui-kit/tsconfig.esm.json @@ -6,5 +6,5 @@ "outDir": "./dist/esm" }, "include": ["src"], - "exclude": ["node_modules", "dist", "src/**/*.stories.tsx", ".storybook/**/*"] + "exclude": ["node_modules", "dist", "src/**/*.stories.tsx", ".storybook/**/*", "./src/**/*.spec.ts", "./src/**/*.spec.tsx"] } diff --git a/packages/fuselage-ui-kit/tsconfig.json b/packages/fuselage-ui-kit/tsconfig.json index 59d360dca033..bad1623ca4d9 100644 --- a/packages/fuselage-ui-kit/tsconfig.json +++ b/packages/fuselage-ui-kit/tsconfig.json @@ -1,14 +1,9 @@ { "extends": "../../tsconfig.base.client.json", "compilerOptions": { - "module": "CommonJS", - "rootDirs": ["./src", "./.storybook"], - "outDir": "./dist", - "allowJs": false, "noImplicitReturns": true, "noImplicitThis": true, - "jsx": "react-jsx" }, "include": ["src", ".storybook/**/*"], - "exclude": ["node_modules", "dist", "src/**/*.stories.tsx"] + "exclude": ["node_modules", "src/**/*.stories.tsx", "src/**/*.spec.ts", "src/**/*.spec.tsx"] } diff --git a/packages/gazzodown/jest.config.ts b/packages/gazzodown/jest.config.ts index 578c2920c79e..597fbebb687b 100644 --- a/packages/gazzodown/jest.config.ts +++ b/packages/gazzodown/jest.config.ts @@ -1,30 +1,12 @@ +import client from '@rocket.chat/jest-presets/client'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', - errorOnDeprecated: true, - testEnvironment: 'jsdom', - modulePathIgnorePatterns: ['/dist/'], - transform: { - '^.+\\.(t|j)sx?$': [ - '@swc/jest', - { - sourceMaps: true, - jsc: { - parser: { - syntax: 'typescript', - tsx: true, - decorators: false, - dynamicImport: true, - }, - transform: { - react: { - runtime: 'automatic', - }, - }, - }, - }, - ], - }, + preset: client.preset, + setupFilesAfterEnv: [...client.setupFilesAfterEnv], moduleNameMapper: { - '\\.css$': 'identity-obj-proxy', + '^react($|/.+)': '/../../node_modules/react$1', + '^react-dom/client$': '/../../node_modules/react-dom$1', + '^react-dom($|/.+)': '/../../node_modules/react-dom$1', }, -}; +} satisfies Config; diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 6161af8b762c..6ecb49fa9544 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -8,6 +8,7 @@ "@rocket.chat/css-in-js": "~0.31.25", "@rocket.chat/fuselage": "^0.57.0", "@rocket.chat/fuselage-tokens": "^0.33.1", + "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/styled": "~0.31.25", "@rocket.chat/ui-client": "workspace:^", @@ -21,15 +22,11 @@ "@storybook/manager-webpack4": "~6.5.16", "@storybook/react": "~6.5.16", "@storybook/testing-library": "~0.0.13", - "@swc/core": "^1.3.95", - "@swc/jest": "^0.2.29", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "~12.1.5", + "@testing-library/react": "~16.0.0", "@types/jest": "~29.5.12", "@types/katex": "~0.16.5", "@types/react": "~17.0.69", "@types/react-dom": "~17.0.22", - "@types/testing-library__jest-dom": "~5.14.9", "@typescript-eslint/eslint-plugin": "~5.60.1", "@typescript-eslint/parser": "~5.60.1", "babel-loader": "^8.3.0", @@ -40,22 +37,20 @@ "eslint-plugin-storybook": "~0.6.15", "identity-obj-proxy": "^3.0.0", "jest": "~29.7.0", - "jest-environment-jsdom": "~29.7.0", "katex": "~0.16.9", "outdent": "^0.8.0", "react-docgen-typescript-plugin": "~1.0.5", "react-dom": "~17.0.2", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { + "build": "rm -rf dist && tsc -p tsconfig.build.json", + "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "testunit": "jest --runInBand", - "test": "jest --runInBand", - "build": "rm -rf dist && tsc -p tsconfig.json", - "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput", - "typecheck": "tsc -p tsconfig.json --noEmit", + "testunit": "jest", + "test": "jest", "storybook": "start-storybook -p 6006", "build-storybook": "build-storybook" }, diff --git a/packages/gazzodown/src/Markup.spec.tsx b/packages/gazzodown/src/Markup.spec.tsx index 29ff8cda0fb0..a773ca73b919 100644 --- a/packages/gazzodown/src/Markup.spec.tsx +++ b/packages/gazzodown/src/Markup.spec.tsx @@ -1,20 +1,15 @@ -import { render, screen, cleanup, waitFor } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { Suspense } from 'react'; -import '@testing-library/jest-dom'; import { MarkupInteractionContext } from '.'; import Markup from './Markup'; -afterEach(cleanup); - -beforeAll(() => { - jest.mock('highlight.js', () => ({ - highlightElement: (): void => undefined, - })); -}); +jest.mock('highlight.js', () => ({ + highlightElement: (): void => undefined, +})); it('renders empty', () => { - const { container } = render(); + const { container } = render(, { legacyRoot: true }); expect(container).toBeEmptyDOMElement(); }); @@ -39,6 +34,7 @@ it('renders a big emoji block', () => { ]} /> , + { legacyRoot: true }, ); expect(screen.getByRole('presentation')).toHaveTextContent(':smile:😀:smile:'); @@ -67,6 +63,7 @@ it('renders a big emoji block with ASCII emoji', () => { ]} /> , + { legacyRoot: true }, ); expect(screen.getByRole('presentation')).toHaveTextContent(':slight_smile:🙂:)'); @@ -84,6 +81,7 @@ it('renders a paragraph', () => { }, ]} />, + { legacyRoot: true }, ); expect(screen.getByText('Hello')).toBeInTheDocument(); @@ -100,6 +98,7 @@ it('renders a heading', () => { }, ]} />, + { legacyRoot: true }, ); expect(screen.getByRole('heading', { name: 'Hello' })).toBeInTheDocument(); @@ -119,6 +118,7 @@ it('renders a unordered list', () => { }, ]} />, + { legacyRoot: true }, ); expect(screen.getByRole('list')).toBeInTheDocument(); @@ -145,6 +145,7 @@ it('renders an ordered list', () => { }, ]} />, + { legacyRoot: true }, ); expect(screen.getByRole('list')).toBeInTheDocument(); @@ -171,6 +172,7 @@ it('renders a task list', () => { }, ]} />, + { legacyRoot: true }, ); expect(screen.getByRole('list')).toBeInTheDocument(); @@ -213,6 +215,7 @@ it('renders a blockquote', () => { }, ]} />, + { legacyRoot: true }, ); expect(screen.getByText('Cogito ergo sum.')).toBeInTheDocument(); @@ -233,6 +236,7 @@ it('renders a code block', async () => { ]} /> , + { legacyRoot: true }, ); await waitFor(() => expect(screen.getByRole('region')).toBeInTheDocument()); @@ -253,6 +257,7 @@ it('renders a code block with language', async () => { ]} /> , + { legacyRoot: true }, ); await waitFor(() => expect(screen.getByRole('region')).toBeInTheDocument()); @@ -273,6 +278,7 @@ it('renders a Katex block', async () => { ]} /> , + { legacyRoot: true }, ); // workaround for jest-dom's inability to handle MathML @@ -292,6 +298,7 @@ it('renders a line break', () => { }, ]} />, + { legacyRoot: true }, ); expect(container).toContainHTML('
'); @@ -319,6 +326,7 @@ it('renders plain text instead of emojis based on preference', () => { ]} /> , + { legacyRoot: true }, ); expect(screen.getByText('Hey! :smile: :)')).toBeInTheDocument(); @@ -346,6 +354,7 @@ it('renders plain text instead of ASCII emojis based on useEmojis preference', ( ]} /> , + { legacyRoot: true }, ); expect(screen.getByText('Hey! :smile: :)')).toBeInTheDocument(); diff --git a/packages/gazzodown/tsconfig.build.json b/packages/gazzodown/tsconfig.build.json new file mode 100644 index 000000000000..9bab40e0b3d8 --- /dev/null +++ b/packages/gazzodown/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src/**/*"], + "exclude": ["./src/**/*.spec.ts", "./src/**/*.spec.tsx"] +} diff --git a/packages/gazzodown/tsconfig.json b/packages/gazzodown/tsconfig.json index e2be47cf5499..a144b6f02aa0 100644 --- a/packages/gazzodown/tsconfig.json +++ b/packages/gazzodown/tsconfig.json @@ -1,8 +1,3 @@ { - "extends": "../../tsconfig.base.client.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist" - }, - "include": ["./src/**/*"] + "extends": "../../tsconfig.base.client.json" } diff --git a/packages/i18n/babel.config.cjs b/packages/i18n/babel.config.cjs deleted file mode 100644 index ab413e04e571..000000000000 --- a/packages/i18n/babel.config.cjs +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [['@babel/preset-env', { bugfixes: true }]], -}; diff --git a/packages/i18n/jest.config.mjs b/packages/i18n/jest.config.mjs deleted file mode 100644 index ab3eeabeabfb..000000000000 --- a/packages/i18n/jest.config.mjs +++ /dev/null @@ -1,6 +0,0 @@ -export default { - testEnvironment: 'node', - transform: {}, - moduleFileExtensions: ['js', 'mjs'], - testMatch: ['**/?(*.)+(spec|test).(m)js'], -}; diff --git a/packages/i18n/jest.config.ts b/packages/i18n/jest.config.ts new file mode 100644 index 000000000000..eb3d5fd797e5 --- /dev/null +++ b/packages/i18n/jest.config.ts @@ -0,0 +1,9 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + +export default { + preset: server.preset, + testMatch: ['/src/**/*.spec.(ts|js|mjs)'], + transformIgnorePatterns: ['/node_modules/@babel', '/node_modules/@jest', 'signal-exit'], + collectCoverage: false, +} satisfies Config; diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 47e3bdeeec7a..6927aae08d1c 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -3,12 +3,9 @@ "version": "0.6.0", "private": true, "devDependencies": { - "@babel/core": "~7.22.20", - "@babel/preset-env": "~7.22.20", - "babel-jest": "^29.5.0", + "@rocket.chat/jest-presets": "workspace:~", "eslint": "~8.45.0", "jest": "~29.7.0", - "ts-jest": "~29.1.1", "tsup": "^6.7.0", "typescript": "~5.3.3" }, @@ -16,7 +13,8 @@ "build": "node ./src/index.mjs", "lint": "eslint --ext .mjs,.js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .mjs,.js,.jsx,.ts,.tsx . --fix", - "test": "NODE_OPTIONS=--experimental-vm-modules jest" + "test": "jest", + "testunit": "jest" }, "main": "./dist/index.js", "module": "./dist/index.mjs", diff --git a/packages/i18n/src/index.spec.mjs b/packages/i18n/src/index.spec.mjs index 5941bf8fa579..b3efdaa10175 100644 --- a/packages/i18n/src/index.spec.mjs +++ b/packages/i18n/src/index.spec.mjs @@ -9,6 +9,8 @@ describe('i18n', () => { jest.spyOn(fs, 'readdirSync').mockReturnValue(['en.i18n.json']); jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {}); jest.spyOn(fs, 'readFileSync').mockImplementation(() => JSON.stringify({})); + jest.spyOn(fs, 'existsSync').mockReturnValue(true); + jest.spyOn(fs, 'rmdirSync').mockImplementation(() => {}); }); afterEach(() => { diff --git a/packages/i18n/tsconfig.json b/packages/i18n/tsconfig.json new file mode 100644 index 000000000000..d3ff0b8bdc07 --- /dev/null +++ b/packages/i18n/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDirs": ["./src", "./"], + "outDir": "./dist", + "declaration": true + }, + "include": ["./src/**/*", "./jest.config.ts"] +} diff --git a/packages/jest-presets/package.json b/packages/jest-presets/package.json index b39ab17f6209..e6c0c9197bce 100644 --- a/packages/jest-presets/package.json +++ b/packages/jest-presets/package.json @@ -13,13 +13,14 @@ "/server" ], "dependencies": { - "@swc/core": "~1.5.24", + "@swc/core": "~1.7.4", "@swc/jest": "~0.2.36", - "@testing-library/jest-dom": "~6.4.5", + "@testing-library/jest-dom": "~6.4.8", "@types/jest-axe": "~3.5.9", "identity-obj-proxy": "~3.0.0", "jest-axe": "~9.0.0", "jest-environment-jsdom": "~29.7.0", + "jest-environment-node": "~29.7.0", "uuid": "~9.0.1" }, "devDependencies": { diff --git a/packages/jest-presets/src/client/jest-preset.ts b/packages/jest-presets/src/client/jest-preset.ts index 79482ba153bb..fbba554c5a1c 100644 --- a/packages/jest-presets/src/client/jest-preset.ts +++ b/packages/jest-presets/src/client/jest-preset.ts @@ -1,3 +1,4 @@ +import type * as SWC from '@swc/core'; import type { Config } from 'jest'; export default { @@ -5,7 +6,7 @@ export default { errorOnDeprecated: true, transform: { - '^.+\\.(t|j)sx?$': [ + '^.+\\.m?(t|j)sx?$': [ '@swc/jest', { sourceMaps: true, @@ -23,9 +24,11 @@ export default { dynamicImport: true, }, }, - }, + } satisfies SWC.Config, ], }, + transformIgnorePatterns: ['/node_modules/@babel', '/node_modules/@jest', '/node_modules/(?!@testing-library/)'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node', 'mjs'], moduleNameMapper: { '\\.css$': 'identity-obj-proxy', diff --git a/packages/jest-presets/src/server/jest-preset.ts b/packages/jest-presets/src/server/jest-preset.ts index e58212991146..df6d550d764f 100644 --- a/packages/jest-presets/src/server/jest-preset.ts +++ b/packages/jest-presets/src/server/jest-preset.ts @@ -1,3 +1,4 @@ +import type * as SWC from '@swc/core'; import type { Config } from 'jest'; export default { @@ -5,16 +6,23 @@ export default { errorOnDeprecated: true, transform: { - '^.+\\.(t|j)sx?$': [ + '^.+\\.m?(t|j)sx?$': [ '@swc/jest', { sourceMaps: true, jsc: { target: 'es2015', + parser: { + syntax: 'typescript', + decorators: false, + dynamicImport: true, + }, }, - }, + } satisfies SWC.Config, ], }, + transformIgnorePatterns: ['/node_modules/@babel', '/node_modules/@jest', '/node_modules/(?!@testing-library/)'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node', 'mjs'], collectCoverage: true, } satisfies Config; diff --git a/packages/jwt/jest.config.js b/packages/jwt/jest.config.js deleted file mode 100644 index 6231bde11685..000000000000 --- a/packages/jwt/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('ts-jest').JestConfigWithTsJest} */ -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', -}; diff --git a/packages/jwt/jest.config.ts b/packages/jwt/jest.config.ts new file mode 100644 index 000000000000..c18c8ae02465 --- /dev/null +++ b/packages/jwt/jest.config.ts @@ -0,0 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + +export default { + preset: server.preset, +} satisfies Config; diff --git a/packages/jwt/package.json b/packages/jwt/package.json index 533664d0878b..a6d989e2c275 100644 --- a/packages/jwt/package.json +++ b/packages/jwt/package.json @@ -3,29 +3,30 @@ "version": "0.1.1", "private": true, "devDependencies": { + "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "ts-jest": "^29.1.1", "typescript": "~5.3.3" }, "scripts": { + "build": "rm -rf dist && tsc", + "dev": "tsc --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", "test": "jest", - "testunit": "jest", - "build": "rm -rf dist && tsc -p tsconfig.json", - "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" + "testunit": "jest" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", "files": [ "/dist" ], - "volta": { - "extends": "../../package.json" - }, "dependencies": { "jose": "^4.14.4" + }, + "volta": { + "extends": "../../package.json" } } diff --git a/packages/log-format/package.json b/packages/log-format/package.json index 7d407c6df345..b43a3954a96f 100644 --- a/packages/log-format/package.json +++ b/packages/log-format/package.json @@ -5,16 +5,12 @@ "devDependencies": { "@types/chalk": "^2.2.0", "@types/ejson": "^2.2.1", - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, diff --git a/packages/logger/package.json b/packages/logger/package.json index 4166f6a6fc06..aae996f35139 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -3,16 +3,12 @@ "version": "0.0.2", "private": true, "devDependencies": { - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, diff --git a/packages/message-parser/jest.config.js b/packages/message-parser/jest.config.js deleted file mode 100644 index 114260f819d9..000000000000 --- a/packages/message-parser/jest.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const path = require('path'); - -module.exports = { - coverageReporters: [], - transform: { - '\\.pegjs$': path.resolve(__dirname, './loaders/pegtransform.js'), - }, - preset: 'ts-jest', - errorOnDeprecated: true, - testMatch: ['/tests/**/*.(spec|test).ts'], - moduleFileExtensions: ['js', 'ts', 'pegjs'], -}; diff --git a/packages/message-parser/jest.config.ts b/packages/message-parser/jest.config.ts new file mode 100644 index 000000000000..e11f29938eb9 --- /dev/null +++ b/packages/message-parser/jest.config.ts @@ -0,0 +1,12 @@ +import { resolve } from 'node:path'; + +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + +export default { + preset: server.preset, + transform: { + '\\.pegjs$': resolve(__dirname, './loaders/pegtransform.js'), + }, + moduleFileExtensions: ['js', 'ts', 'pegjs'], +} satisfies Config; diff --git a/packages/message-parser/package.json b/packages/message-parser/package.json index 2a9680e4a376..fd7e88dc1d86 100644 --- a/packages/message-parser/package.json +++ b/packages/message-parser/package.json @@ -42,9 +42,9 @@ "build": "run-s .:build:clean .:build:bundle", ".:build:clean": "rimraf dist", ".:build:bundle": "webpack", - "testunit": "jest --runInBand --coverage", - "watch": "jest --watch", - "lint": "eslint src", + "lint": "eslint .", + "test": "jest", + "testunit": "jest", "docs": "typedoc" }, "devDependencies": { @@ -52,6 +52,7 @@ "@babel/eslint-parser": "~7.21.3", "@babel/preset-env": "~7.21.4", "@rocket.chat/eslint-config": "workspace:^", + "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/peggy-loader": "workspace:~", "@rocket.chat/prettier-config": "~0.31.25", "@types/jest": "~29.5.12", @@ -65,7 +66,6 @@ "prettier": "~2.8.7", "prettier-plugin-pegjs": "~0.5.4", "rimraf": "^3.0.2", - "ts-jest": "~29.1.0", "ts-loader": "~9.4.2", "typedoc": "~0.24.1", "typescript": "~5.3.3", @@ -74,5 +74,8 @@ }, "dependencies": { "tldts": "~5.7.112" + }, + "volta": { + "extends": "../../package.json" } } diff --git a/packages/mock-providers/package.json b/packages/mock-providers/package.json index 8a7652bacf05..64310f0695cc 100644 --- a/packages/mock-providers/package.json +++ b/packages/mock-providers/package.json @@ -3,20 +3,20 @@ "version": "0.1.1", "private": true, "dependencies": { + "@rocket.chat/emitter": "~0.31.25", "@rocket.chat/i18n": "workspace:~", "i18next": "~23.4.9", - "react-i18next": "~13.2.2" + "react-i18next": "~13.2.2", + "use-sync-external-store": "~1.2.2" }, "devDependencies": { "@rocket.chat/ddp-client": "workspace:~", "@rocket.chat/ui-contexts": "workspace:*", "@storybook/react": "~6.5.16", "@tanstack/react-query": "^4.16.1", - "@types/jest": "~29.5.12", + "@types/use-sync-external-store": "^0.0.5", "eslint": "~8.45.0", - "jest": "~29.7.0", "react": "~17.0.2", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "peerDependencies": { @@ -26,7 +26,6 @@ "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, @@ -34,5 +33,8 @@ "typings": "./dist/index.d.ts", "files": [ "/dist" - ] + ], + "volta": { + "extends": "../../package.json" + } } diff --git a/packages/mock-providers/src/MockedAppRootBuilder.tsx b/packages/mock-providers/src/MockedAppRootBuilder.tsx index 31eb125c0915..15b1339c560d 100644 --- a/packages/mock-providers/src/MockedAppRootBuilder.tsx +++ b/packages/mock-providers/src/MockedAppRootBuilder.tsx @@ -1,9 +1,10 @@ -import { type ISetting, type Serialized, type SettingValue } from '@rocket.chat/core-typings'; +import type { ISetting, Serialized, SettingValue } from '@rocket.chat/core-typings'; import type { ServerMethodName, ServerMethodParameters, ServerMethodReturn } from '@rocket.chat/ddp-client'; +import { Emitter } from '@rocket.chat/emitter'; import languages from '@rocket.chat/i18n/dist/languages'; -import { type Method, type OperationParams, type OperationResult, type PathPattern, type UrlParams } from '@rocket.chat/rest-typings'; +import type { Method, OperationParams, OperationResult, PathPattern, UrlParams } from '@rocket.chat/rest-typings'; +import type { ModalContextValue, TranslationKey } from '@rocket.chat/ui-contexts'; import { - type TranslationKey, AuthorizationContext, ConnectionStatusContext, RouterContext, @@ -14,18 +15,24 @@ import { ActionManagerContext, ModalContext, } from '@rocket.chat/ui-contexts'; -import { type DecoratorFn } from '@storybook/react'; +import type { DecoratorFn } from '@storybook/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { type WrapperComponent } from '@testing-library/react-hooks'; import { createInstance } from 'i18next'; -import { type ObjectId } from 'mongodb'; -import React, { type ContextType, type ReactNode, useEffect, useReducer } from 'react'; +import type { ObjectId } from 'mongodb'; +import type { ContextType, JSXElementConstructor, ReactNode } from 'react'; +import React, { useEffect, useReducer } from 'react'; import { I18nextProvider, initReactI18next } from 'react-i18next'; +import { useSyncExternalStore } from 'use-sync-external-store/shim'; type Mutable = { -readonly [P in keyof T]: T[P]; }; +// eslint-disable-next-line @typescript-eslint/naming-convention +interface MockedAppRootEvents { + 'update-modal': void; +} + export class MockedAppRootBuilder { private wrappers: Array<(children: ReactNode) => ReactNode> = []; @@ -88,10 +95,16 @@ export class MockedAppRootBuilder { userId: null, }; - private modal: ContextType = { + private modal: ModalContextValue = { currentModal: { component: null }, modal: { - setModal: () => undefined, + setModal: (modal) => { + this.modal = { + ...this.modal, + currentModal: { component: modal }, + }; + this.events.emit('update-modal'); + }, }, }; @@ -111,6 +124,8 @@ export class MockedAppRootBuilder { }, }; + private events = new Emitter(); + wrap(wrapper: (children: ReactNode) => ReactNode): this { this.wrappers.push(wrapper); return this; @@ -310,22 +325,25 @@ export class MockedAppRootBuilder { return this; } - private i18n = createInstance( - { - // debug: true, - lng: 'en', - fallbackLng: 'en', - ns: ['core'], - nsSeparator: '.', - partialBundledLanguages: true, - defaultNS: 'core', - interpolation: { - escapeValue: false, - }, - initImmediate: false, + withOpenModal(modal: ReactNode) { + this.modal.currentModal = { component: modal }; + + return this; + } + + private i18n = createInstance({ + // debug: true, + lng: 'en', + fallbackLng: 'en', + ns: ['core'], + nsSeparator: '.', + partialBundledLanguages: true, + defaultNS: 'core', + interpolation: { + escapeValue: false, }, - () => undefined, - ).use(initReactI18next); + initImmediate: false, + }).use(initReactI18next); withTranslations(lng: string, ns: string, resources: Record): this { const addResources = () => { @@ -344,15 +362,20 @@ export class MockedAppRootBuilder { return this; } - build(): WrapperComponent<{ children: ReactNode }> { + build(): JSXElementConstructor<{ children: ReactNode }> { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false }, }, + logger: { + log: console.log, + warn: console.warn, + error: () => undefined, + }, }); - const { connectionStatus, server, router, settings, user, modal, i18n, authorization, wrappers } = this; + const { connectionStatus, server, router, settings, user, i18n, authorization, wrappers } = this; const reduceTranslation = (translation?: ContextType): ContextType => { return { @@ -391,6 +414,12 @@ export class MockedAppRootBuilder { }; }; + const subscribeToModal = (onStoreChange: () => void) => this.events.on('update-modal', onStoreChange); + + const getModalSnapshot = () => this.modal; + + i18n.init(); + return function MockedAppRoot({ children }) { const [translation, updateTranslation] = useReducer(reduceTranslation, undefined, () => reduceTranslation()); @@ -404,6 +433,8 @@ export class MockedAppRootBuilder { }; }, []); + const modal = useSyncExternalStore(subscribeToModal, getModalSnapshot); + return ( @@ -442,7 +473,13 @@ export class MockedAppRootBuilder { {/* */} - {wrappers.reduce((children, wrapper) => wrapper(children), children)} + {wrappers.reduce( + (children, wrapper) => wrapper(children), + <> + {children} + {modal.currentModal.component} + , + )} {/* */} diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index de257d4e6764..f96764fa49af 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -3,18 +3,14 @@ "version": "0.6.0", "private": true, "devDependencies": { - "@types/jest": "~29.5.12", "@types/node-rsa": "^1.1.3", "eslint": "~8.45.0", - "jest": "~29.7.0", "mongodb": "^4.17.2", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json" }, "main": "./dist/index.js", diff --git a/packages/models/jest.config.ts b/packages/models/jest.config.ts index eb3f38119a73..c18c8ae02465 100644 --- a/packages/models/jest.config.ts +++ b/packages/models/jest.config.ts @@ -1,14 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', - errorOnDeprecated: true, - testEnvironment: 'jsdom', - modulePathIgnorePatterns: ['/dist/'], - testMatch: ['**/**.spec.ts'], - transform: { - '^.+\\.(t|j)sx?$': '@swc/jest', - }, - moduleNameMapper: { - '\\.css$': 'identity-obj-proxy', - }, - collectCoverage: true, -}; + preset: server.preset, +} satisfies Config; diff --git a/packages/models/package.json b/packages/models/package.json index 3bd8fe4337ae..19f1f28438f6 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -3,23 +3,22 @@ "version": "0.2.0", "private": true, "devDependencies": { - "@swc/core": "^1.3.95", - "@swc/jest": "^0.2.29", + "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "^29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "dependencies": { - "@rocket.chat/model-typings": "workspace:^" + "@rocket.chat/model-typings": "workspace:~" }, "scripts": { + "build": "rm -rf dist && tsc", + "dev": "tsc --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", "test": "jest", - "dev": "tsc --watch --preserveWatchOutput -p tsconfig.json", - "build": "rm -rf dist && tsc -p tsconfig.json", "unit": "jest", "testunit": "jest" }, diff --git a/packages/node-poplib/package.json b/packages/node-poplib/package.json index 9fa4a74db1e1..a232d6b4c476 100644 --- a/packages/node-poplib/package.json +++ b/packages/node-poplib/package.json @@ -3,15 +3,9 @@ "version": "0.0.2", "private": true, "devDependencies": { - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, - "scripts": { - "test": "jest" - }, "main": "./src/index.js", "typings": "./dist/index.d.ts" } diff --git a/packages/password-policies/jest.config.ts b/packages/password-policies/jest.config.ts index 959a31a7c6bf..c18c8ae02465 100644 --- a/packages/password-policies/jest.config.ts +++ b/packages/password-policies/jest.config.ts @@ -1,3 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', -}; + preset: server.preset, +} satisfies Config; diff --git a/packages/password-policies/package.json b/packages/password-policies/package.json index d243fe079630..d53ffa1f5249 100644 --- a/packages/password-policies/package.json +++ b/packages/password-policies/package.json @@ -3,20 +3,20 @@ "version": "0.0.2", "private": true, "devDependencies": { - "@types/chai": "~4.3.16", + "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", - "chai": "^4.3.10", "eslint": "~8.45.0", "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { + "build": "rm -rf dist && tsc", + "dev": "tsc --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "testunit": "jest", - "build": "rm -rf dist && tsc -p tsconfig.json", - "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" + "test": "jest", + "testunit": "jest" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/password-policies/src/PasswordPolicy.spec.ts b/packages/password-policies/src/PasswordPolicy.spec.ts new file mode 100644 index 000000000000..c85cfc64586e --- /dev/null +++ b/packages/password-policies/src/PasswordPolicy.spec.ts @@ -0,0 +1,219 @@ +import { PasswordPolicy } from './PasswordPolicy'; + +describe('Password tests with default options', () => { + it('should allow all passwords', () => { + const passwordPolicy = new PasswordPolicy({ throwError: false }); + expect(passwordPolicy.validate(null as any)).toBe(false); + expect(passwordPolicy.validate(undefined as any)).toBe(false); + expect(passwordPolicy.validate('')).toBe(false); + expect(passwordPolicy.validate(' ')).toBe(false); + expect(passwordPolicy.validate('a')).toBe(true); + expect(passwordPolicy.validate('aaaaaaaaa')).toBe(true); + }); +}); + +describe('Password tests with options', () => { + it('should not allow non string or empty', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + throwError: false, + }); + expect(passwordPolicy.validate(null as any)).toBe(false); + expect(passwordPolicy.validate(undefined as any)).toBe(false); + expect(passwordPolicy.validate(1 as any)).toBe(false); + expect(passwordPolicy.validate(true as any)).toBe(false); + expect(passwordPolicy.validate(new Date() as any)).toBe(false); + expect(passwordPolicy.validate(new Function() as any)).toBe(false); + expect(passwordPolicy.validate('')).toBe(false); + }); + + it('should restrict by minLength', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + minLength: 5, + throwError: false, + }); + + expect(passwordPolicy.validate('1')).toBe(false); + expect(passwordPolicy.validate('1234')).toBe(false); + expect(passwordPolicy.validate('12345')).toBe(true); + expect(passwordPolicy.validate(' ')).toBe(false); + }); + + it('should restrict by maxLength', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + maxLength: 5, + throwError: false, + }); + + expect(passwordPolicy.validate('1')).toBe(true); + expect(passwordPolicy.validate('12345')).toBe(true); + expect(passwordPolicy.validate('123456')).toBe(false); + expect(passwordPolicy.validate(' ')).toBe(false); + }); + + it('should allow repeated characters', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + forbidRepeatingCharacters: false, + throwError: false, + }); + + expect(passwordPolicy.validate('1')).toBe(true); + expect(passwordPolicy.validate('12345')).toBe(true); + expect(passwordPolicy.validate('123456')).toBe(true); + expect(passwordPolicy.validate(' ')).toBe(false); + expect(passwordPolicy.validate('11111111111111')).toBe(true); + }); + + it('should restrict repeated characters', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + forbidRepeatingCharacters: true, + forbidRepeatingCharactersCount: 3, + throwError: false, + }); + + expect(passwordPolicy.validate('1')).toBe(true); + expect(passwordPolicy.validate('11')).toBe(true); + expect(passwordPolicy.validate('111')).toBe(true); + expect(passwordPolicy.validate('1111')).toBe(false); + expect(passwordPolicy.validate(' ')).toBe(false); + expect(passwordPolicy.validate('123456')).toBe(true); + }); + + it('should restrict repeated characters customized', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + forbidRepeatingCharacters: true, + forbidRepeatingCharactersCount: 5, + throwError: false, + }); + + expect(passwordPolicy.validate('1')).toBe(true); + expect(passwordPolicy.validate('11')).toBe(true); + expect(passwordPolicy.validate('111')).toBe(true); + expect(passwordPolicy.validate('1111')).toBe(true); + expect(passwordPolicy.validate('11111')).toBe(true); + expect(passwordPolicy.validate('111111')).toBe(false); + expect(passwordPolicy.validate(' ')).toBe(false); + expect(passwordPolicy.validate('123456')).toBe(true); + }); + + it('should contain one lowercase', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + mustContainAtLeastOneLowercase: true, + throwError: false, + }); + + expect(passwordPolicy.validate('a')).toBe(true); + expect(passwordPolicy.validate('aa')).toBe(true); + expect(passwordPolicy.validate('A')).toBe(false); + expect(passwordPolicy.validate(' ')).toBe(false); + expect(passwordPolicy.validate('123456')).toBe(false); + expect(passwordPolicy.validate('AAAAA')).toBe(false); + expect(passwordPolicy.validate('AAAaAAA')).toBe(true); + }); + + it('should contain one uppercase', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + mustContainAtLeastOneUppercase: true, + throwError: false, + }); + + expect(passwordPolicy.validate('a')).toBe(false); + expect(passwordPolicy.validate('aa')).toBe(false); + expect(passwordPolicy.validate('A')).toBe(true); + expect(passwordPolicy.validate(' ')).toBe(false); + expect(passwordPolicy.validate('123456')).toBe(false); + expect(passwordPolicy.validate('AAAAA')).toBe(true); + expect(passwordPolicy.validate('AAAaAAA')).toBe(true); + }); + + it('should contain one number', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + mustContainAtLeastOneNumber: true, + throwError: false, + }); + + expect(passwordPolicy.validate('a')).toBe(false); + expect(passwordPolicy.validate('aa')).toBe(false); + expect(passwordPolicy.validate('A')).toBe(false); + expect(passwordPolicy.validate(' ')).toBe(false); + expect(passwordPolicy.validate('123456')).toBe(true); + expect(passwordPolicy.validate('AAAAA')).toBe(false); + expect(passwordPolicy.validate('AAAaAAA')).toBe(false); + expect(passwordPolicy.validate('AAAa1AAA')).toBe(true); + }); + + it('should contain one special character', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + mustContainAtLeastOneSpecialCharacter: true, + throwError: false, + }); + + expect(passwordPolicy.validate('a')).toBe(false); + expect(passwordPolicy.validate('aa')).toBe(false); + expect(passwordPolicy.validate('A')).toBe(false); + expect(passwordPolicy.validate(' ')).toBe(false); + expect(passwordPolicy.validate('123456')).toBe(false); + expect(passwordPolicy.validate('AAAAA')).toBe(false); + expect(passwordPolicy.validate('AAAaAAA')).toBe(false); + expect(passwordPolicy.validate('AAAa1AAA')).toBe(false); + expect(passwordPolicy.validate('AAAa@AAA')).toBe(true); + }); +}); + +describe('Password Policy', () => { + it('should return a correct password policy', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + throwError: false, + minLength: 10, + maxLength: 20, + forbidRepeatingCharacters: true, + forbidRepeatingCharactersCount: 4, + mustContainAtLeastOneLowercase: true, + mustContainAtLeastOneUppercase: true, + mustContainAtLeastOneNumber: true, + mustContainAtLeastOneSpecialCharacter: true, + }); + + const policy = passwordPolicy.getPasswordPolicy(); + + expect(policy).not.toBe(undefined); + expect(policy.enabled).toBe(true); + expect(policy.policy.length).toBe(8); + expect(policy.policy[0][0]).toBe('get-password-policy-minLength'); + expect(policy.policy[0][1]?.minLength).toBe(10); + }); + + it('should return correct values if policy is disabled', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: false, + }); + + const policy = passwordPolicy.getPasswordPolicy(); + + expect(policy.enabled).toBe(false); + expect(policy.policy.length).toBe(0); + }); + + it('should return correct values if policy is enabled but no specifiers exists', () => { + const passwordPolicy = new PasswordPolicy({ + enabled: true, + }); + + const policy = passwordPolicy.getPasswordPolicy(); + + expect(policy.enabled).toBe(true); + // even when no policy is specified, forbidRepeatingCharactersCount is still configured + // since its default value is 3 + expect(policy.policy.length).toBe(1); + }); +}); diff --git a/packages/password-policies/src/PasswordPolicyClass.ts b/packages/password-policies/src/PasswordPolicy.ts similarity index 100% rename from packages/password-policies/src/PasswordPolicyClass.ts rename to packages/password-policies/src/PasswordPolicy.ts diff --git a/packages/password-policies/src/index.ts b/packages/password-policies/src/index.ts index ce94042e029a..fe91af266a93 100644 --- a/packages/password-policies/src/index.ts +++ b/packages/password-policies/src/index.ts @@ -1 +1 @@ -export { PasswordPolicy } from './PasswordPolicyClass'; +export { PasswordPolicy } from './PasswordPolicy'; diff --git a/packages/password-policies/tests/passwordPolicyClass.test.ts b/packages/password-policies/tests/passwordPolicyClass.test.ts deleted file mode 100644 index 4cda16e3dd27..000000000000 --- a/packages/password-policies/tests/passwordPolicyClass.test.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { expect } from 'chai'; - -import { PasswordPolicy } from '../src/PasswordPolicyClass'; - -describe('PasswordPolicy', () => { - describe('Password tests with default options', () => { - it('should allow all passwords', () => { - const passwordPolicy = new PasswordPolicy({ throwError: false }); - expect(passwordPolicy.validate(null as any)).to.be.equal(false); - expect(passwordPolicy.validate(undefined as any)).to.be.equal(false); - expect(passwordPolicy.validate('')).to.be.equal(false); - expect(passwordPolicy.validate(' ')).to.be.equal(false); - expect(passwordPolicy.validate('a')).to.be.equal(true); - expect(passwordPolicy.validate('aaaaaaaaa')).to.be.equal(true); - }); - }); - - describe('Password tests with options', () => { - it('should not allow non string or empty', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - throwError: false, - }); - expect(passwordPolicy.validate(null as any)).to.be.equal(false); - expect(passwordPolicy.validate(undefined as any)).to.be.false; - expect(passwordPolicy.validate(1 as any)).to.be.false; - expect(passwordPolicy.validate(true as any)).to.be.false; - expect(passwordPolicy.validate(new Date() as any)).to.be.false; - expect(passwordPolicy.validate(new Function() as any)).to.be.false; - expect(passwordPolicy.validate('')).to.be.false; - }); - - it('should restrict by minLength', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - minLength: 5, - throwError: false, - }); - - expect(passwordPolicy.validate('1')).to.be.false; - expect(passwordPolicy.validate('1234')).to.be.false; - expect(passwordPolicy.validate('12345')).to.be.true; - expect(passwordPolicy.validate(' ')).to.be.false; - }); - - it('should restrict by maxLength', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - maxLength: 5, - throwError: false, - }); - - expect(passwordPolicy.validate('1')).to.be.true; - expect(passwordPolicy.validate('12345')).to.be.true; - expect(passwordPolicy.validate('123456')).to.be.false; - expect(passwordPolicy.validate(' ')).to.be.false; - }); - - it('should allow repeated characters', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - forbidRepeatingCharacters: false, - throwError: false, - }); - - expect(passwordPolicy.validate('1')).to.be.true; - expect(passwordPolicy.validate('12345')).to.be.true; - expect(passwordPolicy.validate('123456')).to.be.true; - expect(passwordPolicy.validate(' ')).to.be.false; - expect(passwordPolicy.validate('11111111111111')).to.be.true; - }); - - it('should restrict repeated characters', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - forbidRepeatingCharacters: true, - forbidRepeatingCharactersCount: 3, - throwError: false, - }); - - expect(passwordPolicy.validate('1')).to.be.true; - expect(passwordPolicy.validate('11')).to.be.true; - expect(passwordPolicy.validate('111')).to.be.true; - expect(passwordPolicy.validate('1111')).to.be.false; - expect(passwordPolicy.validate(' ')).to.be.false; - expect(passwordPolicy.validate('123456')).to.be.true; - }); - - it('should restrict repeated characters customized', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - forbidRepeatingCharacters: true, - forbidRepeatingCharactersCount: 5, - throwError: false, - }); - - expect(passwordPolicy.validate('1')).to.be.true; - expect(passwordPolicy.validate('11')).to.be.true; - expect(passwordPolicy.validate('111')).to.be.true; - expect(passwordPolicy.validate('1111')).to.be.true; - expect(passwordPolicy.validate('11111')).to.be.true; - expect(passwordPolicy.validate('111111')).to.be.false; - expect(passwordPolicy.validate(' ')).to.be.false; - expect(passwordPolicy.validate('123456')).to.be.true; - }); - - it('should contain one lowercase', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - mustContainAtLeastOneLowercase: true, - throwError: false, - }); - - expect(passwordPolicy.validate('a')).to.be.true; - expect(passwordPolicy.validate('aa')).to.be.true; - expect(passwordPolicy.validate('A')).to.be.false; - expect(passwordPolicy.validate(' ')).to.be.false; - expect(passwordPolicy.validate('123456')).to.be.false; - expect(passwordPolicy.validate('AAAAA')).to.be.false; - expect(passwordPolicy.validate('AAAaAAA')).to.be.true; - }); - - it('should contain one uppercase', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - mustContainAtLeastOneUppercase: true, - throwError: false, - }); - - expect(passwordPolicy.validate('a')).to.be.false; - expect(passwordPolicy.validate('aa')).to.be.false; - expect(passwordPolicy.validate('A')).to.be.true; - expect(passwordPolicy.validate(' ')).to.be.false; - expect(passwordPolicy.validate('123456')).to.be.false; - expect(passwordPolicy.validate('AAAAA')).to.be.true; - expect(passwordPolicy.validate('AAAaAAA')).to.be.true; - }); - - it('should contain one number', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - mustContainAtLeastOneNumber: true, - throwError: false, - }); - - expect(passwordPolicy.validate('a')).to.be.false; - expect(passwordPolicy.validate('aa')).to.be.false; - expect(passwordPolicy.validate('A')).to.be.false; - expect(passwordPolicy.validate(' ')).to.be.false; - expect(passwordPolicy.validate('123456')).to.be.true; - expect(passwordPolicy.validate('AAAAA')).to.be.false; - expect(passwordPolicy.validate('AAAaAAA')).to.be.false; - expect(passwordPolicy.validate('AAAa1AAA')).to.be.true; - }); - - it('should contain one special character', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - mustContainAtLeastOneSpecialCharacter: true, - throwError: false, - }); - - expect(passwordPolicy.validate('a')).to.be.false; - expect(passwordPolicy.validate('aa')).to.be.false; - expect(passwordPolicy.validate('A')).to.be.false; - expect(passwordPolicy.validate(' ')).to.be.false; - expect(passwordPolicy.validate('123456')).to.be.false; - expect(passwordPolicy.validate('AAAAA')).to.be.false; - expect(passwordPolicy.validate('AAAaAAA')).to.be.false; - expect(passwordPolicy.validate('AAAa1AAA')).to.be.false; - expect(passwordPolicy.validate('AAAa@AAA')).to.be.true; - }); - }); - - describe('Password Policy', () => { - it('should return a correct password policy', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - throwError: false, - minLength: 10, - maxLength: 20, - forbidRepeatingCharacters: true, - forbidRepeatingCharactersCount: 4, - mustContainAtLeastOneLowercase: true, - mustContainAtLeastOneUppercase: true, - mustContainAtLeastOneNumber: true, - mustContainAtLeastOneSpecialCharacter: true, - }); - - const policy = passwordPolicy.getPasswordPolicy(); - - expect(policy).to.not.be.undefined; - expect(policy.enabled).to.be.true; - expect(policy.policy.length).to.be.equal(8); - expect(policy.policy[0][0]).to.be.equal('get-password-policy-minLength'); - expect(policy.policy[0][1]?.minLength).to.be.equal(10); - }); - - it('should return correct values if policy is disabled', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: false, - }); - - const policy = passwordPolicy.getPasswordPolicy(); - - expect(policy.enabled).to.be.false; - expect(policy.policy.length).to.be.equal(0); - }); - - it('should return correct values if policy is enabled but no specifiers exists', () => { - const passwordPolicy = new PasswordPolicy({ - enabled: true, - }); - - const policy = passwordPolicy.getPasswordPolicy(); - - expect(policy.enabled).to.be.true; - // even when no policy is specified, forbidRepeatingCharactersCount is still configured - // since its default value is 3 - expect(policy.policy.length).to.be.equal(1); - }); - }); -}); diff --git a/packages/patch-injection/jest.config.ts b/packages/patch-injection/jest.config.ts index 959a31a7c6bf..c18c8ae02465 100644 --- a/packages/patch-injection/jest.config.ts +++ b/packages/patch-injection/jest.config.ts @@ -1,3 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', -}; + preset: server.preset, +} satisfies Config; diff --git a/packages/patch-injection/package.json b/packages/patch-injection/package.json index d2417cb04df4..99f676bff831 100644 --- a/packages/patch-injection/package.json +++ b/packages/patch-injection/package.json @@ -3,18 +3,19 @@ "version": "0.0.1", "private": true, "devDependencies": { + "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { + "build": "rm -rf dist && tsc", + "dev": "tsc --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", - "build": "rm -rf dist && tsc -p tsconfig.json", - "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" + "test": "jest" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/patch-injection/src/makeFunction.spec.ts b/packages/patch-injection/src/makeFunction.spec.ts new file mode 100644 index 000000000000..f88efff2be49 --- /dev/null +++ b/packages/patch-injection/src/makeFunction.spec.ts @@ -0,0 +1,236 @@ +import { makeFunction } from './makeFunction'; + +describe('Make a simple function', () => { + it('should execute the function passed as argument', () => { + const fn = makeFunction(() => { + throw new Error('function was called'); + }); + + expect(fn).toThrow('function was called'); + }); + + it('should return the result of the internal function', () => { + const fn = makeFunction(() => 15); + + expect(fn()).toBe(15); + }); +}); + +describe('Replace a simple function', () => { + it('should execute the patched function', () => { + const fn = makeFunction(() => { + throw new Error('function was called'); + }); + + fn.patch(() => { + throw new Error('patch was called'); + }); + + expect(fn).toThrow('patch was called'); + }); + + it('should return the result of the patched function', () => { + const fn = makeFunction(() => 15); + + fn.patch(() => 20); + + expect(fn()).toBe(20); + }); +}); + +describe('Remove a patch', () => { + it('should execute the function passed as argument', () => { + const fn = makeFunction(() => { + throw new Error('function was called'); + }); + + const remove = fn.patch(() => { + throw new Error('patch was called'); + }); + + expect(fn).toThrow('patch was called'); + + remove(); + + expect(fn).toThrow('function was called'); + }); + + it('should return the result of the internal function', () => { + const fn = makeFunction(() => 15); + + const remove = fn.patch(() => 20); + + expect(fn()).toBe(20); + + remove(); + + expect(fn()).toBe(15); + }); +}); + +describe('Patch Condition', () => { + it('should execute either function depending if the patch is enabled or not', () => { + const fn = makeFunction(() => { + throw new Error('function was called'); + }); + + let enabled = false; + + fn.patch( + () => { + throw new Error('patch was called'); + }, + () => enabled, + ); + + expect(fn).toThrow('function was called'); + enabled = true; + expect(fn).toThrow('patch was called'); + enabled = false; + expect(fn).toThrow('function was called'); + }); + + it('should return the value of the right function based on the condition', () => { + const fn = makeFunction(() => 15); + + let enabled = false; + + fn.patch( + () => 20, + () => enabled, + ); + + expect(fn()).toBe(15); + enabled = true; + expect(fn()).toBe(20); + enabled = false; + expect(fn()).toBe(15); + }); +}); + +describe('Chained calls', () => { + it('Should call the inner function', () => { + const fn = makeFunction(() => { + throw new Error('function was called'); + }); + + fn.patch((next) => { + next(); + throw new Error('patch was called'); + }); + + expect(fn).toThrow('function was called'); + }); + + it('should return the sum of values', () => { + const fn = makeFunction(() => 15); + + fn.patch((next) => 20 + next()); + + expect(fn()).toBe(35); + }); + + it('should send the parameters in the correct order every time', () => { + const fn = makeFunction((a: string, b: string) => `3=${[a, b].join('')}`); + + fn.patch((next, a, b) => `2=${[a, b].join('')},${next('E', 'F')}`); + fn.patch((next, a, b) => `1=${[a, b].join('')},${next('C', 'D')}`); + + expect(fn('A', 'B')).toBe('1=AB,2=CD,3=EF'); + }); +}); + +describe('Multiple patches', () => { + it('Should call the right version of the function', () => { + const fn = makeFunction(() => { + throw new Error('function was called'); + }); + + const remove = fn.patch(() => { + throw new Error('patch was called'); + }); + + const remove2 = fn.patch(() => { + throw new Error('second patch was called'); + }); + + expect(fn).toThrow('second patch was called'); + remove2(); + expect(fn).toThrow('patch was called'); + remove(); + expect(fn).toThrow('function was called'); + }); + + it('Should respect conditions and removals', () => { + const fn = makeFunction(() => { + throw new Error('function was called'); + }); + + let enabled = true; + let enabled2 = true; + + const remove = fn.patch( + () => { + throw new Error('patch was called'); + }, + () => enabled, + ); + + const remove2 = fn.patch( + () => { + throw new Error('second patch was called'); + }, + () => enabled2, + ); + + expect(fn).toThrow('second patch was called'); + enabled2 = false; + expect(fn).toThrow('patch was called'); + enabled = false; + expect(fn).toThrow('function was called'); + enabled2 = true; + expect(fn).toThrow('second patch was called'); + enabled = true; + remove2(); + expect(fn).toThrow('patch was called'); + remove(); + expect(fn).toThrow('function was called'); + }); + + it('should chain on the right order', () => { + const fn = makeFunction(() => [1]); + + let enabled2 = true; + let enabled3 = true; + let enabled4 = true; + + fn.patch( + (next) => [2].concat(next()), + () => enabled2, + ); + const remove3 = fn.patch( + (next) => [3].concat(next()), + () => enabled3, + ); + fn.patch( + (next) => [4].concat(next()), + () => enabled4, + ); + + expect(fn()).toStrictEqual([4, 3, 2, 1]); + + enabled2 = false; + expect(fn()).toStrictEqual([4, 3, 1]); + enabled4 = false; + expect(fn()).toStrictEqual([3, 1]); + enabled3 = false; + expect(fn()).toStrictEqual([1]); + enabled3 = true; + expect(fn()).toStrictEqual([3, 1]); + remove3(); + expect(fn()).toStrictEqual([1]); + enabled2 = true; + enabled4 = true; + expect(fn()).toStrictEqual([4, 2, 1]); + }); +}); diff --git a/packages/patch-injection/tests/patches.test.ts b/packages/patch-injection/tests/patches.test.ts deleted file mode 100644 index 74e3da93268a..000000000000 --- a/packages/patch-injection/tests/patches.test.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { expect } from 'chai'; - -import { makeFunction } from '../src/makeFunction'; - -describe('PatchCoordinator', () => { - describe('Make a simple function', () => { - it('should execute the function passed as argument', () => { - const fn = makeFunction(() => { - throw new Error('function was called'); - }); - - expect(fn).to.throw('function was called'); - }); - - it('should return the result of the internal function', () => { - const fn = makeFunction(() => 15); - - expect(fn()).to.be.equal(15); - }); - }); - - describe('Replace a simple function', () => { - it('should execute the patched function', () => { - const fn = makeFunction(() => { - throw new Error('function was called'); - }); - - fn.patch(() => { - throw new Error('patch was called'); - }); - - expect(fn).to.throw('patch was called'); - }); - - it('should return the result of the patched function', () => { - const fn = makeFunction(() => 15); - - fn.patch(() => 20); - - expect(fn()).to.be.equal(20); - }); - }); - - describe('Remove a patch', () => { - it('should execute the function passed as argument', () => { - const fn = makeFunction(() => { - throw new Error('function was called'); - }); - - const remove = fn.patch(() => { - throw new Error('patch was called'); - }); - - expect(fn).to.throw('patch was called'); - - remove(); - - expect(fn).to.throw('function was called'); - }); - - it('should return the result of the internal function', () => { - const fn = makeFunction(() => 15); - - const remove = fn.patch(() => 20); - - expect(fn()).to.be.equal(20); - - remove(); - - expect(fn()).to.be.equal(15); - }); - }); - - describe('Patch Condition', () => { - it('should execute either function depending if the patch is enabled or not', () => { - const fn = makeFunction(() => { - throw new Error('function was called'); - }); - - let enabled = false; - - fn.patch( - () => { - throw new Error('patch was called'); - }, - () => enabled, - ); - - expect(fn).to.throw('function was called'); - enabled = true; - expect(fn).to.throw('patch was called'); - enabled = false; - expect(fn).to.throw('function was called'); - }); - - it('should return the value of the right function based on the condition', () => { - const fn = makeFunction(() => 15); - - let enabled = false; - - fn.patch( - () => 20, - () => enabled, - ); - - expect(fn()).to.be.equal(15); - enabled = true; - expect(fn()).to.be.equal(20); - enabled = false; - expect(fn()).to.be.equal(15); - }); - }); - - describe('Chained calls', () => { - it('Should call the inner function', () => { - const fn = makeFunction(() => { - throw new Error('function was called'); - }); - - fn.patch((next) => { - next(); - throw new Error('patch was called'); - }); - - expect(fn).to.throw('function was called'); - }); - - it('should return the sum of values', () => { - const fn = makeFunction(() => 15); - - fn.patch((next) => 20 + next()); - - expect(fn()).to.be.equal(35); - }); - - it('should send the parameters in the correct order every time', () => { - const fn = makeFunction((a: string, b: string) => `3=${[a, b].join('')}`); - - fn.patch((next, a, b) => `2=${[a, b].join('')},${next('E', 'F')}`); - fn.patch((next, a, b) => `1=${[a, b].join('')},${next('C', 'D')}`); - - expect(fn('A', 'B')).to.be.equal('1=AB,2=CD,3=EF'); - }); - }); - - describe('Multiple patches', () => { - it('Should call the right version of the function', () => { - const fn = makeFunction(() => { - throw new Error('function was called'); - }); - - const remove = fn.patch(() => { - throw new Error('patch was called'); - }); - - const remove2 = fn.patch(() => { - throw new Error('second patch was called'); - }); - - expect(fn).to.throw('second patch was called'); - remove2(); - expect(fn).to.throw('patch was called'); - remove(); - expect(fn).to.throw('function was called'); - }); - - it('Should respect conditions and removals', () => { - const fn = makeFunction(() => { - throw new Error('function was called'); - }); - - let enabled = true; - let enabled2 = true; - - const remove = fn.patch( - () => { - throw new Error('patch was called'); - }, - () => enabled, - ); - - const remove2 = fn.patch( - () => { - throw new Error('second patch was called'); - }, - () => enabled2, - ); - - expect(fn).to.throw('second patch was called'); - enabled2 = false; - expect(fn).to.throw('patch was called'); - enabled = false; - expect(fn).to.throw('function was called'); - enabled2 = true; - expect(fn).to.throw('second patch was called'); - enabled = true; - remove2(); - expect(fn).to.throw('patch was called'); - remove(); - expect(fn).to.throw('function was called'); - }); - - it('should chain on the right order', () => { - const fn = makeFunction(() => [1]); - - let enabled2 = true; - let enabled3 = true; - let enabled4 = true; - - fn.patch( - (next) => [2].concat(next()), - () => enabled2, - ); - const remove3 = fn.patch( - (next) => [3].concat(next()), - () => enabled3, - ); - fn.patch( - (next) => [4].concat(next()), - () => enabled4, - ); - - expect(fn()).to.be.an('array').deep.equal([4, 3, 2, 1]); - - enabled2 = false; - expect(fn()).to.be.an('array').deep.equal([4, 3, 1]); - enabled4 = false; - expect(fn()).to.be.an('array').deep.equal([3, 1]); - enabled3 = false; - expect(fn()).to.be.an('array').deep.equal([1]); - enabled3 = true; - expect(fn()).to.be.an('array').deep.equal([3, 1]); - remove3(); - expect(fn()).to.be.an('array').deep.equal([1]); - enabled2 = true; - enabled4 = true; - expect(fn()).to.be.an('array').deep.equal([4, 2, 1]); - }); - }); -}); diff --git a/packages/peggy-loader/jest.config.js b/packages/peggy-loader/jest.config.js deleted file mode 100644 index 21526c604f6b..000000000000 --- a/packages/peggy-loader/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - preset: 'ts-jest', - errorOnDeprecated: true, - testMatch: ['/src/**/*.spec.[jt]s?(x)'], -}; diff --git a/packages/peggy-loader/package.json b/packages/peggy-loader/package.json index 2b1983bfa62a..5fa014da7f29 100644 --- a/packages/peggy-loader/package.json +++ b/packages/peggy-loader/package.json @@ -31,7 +31,7 @@ "build": "run-s .:build:clean .:build:esm .:build:cjs", ".:build:clean": "rimraf dist", ".:build:esm": "tsc -p tsconfig.json", - ".:build:cjs": "tsc -p tsconfig-cjs.json", + ".:build:cjs": "tsc -p tsconfig.cjs.json", "lint": "eslint src" }, "bugs": { @@ -50,8 +50,10 @@ "peggy": "3.0.2", "prettier": "~2.8.7", "rimraf": "^3.0.2", - "ts-jest": "~29.1.0", "typescript": "~5.3.3", "webpack": "~5.78.0" + }, + "volta": { + "extends": "../../package.json" } } diff --git a/packages/peggy-loader/tsconfig-cjs.json b/packages/peggy-loader/tsconfig.cjs.json similarity index 100% rename from packages/peggy-loader/tsconfig-cjs.json rename to packages/peggy-loader/tsconfig.cjs.json diff --git a/packages/random/jest.config.ts b/packages/random/jest.config.ts index 959a31a7c6bf..e6005852b621 100644 --- a/packages/random/jest.config.ts +++ b/packages/random/jest.config.ts @@ -1,3 +1,18 @@ +import client from '@rocket.chat/jest-presets/client'; +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', -}; + projects: [ + { + displayName: 'client', + preset: client.preset, + testMatch: ['/src/**/*.client.spec.[jt]s?(x)'], + }, + { + displayName: 'server', + preset: server.preset, + testMatch: ['/src/**/*.server.spec.[jt]s?(x)'], + }, + ], +} satisfies Config; diff --git a/packages/random/package.json b/packages/random/package.json index f1a0ac5de8f7..72fc8c5c566a 100644 --- a/packages/random/package.json +++ b/packages/random/package.json @@ -9,6 +9,7 @@ "scripts": { "build": "rm -rf dist && tsc -p tsconfig.build.json", "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint .", "lint:fix": "eslint . --fix", "test": "jest" @@ -17,12 +18,11 @@ "@babel/core": "~7.22.20", "@babel/preset-env": "~7.22.20", "@rocket.chat/eslint-config": "workspace:^", + "@rocket.chat/jest-presets": "workspace:~", "@typescript-eslint/eslint-plugin": "~5.60.1", "@typescript-eslint/parser": "~5.60.1", "eslint": "~8.45.0", "jest": "~29.7.0", - "jest-environment-jsdom": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "volta": { diff --git a/packages/random/src/main.client.spec.ts b/packages/random/src/main.client.spec.ts index bde7b49b3b11..f5d4d278a5fa 100644 --- a/packages/random/src/main.client.spec.ts +++ b/packages/random/src/main.client.spec.ts @@ -1,7 +1,3 @@ -/** - * @jest-environment jsdom - */ - import { Random } from './main.client'; it('which should generate the same sequence in all environments', () => { diff --git a/packages/rest-typings/jest.config.ts b/packages/rest-typings/jest.config.ts deleted file mode 100644 index e938f931d149..000000000000 --- a/packages/rest-typings/jest.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default { - preset: 'ts-jest', - errorOnDeprecated: true, - testEnvironment: 'jsdom', - modulePathIgnorePatterns: ['/dist/'], -}; diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 2764a9d02634..6a5bf5464e98 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -2,21 +2,20 @@ "name": "@rocket.chat/rest-typings", "version": "6.12.0-develop", "devDependencies": { - "@rocket.chat/eslint-config": "workspace:^", + "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "jest-environment-jsdom": "~29.7.0", "mongodb": "^4.17.2", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { + "build": "rm -rf dist && tsc", + "dev": "tsc --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", - "dev": "tsc --watch --preserveWatchOutput -p tsconfig.json", - "build": "rm -rf dist && tsc -p tsconfig.json" + "test": "jest" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/server-cloud-communication/package.json b/packages/server-cloud-communication/package.json index 15310d3430d1..8c970687ab8b 100644 --- a/packages/server-cloud-communication/package.json +++ b/packages/server-cloud-communication/package.json @@ -4,10 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/license": "workspace:^", - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "volta": { @@ -16,7 +13,6 @@ "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, "main": "./src/index.ts", diff --git a/packages/server-fetch/package.json b/packages/server-fetch/package.json index cb96395099ac..c98b4ba99e54 100644 --- a/packages/server-fetch/package.json +++ b/packages/server-fetch/package.json @@ -3,16 +3,12 @@ "version": "0.0.3", "private": true, "devDependencies": { - "@types/jest": "~29.5.12", "eslint": "~8.45.0", - "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput" }, diff --git a/packages/sha256/jest.config.ts b/packages/sha256/jest.config.ts index 959a31a7c6bf..c18c8ae02465 100644 --- a/packages/sha256/jest.config.ts +++ b/packages/sha256/jest.config.ts @@ -1,3 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', -}; + preset: server.preset, +} satisfies Config; diff --git a/packages/sha256/package.json b/packages/sha256/package.json index b56d25ad3713..6d10f5b80d65 100644 --- a/packages/sha256/package.json +++ b/packages/sha256/package.json @@ -8,6 +8,7 @@ "scripts": { "build": "rm -rf dist && tsc -p tsconfig.build.json", "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint .", "lint:fix": "eslint . --fix", "test": "jest" @@ -16,11 +17,11 @@ "@babel/core": "~7.22.20", "@babel/preset-env": "~7.22.20", "@rocket.chat/eslint-config": "workspace:^", + "@rocket.chat/jest-presets": "workspace:~", "@typescript-eslint/eslint-plugin": "~5.60.1", "@typescript-eslint/parser": "~5.60.1", "eslint": "~8.45.0", "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "volta": { diff --git a/packages/tools/jest.config.ts b/packages/tools/jest.config.ts index 959a31a7c6bf..46e41b9ab170 100644 --- a/packages/tools/jest.config.ts +++ b/packages/tools/jest.config.ts @@ -1,3 +1,7 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + export default { - preset: 'ts-jest', -}; + preset: server.preset, + testMatch: ['/src/**/*.spec.(ts|js|mjs)'], +} satisfies Config; diff --git a/packages/tools/package.json b/packages/tools/package.json index effcdb185408..d1301efb7055 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -3,10 +3,10 @@ "version": "0.2.2", "private": true, "devDependencies": { + "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", "eslint": "~8.45.0", "jest": "~29.7.0", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { diff --git a/packages/ui-client/jest.config.ts b/packages/ui-client/jest.config.ts index d5dd6be2fd45..597fbebb687b 100644 --- a/packages/ui-client/jest.config.ts +++ b/packages/ui-client/jest.config.ts @@ -1,27 +1,12 @@ +import client from '@rocket.chat/jest-presets/client'; +import type { Config } from 'jest'; + export default { - errorOnDeprecated: true, - testEnvironment: 'jsdom', - modulePathIgnorePatterns: ['/dist/'], - testMatch: ['/src/**/**.spec.[jt]s?(x)'], - transform: { - '^.+\\.(t|j)sx?$': [ - '@swc/jest', - { - jsc: { - transform: { - react: { - runtime: 'automatic', - }, - }, - }, - }, - ], - }, + preset: client.preset, + setupFilesAfterEnv: [...client.setupFilesAfterEnv], moduleNameMapper: { - '\\.css$': 'identity-obj-proxy', '^react($|/.+)': '/../../node_modules/react$1', + '^react-dom/client$': '/../../node_modules/react-dom$1', + '^react-dom($|/.+)': '/../../node_modules/react-dom$1', }, - collectCoverage: true, - collectCoverageFrom: ['src/**/*.{ts,tsx}'], - setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'], -}; +} satisfies Config; diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index e71d3aacf692..69ca7e8b7f5b 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -9,6 +9,7 @@ "@rocket.chat/fuselage": "^0.57.0", "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/icons": "^0.36.0", + "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/mock-providers": "workspace:^", "@rocket.chat/ui-contexts": "workspace:~", "@storybook/addon-actions": "~6.5.16", @@ -21,10 +22,7 @@ "@storybook/manager-webpack4": "~6.5.16", "@storybook/react": "~6.5.16", "@storybook/testing-library": "~0.0.13", - "@swc/jest": "^0.2.29", - "@testing-library/jest-dom": "~5.16.5", - "@testing-library/react": "^12.1.5", - "@testing-library/react-hooks": "^8.0.1", + "@testing-library/react": "~16.0.0", "@types/babel__core": "~7.20.3", "@types/jest": "~29.5.12", "@types/react": "~17.0.69", @@ -39,18 +37,17 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-hook-form": "~7.45.4", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "scripts": { + "build": "rm -rf dist && tsc -p tsconfig.build.json", + "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput", + "typecheck": "tsc --noEmit", "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", "test": "jest", "testunit": "jest", - "build": "rm -rf dist && tsc -p tsconfig-build.json", - "typecheck": "tsc -p tsconfig.json --noEmit", - "storybook": "start-storybook -p 6006", - "dev": "tsc -p tsconfig-build.json --watch --preserveWatchOutput" + "storybook": "start-storybook -p 6006" }, "main": "./dist/index.js", "typings": "./dist/index.d.ts", diff --git a/packages/ui-client/src/components/FeaturePreview/FeaturePreview.spec.tsx b/packages/ui-client/src/components/FeaturePreview/FeaturePreview.spec.tsx index e8e093eb25f6..03c297e7a10b 100644 --- a/packages/ui-client/src/components/FeaturePreview/FeaturePreview.spec.tsx +++ b/packages/ui-client/src/components/FeaturePreview/FeaturePreview.spec.tsx @@ -2,7 +2,6 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; import { render, screen } from '@testing-library/react'; import { FeaturePreview, FeaturePreviewOff, FeaturePreviewOn } from './FeaturePreview'; -import '@testing-library/jest-dom'; test('should renders off if the feature is disabled', async () => { render( @@ -11,6 +10,7 @@ test('should renders off if the feature is disabled', async () => { off , { + legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', true).build(), }, ); @@ -25,6 +25,7 @@ test('should renders on if the feature is enabled', async () => { off , { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) .withUserPreference('featuresPreview', [{ name: 'quickReactions', value: true }]) diff --git a/packages/ui-client/src/components/PasswordVerifier/PasswordVerifiers.spec.tsx b/packages/ui-client/src/components/PasswordVerifier/PasswordVerifiers.spec.tsx index cb2efaca19f5..108a13713707 100644 --- a/packages/ui-client/src/components/PasswordVerifier/PasswordVerifiers.spec.tsx +++ b/packages/ui-client/src/components/PasswordVerifier/PasswordVerifiers.spec.tsx @@ -10,6 +10,7 @@ afterEach(() => { it('should render no policy if its disabled ', () => { const { queryByRole } = render(, { + legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_Password_Policy_Enabled', 'true').build(), }); @@ -18,6 +19,7 @@ it('should render no policy if its disabled ', () => { it('should render no policy if its enabled but empty', async () => { const { queryByRole, queryByTestId } = render(, { + legacyRoot: true, wrapper: mockAppRoot().build(), }); @@ -29,6 +31,7 @@ it('should render no policy if its enabled but empty', async () => { it('should render policy list if its enabled and not empty', async () => { const { queryByRole, queryByTestId } = render(, { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_Password_Policy_Enabled', 'true') .withSetting('Accounts_Password_Policy_MinLength', '6') @@ -45,6 +48,7 @@ it('should render policy list if its enabled and not empty', async () => { it('should render all the policies when all policies are enabled', async () => { const { queryByTestId, queryAllByRole } = render(, { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_Password_Policy_Enabled', 'true') .withSetting('Accounts_Password_Policy_MinLength', '6') @@ -67,6 +71,7 @@ it('should render all the policies when all policies are enabled', async () => { it("should render policy as invalid if password doesn't match the requirements", async () => { const { queryByTestId, getByRole } = render(, { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_Password_Policy_Enabled', 'true') .withSetting('Accounts_Password_Policy_MinLength', '10') @@ -82,6 +87,7 @@ it("should render policy as invalid if password doesn't match the requirements", it('should render policy as valid if password matches the requirements', async () => { const { queryByTestId, getByRole } = render(, { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_Password_Policy_Enabled', 'true') .withSetting('Accounts_Password_Policy_MinLength', '2') diff --git a/packages/ui-client/src/hooks/useDocumentTitle.spec.ts b/packages/ui-client/src/hooks/useDocumentTitle.spec.ts index e5df07fb354c..a14d34e63c22 100644 --- a/packages/ui-client/src/hooks/useDocumentTitle.spec.ts +++ b/packages/ui-client/src/hooks/useDocumentTitle.spec.ts @@ -1,4 +1,4 @@ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useDocumentTitle } from './useDocumentTitle'; @@ -6,21 +6,26 @@ const DEFAULT_TITLE = 'Default Title'; const EXAMPLE_TITLE = 'Example Title'; it('should return the default title', () => { - const { result } = renderHook(() => useDocumentTitle(DEFAULT_TITLE)); + const { result } = renderHook(() => useDocumentTitle(DEFAULT_TITLE), { legacyRoot: true }); expect(result.current.title).toBe(DEFAULT_TITLE); }); it('should return the default title and empty key value if refocus param is false', () => { - const { result } = renderHook(() => useDocumentTitle(DEFAULT_TITLE, false)); + const { result } = renderHook(() => useDocumentTitle(DEFAULT_TITLE, false), { legacyRoot: true }); expect(result.current.title).toBe(DEFAULT_TITLE); expect(result.current.key).toBe(''); }); it('should return the default title and the example title concatenated', () => { - renderHook(() => useDocumentTitle(DEFAULT_TITLE)); - const { result } = renderHook(() => useDocumentTitle(EXAMPLE_TITLE)); + const { result } = renderHook( + () => { + useDocumentTitle(DEFAULT_TITLE); + return useDocumentTitle(EXAMPLE_TITLE); + }, + { legacyRoot: true }, + ); expect(result.current.title).toBe(`${EXAMPLE_TITLE} - ${DEFAULT_TITLE}`); }); diff --git a/packages/ui-client/src/hooks/useFeaturePreview.spec.tsx b/packages/ui-client/src/hooks/useFeaturePreview.spec.tsx index 7f6cda873e88..91bc0c91d070 100644 --- a/packages/ui-client/src/hooks/useFeaturePreview.spec.tsx +++ b/packages/ui-client/src/hooks/useFeaturePreview.spec.tsx @@ -1,41 +1,45 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useFeaturePreview } from './useFeaturePreview'; it('should return false if featurePreviewEnabled is false', () => { const { result } = renderHook(() => useFeaturePreview('quickReactions'), { + legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', false).build(), }); - expect(result.all[0]).toBe(false); + expect(result.current).toBe(false); }); // TODO: fix this test it('should return false if featurePreviewEnabled is true but feature is not in userPreferences', () => { const { result } = renderHook(() => useFeaturePreview('quickReactions'), { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', false) .withUserPreference('featuresPreview', [{ name: 'quickReactions', value: true }]) .build(), }); - expect(result.all[0]).toBe(false); + expect(result.current).toBe(false); }); it('should return true if featurePreviewEnabled is true and feature is in userPreferences', () => { const { result } = renderHook(() => useFeaturePreview('quickReactions'), { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) .withUserPreference('featuresPreview', [{ name: 'quickReactions', value: true }]) .build(), }); - expect(result.all[0]).toBe(true); + expect(result.current).toBe(true); }); it('should return false for disabled features', () => { const { result } = renderHook(() => useFeaturePreview('navigationBar'), { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) .withUserPreference('featuresPreview', [ diff --git a/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx b/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx index d6f09c72bac7..e348cfb6a864 100644 --- a/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx +++ b/packages/ui-client/src/hooks/useFeaturePreviewList.spec.tsx @@ -1,14 +1,15 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useFeaturePreviewList, enabledDefaultFeatures } from './useFeaturePreviewList'; it('should return the number of unseen features and Accounts_AllowFeaturePreview enabled ', () => { const { result } = renderHook(() => useFeaturePreviewList(), { + legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', true).build(), }); - expect(result.all[0]).toEqual( + expect(result.current).toEqual( expect.objectContaining({ featurePreviewEnabled: true, unseenFeatures: enabledDefaultFeatures.length, @@ -18,10 +19,11 @@ it('should return the number of unseen features and Accounts_AllowFeaturePreview it('should return the number of unseen features and Accounts_AllowFeaturePreview disabled ', () => { const { result } = renderHook(() => useFeaturePreviewList(), { + legacyRoot: true, wrapper: mockAppRoot().withSetting('Accounts_AllowFeaturePreview', false).build(), }); - expect(result.all[0]).toEqual( + expect(result.current).toEqual( expect.objectContaining({ featurePreviewEnabled: false, unseenFeatures: 0, @@ -31,13 +33,14 @@ it('should return the number of unseen features and Accounts_AllowFeaturePreview it('should return 0 unseen features', () => { const { result } = renderHook(() => useFeaturePreviewList(), { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) .withUserPreference('featuresPreview', enabledDefaultFeatures) .build(), }); - expect(result.all[0]).toEqual( + expect(result.current).toEqual( expect.objectContaining({ featurePreviewEnabled: true, unseenFeatures: 0, @@ -47,6 +50,7 @@ it('should return 0 unseen features', () => { it('should ignore removed feature previews', () => { const { result } = renderHook(() => useFeaturePreviewList(), { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) .withUserPreference('featuresPreview', [ @@ -69,6 +73,7 @@ it('should ignore removed feature previews', () => { it('should turn off ignored feature previews', async () => { const { result } = renderHook(() => useFeaturePreviewList(), { + legacyRoot: true, wrapper: mockAppRoot() .withSetting('Accounts_AllowFeaturePreview', true) .withUserPreference('featuresPreview', [ diff --git a/packages/ui-client/src/hooks/useValidatePassword.spec.ts b/packages/ui-client/src/hooks/useValidatePassword.spec.ts index 275e4ab8d6f5..8c68e2f0070d 100644 --- a/packages/ui-client/src/hooks/useValidatePassword.spec.ts +++ b/packages/ui-client/src/hooks/useValidatePassword.spec.ts @@ -1,5 +1,5 @@ import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useValidatePassword } from './useValidatePassword'; @@ -17,6 +17,7 @@ const settingsMockWrapper = mockAppRoot() it("should return `false` if password doesn't match all the requirements", async () => { const { result } = renderHook(async () => useValidatePassword('secret'), { + legacyRoot: true, wrapper: settingsMockWrapper, }); @@ -26,6 +27,7 @@ it("should return `false` if password doesn't match all the requirements", async it('should return `true` if password matches all the requirements', async () => { const { result } = renderHook(async () => useValidatePassword('5kgnGPq^&t4DSYW!SH#4N'), { + legacyRoot: true, wrapper: settingsMockWrapper, }); diff --git a/packages/ui-client/tsconfig-build.json b/packages/ui-client/tsconfig-build.json deleted file mode 100644 index d65872bd407d..000000000000 --- a/packages/ui-client/tsconfig-build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["**/*.stories.tsx"] -} diff --git a/packages/ui-client/tsconfig.build.json b/packages/ui-client/tsconfig.build.json new file mode 100644 index 000000000000..14a02ca5a1dc --- /dev/null +++ b/packages/ui-client/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src/**/*"], + "exclude": ["**/*.stories.tsx", "./src/**/*.spec.ts", "./src/**/*.spec.tsx"] +} diff --git a/packages/ui-client/tsconfig.json b/packages/ui-client/tsconfig.json index 7fec1e9ddf1f..2c150afcf5d4 100644 --- a/packages/ui-client/tsconfig.json +++ b/packages/ui-client/tsconfig.json @@ -1,8 +1,3 @@ { "extends": "../../tsconfig.base.client.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist" - }, - "include": ["./src"] } diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index 485f4d7ac725..2b3fae217aac 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -10,7 +10,6 @@ "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "build": "rm -rf dist && tsc -p tsconfig.build.json", "typecheck": "tsc --noEmit", "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput", @@ -30,18 +29,15 @@ "@storybook/react": "~6.5.16", "@storybook/testing-library": "~0.0.13", "@types/babel__core": "~7.20.3", - "@types/jest": "~29.5.12", "@types/react": "~17.0.69", "@types/react-dom": "~17.0.22", "eslint": "~8.45.0", "eslint-plugin-react": "~7.32.2", "eslint-plugin-react-hooks": "~4.6.0", "eslint-plugin-storybook": "~0.6.15", - "jest": "~29.7.0", "react": "~17.0.2", "react-docgen-typescript-plugin": "~1.0.5", "react-dom": "~17.0.2", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "peerDependencies": { diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index febbeecf90b6..513aebd86a30 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -9,16 +9,13 @@ "@rocket.chat/fuselage-hooks": "^0.33.1", "@rocket.chat/i18n": "workspace:~", "@rocket.chat/rest-typings": "workspace:^", - "@types/jest": "~29.5.12", "@types/react": "~17.0.69", "@types/react-dom": "~17.0.22", "@types/use-sync-external-store": "^0.0.5", "eslint": "~8.45.0", "eslint-plugin-react-hooks": "^4.6.0", - "jest": "~29.7.0", "mongodb": "^4.17.2", "react": "~17.0.2", - "ts-jest": "~29.1.1", "typescript": "~5.3.3", "use-sync-external-store": "^1.2.0" }, @@ -41,7 +38,6 @@ "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "dev": "tsc --watch --preserveWatchOutput -p tsconfig.json", "build": "rm -rf dist && tsc -p tsconfig.json" }, diff --git a/packages/ui-kit/jest.config.js b/packages/ui-kit/jest.config.js deleted file mode 100644 index 1ea2839f0cb8..000000000000 --- a/packages/ui-kit/jest.config.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = /** @satisfies {import('jest').Config} */ ({ - preset: 'ts-jest', - testEnvironment: 'node', - errorOnDeprecated: true, - testMatch: ['/src/**/*.spec.[jt]s?(x)'], - setupFilesAfterEnv: ['/src/jest-setup.ts'], - collectCoverage: true, -}); diff --git a/packages/ui-kit/jest.config.ts b/packages/ui-kit/jest.config.ts new file mode 100644 index 000000000000..c18c8ae02465 --- /dev/null +++ b/packages/ui-kit/jest.config.ts @@ -0,0 +1,6 @@ +import server from '@rocket.chat/jest-presets/server'; +import type { Config } from 'jest'; + +export default { + preset: server.preset, +} satisfies Config; diff --git a/packages/ui-kit/package.json b/packages/ui-kit/package.json index bdced3b1ee91..817b03a22ba7 100644 --- a/packages/ui-kit/package.json +++ b/packages/ui-kit/package.json @@ -40,6 +40,7 @@ "@babel/plugin-transform-runtime": "~7.21.4", "@babel/preset-env": "~7.21.4", "@rocket.chat/eslint-config": "workspace:~", + "@rocket.chat/jest-presets": "workspace:~", "@types/jest": "~29.5.12", "babel-loader": "~9.1.2", "eslint": "~8.45.0", @@ -47,7 +48,6 @@ "npm-run-all": "~4.1.5", "prettier": "~2.8.8", "rimraf": "~3.0.2", - "ts-jest": "~29.1.1", "ts-loader": "~9.4.2", "ts-node": "~10.9.1", "ts-patch": "~3.0.2", diff --git a/packages/ui-kit/tsconfig.cjs.json b/packages/ui-kit/tsconfig.cjs.json index fd872164da6a..2784364aac38 100644 --- a/packages/ui-kit/tsconfig.cjs.json +++ b/packages/ui-kit/tsconfig.cjs.json @@ -7,5 +7,5 @@ "plugins": [{ "transform": "typia/lib/transform" }] }, "include": ["./src/**/*"], - "exclude": ["./src/**/*.spec.ts", "./src/jest-setup.ts"], + "exclude": ["./src/**/*.spec.ts"], } diff --git a/packages/ui-kit/tsconfig.esm.json b/packages/ui-kit/tsconfig.esm.json index 6eea7b79756f..a001f3197042 100644 --- a/packages/ui-kit/tsconfig.esm.json +++ b/packages/ui-kit/tsconfig.esm.json @@ -5,5 +5,5 @@ "outDir": "./dist/esm" }, "include": ["./src/**/*"], - "exclude": ["./src/**/*.spec.ts", "./src/jest-setup.ts"] + "exclude": ["./src/**/*.spec.ts"] } diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index f05da3a0d3c0..d0dc218808c9 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -32,7 +32,6 @@ "jest": "~29.7.0", "jest-axe": "~9.0.0", "react-docgen-typescript-plugin": "~1.0.5", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "peerDependencies": { diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index a85c82445b84..ba3dc31423a6 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -11,7 +11,6 @@ "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", - "test": "jest", "storybook": "start-storybook -p 6006 --no-version-updates", "build": "tsc -p tsconfig.build.json", "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput" @@ -35,17 +34,14 @@ "@storybook/react": "~6.5.16", "@storybook/testing-library": "^0.2.2", "@tanstack/react-query": "^4.16.1", - "@testing-library/react": "^13.3.0", - "@types/jest": "~29.5.12", + "@testing-library/react": "~16.0.0", "@types/react": "~17.0.69", "babel-loader": "~8.3.0", "eslint": "~8.45.0", - "jest": "~29.7.0", "react": "~17.0.2", "react-hook-form": "~7.45.4", "react-i18next": "~13.2.2", "storybook-dark-mode": "~3.0.1", - "ts-jest": "~29.1.1", "typescript": "~5.3.3" }, "peerDependencies": { diff --git a/yarn.lock b/yarn.lock index 6b839b4b9cbe..00ca4ab5c550 100644 --- a/yarn.lock +++ b/yarn.lock @@ -59,7 +59,7 @@ __metadata: languageName: node linkType: hard -"@adobe/css-tools@npm:^4.0.1, @adobe/css-tools@npm:^4.4.0": +"@adobe/css-tools@npm:^4.4.0": version: 4.4.0 resolution: "@adobe/css-tools@npm:4.4.0" checksum: 1f08fb49bf17fc7f2d1a86d3e739f29ca80063d28168307f1b0a962ef37501c5667271f6771966578897f2e94e43c4770fd802728a6e6495b812da54112d506a @@ -4493,15 +4493,6 @@ __metadata: languageName: node linkType: hard -"@jest/schemas@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/schemas@npm:28.1.3" - dependencies: - "@sinclair/typebox": ^0.24.1 - checksum: 3cf1d4b66c9c4ffda58b246de1ddcba8e6ad085af63dccdf07922511f13b68c0cc480a7bc620cb4f3099a6f134801c747e1df7bfc7a4ef4dceefbdea3e31e1de - languageName: node - linkType: hard - "@jest/schemas@npm:^29.6.3": version: 29.6.3 resolution: "@jest/schemas@npm:29.6.3" @@ -8451,10 +8442,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/account-utils@workspace:packages/account-utils" dependencies: - "@types/jest": ~29.5.12 eslint: ~8.45.0 - jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -8464,16 +8452,13 @@ __metadata: resolution: "@rocket.chat/agenda@workspace:packages/agenda" dependencies: "@types/debug": ^4.1.10 - "@types/jest": ~29.5.12 cron: ~1.8.2 date.js: ~0.3.3 debug: ~4.1.1 eslint: ~8.45.0 human-interval: ^2.0.1 - jest: ~29.7.0 moment-timezone: ~0.5.43 mongodb: ^4.17.2 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -8483,9 +8468,8 @@ __metadata: resolution: "@rocket.chat/api-client@workspace:ee/packages/api-client" dependencies: "@rocket.chat/core-typings": "workspace:^" + "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/rest-typings": "workspace:^" - "@swc/core": ^1.3.95 - "@swc/jest": ^0.2.29 "@types/jest": ~29.5.12 "@types/strict-uri-encode": ^2.0.1 eslint: ~8.45.0 @@ -8495,7 +8479,6 @@ __metadata: query-string: ^7.1.3 split-on-first: ^3.0.0 strict-uri-encode: ^2.0.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -8529,10 +8512,7 @@ __metadata: "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/model-typings": "workspace:^" - "@types/jest": ~29.5.12 eslint: ~8.45.0 - jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -8576,11 +8556,11 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@rocket.chat/eslint-config": "workspace:^" + "@rocket.chat/jest-presets": "workspace:~" "@typescript-eslint/eslint-plugin": ~5.60.1 "@typescript-eslint/parser": ~5.60.1 eslint: ~8.45.0 jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -8589,11 +8569,8 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/cas-validate@workspace:packages/cas-validate" dependencies: - "@types/jest": ~29.5.12 cheerio: 1.0.0-rc.10 eslint: ~8.45.0 - jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -8609,6 +8586,7 @@ __metadata: "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/icons": ^0.36.0 + "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/message-parser": "workspace:^" "@rocket.chat/models": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" @@ -8651,11 +8629,8 @@ __metadata: "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/models": "workspace:^" "@rocket.chat/random": "workspace:^" - "@types/jest": ~29.5.12 eslint: ~8.45.0 - jest: ~29.7.0 mongodb: ^4.17.2 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -8688,16 +8663,13 @@ __metadata: dependencies: "@rocket.chat/api-client": "workspace:^" "@rocket.chat/core-typings": "workspace:~" + "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/rest-typings": "workspace:^" - "@swc/core": ^1.3.95 - "@swc/jest": ^0.2.29 "@types/jest": ~29.5.12 "@types/ws": ^8.5.8 eslint: ~8.45.0 jest: ~29.7.0 - jest-environment-jsdom: ~29.7.0 - jest-websocket-mock: ^2.4.0 - ts-jest: ^29.1.2 + jest-websocket-mock: ~2.5.0 typescript: ~5.3.3 ws: ^8.13.0 peerDependencies: @@ -8915,6 +8887,7 @@ __metadata: "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/gazzodown": "workspace:^" "@rocket.chat/icons": ^0.36.0 + "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/mock-providers": "workspace:^" "@rocket.chat/prettier-config": ~0.31.25 "@rocket.chat/styled": ~0.31.25 @@ -8930,9 +8903,8 @@ __metadata: "@storybook/source-loader": ~6.5.16 "@storybook/theming": ~6.5.16 "@tanstack/react-query": ^4.16.1 - "@testing-library/react": ^12.1.4 - "@testing-library/react-hooks": ^8.0.1 - "@testing-library/user-event": ^14.5.2 + "@testing-library/react": ~16.0.0 + "@testing-library/user-event": ~14.5.2 "@types/babel__core": ^7.20.3 "@types/babel__preset-env": ^7.9.4 "@types/react": ~17.0.69 @@ -8950,7 +8922,6 @@ __metadata: react-i18next: ^14.1.0 rimraf: ^3.0.2 storybook-dark-mode: ~3.0.1 - ts-jest: ^29.1.2 tslib: ^2.5.3 typescript: ~5.3.3 peerDependencies: @@ -9005,6 +8976,7 @@ __metadata: "@rocket.chat/css-in-js": ~0.31.25 "@rocket.chat/fuselage": ^0.57.0 "@rocket.chat/fuselage-tokens": ^0.33.1 + "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/message-parser": "workspace:^" "@rocket.chat/styled": ~0.31.25 "@rocket.chat/ui-client": "workspace:^" @@ -9018,15 +8990,11 @@ __metadata: "@storybook/manager-webpack4": ~6.5.16 "@storybook/react": ~6.5.16 "@storybook/testing-library": ~0.0.13 - "@swc/core": ^1.3.95 - "@swc/jest": ^0.2.29 - "@testing-library/jest-dom": ^5.16.5 - "@testing-library/react": ~12.1.5 + "@testing-library/react": ~16.0.0 "@types/jest": ~29.5.12 "@types/katex": ~0.16.5 "@types/react": ~17.0.69 "@types/react-dom": ~17.0.22 - "@types/testing-library__jest-dom": ~5.14.9 "@typescript-eslint/eslint-plugin": ~5.60.1 "@typescript-eslint/parser": ~5.60.1 babel-loader: ^8.3.0 @@ -9039,13 +9007,11 @@ __metadata: highlight.js: ^11.5.1 identity-obj-proxy: ^3.0.0 jest: ~29.7.0 - jest-environment-jsdom: ~29.7.0 katex: ~0.16.9 outdent: ^0.8.0 react-docgen-typescript-plugin: ~1.0.5 react-dom: ~17.0.2 react-error-boundary: ^3.1.4 - ts-jest: ~29.1.1 typescript: ~5.3.3 peerDependencies: "@rocket.chat/core-typings": "workspace:^" @@ -9065,12 +9031,9 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/i18n@workspace:packages/i18n" dependencies: - "@babel/core": ~7.22.20 - "@babel/preset-env": ~7.22.20 - babel-jest: ^29.5.0 + "@rocket.chat/jest-presets": "workspace:~" eslint: ~8.45.0 jest: ~29.7.0 - ts-jest: ~29.1.1 tsup: ^6.7.0 typescript: ~5.3.3 languageName: unknown @@ -9101,9 +9064,9 @@ __metadata: resolution: "@rocket.chat/jest-presets@workspace:packages/jest-presets" dependencies: "@rocket.chat/eslint-config": "workspace:~" - "@swc/core": ~1.5.24 + "@swc/core": ~1.7.4 "@swc/jest": ~0.2.36 - "@testing-library/jest-dom": ~6.4.5 + "@testing-library/jest-dom": ~6.4.8 "@types/identity-obj-proxy": ^3 "@types/jest": ~29.5.12 "@types/jest-axe": ~3.5.9 @@ -9113,6 +9076,7 @@ __metadata: jest: ~29.7.0 jest-axe: ~9.0.0 jest-environment-jsdom: ~29.7.0 + jest-environment-node: ~29.7.0 typescript: ~5.4.5 uuid: ~9.0.1 languageName: unknown @@ -9122,11 +9086,11 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/jwt@workspace:packages/jwt" dependencies: + "@rocket.chat/jest-presets": "workspace:~" "@types/jest": ~29.5.12 eslint: ~8.45.0 jest: ~29.7.0 jose: ^4.14.4 - ts-jest: ^29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9148,19 +9112,16 @@ __metadata: resolution: "@rocket.chat/license@workspace:ee/packages/license" dependencies: "@rocket.chat/core-typings": "workspace:^" + "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/jwt": "workspace:^" "@rocket.chat/logger": "workspace:^" - "@swc/core": ^1.3.95 - "@swc/jest": ^0.2.29 "@types/bcrypt": ^5.0.1 "@types/jest": ~29.5.12 "@types/ws": ^8.5.8 bcrypt: ^5.0.1 eslint: ~8.45.0 jest: ~29.7.0 - jest-environment-jsdom: ~29.7.0 - jest-websocket-mock: ^2.4.0 - ts-jest: ~29.1.1 + jest-websocket-mock: ~2.5.0 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9268,12 +9229,9 @@ __metadata: dependencies: "@types/chalk": ^2.2.0 "@types/ejson": ^2.2.1 - "@types/jest": ~29.5.12 chalk: ^4.0.0 ejson: ^2.2.3 eslint: ~8.45.0 - jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9283,11 +9241,8 @@ __metadata: resolution: "@rocket.chat/logger@workspace:packages/logger" dependencies: "@rocket.chat/emitter": ~0.31.25 - "@types/jest": ~29.5.12 eslint: ~8.45.0 - jest: ~29.7.0 pino: ^8.15.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9320,6 +9275,7 @@ __metadata: "@babel/eslint-parser": ~7.21.3 "@babel/preset-env": ~7.21.4 "@rocket.chat/eslint-config": "workspace:^" + "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/peggy-loader": "workspace:~" "@rocket.chat/prettier-config": ~0.31.25 "@types/jest": ~29.5.12 @@ -9334,7 +9290,6 @@ __metadata: prettier-plugin-pegjs: ~0.5.4 rimraf: ^3.0.2 tldts: ~5.7.112 - ts-jest: ~29.1.0 ts-loader: ~9.4.2 typedoc: ~0.24.1 typescript: ~5.3.3 @@ -9442,13 +9397,10 @@ __metadata: "@storybook/addons": ~6.5.16 "@storybook/react": ~6.5.16 "@storybook/testing-library": 0.0.13 - "@swc/core": ^1.3.95 - "@swc/jest": ^0.2.29 "@tanstack/react-query": ^4.16.1 "@tanstack/react-query-devtools": ^4.19.1 - "@testing-library/react": ~12.1.5 - "@testing-library/react-hooks": ^8.0.1 - "@testing-library/user-event": ~13.5.0 + "@testing-library/react": ~16.0.0 + "@testing-library/user-event": ~14.5.2 "@types/adm-zip": ^0.5.3 "@types/archiver": ^5.3.4 "@types/bad-words": ^3.0.2 @@ -9475,6 +9427,7 @@ __metadata: "@types/he": ^1.1.2 "@types/i18next-sprintf-postprocessor": ^0.2.2 "@types/imap": ^0.8.39 + "@types/jest": ~29.5.12 "@types/jsdom": ^16.2.15 "@types/jsdom-global": ^3.0.6 "@types/jsrsasign": ^10.5.11 @@ -9583,7 +9536,7 @@ __metadata: eslint-plugin-prettier: ~4.2.1 eslint-plugin-react: ~7.32.2 eslint-plugin-react-hooks: ~4.6.0 - eslint-plugin-testing-library: ~5.11.1 + eslint-plugin-testing-library: ~6.2.2 eslint-plugin-you-dont-need-lodash-underscore: ~6.12.0 eventemitter3: ^4.0.7 exif-be-gone: ^1.3.2 @@ -9736,35 +9689,32 @@ __metadata: resolution: "@rocket.chat/mock-providers@workspace:packages/mock-providers" dependencies: "@rocket.chat/ddp-client": "workspace:~" + "@rocket.chat/emitter": ~0.31.25 "@rocket.chat/i18n": "workspace:~" "@rocket.chat/ui-contexts": "workspace:*" "@storybook/react": ~6.5.16 "@tanstack/react-query": ^4.16.1 - "@types/jest": ~29.5.12 + "@types/use-sync-external-store": ^0.0.5 eslint: ~8.45.0 i18next: ~23.4.9 - jest: ~29.7.0 react: ~17.0.2 react-i18next: ~13.2.2 - ts-jest: ~29.1.1 typescript: ~5.3.3 + use-sync-external-store: ~1.2.2 peerDependencies: "@tanstack/react-query": "*" react: "*" languageName: unknown linkType: soft -"@rocket.chat/model-typings@workspace:^, @rocket.chat/model-typings@workspace:packages/model-typings": +"@rocket.chat/model-typings@workspace:^, @rocket.chat/model-typings@workspace:packages/model-typings, @rocket.chat/model-typings@workspace:~": version: 0.0.0-use.local resolution: "@rocket.chat/model-typings@workspace:packages/model-typings" dependencies: "@rocket.chat/core-typings": "workspace:^" - "@types/jest": ~29.5.12 "@types/node-rsa": ^1.1.3 eslint: ~8.45.0 - jest: ~29.7.0 mongodb: ^4.17.2 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9773,13 +9723,11 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/models@workspace:packages/models" dependencies: - "@rocket.chat/model-typings": "workspace:^" - "@swc/core": ^1.3.95 - "@swc/jest": ^0.2.29 + "@rocket.chat/jest-presets": "workspace:~" + "@rocket.chat/model-typings": "workspace:~" "@types/jest": ~29.5.12 eslint: ~8.45.0 jest: ^29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9801,6 +9749,7 @@ __metadata: "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/emitter": ~0.31.25 "@rocket.chat/eslint-config": "workspace:^" + "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/logger": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@rocket.chat/models": "workspace:^" @@ -9822,7 +9771,6 @@ __metadata: mongo-message-queue: ^1.0.0 mongodb: ^4.17.2 pino: ^8.15.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9890,12 +9838,10 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/password-policies@workspace:packages/password-policies" dependencies: - "@types/chai": ~4.3.16 + "@rocket.chat/jest-presets": "workspace:~" "@types/jest": ~29.5.12 - chai: ^4.3.10 eslint: ~8.45.0 jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9904,10 +9850,10 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/patch-injection@workspace:packages/patch-injection" dependencies: + "@rocket.chat/jest-presets": "workspace:~" "@types/jest": ~29.5.12 eslint: ~8.45.0 jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9919,25 +9865,22 @@ __metadata: "@react-pdf/renderer": ^3.1.14 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/fuselage-tokens": ^0.33.1 + "@rocket.chat/jest-presets": "workspace:~" "@storybook/addon-essentials": ~6.5.16 "@storybook/react": ~6.5.16 - "@testing-library/jest-dom": ^5.16.5 - "@testing-library/react": ~13.4.0 + "@testing-library/react": ~16.0.0 "@types/emojione": ^2.2.8 "@types/jest": ~29.5.12 "@types/react": ~17.0.69 "@types/react-dom": ~17.0.22 - "@types/testing-library__jest-dom": ~5.14.9 emoji-assets: ^7.0.1 emoji-toolkit: ^7.0.1 eslint: ~8.45.0 jest: ~29.7.0 - jest-environment-jsdom: ~29.7.0 moment: ^2.29.4 moment-timezone: ^0.5.43 - react: ^18.2.0 - react-dom: ^18.2.0 - ts-jest: ~29.1.1 + react: ~18.3.1 + react-dom: ~18.3.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -9954,7 +9897,6 @@ __metadata: peggy: 3.0.2 prettier: ~2.8.7 rimraf: ^3.0.2 - ts-jest: ~29.1.0 typescript: ~5.3.3 webpack: ~5.78.0 peerDependencies: @@ -9967,10 +9909,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/poplib@workspace:packages/node-poplib" dependencies: - "@types/jest": ~29.5.12 eslint: ~8.45.0 - jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -10081,12 +10020,11 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@rocket.chat/eslint-config": "workspace:^" + "@rocket.chat/jest-presets": "workspace:~" "@typescript-eslint/eslint-plugin": ~5.60.1 "@typescript-eslint/parser": ~5.60.1 eslint: ~8.45.0 jest: ~29.7.0 - jest-environment-jsdom: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -10131,7 +10069,7 @@ __metadata: dependencies: "@rocket.chat/apps-engine": 1.44.0 "@rocket.chat/core-typings": "workspace:^" - "@rocket.chat/eslint-config": "workspace:^" + "@rocket.chat/eslint-config": "workspace:~" "@rocket.chat/message-parser": "workspace:^" "@rocket.chat/ui-kit": "workspace:~" "@types/jest": ~29.5.12 @@ -10139,9 +10077,7 @@ __metadata: ajv-formats: ^2.1.1 eslint: ~8.45.0 jest: ~29.7.0 - jest-environment-jsdom: ~29.7.0 mongodb: ^4.17.2 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -10164,10 +10100,7 @@ __metadata: resolution: "@rocket.chat/server-cloud-communication@workspace:packages/server-cloud-communication" dependencies: "@rocket.chat/license": "workspace:^" - "@types/jest": ~29.5.12 eslint: ~8.45.0 - jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -10176,15 +10109,12 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/server-fetch@workspace:packages/server-fetch" dependencies: - "@types/jest": ~29.5.12 "@types/proxy-from-env": ^1.0.3 eslint: ~8.45.0 http-proxy-agent: ^5.0.0 https-proxy-agent: ^5.0.1 - jest: ~29.7.0 node-fetch: 2.3.0 proxy-from-env: ^1.1.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -10196,11 +10126,11 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@rocket.chat/eslint-config": "workspace:^" + "@rocket.chat/jest-presets": "workspace:~" "@typescript-eslint/eslint-plugin": ~5.60.1 "@typescript-eslint/parser": ~5.60.1 eslint: ~8.45.0 jest: ~29.7.0 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -10270,11 +10200,11 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/tools@workspace:packages/tools" dependencies: + "@rocket.chat/jest-presets": "workspace:~" "@types/jest": ~29.5.12 eslint: ~8.45.0 jest: ~29.7.0 moment-timezone: ^0.5.43 - ts-jest: ~29.1.1 typescript: ~5.3.3 languageName: unknown linkType: soft @@ -10313,6 +10243,7 @@ __metadata: "@rocket.chat/fuselage": ^0.57.0 "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ^0.36.0 + "@rocket.chat/jest-presets": "workspace:~" "@rocket.chat/mock-providers": "workspace:^" "@rocket.chat/ui-contexts": "workspace:~" "@storybook/addon-actions": ~6.5.16 @@ -10325,10 +10256,7 @@ __metadata: "@storybook/manager-webpack4": ~6.5.16 "@storybook/react": ~6.5.16 "@storybook/testing-library": ~0.0.13 - "@swc/jest": ^0.2.29 - "@testing-library/jest-dom": ~5.16.5 - "@testing-library/react": ^12.1.5 - "@testing-library/react-hooks": ^8.0.1 + "@testing-library/react": ~16.0.0 "@types/babel__core": ~7.20.3 "@types/jest": ~29.5.12 "@types/react": ~17.0.69 @@ -10343,7 +10271,6 @@ __metadata: react: ^17.0.2 react-dom: ^17.0.2 react-hook-form: ~7.45.4 - ts-jest: ~29.1.1 typescript: ~5.3.3 peerDependencies: "@react-aria/toolbar": "*" @@ -10373,18 +10300,15 @@ __metadata: "@storybook/react": ~6.5.16 "@storybook/testing-library": ~0.0.13 "@types/babel__core": ~7.20.3 - "@types/jest": ~29.5.12 "@types/react": ~17.0.69 "@types/react-dom": ~17.0.22 eslint: ~8.45.0 eslint-plugin-react: ~7.32.2 eslint-plugin-react-hooks: ~4.6.0 eslint-plugin-storybook: ~0.6.15 - jest: ~29.7.0 react: ~17.0.2 react-docgen-typescript-plugin: ~1.0.5 react-dom: ~17.0.2 - ts-jest: ~29.1.1 typescript: ~5.3.3 peerDependencies: "@react-aria/toolbar": "*" @@ -10406,16 +10330,13 @@ __metadata: "@rocket.chat/i18n": "workspace:~" "@rocket.chat/password-policies": "workspace:^" "@rocket.chat/rest-typings": "workspace:^" - "@types/jest": ~29.5.12 "@types/react": ~17.0.69 "@types/react-dom": ~17.0.22 "@types/use-sync-external-store": ^0.0.5 eslint: ~8.45.0 eslint-plugin-react-hooks: ^4.6.0 - jest: ~29.7.0 mongodb: ^4.17.2 react: ~17.0.2 - ts-jest: ~29.1.1 typescript: ~5.3.3 use-sync-external-store: ^1.2.0 peerDependencies: @@ -10439,6 +10360,7 @@ __metadata: "@babel/plugin-transform-runtime": ~7.21.4 "@babel/preset-env": ~7.21.4 "@rocket.chat/eslint-config": "workspace:~" + "@rocket.chat/jest-presets": "workspace:~" "@types/jest": ~29.5.12 babel-loader: ~9.1.2 eslint: ~8.45.0 @@ -10446,7 +10368,6 @@ __metadata: npm-run-all: ~4.1.5 prettier: ~2.8.8 rimraf: ~3.0.2 - ts-jest: ~29.1.1 ts-loader: ~9.4.2 ts-node: ~10.9.1 ts-patch: ~3.0.2 @@ -10464,27 +10385,14 @@ __metadata: "@rocket.chat/fuselage-hooks": ^0.33.1 "@rocket.chat/icons": ^0.36.0 "@rocket.chat/ui-contexts": "workspace:~" - "@storybook/addon-actions": ~6.5.16 - "@storybook/addon-docs": ~6.5.16 - "@storybook/addon-essentials": ~6.5.16 - "@storybook/addon-interactions": ~6.5.16 - "@storybook/addon-links": ~6.5.16 - "@storybook/addon-postcss": ~2.0.0 - "@storybook/builder-webpack4": ~6.5.16 - "@storybook/manager-webpack4": ~6.5.16 - "@storybook/react": ~6.5.16 - "@storybook/testing-library": ~0.0.13 - "@types/jest": ~29.5.12 "@types/react": ~17.0.69 eslint: ~8.45.0 eslint-plugin-anti-trojan-source: ~1.1.1 eslint-plugin-react: ~7.32.2 eslint-plugin-react-hooks: ~4.6.0 eslint-plugin-testing-library: ^5.11.1 - jest: ~29.7.0 react: ~17.0.2 react-docgen-typescript-plugin: ~1.0.5 - ts-jest: ~29.1.1 typescript: ~5.3.3 peerDependencies: "@rocket.chat/css-in-js": "*" @@ -10529,7 +10437,6 @@ __metadata: jest: ~29.7.0 jest-axe: ~9.0.0 react-docgen-typescript-plugin: ~1.0.5 - ts-jest: ~29.1.1 typescript: ~5.3.3 peerDependencies: "@rocket.chat/css-in-js": "*" @@ -10613,17 +10520,14 @@ __metadata: "@storybook/react": ~6.5.16 "@storybook/testing-library": ^0.2.2 "@tanstack/react-query": ^4.16.1 - "@testing-library/react": ^13.3.0 - "@types/jest": ~29.5.12 + "@testing-library/react": ~16.0.0 "@types/react": ~17.0.69 babel-loader: ~8.3.0 eslint: ~8.45.0 - jest: ~29.7.0 react: ~17.0.2 react-hook-form: ~7.45.4 react-i18next: ~13.2.2 storybook-dark-mode: ~3.0.1 - ts-jest: ~29.1.1 typescript: ~5.3.3 peerDependencies: "@rocket.chat/layout": "*" @@ -10661,13 +10565,6 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.24.1": - version: 0.24.51 - resolution: "@sinclair/typebox@npm:0.24.51" - checksum: fd0d855e748ef767eb19da1a60ed0ab928e91e0f358c1dd198d600762c0015440b15755e96d1176e2a0db7e09c6a64ed487828ee10dd0c3e22f61eb09c478cd0 - languageName: node - linkType: hard - "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -12494,92 +12391,92 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-darwin-arm64@npm:1.5.29" +"@swc/core-darwin-arm64@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-darwin-arm64@npm:1.7.4" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-darwin-x64@npm:1.5.29" +"@swc/core-darwin-x64@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-darwin-x64@npm:1.7.4" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.5.29" +"@swc/core-linux-arm-gnueabihf@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.7.4" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-linux-arm64-gnu@npm:1.5.29" +"@swc/core-linux-arm64-gnu@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-linux-arm64-gnu@npm:1.7.4" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-linux-arm64-musl@npm:1.5.29" +"@swc/core-linux-arm64-musl@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-linux-arm64-musl@npm:1.7.4" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-linux-x64-gnu@npm:1.5.29" +"@swc/core-linux-x64-gnu@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-linux-x64-gnu@npm:1.7.4" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-linux-x64-musl@npm:1.5.29" +"@swc/core-linux-x64-musl@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-linux-x64-musl@npm:1.7.4" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-win32-arm64-msvc@npm:1.5.29" +"@swc/core-win32-arm64-msvc@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-win32-arm64-msvc@npm:1.7.4" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-win32-ia32-msvc@npm:1.5.29" +"@swc/core-win32-ia32-msvc@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-win32-ia32-msvc@npm:1.7.4" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.5.29": - version: 1.5.29 - resolution: "@swc/core-win32-x64-msvc@npm:1.5.29" +"@swc/core-win32-x64-msvc@npm:1.7.4": + version: 1.7.4 + resolution: "@swc/core-win32-x64-msvc@npm:1.7.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core@npm:^1.3.95, @swc/core@npm:~1.5.24": - version: 1.5.29 - resolution: "@swc/core@npm:1.5.29" - dependencies: - "@swc/core-darwin-arm64": 1.5.29 - "@swc/core-darwin-x64": 1.5.29 - "@swc/core-linux-arm-gnueabihf": 1.5.29 - "@swc/core-linux-arm64-gnu": 1.5.29 - "@swc/core-linux-arm64-musl": 1.5.29 - "@swc/core-linux-x64-gnu": 1.5.29 - "@swc/core-linux-x64-musl": 1.5.29 - "@swc/core-win32-arm64-msvc": 1.5.29 - "@swc/core-win32-ia32-msvc": 1.5.29 - "@swc/core-win32-x64-msvc": 1.5.29 +"@swc/core@npm:~1.7.4": + version: 1.7.4 + resolution: "@swc/core@npm:1.7.4" + dependencies: + "@swc/core-darwin-arm64": 1.7.4 + "@swc/core-darwin-x64": 1.7.4 + "@swc/core-linux-arm-gnueabihf": 1.7.4 + "@swc/core-linux-arm64-gnu": 1.7.4 + "@swc/core-linux-arm64-musl": 1.7.4 + "@swc/core-linux-x64-gnu": 1.7.4 + "@swc/core-linux-x64-musl": 1.7.4 + "@swc/core-win32-arm64-msvc": 1.7.4 + "@swc/core-win32-ia32-msvc": 1.7.4 + "@swc/core-win32-x64-msvc": 1.7.4 "@swc/counter": ^0.1.3 - "@swc/types": ^0.1.8 + "@swc/types": ^0.1.12 peerDependencies: "@swc/helpers": "*" dependenciesMeta: @@ -12606,7 +12503,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 19e3f8525ce4f4d9f6f3f62825b1f13e1e76146390930b6d5e663c0bb2c5e95ef3bf30268110d1444ea92b99dd95bfe5a3c6e2a3c0dd79291505dc7da1ed3dab + checksum: 1b2231fcb6a2a63171e34e80f0d43cd459d259b0a2fa269a129456291dc11b95a716aed60f61e5fcafd039a217916ece375876b02d125d88cdc7927382805e55 languageName: node linkType: hard @@ -12635,7 +12532,7 @@ __metadata: languageName: node linkType: hard -"@swc/jest@npm:^0.2.29, @swc/jest@npm:~0.2.36": +"@swc/jest@npm:~0.2.36": version: 0.2.36 resolution: "@swc/jest@npm:0.2.36" dependencies: @@ -12648,12 +12545,12 @@ __metadata: languageName: node linkType: hard -"@swc/types@npm:^0.1.8": - version: 0.1.9 - resolution: "@swc/types@npm:0.1.9" +"@swc/types@npm:^0.1.12": + version: 0.1.12 + resolution: "@swc/types@npm:0.1.12" dependencies: "@swc/counter": ^0.1.3 - checksum: 16fcdf331c94c52f6dbf234bd9c294a5479e4b107eb8bce364b46cd5cf86ff7073e371a3a02573e6843b0ec979e6d8912b6f60212ad297aa170a9025e7ebb716 + checksum: cf7f89e46f859864075d7965582baea9c5f98830f45b1046251568c9bdf1ca484b1bf37f6d3c32b7c82ecf8cd5df89d22f05268c391819c44e49911bb1a8e71a languageName: node linkType: hard @@ -12707,25 +12604,25 @@ __metadata: languageName: node linkType: hard -"@testing-library/dom@npm:^8.0.0, @testing-library/dom@npm:^8.3.0, @testing-library/dom@npm:^8.5.0": - version: 8.17.1 - resolution: "@testing-library/dom@npm:8.17.1" +"@testing-library/dom@npm:^8.3.0": + version: 8.20.1 + resolution: "@testing-library/dom@npm:8.20.1" dependencies: "@babel/code-frame": ^7.10.4 "@babel/runtime": ^7.12.5 - "@types/aria-query": ^4.2.0 - aria-query: ^5.0.0 + "@types/aria-query": ^5.0.1 + aria-query: 5.1.3 chalk: ^4.1.0 dom-accessibility-api: ^0.5.9 - lz-string: ^1.4.4 + lz-string: ^1.5.0 pretty-format: ^27.0.2 - checksum: e4df091fcf84c9eac4a6ee4c76674c1d562bf98732f0ac8820972d7718ab10397b672b9f082aace3cacd1f610fc77de6e1b6094e67afe1df0443bf22eb9deab2 + checksum: 06fc8dc67849aadb726cbbad0e7546afdf8923bd39acb64c576d706249bd7d0d05f08e08a31913fb621162e3b9c2bd0dce15964437f030f9fa4476326fdd3007 languageName: node linkType: hard "@testing-library/dom@npm:^9.0.0": - version: 9.3.1 - resolution: "@testing-library/dom@npm:9.3.1" + version: 9.3.4 + resolution: "@testing-library/dom@npm:9.3.4" dependencies: "@babel/code-frame": ^7.10.4 "@babel/runtime": ^7.12.5 @@ -12735,30 +12632,13 @@ __metadata: dom-accessibility-api: ^0.5.9 lz-string: ^1.5.0 pretty-format: ^27.0.2 - checksum: 8ee3136451644e39990edea93709c38cf1e8ce5306f3c66273ca00935963faa51ca74e8d92b02eb442ccb842cfa28ca62833e393e075eb269cf9bef6f5600663 + checksum: dfd6fb0d6c7b4dd716ba3c47309bc9541b4a55772cb61758b4f396b3785efe2dbc75dc63423545c039078c7ffcc5e4b8c67c2db1b6af4799580466036f70026f languageName: node linkType: hard -"@testing-library/jest-dom@npm:^5.16.5, @testing-library/jest-dom@npm:~5.16.5": - version: 5.16.5 - resolution: "@testing-library/jest-dom@npm:5.16.5" - dependencies: - "@adobe/css-tools": ^4.0.1 - "@babel/runtime": ^7.9.2 - "@types/testing-library__jest-dom": ^5.9.1 - aria-query: ^5.0.0 - chalk: ^3.0.0 - css.escape: ^1.5.1 - dom-accessibility-api: ^0.5.6 - lodash: ^4.17.15 - redent: ^3.0.0 - checksum: 94911f901a8031f3e489d04ac057cb5373621230f5d92bed80e514e24b069fb58a3166d1dd86963e55f078a1bd999da595e2ab96ed95f452d477e272937d792a - languageName: node - linkType: hard - -"@testing-library/jest-dom@npm:~6.4.5": - version: 6.4.6 - resolution: "@testing-library/jest-dom@npm:6.4.6" +"@testing-library/jest-dom@npm:~6.4.8": + version: 6.4.8 + resolution: "@testing-library/jest-dom@npm:6.4.8" dependencies: "@adobe/css-tools": ^4.4.0 "@babel/runtime": ^7.9.2 @@ -12768,78 +12648,31 @@ __metadata: dom-accessibility-api: ^0.6.3 lodash: ^4.17.21 redent: ^3.0.0 - peerDependencies: - "@jest/globals": ">= 28" - "@types/bun": "*" - "@types/jest": ">= 28" - jest: ">= 28" - vitest: ">= 0.32" - peerDependenciesMeta: - "@jest/globals": - optional: true - "@types/bun": - optional: true - "@types/jest": - optional: true - jest: - optional: true - vitest: - optional: true - checksum: d70acbfc5d842065292dc1b4113ac2b4c2a2b83f9868e454d7f24d97ee92fddf7852e0e079b6eecaf21154bfe6e9ad03eb32e72f16854f64d7ce1ff42288828b + checksum: b601688950e522557c2c6bbc0f026ae31a10583577c8a557814b0eb33648fe82afc06299f3cdb79ff0c5076fd1a6106f3d76e2ca0dde6f7ee0555e63008fbd72 languageName: node linkType: hard -"@testing-library/react-hooks@npm:^8.0.1": - version: 8.0.1 - resolution: "@testing-library/react-hooks@npm:8.0.1" +"@testing-library/react@npm:~16.0.0": + version: 16.0.0 + resolution: "@testing-library/react@npm:16.0.0" dependencies: "@babel/runtime": ^7.12.5 - react-error-boundary: ^3.1.0 peerDependencies: - "@types/react": ^16.9.0 || ^17.0.0 - react: ^16.9.0 || ^17.0.0 - react-dom: ^16.9.0 || ^17.0.0 - react-test-renderer: ^16.9.0 || ^17.0.0 + "@testing-library/dom": ^10.0.0 + "@types/react": ^18.0.0 + "@types/react-dom": ^18.0.0 + react: ^18.0.0 + react-dom: ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - react-dom: - optional: true - react-test-renderer: + "@types/react-dom": optional: true - checksum: 7fe44352e920deb5cb1876f80d64e48615232072c9d5382f1e0284b3aab46bb1c659a040b774c45cdf084a5257b8fe463f7e08695ad8480d8a15635d4d3d1f6d - languageName: node - linkType: hard - -"@testing-library/react@npm:^12.1.4, @testing-library/react@npm:^12.1.5, @testing-library/react@npm:~12.1.5": - version: 12.1.5 - resolution: "@testing-library/react@npm:12.1.5" - dependencies: - "@babel/runtime": ^7.12.5 - "@testing-library/dom": ^8.0.0 - "@types/react-dom": <18.0.0 - peerDependencies: - react: <18.0.0 - react-dom: <18.0.0 - checksum: 4abd0490405e709a7df584a0db604e508a4612398bb1326e8fa32dd9393b15badc826dcf6d2f7525437886d507871f719f127b9860ed69ddd204d1fa834f576a + checksum: 45a35f0b5f34b5a7f4dcefdd3f1d202d5421692e5cc7a491c9bc71e6ed9dd5872a182b80b4dfefb4a56d9c1df35e50f6fa2917bcf657cc26b4bc0d2259df0027 languageName: node linkType: hard -"@testing-library/react@npm:^13.3.0, @testing-library/react@npm:~13.4.0": - version: 13.4.0 - resolution: "@testing-library/react@npm:13.4.0" - dependencies: - "@babel/runtime": ^7.12.5 - "@testing-library/dom": ^8.5.0 - "@types/react-dom": ^18.0.0 - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - checksum: 51ec548c1fdb1271089a5c63e0908f0166f2c7fcd9cacd3108ebbe0ce64cb4351812d885892020dc37608418cfb15698514856502b3cab0e5cc58d6cc1bd4a3e - languageName: node - linkType: hard - -"@testing-library/user-event@npm:^13.2.1, @testing-library/user-event@npm:~13.5.0": +"@testing-library/user-event@npm:^13.2.1": version: 13.5.0 resolution: "@testing-library/user-event@npm:13.5.0" dependencies: @@ -12850,7 +12683,7 @@ __metadata: languageName: node linkType: hard -"@testing-library/user-event@npm:^14.4.0, @testing-library/user-event@npm:^14.5.2": +"@testing-library/user-event@npm:^14.4.0, @testing-library/user-event@npm:~14.5.2": version: 14.5.2 resolution: "@testing-library/user-event@npm:14.5.2" peerDependencies: @@ -12933,17 +12766,10 @@ __metadata: languageName: node linkType: hard -"@types/aria-query@npm:^4.2.0": - version: 4.2.2 - resolution: "@types/aria-query@npm:4.2.2" - checksum: 6f2ce11d91e2d665f3873258db19da752d91d85d3679eb5efcdf9c711d14492287e1e4eb52613b28e60375841a9e428594e745b68436c963d8bad4bf72188df3 - languageName: node - linkType: hard - "@types/aria-query@npm:^5.0.1": - version: 5.0.1 - resolution: "@types/aria-query@npm:5.0.1" - checksum: 69fd7cceb6113ed370591aef04b3fd0742e9a1b06dd045c43531448847b85de181495e4566f98e776b37c422a12fd71866e0a1dfd904c5ec3f84d271682901de + version: 5.0.4 + resolution: "@types/aria-query@npm:5.0.4" + checksum: ad8b87e4ad64255db5f0a73bc2b4da9b146c38a3a8ab4d9306154334e0fc67ae64e76bfa298eebd1e71830591fb15987e5de7111bdb36a2221bdc379e3415fb0 languageName: node linkType: hard @@ -14360,7 +14186,7 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:<18.0.0, @types/react-dom@npm:~17.0.22": +"@types/react-dom@npm:~17.0.22": version: 17.0.22 resolution: "@types/react-dom@npm:17.0.22" dependencies: @@ -14369,15 +14195,6 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^18.0.0": - version: 18.0.10 - resolution: "@types/react-dom@npm:18.0.10" - dependencies: - "@types/react": "*" - checksum: ff8282d5005a0b1cd95fb65bf79d3d8485e4cfe2aaf052129033a178684b940014a3f4536bc20d573f8a01cf4c6f4770c74988cef7c2b5cac3041d9f172647e3 - languageName: node - linkType: hard - "@types/react-lifecycles-compat@npm:^3.0.1": version: 3.0.4 resolution: "@types/react-lifecycles-compat@npm:3.0.4" @@ -14625,15 +14442,6 @@ __metadata: languageName: node linkType: hard -"@types/testing-library__jest-dom@npm:^5.9.1, @types/testing-library__jest-dom@npm:~5.14.9": - version: 5.14.9 - resolution: "@types/testing-library__jest-dom@npm:5.14.9" - dependencies: - "@types/jest": "*" - checksum: d364494fc2545316292e88861146146af1e3818792ca63b62a63758b2f737669b687f4aaddfcfbcb7d0e1ed7890a9bd05de23ff97f277d5e68de574497a9ee72 - languageName: node - linkType: hard - "@types/textarea-caret@npm:^3.0.2": version: 3.0.2 resolution: "@types/textarea-caret@npm:3.0.2" @@ -15742,9 +15550,9 @@ __metadata: linkType: hard "acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.2.0": - version: 8.2.0 - resolution: "acorn-walk@npm:8.2.0" - checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 + version: 8.3.2 + resolution: "acorn-walk@npm:8.3.2" + checksum: 3626b9d26a37b1b427796feaa5261faf712307a8920392c8dce9a5739fb31077667f4ad2ec71c7ac6aaf9f61f04a9d3d67ff56f459587206fc04aa31c27ef392 languageName: node linkType: hard @@ -15767,11 +15575,11 @@ __metadata: linkType: hard "acorn@npm:^8.0.4, acorn@npm:^8.1.0, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.0, acorn@npm:^8.7.1, acorn@npm:^8.8.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.10.0 - resolution: "acorn@npm:8.10.0" + version: 8.11.3 + resolution: "acorn@npm:8.11.3" bin: acorn: bin/acorn - checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d + checksum: 76d8e7d559512566b43ab4aadc374f11f563f0a9e21626dd59cb2888444e9445923ae9f3699972767f18af61df89cd89f5eaaf772d1327b055b45cb829b4a88c languageName: node linkType: hard @@ -17895,15 +17703,6 @@ __metadata: languageName: node linkType: hard -"bs-logger@npm:0.x": - version: 0.2.6 - resolution: "bs-logger@npm:0.2.6" - dependencies: - fast-json-stable-stringify: 2.x - checksum: d34bdaf68c64bd099ab97c3ea608c9ae7d3f5faa1178b3f3f345acd94e852e608b2d4f9103fb2e503f5e69780e98293df41691b84be909b41cf5045374d54606 - languageName: node - linkType: hard - "bs58@npm:^4.0.1": version: 4.0.1 resolution: "bs58@npm:4.0.1" @@ -20930,13 +20729,13 @@ __metadata: linkType: hard "deep-equal@npm:^2.0.5": - version: 2.2.2 - resolution: "deep-equal@npm:2.2.2" + version: 2.2.3 + resolution: "deep-equal@npm:2.2.3" dependencies: array-buffer-byte-length: ^1.0.0 - call-bind: ^1.0.2 + call-bind: ^1.0.5 es-get-iterator: ^1.1.3 - get-intrinsic: ^1.2.1 + get-intrinsic: ^1.2.2 is-arguments: ^1.1.1 is-array-buffer: ^3.0.2 is-date-object: ^1.0.5 @@ -20946,12 +20745,12 @@ __metadata: object-is: ^1.1.5 object-keys: ^1.1.1 object.assign: ^4.1.4 - regexp.prototype.flags: ^1.5.0 + regexp.prototype.flags: ^1.5.1 side-channel: ^1.0.4 which-boxed-primitive: ^1.0.2 which-collection: ^1.0.1 - which-typed-array: ^1.1.9 - checksum: eb61c35157b6ecb96a5359b507b083fbff8ddb4c86a78a781ee38485f77a667465e45d63ee2ebd8a00e86d94c80e499906900cd82c2debb400237e1662cd5397 + which-typed-array: ^1.1.13 + checksum: ee8852f23e4d20a5626c13b02f415ba443a1b30b4b3d39eaf366d59c4a85e6545d7ec917db44d476a85ae5a86064f7e5f7af7479f38f113995ba869f3a1ddc53 languageName: node linkType: hard @@ -21265,13 +21064,6 @@ __metadata: languageName: node linkType: hard -"diff-sequences@npm:^28.1.1": - version: 28.1.1 - resolution: "diff-sequences@npm:28.1.1" - checksum: e2529036505567c7ca5a2dea86b6bcd1ca0e3ae63bf8ebf529b8a99cfa915bbf194b7021dc1c57361a4017a6d95578d4ceb29fabc3232a4f4cb866a2726c7690 - languageName: node - linkType: hard - "diff-sequences@npm:^29.6.3": version: 29.6.3 resolution: "diff-sequences@npm:29.6.3" @@ -21379,7 +21171,7 @@ __metadata: languageName: node linkType: hard -"dom-accessibility-api@npm:^0.5.6, dom-accessibility-api@npm:^0.5.9": +"dom-accessibility-api@npm:^0.5.9": version: 0.5.14 resolution: "dom-accessibility-api@npm:0.5.14" checksum: 782c813f75a09ba6735ef03b5e1624406a3829444ae49d5bdedd272a49d437ae3354f53e02ffc8c9fd9165880250f41546538f27461f839dd4ea1234e77e8d5e @@ -22718,6 +22510,17 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-testing-library@npm:~6.2.2": + version: 6.2.2 + resolution: "eslint-plugin-testing-library@npm:6.2.2" + dependencies: + "@typescript-eslint/utils": ^5.58.0 + peerDependencies: + eslint: ^7.5.0 || ^8.0.0 + checksum: df55ca98415bad3e7d6b21adcd0f817d7c6df59cb32099528e45b39e8d7edf95e040334106fc7574fd402ed624ca65215ccf37745e1da1a9c90cfe00b99c5be4 + languageName: node + linkType: hard + "eslint-plugin-you-dont-need-lodash-underscore@npm:~6.12.0": version: 6.12.0 resolution: "eslint-plugin-you-dont-need-lodash-underscore@npm:6.12.0" @@ -23466,7 +23269,7 @@ __metadata: languageName: node linkType: hard -"fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": +"fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb @@ -24628,7 +24431,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": +"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": version: 1.2.4 resolution: "get-intrinsic@npm:1.2.4" dependencies: @@ -28061,19 +27864,7 @@ __metadata: languageName: node linkType: hard -"jest-diff@npm:^28.0.2": - version: 28.1.3 - resolution: "jest-diff@npm:28.1.3" - dependencies: - chalk: ^4.0.0 - diff-sequences: ^28.1.1 - jest-get-type: ^28.0.2 - pretty-format: ^28.1.3 - checksum: fa8583e0ccbe775714ce850b009be1b0f6b17a4b6759f33ff47adef27942ebc610dbbcc8a5f7cfb7f12b3b3b05afc9fb41d5f766674616025032ff1e4f9866e0 - languageName: node - linkType: hard - -"jest-diff@npm:^29.2.1, jest-diff@npm:^29.7.0": +"jest-diff@npm:^29.2.0, jest-diff@npm:^29.2.1, jest-diff@npm:^29.7.0": version: 29.7.0 resolution: "jest-diff@npm:29.7.0" dependencies: @@ -28128,7 +27919,7 @@ __metadata: languageName: node linkType: hard -"jest-environment-node@npm:^29.7.0": +"jest-environment-node@npm:^29.7.0, jest-environment-node@npm:~29.7.0": version: 29.7.0 resolution: "jest-environment-node@npm:29.7.0" dependencies: @@ -28152,13 +27943,6 @@ __metadata: languageName: node linkType: hard -"jest-get-type@npm:^28.0.2": - version: 28.0.2 - resolution: "jest-get-type@npm:28.0.2" - checksum: 5281d7c89bc8156605f6d15784f45074f4548501195c26e9b188742768f72d40948252d13230ea905b5349038865a1a8eeff0e614cc530ff289dfc41fe843abd - languageName: node - linkType: hard - "jest-get-type@npm:^29.2.0, jest-get-type@npm:^29.6.3": version: 29.6.3 resolution: "jest-get-type@npm:29.6.3" @@ -28450,7 +28234,7 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^29.0.0, jest-util@npm:^29.7.0": +"jest-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-util@npm:29.7.0" dependencies: @@ -28494,13 +28278,13 @@ __metadata: languageName: node linkType: hard -"jest-websocket-mock@npm:^2.4.0": - version: 2.4.0 - resolution: "jest-websocket-mock@npm:2.4.0" +"jest-websocket-mock@npm:~2.5.0": + version: 2.5.0 + resolution: "jest-websocket-mock@npm:2.5.0" dependencies: - jest-diff: ^28.0.2 - mock-socket: ^9.1.0 - checksum: 03c0707b70bbdbcdf4c2f5579d3423b41317bdecb38ede593061c7894421d24d903bf9dc53062f7a3f2fc3302374d35436cb36d6db6ac84058b63862438d6d27 + jest-diff: ^29.2.0 + mock-socket: ^9.3.0 + checksum: df52989d62f59aea3408d37089ab56490efdfa75d81c851dde65758474844e273a9a4ebd9c13db49d226b87d8272896cabd91173dd8cc56b96beec309d46554d languageName: node linkType: hard @@ -29671,7 +29455,7 @@ __metadata: languageName: node linkType: hard -"lodash.memoize@npm:4.x, lodash.memoize@npm:^4.1.2": +"lodash.memoize@npm:^4.1.2": version: 4.1.2 resolution: "lodash.memoize@npm:4.1.2" checksum: 9ff3942feeccffa4f1fafa88d32f0d24fdc62fd15ded5a74a5f950ff5f0c6f61916157246744c620173dddf38d37095a92327d5fd3861e2063e736a5c207d089 @@ -29946,7 +29730,7 @@ __metadata: languageName: node linkType: hard -"lz-string@npm:^1.4.4, lz-string@npm:^1.5.0": +"lz-string@npm:^1.5.0": version: 1.5.0 resolution: "lz-string@npm:1.5.0" bin: @@ -30011,7 +29795,7 @@ __metadata: languageName: node linkType: hard -"make-error@npm:1.x, make-error@npm:^1.1.1": +"make-error@npm:^1.1.1": version: 1.3.6 resolution: "make-error@npm:1.3.6" checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 @@ -31090,10 +30874,10 @@ __metadata: languageName: node linkType: hard -"mock-socket@npm:^9.1.0": - version: 9.2.1 - resolution: "mock-socket@npm:9.2.1" - checksum: daf07689563163dbcefbefe23b2a9784a75d0af31706f23ad535c6ab2abbcdefa2e91acddeb50a3c39009139e47a8f909cbb38e8137452193ccb9331637fee3e +"mock-socket@npm:^9.3.0": + version: 9.3.1 + resolution: "mock-socket@npm:9.3.1" + checksum: cb2dde4fc5dde280dd5ccb78eaaa223382ee16437f46b86558017655584ad08c22e733bde2dd5cc86927def506b6caeb0147e3167b9a62d70d5cf19d44103853 languageName: node linkType: hard @@ -32145,9 +31929,9 @@ __metadata: linkType: hard "nwsapi@npm:^2.2.0, nwsapi@npm:^2.2.2": - version: 2.2.2 - resolution: "nwsapi@npm:2.2.2" - checksum: 43769106292bc95f776756ca2f3513dab7b4d506a97c67baec32406447841a35f65f29c1f95ab5d42785210fd41668beed33ca16fa058780be43b101ad73e205 + version: 2.2.10 + resolution: "nwsapi@npm:2.2.10" + checksum: 5f1d361b38c47ab49727d5ea8bbfeb5867ae6de0e538eec9a8b77c88005ddde36d8b930e0730b50ee5e5dda949112c0f9ffed1bf15e7e1b3cd9cfa319f5a9b6f languageName: node linkType: hard @@ -32242,12 +32026,12 @@ __metadata: linkType: hard "object-is@npm:^1.0.1, object-is@npm:^1.1.5": - version: 1.1.5 - resolution: "object-is@npm:1.1.5" + version: 1.1.6 + resolution: "object-is@npm:1.1.6" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - checksum: 989b18c4cba258a6b74dc1d74a41805c1a1425bce29f6cabb50dcb1a6a651ea9104a1b07046739a49a5bb1bc49727bcb00efd5c55f932f6ea04ec8927a7901fe + call-bind: ^1.0.7 + define-properties: ^1.2.1 + checksum: 3ea22759967e6f2380a2cbbd0f737b42dc9ddb2dfefdb159a1b927fea57335e1b058b564bfa94417db8ad58cddab33621a035de6f5e5ad56d89f2dd03e66c6a1 languageName: node linkType: hard @@ -34660,18 +34444,6 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^28.1.3": - version: 28.1.3 - resolution: "pretty-format@npm:28.1.3" - dependencies: - "@jest/schemas": ^28.1.3 - ansi-regex: ^5.0.1 - ansi-styles: ^5.0.0 - react-is: ^18.0.0 - checksum: e69f857358a3e03d271252d7524bec758c35e44680287f36c1cb905187fbc82da9981a6eb07edfd8a03bc3cbeebfa6f5234c13a3d5b59f2bbdf9b4c4053e0a7f - languageName: node - linkType: hard - "pretty-format@npm:^29.0.0, pretty-format@npm:^29.2.1, pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" @@ -35558,15 +35330,15 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^18.2.0": - version: 18.2.0 - resolution: "react-dom@npm:18.2.0" +"react-dom@npm:~18.3.1": + version: 18.3.1 + resolution: "react-dom@npm:18.3.1" dependencies: loose-envify: ^1.1.0 - scheduler: ^0.23.0 + scheduler: ^0.23.2 peerDependencies: - react: ^18.2.0 - checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc + react: ^18.3.1 + checksum: 298954ecd8f78288dcaece05e88b570014d8f6dce5db6f66e6ee91448debeb59dcd31561dddb354eee47e6c1bb234669459060deb238ed0213497146e555a0b9 languageName: node linkType: hard @@ -35584,7 +35356,7 @@ __metadata: languageName: node linkType: hard -"react-error-boundary@npm:^3.1.0, react-error-boundary@npm:^3.1.4": +"react-error-boundary@npm:^3.1.4": version: 3.1.4 resolution: "react-error-boundary@npm:3.1.4" dependencies: @@ -35925,12 +35697,12 @@ __metadata: languageName: node linkType: hard -"react@npm:^18.2.0": - version: 18.2.0 - resolution: "react@npm:18.2.0" +"react@npm:~18.3.1": + version: 18.3.1 + resolution: "react@npm:18.3.1" dependencies: loose-envify: ^1.1.0 - checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b + checksum: a27bcfa8ff7c15a1e50244ad0d0c1cb2ad4375eeffefd266a64889beea6f6b64c4966c9b37d14ee32d6c9fcd5aa6ba183b6988167ab4d127d13e7cb5b386a376 languageName: node linkType: hard @@ -36328,7 +36100,7 @@ __metadata: languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.4.3, regexp.prototype.flags@npm:^1.5.0, regexp.prototype.flags@npm:^1.5.2": +"regexp.prototype.flags@npm:^1.4.3, regexp.prototype.flags@npm:^1.5.1, regexp.prototype.flags@npm:^1.5.2": version: 1.5.2 resolution: "regexp.prototype.flags@npm:1.5.2" dependencies: @@ -37271,12 +37043,12 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.23.0": - version: 0.23.0 - resolution: "scheduler@npm:0.23.0" +"scheduler@npm:^0.23.2": + version: 0.23.2 + resolution: "scheduler@npm:0.23.2" dependencies: loose-envify: ^1.1.0 - checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a + checksum: 3e82d1f419e240ef6219d794ff29c7ee415fbdc19e038f680a10c067108e06284f1847450a210b29bbaf97b9d8a97ced5f624c31c681248ac84c80d56ad5a2c4 languageName: node linkType: hard @@ -40076,14 +39848,14 @@ __metadata: linkType: hard "tough-cookie@npm:^4.0.0, tough-cookie@npm:^4.1.2": - version: 4.1.2 - resolution: "tough-cookie@npm:4.1.2" + version: 4.1.4 + resolution: "tough-cookie@npm:4.1.4" dependencies: psl: ^1.1.33 punycode: ^2.1.1 universalify: ^0.2.0 url-parse: ^1.5.3 - checksum: a7359e9a3e875121a84d6ba40cc184dec5784af84f67f3a56d1d2ae39b87c0e004e6ba7c7331f9622a7d2c88609032473488b28fe9f59a1fec115674589de39a + checksum: 5815059f014c31179a303c673f753f7899a6fce94ac93712c88ea5f3c26e0c042b5f0c7a599a00f8e0feeca4615dba75c3dffc54f3c1a489978aa8205e09307c languageName: node linkType: hard @@ -40211,39 +39983,6 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:^29.1.1, ts-jest@npm:^29.1.2, ts-jest@npm:~29.1.0, ts-jest@npm:~29.1.1": - version: 29.1.2 - resolution: "ts-jest@npm:29.1.2" - dependencies: - bs-logger: 0.x - fast-json-stable-stringify: 2.x - jest-util: ^29.0.0 - json5: ^2.2.3 - lodash.memoize: 4.x - make-error: 1.x - semver: ^7.5.3 - yargs-parser: ^21.0.1 - peerDependencies: - "@babel/core": ">=7.0.0-beta.0 <8" - "@jest/types": ^29.0.0 - babel-jest: ^29.0.0 - jest: ^29.0.0 - typescript: ">=4.3 <6" - peerDependenciesMeta: - "@babel/core": - optional: true - "@jest/types": - optional: true - babel-jest: - optional: true - esbuild: - optional: true - bin: - ts-jest: cli.js - checksum: a0ce0affc1b716c78c9ab55837829c42cb04b753d174a5c796bb1ddf9f0379fc20647b76fbe30edb30d9b23181908138d6b4c51ef2ae5e187b66635c295cefd5 - languageName: node - linkType: hard - "ts-loader@npm:~9.4.2": version: 9.4.4 resolution: "ts-loader@npm:9.4.4" @@ -41512,7 +41251,7 @@ __metadata: languageName: node linkType: hard -"use-sync-external-store@npm:1.2.0, use-sync-external-store@npm:^1.2.0, use-sync-external-store@npm:~1.2.0": +"use-sync-external-store@npm:1.2.0": version: 1.2.0 resolution: "use-sync-external-store@npm:1.2.0" peerDependencies: @@ -41521,6 +41260,15 @@ __metadata: languageName: node linkType: hard +"use-sync-external-store@npm:^1.2.0, use-sync-external-store@npm:~1.2.0, use-sync-external-store@npm:~1.2.2": + version: 1.2.2 + resolution: "use-sync-external-store@npm:1.2.2" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: fe07c071c4da3645f112c38c0e57beb479a8838616ff4e92598256ecce527f2888c08febc7f9b2f0ce2f0e18540ba3cde41eb2035e4fafcb4f52955037098a81 + languageName: node + linkType: hard + "use@npm:^3.1.0": version: 3.1.1 resolution: "use@npm:3.1.1" @@ -42689,7 +42437,7 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": +"which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": version: 1.1.15 resolution: "which-typed-array@npm:1.1.15" dependencies: @@ -42945,8 +42693,8 @@ __metadata: linkType: hard "ws@npm:^8.11.0, ws@npm:^8.13.0, ws@npm:^8.2.3, ws@npm:^8.8.1": - version: 8.13.0 - resolution: "ws@npm:8.13.0" + version: 8.17.0 + resolution: "ws@npm:8.17.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -42955,7 +42703,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c + checksum: 147ef9eab0251364e1d2c55338ad0efb15e6913923ccbfdf20f7a8a6cb8f88432bcd7f4d8f66977135bfad35575644f9983201c1a361019594a4e53977bf6d4e languageName: node linkType: hard @@ -43205,7 +42953,7 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^21.0.1, yargs-parser@npm:^21.1.1": +"yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c From ccf68286a981dd96ee12a5b616a6951dbcfb5368 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 12 Aug 2024 06:46:16 -0600 Subject: [PATCH 34/80] chore: Add `departmentName` to the return values of `:agentId/departments` endpoint (#32943) --- .../app/livechat/server/api/lib/agents.ts | 10 +-- .../models/raw/LivechatDepartmentAgents.ts | 62 ++++++++++--------- apps/meteor/tests/data/livechat/department.ts | 6 +- .../end-to-end/api/livechat/01-agents.ts | 55 ++++++++++++++-- .../src/ILivechatDepartmentAgents.ts | 5 +- .../models/ILivechatDepartmentAgentsModel.ts | 22 +------ packages/rest-typings/src/v1/omnichannel.ts | 4 +- 7 files changed, 100 insertions(+), 64 deletions(-) diff --git a/apps/meteor/app/livechat/server/api/lib/agents.ts b/apps/meteor/app/livechat/server/api/lib/agents.ts index 3bc5180c2f59..2dbcce8c7e2e 100644 --- a/apps/meteor/app/livechat/server/api/lib/agents.ts +++ b/apps/meteor/app/livechat/server/api/lib/agents.ts @@ -7,14 +7,8 @@ export async function findAgentDepartments({ }: { enabledDepartmentsOnly?: boolean; agentId: string; -}): Promise<{ departments: ILivechatDepartmentAgents[] }> { - if (enabledDepartmentsOnly) { - return { - departments: await LivechatDepartmentAgents.findActiveDepartmentsByAgentId(agentId).toArray(), - }; - } - +}): Promise<{ departments: (ILivechatDepartmentAgents & { departmentName: string })[] }> { return { - departments: await LivechatDepartmentAgents.find({ agentId }).toArray(), + departments: await LivechatDepartmentAgents.findDepartmentsOfAgent(agentId, enabledDepartmentsOnly).toArray(), }; } diff --git a/apps/meteor/server/models/raw/LivechatDepartmentAgents.ts b/apps/meteor/server/models/raw/LivechatDepartmentAgents.ts index 76a0e7610445..891542f03e7a 100644 --- a/apps/meteor/server/models/raw/LivechatDepartmentAgents.ts +++ b/apps/meteor/server/models/raw/LivechatDepartmentAgents.ts @@ -12,6 +12,7 @@ import type { DeleteResult, IndexDescription, SortDirection, + AggregationCursor, } from 'mongodb'; import { BaseRaw } from './BaseRaw'; @@ -111,34 +112,6 @@ export class LivechatDepartmentAgentsRaw extends BaseRaw; - - findActiveDepartmentsByAgentId(agentId: string, options: FindOptions): FindCursor; - - findActiveDepartmentsByAgentId

( - agentId: string, - options: FindOptions

, - ): FindCursor

; - - findActiveDepartmentsByAgentId

( - agentId: string, - options?: - | undefined - | FindOptions - | FindOptions

, - ): FindCursor | FindCursor

{ - const query = { - agentId, - departmentEnabled: true, - }; - - if (options === undefined) { - return this.find(query); - } - - return this.find(query, options); - } - findByDepartmentIds(departmentIds: string[], options = {}): FindCursor { return this.find({ departmentId: { $in: departmentIds } }, options); } @@ -395,6 +368,39 @@ export class LivechatDepartmentAgentsRaw extends BaseRaw { return this.find({ agentId: { $in: agentsIds }, departmentId }, options); } + + findDepartmentsOfAgent(agentId: string, enabled = false): AggregationCursor { + return this.col.aggregate([ + { + $match: { + agentId, + ...(enabled && { departmentEnabled: true }), + }, + }, + { + $lookup: { + from: 'rocketchat_livechat_department', + localField: 'departmentId', + foreignField: '_id', + as: 'department', + }, + }, + { $unwind: '$department' }, + { + $project: { + _id: '$_id', + agentId: '$agentId', + departmentId: '$departmentId', + departmentName: '$department.name', + username: '$username', + count: '$count', + order: '$order', + departmentEnabled: '$departmentEnabled', + _updatedAt: '$_updatedAt', + }, + }, + ]); + } } const isStringValue = (value: any): value is string => typeof value === 'string'; diff --git a/apps/meteor/tests/data/livechat/department.ts b/apps/meteor/tests/data/livechat/department.ts index fa37e698c52c..72ab0af9f267 100644 --- a/apps/meteor/tests/data/livechat/department.ts +++ b/apps/meteor/tests/data/livechat/department.ts @@ -16,12 +16,16 @@ const NewDepartmentData = ((): Partial => ({ showOnOfflineForm: true, }))(); -export const createDepartment = async (departmentData: Partial = NewDepartmentData): Promise => { +export const createDepartment = async ( + departmentData: Partial = NewDepartmentData, + agents?: { agentId: string; count?: string; order?: string }[], +): Promise => { const response = await request .post(api('livechat/department')) .set(credentials) .send({ department: departmentData, + ...(agents && { agents }), }) .expect(200); return response.body.department; diff --git a/apps/meteor/tests/end-to-end/api/livechat/01-agents.ts b/apps/meteor/tests/end-to-end/api/livechat/01-agents.ts index fc81488ac37d..d8cd23d97752 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/01-agents.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/01-agents.ts @@ -1,11 +1,13 @@ import type { Credentials } from '@rocket.chat/api-client'; import { UserStatus, type ILivechatAgent, type ILivechatDepartment, type IRoom, type IUser } from '@rocket.chat/core-typings'; +import { Random } from '@rocket.chat/random'; import { expect } from 'chai'; import { after, before, describe, it } from 'mocha'; import type { Response } from 'supertest'; import { getCredentials, api, request, credentials } from '../../../data/api-data'; import { disableDefaultBusinessHour, makeDefaultBusinessHourActiveAndClosed } from '../../../data/livechat/businessHours'; +import { createDepartment, deleteDepartment } from '../../../data/livechat/department'; import { createAgent, createManager, @@ -21,6 +23,7 @@ import { import { updatePermission, updateSetting } from '../../../data/permissions.helper'; import { password } from '../../../data/user'; import { createUser, deleteUser, getMe, login, setUserStatus } from '../../../data/users.helper'; +import { IS_EE } from '../../../e2e/config/constants'; describe('LIVECHAT - Agents', () => { let agent: ILivechatAgent; @@ -377,7 +380,36 @@ describe('LIVECHAT - Agents', () => { }); }); - describe('livechat/agents/:agentId/departments', () => { + (IS_EE ? describe : describe.skip)('livechat/agents/:agentId/departments', () => { + let dep1: ILivechatDepartment; + let dep2: ILivechatDepartment; + before(async () => { + dep1 = await createDepartment( + { + enabled: true, + name: Random.id(), + showOnRegistration: true, + email: `${Random.id()}@example.com`, + showOnOfflineForm: true, + }, + [{ agentId: credentials['X-User-Id'] }], + ); + dep2 = await createDepartment( + { + enabled: false, + name: Random.id(), + email: `${Random.id()}@example.com`, + showOnRegistration: true, + showOnOfflineForm: true, + }, + [{ agentId: credentials['X-User-Id'] }], + ); + }); + + after(async () => { + await deleteDepartment(dep1._id); + await deleteDepartment(dep2._id); + }); it('should return an "unauthorized error" when the user does not have the necessary permission', async () => { await updatePermission('view-l-room', []); await request @@ -385,9 +417,9 @@ describe('LIVECHAT - Agents', () => { .set(credentials) .expect('Content-Type', 'application/json') .expect(403); + await updatePermission('view-l-room', ['livechat-manager', 'livechat-agent', 'admin']); }); it('should return an empty array of departments when the agentId is invalid', async () => { - await updatePermission('view-l-room', ['admin']); await request .get(api('livechat/agents/invalid-id/departments')) .set(credentials) @@ -399,7 +431,6 @@ describe('LIVECHAT - Agents', () => { }); }); it('should return an array of departments when the agentId is valid', async () => { - await updatePermission('view-l-room', ['admin']); await request .get(api(`livechat/agents/${agent._id}/departments`)) .set(credentials) @@ -408,12 +439,26 @@ describe('LIVECHAT - Agents', () => { .expect((res: Response) => { expect(res.body).to.have.property('success', true); expect(res.body).to.have.property('departments').and.to.be.an('array'); + expect(res.body.departments.length).to.be.equal(2); (res.body.departments as ILivechatDepartment[]).forEach((department) => { expect(department.agentId).to.be.equal(agent._id); + expect(department).to.have.property('departmentName').that.is.a('string'); }); }); - - await updatePermission('view-l-room', ['livechat-manager', 'livechat-agent', 'admin']); + }); + it('should return only enabled departments when param `enabledDepartmentsOnly` is true ', async () => { + await request + .get(api(`livechat/agents/${agent._id}/departments`)) + .set(credentials) + .query({ enabledDepartmentsOnly: true }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('departments').and.to.be.an('array'); + expect(res.body.departments.length).to.be.equal(1); + expect(res.body.departments[0].departmentEnabled).to.be.true; + }); }); }); diff --git a/packages/core-typings/src/ILivechatDepartmentAgents.ts b/packages/core-typings/src/ILivechatDepartmentAgents.ts index e33c80ff9245..7de0f01b258e 100644 --- a/packages/core-typings/src/ILivechatDepartmentAgents.ts +++ b/packages/core-typings/src/ILivechatDepartmentAgents.ts @@ -1,5 +1,6 @@ -export interface ILivechatDepartmentAgents { - _id: string; +import type { IRocketChatRecord } from './IRocketChatRecord'; + +export interface ILivechatDepartmentAgents extends IRocketChatRecord { departmentId: string; departmentEnabled: boolean; agentId: string; diff --git a/packages/model-typings/src/models/ILivechatDepartmentAgentsModel.ts b/packages/model-typings/src/models/ILivechatDepartmentAgentsModel.ts index 45709dc7ff37..f0f151fa70d4 100644 --- a/packages/model-typings/src/models/ILivechatDepartmentAgentsModel.ts +++ b/packages/model-typings/src/models/ILivechatDepartmentAgentsModel.ts @@ -1,5 +1,5 @@ import type { ILivechatDepartmentAgents, IUser } from '@rocket.chat/core-typings'; -import type { DeleteResult, FindCursor, FindOptions, Document, UpdateResult, Filter } from 'mongodb'; +import type { DeleteResult, FindCursor, FindOptions, Document, UpdateResult, Filter, AggregationCursor } from 'mongodb'; import type { FindPaginated, IBaseModel } from './IBaseModel'; @@ -39,23 +39,6 @@ export interface ILivechatDepartmentAgentsModel extends IBaseModel, ): FindPaginated>; - findActiveDepartmentsByAgentId(agentId: string): FindCursor; - - findActiveDepartmentsByAgentId(agentId: string, options: FindOptions): FindCursor; - - findActiveDepartmentsByAgentId

( - agentId: string, - options: FindOptions

, - ): FindCursor

; - - findActiveDepartmentsByAgentId

( - agentId: string, - options?: - | undefined - | FindOptions - | FindOptions

, - ): FindCursor | FindCursor

; - findByDepartmentIds(departmentIds: string[], options?: Record): FindCursor; findAgentsByAgentIdAndBusinessHourId(_agentId: string, _businessHourId: string): Promise; setDepartmentEnabledByDepartmentId(departmentId: string, departmentEnabled: boolean): Promise; @@ -67,7 +50,7 @@ export interface ILivechatDepartmentAgentsModel extends IBaseModel, ): Promise; findOneByAgentIdAndDepartmentId(agentId: string, departmentId: string): Promise; - saveAgent(agent: Omit): Promise; + saveAgent(agent: Omit): Promise; removeByAgentId(agentId: string): Promise; removeByDepartmentIdAndAgentId(departmentId: string, agentId: string): Promise; getNextAgentForDepartment( @@ -97,4 +80,5 @@ export interface ILivechatDepartmentAgentsModel extends IBaseModel, ): FindCursor; + findDepartmentsOfAgent(agentId: string, enabled?: boolean): AggregationCursor; } diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index ec53304605fc..b8519bf8fe02 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -3736,7 +3736,9 @@ export type OmnichannelEndpoints = { }; }; '/v1/livechat/agents/:agentId/departments': { - GET: (params?: GETLivechatAgentsAgentIdDepartmentsParams) => { departments: ILivechatDepartmentAgents[] }; + GET: (params?: GETLivechatAgentsAgentIdDepartmentsParams) => { + departments: (ILivechatDepartmentAgents & { departmentName: string })[]; + }; }; '/v1/livechat/business-hour': { GET: (params: GETBusinessHourParams) => { businessHour: ILivechatBusinessHour }; From 08ac2f39fad9857643b4a1e3fb7376332976a7f6 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Mon, 12 Aug 2024 10:56:38 -0300 Subject: [PATCH 35/80] chore: add roomUpdater on notifyUsersOnMessage (#33026) --- .../federation/server/endpoints/dispatch.js | 8 +++- .../lib/server/lib/notifyUsersOnMessage.ts | 24 +++++++--- apps/meteor/server/models/dummy/BaseDummy.ts | 7 ++- apps/meteor/server/models/raw/BaseRaw.ts | 2 +- .../meteor/server/models/raw/LivechatRooms.ts | 4 -- apps/meteor/server/models/raw/Rooms.ts | 45 ++++++++----------- .../model-typings/src/models/IBaseModel.ts | 3 ++ .../model-typings/src/models/IRoomsModel.ts | 11 ++++- 8 files changed, 60 insertions(+), 44 deletions(-) diff --git a/apps/meteor/app/federation/server/endpoints/dispatch.js b/apps/meteor/app/federation/server/endpoints/dispatch.js index 6c7fa5cad0e8..a7ab98accd36 100644 --- a/apps/meteor/app/federation/server/endpoints/dispatch.js +++ b/apps/meteor/app/federation/server/endpoints/dispatch.js @@ -293,8 +293,12 @@ const eventHandlers = { await processThreads(denormalizedMessage, room); - // Notify users - await notifyUsersOnMessage(denormalizedMessage, room); + const roomUpdater = Rooms.getUpdater(); + await notifyUsersOnMessage(denormalizedMessage, room, roomUpdater); + if (roomUpdater.hasChanges()) { + await roomUpdater.persist({ _id: room._id }); + } + sendAllNotifications(denormalizedMessage, room); messageForNotification = denormalizedMessage; } catch (err) { diff --git a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts index 76a18eba3362..0b80b9bb06df 100644 --- a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts +++ b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts @@ -1,5 +1,6 @@ import type { IMessage, IRoom, IUser, RoomType } from '@rocket.chat/core-typings'; import { isEditedMessage } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/models'; import { Subscriptions, Rooms } from '@rocket.chat/models'; import { escapeRegExp } from '@rocket.chat/string-helpers'; import moment from 'moment'; @@ -141,12 +142,12 @@ export async function updateThreadUsersSubscriptions(message: IMessage, replies: await Subscriptions.setLastReplyForRoomIdAndUserIds(message.rid, repliesPlusSender, new Date()); } -export async function notifyUsersOnMessage(message: IMessage, room: IRoom): Promise { +export async function notifyUsersOnMessage(message: IMessage, room: IRoom, roomUpdater: Updater): Promise { // Skips this callback if the message was edited and increments it if the edit was way in the past (aka imported) if (isEditedMessage(message)) { if (Math.abs(moment(message.editedAt).diff(Date.now())) > 60000) { // TODO: Review as I am not sure how else to get around this as the incrementing of the msgs count shouldn't be in this callback - await Rooms.incMsgCountById(message.rid, 1); + Rooms.getIncMsgCountUpdateQuery(1, roomUpdater); return message; } @@ -156,25 +157,25 @@ export async function notifyUsersOnMessage(message: IMessage, room: IRoom): Prom (!message.tmid || message.tshow) && (!room.lastMessage || room.lastMessage._id === message._id) ) { - await Rooms.setLastMessageById(message.rid, message); + Rooms.getLastMessageUpdateQuery(message, roomUpdater); } return message; } if (message.ts && Math.abs(moment(message.ts).diff(Date.now())) > 60000) { - await Rooms.incMsgCountById(message.rid, 1); + Rooms.getIncMsgCountUpdateQuery(1, roomUpdater); return message; } // If message sent ONLY on a thread, skips the rest as it is done on a callback specific to threads if (message.tmid && !message.tshow) { - await Rooms.incMsgCountById(message.rid, 1); + Rooms.getIncMsgCountUpdateQuery(1, roomUpdater); return message; } // Update all the room activity tracker fields - await Rooms.incMsgCountAndSetLastMessageById(message.rid, 1, message.ts, settings.get('Store_Last_Message') ? message : undefined); + Rooms.setIncMsgCountAndSetLastMessageUpdateQuery(1, message, !!settings.get('Store_Last_Message'), roomUpdater); await updateUsersSubscriptions(message, room); return message; @@ -182,7 +183,16 @@ export async function notifyUsersOnMessage(message: IMessage, room: IRoom): Prom callbacks.add( 'afterSaveMessage', - (message, room) => notifyUsersOnMessage(message, room), + async (message, room) => { + const roomUpdater = Rooms.getUpdater(); + await notifyUsersOnMessage(message, room, roomUpdater); + + if (roomUpdater.hasChanges()) { + await roomUpdater.persist({ _id: room._id }); + } + + return message; + }, callbacks.priority.MEDIUM, 'notifyUsersOnMessage', ); diff --git a/apps/meteor/server/models/dummy/BaseDummy.ts b/apps/meteor/server/models/dummy/BaseDummy.ts index 9c91036d3969..9ba590151c02 100644 --- a/apps/meteor/server/models/dummy/BaseDummy.ts +++ b/apps/meteor/server/models/dummy/BaseDummy.ts @@ -1,6 +1,7 @@ import type { RocketChatRecordDeleted } from '@rocket.chat/core-typings'; import type { DefaultFields, FindPaginated, IBaseModel, InsertionModel, ResultFields } from '@rocket.chat/model-typings'; -import { getCollectionName } from '@rocket.chat/models'; +import { getCollectionName, UpdaterImpl } from '@rocket.chat/models'; +import type { Updater } from '@rocket.chat/models'; import type { BulkWriteOptions, ChangeStream, @@ -40,6 +41,10 @@ export class BaseDummy< // nothing to do } + public getUpdater(): Updater { + return new UpdaterImpl(this.col as unknown as IBaseModel); + } + getCollectionName(): string { return this.collectionName; } diff --git a/apps/meteor/server/models/raw/BaseRaw.ts b/apps/meteor/server/models/raw/BaseRaw.ts index 7d4c78697ecb..0a41a0fbb3eb 100644 --- a/apps/meteor/server/models/raw/BaseRaw.ts +++ b/apps/meteor/server/models/raw/BaseRaw.ts @@ -110,7 +110,7 @@ export abstract class BaseRaw< return this.collectionName; } - protected getUpdater(): Updater { + public getUpdater(): Updater { return new UpdaterImpl(this.col as unknown as IBaseModel); } diff --git a/apps/meteor/server/models/raw/LivechatRooms.ts b/apps/meteor/server/models/raw/LivechatRooms.ts index b588b48cef5b..ebe10ec67fbc 100644 --- a/apps/meteor/server/models/raw/LivechatRooms.ts +++ b/apps/meteor/server/models/raw/LivechatRooms.ts @@ -78,10 +78,6 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive ]; } - getUpdater(): Updater { - return super.getUpdater(); - } - getQueueMetrics({ departmentId, agentId, diff --git a/apps/meteor/server/models/raw/Rooms.ts b/apps/meteor/server/models/raw/Rooms.ts index f967068158f9..bb496bf79971 100644 --- a/apps/meteor/server/models/raw/Rooms.ts +++ b/apps/meteor/server/models/raw/Rooms.ts @@ -10,6 +10,7 @@ import type { } from '@rocket.chat/core-typings'; import type { FindPaginated, IRoomsModel, IChannelsWithNumberOfMessagesBetweenDate } from '@rocket.chat/model-typings'; import { Subscriptions } from '@rocket.chat/models'; +import type { Updater } from '@rocket.chat/models'; import { escapeRegExp } from '@rocket.chat/string-helpers'; import type { AggregationCursor, @@ -888,6 +889,10 @@ export class RoomsRaw extends BaseRaw implements IRoomsModel { return this.updateOne(query, update); } + getIncMsgCountUpdateQuery(inc: number, roomUpdater: Updater): Updater { + return roomUpdater.inc('msgs', inc); + } + decreaseMessageCountById(_id: IRoom['_id'], count = 1) { return this.incMsgCountById(_id, -count); } @@ -1527,25 +1532,19 @@ export class RoomsRaw extends BaseRaw implements IRoomsModel { return this.updateOne(query, update); } - incMsgCountAndSetLastMessageById( - _id: IRoom['_id'], - inc = 1, - lastMessageTimestamp: NonNullable, - lastMessage?: IMessage, - ): Promise { - const query: Filter = { _id }; + setIncMsgCountAndSetLastMessageUpdateQuery( + inc: number, + lastMessage: IMessage, + shouldStoreLastMessage: boolean, + roomUpdater: Updater, + ): Updater { + roomUpdater.inc('msgs', inc).set('lm', lastMessage.ts); - const update: UpdateFilter = { - $set: { - lm: lastMessageTimestamp, - ...(lastMessage ? { lastMessage } : {}), - }, - $inc: { - msgs: inc, - }, - }; + if (shouldStoreLastMessage) { + roomUpdater.set('lastMessage', lastMessage); + } - return this.updateOne(query, update); + return roomUpdater; } incUsersCountById(_id: IRoom['_id'], inc = 1): Promise { @@ -1578,16 +1577,8 @@ export class RoomsRaw extends BaseRaw implements IRoomsModel { return this.updateMany(query, update); } - setLastMessageById(_id: IRoom['_id'], lastMessage: IRoom['lastMessage']): Promise { - const query: Filter = { _id }; - - const update: UpdateFilter = { - $set: { - lastMessage, - }, - }; - - return this.updateOne(query, update); + getLastMessageUpdateQuery(lastMessage: IRoom['lastMessage'], roomUpdater: Updater): Updater { + return roomUpdater.set('lastMessage', lastMessage); } async resetLastMessageById(_id: IRoom['_id'], lastMessage: IRoom['lastMessage'] | null, msgCountDelta?: number): Promise { diff --git a/packages/model-typings/src/models/IBaseModel.ts b/packages/model-typings/src/models/IBaseModel.ts index fa053fef9ec8..59a5f67273eb 100644 --- a/packages/model-typings/src/models/IBaseModel.ts +++ b/packages/model-typings/src/models/IBaseModel.ts @@ -22,6 +22,8 @@ import type { WithId, } from 'mongodb'; +import type { Updater } from '../updater'; + export type DefaultFields = Record | Record | void; export type ResultFields = Defaults extends void ? Base @@ -48,6 +50,7 @@ export interface IBaseModel< createIndexes(): Promise; getCollectionName(): string; + getUpdater(): Updater; findOneAndUpdate(query: Filter, update: UpdateFilter | T, options?: FindOneAndUpdateOptions): Promise>; diff --git a/packages/model-typings/src/models/IRoomsModel.ts b/packages/model-typings/src/models/IRoomsModel.ts index a88a5bde7f4e..1808c9f361f4 100644 --- a/packages/model-typings/src/models/IRoomsModel.ts +++ b/packages/model-typings/src/models/IRoomsModel.ts @@ -1,6 +1,7 @@ import type { IDirectMessageRoom, IMessage, IOmnichannelGenericRoom, IRoom, IRoomFederated, ITeam, IUser } from '@rocket.chat/core-typings'; import type { AggregationCursor, DeleteResult, Document, FindCursor, FindOptions, UpdateOptions, UpdateResult } from 'mongodb'; +import type { Updater } from '../updater'; import type { FindPaginated, IBaseModel } from './IBaseModel'; export interface IChannelsWithNumberOfMessagesBetweenDate { @@ -162,6 +163,7 @@ export interface IRoomsModel extends IBaseModel { countFederatedRooms(): Promise; incMsgCountById(rid: string, inc: number): Promise; + getIncMsgCountUpdateQuery(inc: number, roomUpdater: Updater): Updater; decreaseMessageCountById(rid: string, dec: number): Promise; findOneByIdOrName(_idOrName: string, options?: FindOptions): Promise; setCallStatus(_id: string, callStatus: IRoom['callStatus']): Promise; @@ -234,10 +236,15 @@ export interface IRoomsModel extends IBaseModel { archiveById(rid: string): Promise; unarchiveById(rid: string): Promise; setNameById(rid: string, name: string, fname: string): Promise; - incMsgCountAndSetLastMessageById(rid: IRoom['_id'], inc: number, lastMessageTs: Date, lastMessage?: IMessage): Promise; + setIncMsgCountAndSetLastMessageUpdateQuery( + inc: number, + lastMessage: IMessage, + shouldStoreLastMessage: boolean, + roomUpdater: Updater, + ): Updater; incUsersCountById(rid: string, inc: number): Promise; incUsersCountNotDMsByIds(rids: string[], inc: number): Promise; - setLastMessageById(rid: string, lastMessage: IRoom['lastMessage']): Promise; + getLastMessageUpdateQuery(lastMessage: IRoom['lastMessage'], roomUpdater: Updater): Updater; resetLastMessageById(rid: string, lastMessage: IMessage | null, msgCountDelta?: number): Promise; replaceUsername(username: string, newUsername: string): Promise; replaceMutedUsername(username: string, newUsername: string): Promise; From 127866ce97ce74479ceba1d9826300be8b277a77 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 12 Aug 2024 09:55:58 -0600 Subject: [PATCH 36/80] feat(audit): New endpoint for listing members of any room (#32916) --- .changeset/funny-boats-guess.md | 6 + .../audit/components/AuditFiltersDisplay.tsx | 16 +- .../views/audit/components/AuditLogEntry.tsx | 8 +- apps/meteor/ee/server/api/audit.ts | 95 ++++++ apps/meteor/ee/server/lib/audit/startup.ts | 1 + apps/meteor/ee/server/startup/audit.ts | 1 + apps/meteor/tests/end-to-end/api/audit.ts | 301 ++++++++++++++++++ packages/core-typings/src/ee/IAuditLog.ts | 5 +- packages/i18n/src/locales/en.i18n.json | 3 + 9 files changed, 425 insertions(+), 11 deletions(-) create mode 100644 .changeset/funny-boats-guess.md create mode 100644 apps/meteor/ee/server/api/audit.ts create mode 100644 apps/meteor/tests/end-to-end/api/audit.ts diff --git a/.changeset/funny-boats-guess.md b/.changeset/funny-boats-guess.md new file mode 100644 index 000000000000..076acff98329 --- /dev/null +++ b/.changeset/funny-boats-guess.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/i18n": minor +--- + +Added a new Audit endpoint `audit/rooms.members` that allows users with `view-members-list-all-rooms` to fetch a list of the members of any room even if the user is not part of it. diff --git a/apps/meteor/client/views/audit/components/AuditFiltersDisplay.tsx b/apps/meteor/client/views/audit/components/AuditFiltersDisplay.tsx index dadb59b04777..276d8c355c9b 100644 --- a/apps/meteor/client/views/audit/components/AuditFiltersDisplay.tsx +++ b/apps/meteor/client/views/audit/components/AuditFiltersDisplay.tsx @@ -9,20 +9,24 @@ import { useFormatDate } from '../../../hooks/useFormatDate'; type AuditFiltersDisplayProps = { users?: IUser['username'][]; room?: IRoom['name']; - startDate: Date; - endDate: Date; + startDate?: Date; + endDate?: Date; + filters?: string; }; -const AuditFiltersDisplay = ({ users, room, startDate, endDate }: AuditFiltersDisplayProps): ReactElement => { +const AuditFiltersDisplay = ({ users, room, startDate, endDate, filters }: AuditFiltersDisplayProps): ReactElement => { const formatDate = useFormatDate(); const t = useTranslation(); return ( {users?.length ? users.map((user) => `@${user}`).join(' : ') : `#${room}`} - - {formatDate(startDate)} {t('Date_to')} {formatDate(endDate)} {/* TODO: fix this translation */} - + {startDate && endDate ? ( + + {formatDate(startDate)} {t('Date_to')} {formatDate(endDate)} {/* TODO: fix this translation */} + + ) : null} + {filters ? {filters} : null} ); }; diff --git a/apps/meteor/client/views/audit/components/AuditLogEntry.tsx b/apps/meteor/client/views/audit/components/AuditLogEntry.tsx index 0ec56c1e5652..8e3f9788880b 100644 --- a/apps/meteor/client/views/audit/components/AuditLogEntry.tsx +++ b/apps/meteor/client/views/audit/components/AuditLogEntry.tsx @@ -2,6 +2,7 @@ import type { IAuditLog } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; import { useMediaQuery } from '@rocket.chat/fuselage-hooks'; import { UserAvatar } from '@rocket.chat/ui-avatar'; +import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { memo, useMemo } from 'react'; @@ -13,10 +14,11 @@ type AuditLogEntryProps = { value: IAuditLog }; const AuditLogEntry = ({ value: { u, results, ts, _id, fields } }: AuditLogEntryProps): ReactElement => { const formatDateAndTime = useFormatDateAndTime(); + const t = useTranslation(); const { username, name, avatarETag } = u; - const { msg, users, room, startDate, endDate } = fields; + const { msg, users, room, startDate, endDate, type, filters } = fields; const when = useMemo(() => formatDateAndTime(ts), [formatDateAndTime, ts]); @@ -43,12 +45,12 @@ const AuditLogEntry = ({ value: { u, results, ts, _id, fields } }: AuditLogEntry - {msg} + {type === 'room_member_list' ? t('Room_members_list') : msg} {when} {results} - + ); diff --git a/apps/meteor/ee/server/api/audit.ts b/apps/meteor/ee/server/api/audit.ts new file mode 100644 index 000000000000..748368f0d569 --- /dev/null +++ b/apps/meteor/ee/server/api/audit.ts @@ -0,0 +1,95 @@ +import type { IUser, IRoom } from '@rocket.chat/core-typings'; +import { Rooms, AuditLog } from '@rocket.chat/models'; +import type { PaginatedRequest, PaginatedResult } from '@rocket.chat/rest-typings'; +import Ajv from 'ajv'; + +import { API } from '../../../app/api/server/api'; +import { getPaginationItems } from '../../../app/api/server/helpers/getPaginationItems'; +import { findUsersOfRoom } from '../../../server/lib/findUsersOfRoom'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type AuditRoomMembersParams = PaginatedRequest<{ + roomId: string; + filter: string; +}>; + +const auditRoomMembersSchema = { + type: 'object', + properties: { + roomId: { type: 'string', minLength: 1 }, + filter: { type: 'string' }, + count: { type: 'number' }, + offset: { type: 'number' }, + sort: { type: 'string' }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isAuditRoomMembersProps = ajv.compile(auditRoomMembersSchema); + +declare module '@rocket.chat/rest-typings' { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Endpoints { + '/v1/audit/rooms.members': { + GET: ( + params: AuditRoomMembersParams, + ) => PaginatedResult<{ members: Pick[] }>; + }; + } +} + +API.v1.addRoute( + 'audit/rooms.members', + { authRequired: true, permissionsRequired: ['view-members-list-all-rooms'], validateParams: isAuditRoomMembersProps }, + { + async get() { + const { roomId, filter } = this.queryParams; + const { count: limit, offset: skip } = await getPaginationItems(this.queryParams); + const { sort } = await this.parseJsonQuery(); + + const room = await Rooms.findOneById>(roomId, { projection: { _id: 1, name: 1, fname: 1 } }); + if (!room) { + return API.v1.notFound(); + } + + const { cursor, totalCount } = findUsersOfRoom({ + rid: room._id, + filter, + skip, + limit, + ...(sort?.username && { sort: { username: sort.username } }), + }); + + const [members, total] = await Promise.all([cursor.toArray(), totalCount]); + + await AuditLog.insertOne({ + ts: new Date(), + results: total, + u: { + _id: this.user._id, + username: this.user.username, + name: this.user.name, + avatarETag: this.user.avatarETag, + }, + fields: { + msg: 'Room_members_list', + rids: [room._id], + type: 'room_member_list', + room: room.name || room.fname, + filters: filter, + }, + }); + + return API.v1.success({ + members, + count: members.length, + offset: skip, + total, + }); + }, + }, +); diff --git a/apps/meteor/ee/server/lib/audit/startup.ts b/apps/meteor/ee/server/lib/audit/startup.ts index ba50eb48e244..076336b50fe6 100644 --- a/apps/meteor/ee/server/lib/audit/startup.ts +++ b/apps/meteor/ee/server/lib/audit/startup.ts @@ -6,6 +6,7 @@ export const createPermissions = async () => { const permissions = [ { _id: 'can-audit', roles: ['admin', 'auditor'] }, { _id: 'can-audit-log', roles: ['admin', 'auditor-log'] }, + { _id: 'view-members-list-all-rooms', roles: ['admin', 'auditor'] }, ]; const defaultRoles = [ diff --git a/apps/meteor/ee/server/startup/audit.ts b/apps/meteor/ee/server/startup/audit.ts index c38794a7582e..9f8135a16a65 100644 --- a/apps/meteor/ee/server/startup/audit.ts +++ b/apps/meteor/ee/server/startup/audit.ts @@ -4,6 +4,7 @@ import { createPermissions } from '../lib/audit/startup'; await License.onLicense('auditing', async () => { await import('../lib/audit/methods'); + await import('../api/audit'); await createPermissions(); }); diff --git a/apps/meteor/tests/end-to-end/api/audit.ts b/apps/meteor/tests/end-to-end/api/audit.ts new file mode 100644 index 000000000000..ba62caf621b8 --- /dev/null +++ b/apps/meteor/tests/end-to-end/api/audit.ts @@ -0,0 +1,301 @@ +import type { Credentials } from '@rocket.chat/api-client'; +import type { IRoom, IUser } from '@rocket.chat/core-typings'; +import { Random } from '@rocket.chat/random'; +import { expect } from 'chai'; +import EJSON from 'ejson'; +import { before, describe, it, after } from 'mocha'; + +import { getCredentials, api, request, credentials, methodCall } from '../../data/api-data'; +import { updatePermission } from '../../data/permissions.helper'; +import { createRoom, deleteRoom } from '../../data/rooms.helper'; +import { password } from '../../data/user'; +import { createUser, deleteUser, login } from '../../data/users.helper'; +import { IS_EE } from '../../e2e/config/constants'; + +(IS_EE ? describe : describe.skip)('Audit Panel', () => { + let testChannel: IRoom; + let testPrivateChannel: IRoom; + let dummyUser: IUser; + let auditor: IUser; + let auditorCredentials: Credentials; + before((done) => getCredentials(done)); + before(async () => { + testChannel = (await createRoom({ type: 'c', name: `chat.api-test-${Date.now()}` })).body.channel; + testPrivateChannel = (await createRoom({ type: 'p', name: `chat.api-test-${Date.now()}` })).body.group; + dummyUser = await createUser(); + auditor = await createUser({ roles: ['user', 'auditor'] }); + + auditorCredentials = await login(auditor.username, password); + }); + after(async () => { + await deleteRoom({ type: 'c', roomId: testChannel._id }); + await deleteUser({ _id: dummyUser._id }); + await deleteUser({ _id: auditor._id }); + await deleteRoom({ type: 'p', roomId: testPrivateChannel._id }); + }); + + describe('audit/rooms.members [no permissions]', () => { + before(async () => { + await updatePermission('view-members-list-all-rooms', []); + }); + after(async () => { + await updatePermission('view-members-list-all-rooms', ['admin', 'auditor']); + }); + it('should fail if user does not have view-members-list-all-rooms permission', async () => { + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: 'GENERAL', + }) + .expect(403); + await request + .get(api('audit/rooms.members')) + .set(auditorCredentials) + .query({ + roomId: 'GENERAL', + }) + .expect(403); + }); + }); + + describe('audit/rooms.members', () => { + it('should fail if user is not logged in', async () => { + await request + .get(api('audit/rooms.members')) + .query({ + roomId: 'GENERAL', + }) + .expect(401); + }); + it('should fail if roomId is invalid', async () => { + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: Random.id(), + }) + .expect(404); + }); + it('should fail if roomId is not present', async () => { + await request.get(api('audit/rooms.members')).set(credentials).query({}).expect(400); + }); + it('should fail if roomId is an empty string', async () => { + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: '', + }) + .expect(400); + }); + it('should fetch the members of a room', async () => { + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: testChannel._id, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.members).to.be.an('array'); + expect(res.body.members).to.have.lengthOf(1); + }); + }); + it('should persist a log entry', async () => { + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: testChannel._id, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.members).to.be.an('array'); + expect(res.body.members).to.have.lengthOf(1); + }); + + await request + .post(methodCall('auditGetAuditions')) + .set(credentials) + .send({ + message: EJSON.stringify({ + method: 'auditGetAuditions', + params: [{ startDate: new Date(Date.now() - 86400000), endDate: new Date() }], + id: 'id', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + const message = JSON.parse(res.body.message); + + expect(message.result).to.be.an('array').with.lengthOf.greaterThan(1); + const entry = message.result.find((audition: any) => { + return audition.fields.rids.includes(testChannel._id); + }); + expect(entry).to.have.property('u').that.is.an('object').deep.equal({ + _id: 'rocketchat.internal.admin.test', + username: 'rocketchat.internal.admin.test', + name: 'RocketChat Internal Admin Test', + }); + expect(entry).to.have.property('fields').that.is.an('object'); + const { fields } = entry; + + expect(fields).to.have.property('msg', 'Room_members_list'); + expect(fields).to.have.property('rids').that.is.an('array').with.lengthOf(1); + }); + }); + it('should fetch the members of a room with offset and count', async () => { + await request + .post(methodCall('addUsersToRoom')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'addUsersToRoom', + params: [{ rid: testChannel._id, users: [dummyUser.username] }], + id: 'id', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }); + + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: testChannel._id, + offset: 1, + count: 1, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.members).to.be.an('array'); + expect(res.body.members).to.have.lengthOf(1); + expect(res.body.members[0].username).to.be.equal(dummyUser.username); + expect(res.body.total).to.be.equal(2); + expect(res.body.offset).to.be.equal(1); + expect(res.body.count).to.be.equal(1); + }); + }); + + it('should filter by username', async () => { + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: testChannel._id, + filter: dummyUser.username, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.members).to.be.an('array'); + expect(res.body.members).to.have.lengthOf(1); + expect(res.body.members[0].username).to.be.equal(dummyUser.username); + }); + }); + + it('should filter by user name', async () => { + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: testChannel._id, + filter: dummyUser.name, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.members).to.be.an('array'); + expect(res.body.members).to.have.lengthOf(1); + expect(res.body.members[0].name).to.be.equal(dummyUser.name); + }); + }); + + it('should sort by username', async () => { + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: testChannel._id, + sort: '{ "username": -1 }', + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.members).to.be.an('array'); + expect(res.body.members).to.have.lengthOf(2); + expect(res.body.members[1].username).to.be.equal('rocketchat.internal.admin.test'); + expect(res.body.members[0].username).to.be.equal(dummyUser.username); + }); + }); + + it('should not allow nosqlinjection on filter param', async () => { + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: testChannel._id, + filter: '{ "$ne": "rocketchat.internal.admin.test" }', + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.members).to.be.an('array'); + expect(res.body.members).to.have.lengthOf(0); + }); + + await request + .get(api('audit/rooms.members')) + .set(credentials) + .query({ + roomId: testChannel._id, + filter: { username: 'rocketchat.internal.admin.test' }, + }) + .expect(400); + }); + + it('should allow to fetch info even if user is not in the room', async () => { + await request + .get(api('audit/rooms.members')) + .set(auditorCredentials) + .query({ + roomId: testChannel._id, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.members).to.be.an('array'); + expect(res.body.members[0].username).to.be.equal('rocketchat.internal.admin.test'); + expect(res.body.members[1].username).to.be.equal(dummyUser.username); + expect(res.body.total).to.be.equal(2); + }); + }); + + it('should allow to fetch info from private rooms', async () => { + await request + .get(api('audit/rooms.members')) + .set(auditorCredentials) + .query({ + roomId: testPrivateChannel._id, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.members).to.be.an('array'); + expect(res.body.members[0].username).to.be.equal('rocketchat.internal.admin.test'); + expect(res.body.total).to.be.equal(1); + }); + }); + }); +}); diff --git a/packages/core-typings/src/ee/IAuditLog.ts b/packages/core-typings/src/ee/IAuditLog.ts index de1c6ff5213f..4618400d8017 100644 --- a/packages/core-typings/src/ee/IAuditLog.ts +++ b/packages/core-typings/src/ee/IAuditLog.ts @@ -12,12 +12,13 @@ export interface IAuditLog extends IRocketChatRecord { fields: { type: string; msg: IMessage['msg']; - startDate: Date; - endDate: Date; + startDate?: Date; + endDate?: Date; rids?: IRoom['_id'][]; room: IRoom['name']; users?: IUser['username'][]; visitor?: ILivechatVisitor['_id']; agent?: ILivechatAgent['_id']; + filters?: string; }; } diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 12f0dbf628c5..c270bb9bffb1 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -5791,6 +5791,9 @@ "view-all-teams_description": "Permission to view all teams", "view-all-team-channels": "View All Team Channels", "view-all-team-channels_description": "Permission to view all team's channels", + "view-members-list-all-rooms": "Can view members in all rooms", + "view-members-list-all-rooms_description": "Gives the ability to see the members list in all rooms, even those the user is not part of", + "Room_members_list": "Members list", "view-broadcast-member-list": "View Members List in Broadcast Room", "view-broadcast-member-list_description": "Permission to view list of users in broadcast channel", "view-c-room": "View Public Channel", From fd8b321225c13a7cf66b8a69e9f1906e5320ba6d Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 13 Aug 2024 10:51:50 -0300 Subject: [PATCH 37/80] ci: regression `actions/upload-artifact@v4` meteor build production (#33032) --- .github/actions/meteor-build/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/meteor-build/action.yml b/.github/actions/meteor-build/action.yml index 87c0c2d4a652..dfbc1cef4150 100644 --- a/.github/actions/meteor-build/action.yml +++ b/.github/actions/meteor-build/action.yml @@ -128,3 +128,4 @@ runs: with: name: build path: /tmp/Rocket.Chat.tar.gz + overwrite: true From c11f3722df9ae8f41424248fb4180f8aca1e1cba Mon Sep 17 00:00:00 2001 From: Tiago Evangelista Pinto Date: Tue, 13 Aug 2024 13:07:50 -0300 Subject: [PATCH 38/80] fix(ui-kit): Missing a peer dependency (#33000) --- .changeset/calm-tigers-peel.md | 5 ++ packages/ui-kit/package.json | 125 +++++++++++++++++---------------- yarn.lock | 59 ++++++++++++++-- 3 files changed, 124 insertions(+), 65 deletions(-) create mode 100644 .changeset/calm-tigers-peel.md diff --git a/.changeset/calm-tigers-peel.md b/.changeset/calm-tigers-peel.md new file mode 100644 index 000000000000..32feed6f7107 --- /dev/null +++ b/.changeset/calm-tigers-peel.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/ui-kit": patch +--- + +fix UiKit error message: Failed to resolve module: @rocket.chat/icons diff --git a/packages/ui-kit/package.json b/packages/ui-kit/package.json index 817b03a22ba7..44aac1e25d17 100644 --- a/packages/ui-kit/package.json +++ b/packages/ui-kit/package.json @@ -1,62 +1,67 @@ { - "name": "@rocket.chat/ui-kit", - "version": "0.36.0", - "description": "Interactive UI elements for Rocket.Chat Apps", - "homepage": "https://rocket.chat", - "author": { - "name": "Rocket.Chat", - "url": "https://rocket.chat/" - }, - "license": "MIT", - "repository": { - "type": "git", - "url": "git+https://github.com/RocketChat/Rocket.Chat.git" - }, - "bugs": { - "url": "https://github.com/RocketChat/Rocket.Chat/issues" - }, - "main": "dist/cjs/index.js", - "module": "dist/esm/index.js", - "types": "dist/esm/index.d.ts", - "files": [ - "/dist" - ], - "publishConfig": { - "access": "public" - }, - "scripts": { - "build": "run-s .:build:prepare .:build:clean .:build:esm .:build:cjs", - ".:build:prepare": "ts-patch install && typia patch", - ".:build:clean": "rimraf dist", - ".:build:esm": "tsc -p tsconfig.esm.json", - ".:build:cjs": "tsc -p tsconfig.cjs.json", - "typecheck": "tsc --noEmit", - "lint": "eslint . --ext .ts,.tsx", - "test": "jest" - }, - "devDependencies": { - "@babel/core": "~7.21.4", - "@babel/eslint-parser": "~7.23.3", - "@babel/plugin-transform-runtime": "~7.21.4", - "@babel/preset-env": "~7.21.4", - "@rocket.chat/eslint-config": "workspace:~", - "@rocket.chat/jest-presets": "workspace:~", - "@types/jest": "~29.5.12", - "babel-loader": "~9.1.2", - "eslint": "~8.45.0", - "jest": "~29.7.0", - "npm-run-all": "~4.1.5", - "prettier": "~2.8.8", - "rimraf": "~3.0.2", - "ts-loader": "~9.4.2", - "ts-node": "~10.9.1", - "ts-patch": "~3.0.2", - "typescript": "~5.3.3" - }, - "dependencies": { - "typia": "~5.3.3" - }, - "volta": { - "extends": "../../package.json" - } + "name": "@rocket.chat/ui-kit", + "version": "0.36.0", + "description": "Interactive UI elements for Rocket.Chat Apps", + "homepage": "https://rocket.chat", + "author": { + "name": "Rocket.Chat", + "url": "https://rocket.chat/" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/RocketChat/Rocket.Chat.git" + }, + "bugs": { + "url": "https://github.com/RocketChat/Rocket.Chat/issues" + }, + "main": "dist/cjs/index.js", + "module": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "files": [ + "/dist" + ], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "run-s .:build:prepare .:build:clean .:build:esm .:build:cjs", + ".:build:prepare": "ts-patch install && typia patch", + ".:build:clean": "rimraf dist", + ".:build:esm": "tsc -p tsconfig.esm.json", + ".:build:cjs": "tsc -p tsconfig.cjs.json", + "typecheck": "tsc --noEmit", + "lint": "eslint . --ext .ts,.tsx", + "test": "jest" + }, + "devDependencies": { + "@babel/core": "~7.21.4", + "@babel/eslint-parser": "~7.23.3", + "@babel/plugin-transform-runtime": "~7.21.4", + "@babel/preset-env": "~7.21.4", + "@rocket.chat/eslint-config": "workspace:~", + "@rocket.chat/icons": "^0.36.0", + "@rocket.chat/jest-presets": "workspace:~", + "@types/jest": "~29.5.12", + "babel-loader": "~9.1.2", + "eslint": "~8.45.0", + "jest": "~29.7.0", + "npm-run-all": "~4.1.5", + "prettier": "~2.8.8", + "rimraf": "~3.0.2", + "ts-jest": "~29.1.1", + "ts-loader": "~9.4.2", + "ts-node": "~10.9.1", + "ts-patch": "~3.0.2", + "typescript": "~5.3.3" + }, + "dependencies": { + "typia": "~5.3.3" + }, + "peerDependencies": { + "@rocket.chat/icons": "*" + }, + "volta": { + "extends": "../../package.json" + } } diff --git a/yarn.lock b/yarn.lock index 00ca4ab5c550..de477be8048a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10360,6 +10360,7 @@ __metadata: "@babel/plugin-transform-runtime": ~7.21.4 "@babel/preset-env": ~7.21.4 "@rocket.chat/eslint-config": "workspace:~" + "@rocket.chat/icons": ^0.36.0 "@rocket.chat/jest-presets": "workspace:~" "@types/jest": ~29.5.12 babel-loader: ~9.1.2 @@ -10368,11 +10369,14 @@ __metadata: npm-run-all: ~4.1.5 prettier: ~2.8.8 rimraf: ~3.0.2 + ts-jest: ~29.1.1 ts-loader: ~9.4.2 ts-node: ~10.9.1 ts-patch: ~3.0.2 typescript: ~5.3.3 typia: ~5.3.3 + peerDependencies: + "@rocket.chat/icons": "*" languageName: unknown linkType: soft @@ -17703,6 +17707,15 @@ __metadata: languageName: node linkType: hard +"bs-logger@npm:0.x": + version: 0.2.6 + resolution: "bs-logger@npm:0.2.6" + dependencies: + fast-json-stable-stringify: 2.x + checksum: d34bdaf68c64bd099ab97c3ea608c9ae7d3f5faa1178b3f3f345acd94e852e608b2d4f9103fb2e503f5e69780e98293df41691b84be909b41cf5045374d54606 + languageName: node + linkType: hard + "bs58@npm:^4.0.1": version: 4.0.1 resolution: "bs58@npm:4.0.1" @@ -23269,7 +23282,7 @@ __metadata: languageName: node linkType: hard -"fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": +"fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb @@ -28234,7 +28247,7 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^29.7.0": +"jest-util@npm:^29.0.0, jest-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-util@npm:29.7.0" dependencies: @@ -29455,7 +29468,7 @@ __metadata: languageName: node linkType: hard -"lodash.memoize@npm:^4.1.2": +"lodash.memoize@npm:4.x, lodash.memoize@npm:^4.1.2": version: 4.1.2 resolution: "lodash.memoize@npm:4.1.2" checksum: 9ff3942feeccffa4f1fafa88d32f0d24fdc62fd15ded5a74a5f950ff5f0c6f61916157246744c620173dddf38d37095a92327d5fd3861e2063e736a5c207d089 @@ -29795,7 +29808,7 @@ __metadata: languageName: node linkType: hard -"make-error@npm:^1.1.1": +"make-error@npm:1.x, make-error@npm:^1.1.1": version: 1.3.6 resolution: "make-error@npm:1.3.6" checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 @@ -39983,6 +39996,42 @@ __metadata: languageName: node linkType: hard +"ts-jest@npm:~29.1.1": + version: 29.1.5 + resolution: "ts-jest@npm:29.1.5" + dependencies: + bs-logger: 0.x + fast-json-stable-stringify: 2.x + jest-util: ^29.0.0 + json5: ^2.2.3 + lodash.memoize: 4.x + make-error: 1.x + semver: ^7.5.3 + yargs-parser: ^21.0.1 + peerDependencies: + "@babel/core": ">=7.0.0-beta.0 <8" + "@jest/transform": ^29.0.0 + "@jest/types": ^29.0.0 + babel-jest: ^29.0.0 + jest: ^29.0.0 + typescript: ">=4.3 <6" + peerDependenciesMeta: + "@babel/core": + optional: true + "@jest/transform": + optional: true + "@jest/types": + optional: true + babel-jest: + optional: true + esbuild: + optional: true + bin: + ts-jest: cli.js + checksum: 96bfdea46d7faa83457c2647806a31a86f28656f703515fee9f6d2ff1ccfc58ccfbbe3ae9283f40141a85af0def30afe887843be5b002c08ed5d5189c941eab1 + languageName: node + linkType: hard + "ts-loader@npm:~9.4.2": version: 9.4.4 resolution: "ts-loader@npm:9.4.4" @@ -42953,7 +43002,7 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^21.1.1": +"yargs-parser@npm:^21.0.1, yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c From d9995a2151dae649dbfc74e1dc561cfd9bf52a88 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 13 Aug 2024 15:34:31 -0300 Subject: [PATCH 39/80] refactor: Cover implicit `any` types (#33030) --- packages/fuselage-ui-kit/src/blocks/InputBlock.tsx | 10 +++++++++- .../ChannelsSelectElement/ChannelsSelectElement.tsx | 4 ++-- .../MultiChannelsSelectElement.tsx | 4 ++-- .../src/elements/MultiStaticSelectElement.tsx | 2 +- .../src/elements/StaticSelectElement.tsx | 2 +- .../UsersSelectElement/MultiUsersSelectElement.tsx | 4 ++-- .../UsersSelectElement/UsersSelectElement.tsx | 4 ++-- .../src/surfaces/createSurfaceRenderer.tsx | 4 ++-- .../src/elements/Timestamp/ErrorBoundary.tsx | 11 ++++++++--- .../ui-client/src/components/CustomFieldsForm.tsx | 6 +++--- .../MultiSelectCustom/MultiSelectCustom.tsx | 4 ++-- .../MultiSelectCustom/MultiSelectCustomList.tsx | 2 +- .../src/Components/FlowContainer/FlowContainer.tsx | 12 +++++++----- .../src/Components/SurfaceSelect/SurfaceSelect.tsx | 2 +- .../src/components/LoginSwitchLanguageFooter.tsx | 5 ++++- 15 files changed, 47 insertions(+), 29 deletions(-) diff --git a/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx b/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx index 979e04e808c7..9844372a3060 100644 --- a/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx @@ -46,7 +46,15 @@ const InputBlock = ({ {surfaceRenderer.renderInputBlockElement(inputElement, 0)} {error && {error}} - {block.hint && {block.hint}} + {block.hint && ( + + {surfaceRenderer.renderTextObject( + block.hint, + 0, + UiKit.BlockContext.NONE + )} + + )} ); }; diff --git a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.tsx b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.tsx index 49b24545dbf1..a26037373aa7 100644 --- a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.tsx @@ -22,8 +22,8 @@ const ChannelsSelectElement = ({ const options = useChannelsData({ filter: filterDebounced }); const handleChange = useCallback( - (value) => { - action({ target: { value } }); + (value: string | string[]) => { + if (!Array.isArray(value)) action({ target: { value } }); }, [action] ); diff --git a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/MultiChannelsSelectElement.tsx b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/MultiChannelsSelectElement.tsx index 78bf07bbf599..b050a137860d 100644 --- a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/MultiChannelsSelectElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/MultiChannelsSelectElement.tsx @@ -22,8 +22,8 @@ const MultiChannelsSelectElement = ({ const options = useChannelsData({ filter: filterDebounced }); const handleChange = useCallback( - (value) => { - action({ target: { value } }); + (value: string | string[]) => { + if (Array.isArray(value)) action({ target: { value } }); }, [action] ); diff --git a/packages/fuselage-ui-kit/src/elements/MultiStaticSelectElement.tsx b/packages/fuselage-ui-kit/src/elements/MultiStaticSelectElement.tsx index a1948a921f49..9bb5746f7ef0 100644 --- a/packages/fuselage-ui-kit/src/elements/MultiStaticSelectElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/MultiStaticSelectElement.tsx @@ -27,7 +27,7 @@ const MultiStaticSelectElement = ({ ); const handleChange = useCallback( - (value) => { + (value: string[]) => { action({ target: { value } }); }, [action] diff --git a/packages/fuselage-ui-kit/src/elements/StaticSelectElement.tsx b/packages/fuselage-ui-kit/src/elements/StaticSelectElement.tsx index c68a7f067a8d..549ef2d8bd6e 100644 --- a/packages/fuselage-ui-kit/src/elements/StaticSelectElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/StaticSelectElement.tsx @@ -26,7 +26,7 @@ const StaticSelectElement = ({ ); const handleChange = useCallback( - (value) => { + (value: string) => { action({ target: { value } }); }, [action] diff --git a/packages/fuselage-ui-kit/src/elements/UsersSelectElement/MultiUsersSelectElement.tsx b/packages/fuselage-ui-kit/src/elements/UsersSelectElement/MultiUsersSelectElement.tsx index bdf7bfef4a31..3fd3351c2bb6 100644 --- a/packages/fuselage-ui-kit/src/elements/UsersSelectElement/MultiUsersSelectElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/UsersSelectElement/MultiUsersSelectElement.tsx @@ -31,8 +31,8 @@ const MultiUsersSelectElement = ({ const data = useUsersData({ filter: debouncedFilter }); const handleChange = useCallback( - (value) => { - action({ target: { value } }); + (value: string | string[]) => { + if (Array.isArray(value)) action({ target: { value } }); }, [action] ); diff --git a/packages/fuselage-ui-kit/src/elements/UsersSelectElement/UsersSelectElement.tsx b/packages/fuselage-ui-kit/src/elements/UsersSelectElement/UsersSelectElement.tsx index 39e71bd4fce8..03306a36905c 100644 --- a/packages/fuselage-ui-kit/src/elements/UsersSelectElement/UsersSelectElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/UsersSelectElement/UsersSelectElement.tsx @@ -24,8 +24,8 @@ const UsersSelectElement = ({ block, context }: UsersSelectElementProps) => { const data = useUsersData({ filter: debouncedFilter }); const handleChange = useCallback( - (value) => { - action({ target: { value } }); + (value: string | string[]) => { + if (!Array.isArray(value)) action({ target: { value } }); }, [action] ); diff --git a/packages/fuselage-ui-kit/src/surfaces/createSurfaceRenderer.tsx b/packages/fuselage-ui-kit/src/surfaces/createSurfaceRenderer.tsx index 2f6115f8ca66..0208198f0268 100644 --- a/packages/fuselage-ui-kit/src/surfaces/createSurfaceRenderer.tsx +++ b/packages/fuselage-ui-kit/src/surfaces/createSurfaceRenderer.tsx @@ -1,11 +1,11 @@ import type * as UiKit from '@rocket.chat/ui-kit'; -import type { ComponentType, ReactElement } from 'react'; +import type { ComponentType, ReactElement, ReactNode } from 'react'; export const createSurfaceRenderer = < S extends UiKit.SurfaceRenderer >( // eslint-disable-next-line @typescript-eslint/naming-convention - SurfaceComponent: ComponentType, + SurfaceComponent: ComponentType<{ children: ReactNode }>, surfaceRenderer: S ) => function Surface( diff --git a/packages/gazzodown/src/elements/Timestamp/ErrorBoundary.tsx b/packages/gazzodown/src/elements/Timestamp/ErrorBoundary.tsx index 453853275f8a..a659adec2aa7 100644 --- a/packages/gazzodown/src/elements/Timestamp/ErrorBoundary.tsx +++ b/packages/gazzodown/src/elements/Timestamp/ErrorBoundary.tsx @@ -1,7 +1,12 @@ -import React, { Component, ReactNode } from 'react'; +import { Component, ReactNode } from 'react'; -export class ErrorBoundary extends Component<{ fallback: React.ReactNode }, { hasError: boolean }> { - constructor(props: { fallback: React.ReactNode }) { +interface ErrorBoundaryProps { + fallback: ReactNode; + children: ReactNode; +} + +export class ErrorBoundary extends Component { + constructor(props: ErrorBoundaryProps) { super(props); this.state = { hasError: false }; } diff --git a/packages/ui-client/src/components/CustomFieldsForm.tsx b/packages/ui-client/src/components/CustomFieldsForm.tsx index 0d1ba2ca5b1b..3a9c66014e4d 100644 --- a/packages/ui-client/src/components/CustomFieldsForm.tsx +++ b/packages/ui-client/src/components/CustomFieldsForm.tsx @@ -5,7 +5,7 @@ import { useUniqueId } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useTranslation } from '@rocket.chat/ui-contexts'; import { useCallback, useMemo } from 'react'; -import type { Control, FieldValues } from 'react-hook-form'; +import type { Control, FieldValues, FieldError as RHFFieldError } from 'react-hook-form'; import { Controller, useFormState, get } from 'react-hook-form'; type CustomFieldFormProps = { @@ -46,10 +46,10 @@ const CustomField = ({ [defaultValue, options], ); - const validateRequired = useCallback((value) => (required ? typeof value === 'string' && !!value.trim() : true), [required]); + const validateRequired = useCallback((value: string) => (required ? typeof value === 'string' && !!value.trim() : true), [required]); const getErrorMessage = useCallback( - (error) => { + (error: RHFFieldError) => { switch (error?.type) { case 'required': return t('The_field_is_required', label || name); diff --git a/packages/ui-client/src/components/MultiSelectCustom/MultiSelectCustom.tsx b/packages/ui-client/src/components/MultiSelectCustom/MultiSelectCustom.tsx index 317f56899d05..a90cfb1bd1c6 100644 --- a/packages/ui-client/src/components/MultiSelectCustom/MultiSelectCustom.tsx +++ b/packages/ui-client/src/components/MultiSelectCustom/MultiSelectCustom.tsx @@ -64,8 +64,8 @@ export const MultiSelectCustom = ({ const [collapsed, toggleCollapsed] = useToggle(false); const onClose = useCallback( - (e) => { - if (isValidReference(reference, e)) { + (e: MouseEvent) => { + if (isValidReference(reference, e as { target: Node | null })) { toggleCollapsed(false); return; } diff --git a/packages/ui-client/src/components/MultiSelectCustom/MultiSelectCustomList.tsx b/packages/ui-client/src/components/MultiSelectCustom/MultiSelectCustomList.tsx index 71cb54f81aa5..4afe036e74d2 100644 --- a/packages/ui-client/src/components/MultiSelectCustom/MultiSelectCustomList.tsx +++ b/packages/ui-client/src/components/MultiSelectCustom/MultiSelectCustomList.tsx @@ -20,7 +20,7 @@ const MultiSelectCustomList = ({ const [text, setText] = useState(''); - const handleChange = useCallback((event) => setText(event.currentTarget.value), []); + const handleChange = useCallback((event: FormEvent) => setText(event.currentTarget.value), []); const filteredOptions = useFilteredOptions(text, options); diff --git a/packages/uikit-playground/src/Components/FlowContainer/FlowContainer.tsx b/packages/uikit-playground/src/Components/FlowContainer/FlowContainer.tsx index f04d95b274c2..311ddaae795c 100644 --- a/packages/uikit-playground/src/Components/FlowContainer/FlowContainer.tsx +++ b/packages/uikit-playground/src/Components/FlowContainer/FlowContainer.tsx @@ -8,6 +8,8 @@ import ReactFlow, { Viewport, ReactFlowInstance, useReactFlow, + Connection, + Edge, } from 'reactflow'; import 'reactflow/dist/style.css'; @@ -39,10 +41,10 @@ const FlowContainer = () => { const edgeUpdateSuccessful = useRef(true); const onConnect = useCallback( - (params) => { - if (params.source === params.target) return; + (connection: Connection) => { + if (connection.source === connection.target) return; const newEdge = { - ...params, + ...connection, type: FlowParams.edgeType, markerEnd: FlowParams.markerEnd, style: FlowParams.style, @@ -57,7 +59,7 @@ const FlowContainer = () => { }, []); const onEdgeUpdate = useCallback( - (oldEdge, newConnection) => { + (oldEdge: Edge, newConnection: Connection) => { edgeUpdateSuccessful.current = true; setEdges((els) => updateEdge(oldEdge, newConnection, els)); }, @@ -65,7 +67,7 @@ const FlowContainer = () => { ); const onEdgeUpdateEnd = useCallback( - (_, edge) => { + (_: MouseEvent | TouchEvent, edge: Edge) => { if (!edgeUpdateSuccessful.current) { setEdges((eds) => { return eds.filter((e) => e.id !== edge.id); diff --git a/packages/uikit-playground/src/Components/SurfaceSelect/SurfaceSelect.tsx b/packages/uikit-playground/src/Components/SurfaceSelect/SurfaceSelect.tsx index d0a59cc42a45..e6c0abba57e7 100644 --- a/packages/uikit-playground/src/Components/SurfaceSelect/SurfaceSelect.tsx +++ b/packages/uikit-playground/src/Components/SurfaceSelect/SurfaceSelect.tsx @@ -16,7 +16,7 @@ const SurfaceSelect: FC = () => { value={`${screens[activeScreen].payload.surface}`} placeholder="Surface" onChange={(e) => { - dispatch(surfaceAction(typeof e === 'string' ? parseInt(e) : e)); + dispatch(surfaceAction(typeof e === 'string' ? parseInt(e) : Number(e))); }} /> ); diff --git a/packages/web-ui-registration/src/components/LoginSwitchLanguageFooter.tsx b/packages/web-ui-registration/src/components/LoginSwitchLanguageFooter.tsx index 0d08fba8a3ac..46ce5112b9d4 100644 --- a/packages/web-ui-registration/src/components/LoginSwitchLanguageFooter.tsx +++ b/packages/web-ui-registration/src/components/LoginSwitchLanguageFooter.tsx @@ -62,7 +62,10 @@ const LoginSwitchLanguageFooter = ({ {suggestions.map((suggestion) => ( ))} From 938337f585c1a44546edf44bcba8f75693786491 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 13 Aug 2024 16:31:49 -0300 Subject: [PATCH 40/80] ci: fix prs from forks (#32998) --- .github/actions/setup-node/action.yml | 1 + .github/workflows/ci-test-e2e.yml | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml index caa3c63e00f0..60d54ab896dd 100644 --- a/.github/actions/setup-node/action.yml +++ b/.github/actions/setup-node/action.yml @@ -32,6 +32,7 @@ runs: uses: actions/cache@v3 with: path: | + .turbo/cache node_modules ${{ env.DENO_DIR }} apps/meteor/node_modules diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index c700512ec1ef..e8dd480d5b27 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -188,10 +188,8 @@ jobs: docker compose -f docker-compose-ci.yml up -d - name: Clean up temporary files - # remove all folders inside /tmp except /tmp/coverage run: | - cd /tmp - sudo find . -mindepth 1 -maxdepth 1 -type d | grep -v './coverage' | sudo xargs rm -rf + sudo rm -rf /tmp/bundle - name: Cache Playwright binaries if: inputs.type == 'ui' From 1f061a1aa54960ba2440da3795d10a3a2e1b4c7f Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Tue, 13 Aug 2024 17:48:36 -0300 Subject: [PATCH 41/80] fix(i18n): fixes onboarding.component.emailCodeFallback translation (#33029) --- .changeset/proud-years-buy.md | 5 +++++ packages/i18n/src/locales/de.i18n.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/proud-years-buy.md diff --git a/.changeset/proud-years-buy.md b/.changeset/proud-years-buy.md new file mode 100644 index 000000000000..94f4ab0df736 --- /dev/null +++ b/.changeset/proud-years-buy.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/i18n': patch +--- + +Fixes a typo in german translation and fixes the broken hyperlink for Resend and Change Email diff --git a/packages/i18n/src/locales/de.i18n.json b/packages/i18n/src/locales/de.i18n.json index 2208fe4a6d81..a67509672d33 100644 --- a/packages/i18n/src/locales/de.i18n.json +++ b/packages/i18n/src/locales/de.i18n.json @@ -5432,7 +5432,7 @@ "onboarding.component.form.action.confirm": "Bestätigen", "onboarding.component.form.action.pasteHere": "Hier einfügen...", "onboarding.component.form.termsAndConditions": "Ich bin mit den Nutzungsvereinbarung und den Datenschutzbestimmungen einverstanden", - "onboarding.component.emailCodeFallback": "Keine E-Mail erhalten? Noch einemal versenden oder E-Mailadresse ändern", + "onboarding.component.emailCodeFallback": "Keine E-Mail erhalten? <1>Noch einmal versenden oder <3>E-Mailadresse ändern", "onboarding.page.form.title": "Starten wir Ihren Arbeitsbereich", "onboarding.page.emailConfirmed.title": "E-Mail bestätigt", "onboarding.page.emailConfirmed.subtitle": "Sie können zu Ihrer Rocket.Chat-Anwendung zurückkehren - wir haben Ihren Arbeitsbereich bereits gestartet.", From 284b5cecd20dcd8d80c179a226f0c084c5ca30bb Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Wed, 14 Aug 2024 10:47:21 -0300 Subject: [PATCH 42/80] fix: Retention policy cron max age settings reactivity (#33025) --- .../server/cronPruneMessages.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/meteor/app/retention-policy/server/cronPruneMessages.ts b/apps/meteor/app/retention-policy/server/cronPruneMessages.ts index 337691bfbe57..640aa517a679 100644 --- a/apps/meteor/app/retention-policy/server/cronPruneMessages.ts +++ b/apps/meteor/app/retention-policy/server/cronPruneMessages.ts @@ -6,13 +6,20 @@ import { getCronAdvancedTimerFromPrecisionSetting } from '../../../lib/getCronAd import { cleanRoomHistory } from '../../lib/server/functions/cleanRoomHistory'; import { settings } from '../../settings/server'; -const maxTimes = { - c: 0, - p: 0, - d: 0, +type RetentionRoomTypes = 'c' | 'p' | 'd'; + +const getMaxAgeSettingIdByRoomType = (type: RetentionRoomTypes) => { + switch (type) { + case 'c': + return settings.get('RetentionPolicy_TTL_Channels'); + case 'p': + return settings.get('RetentionPolicy_TTL_Groups'); + case 'd': + return settings.get('RetentionPolicy_TTL_DMs'); + } }; -let types: (keyof typeof maxTimes)[] = []; +let types: RetentionRoomTypes[] = []; const oldest = new Date('0001-01-01T00:00:00Z'); @@ -29,7 +36,7 @@ async function job(): Promise { // get all rooms with default values for await (const type of types) { - const maxAge = maxTimes[type] || 0; + const maxAge = getMaxAgeSettingIdByRoomType(type) || 0; const latest = new Date(now.getTime() - maxAge); const rooms = await Rooms.find( @@ -95,9 +102,6 @@ settings.watchMultiple( 'RetentionPolicy_AppliesToChannels', 'RetentionPolicy_AppliesToGroups', 'RetentionPolicy_AppliesToDMs', - 'RetentionPolicy_TTL_Channels', - 'RetentionPolicy_TTL_Groups', - 'RetentionPolicy_TTL_DMs', 'RetentionPolicy_Advanced_Precision', 'RetentionPolicy_Advanced_Precision_Cron', 'RetentionPolicy_Precision', @@ -120,10 +124,6 @@ settings.watchMultiple( types.push('d'); } - maxTimes.c = settings.get('RetentionPolicy_TTL_Channels'); - maxTimes.p = settings.get('RetentionPolicy_TTL_Groups'); - maxTimes.d = settings.get('RetentionPolicy_TTL_DMs'); - const precision = (settings.get('RetentionPolicy_Advanced_Precision') && settings.get('RetentionPolicy_Advanced_Precision_Cron')) || getCronAdvancedTimerFromPrecisionSetting(settings.get('RetentionPolicy_Precision')); From 19824bde976dae0b74f01d88fb3b3342cfef58db Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 14 Aug 2024 10:51:58 -0300 Subject: [PATCH 43/80] chore: remove `persists` from updater (#33037) --- .../federation/server/endpoints/dispatch.js | 2 +- .../lib/server/lib/notifyUsersOnMessage.ts | 2 +- .../hooks/afterSaveOmnichannelMessage.ts | 2 +- apps/meteor/server/models/dummy/BaseDummy.ts | 6 +- apps/meteor/server/models/raw/BaseRaw.ts | 10 +- .../model-typings/src/models/IBaseModel.ts | 1 + packages/model-typings/src/updater.ts | 3 +- packages/models/src/updater.spec.ts | 170 ++++++------------ packages/models/src/updater.ts | 45 +++-- 9 files changed, 96 insertions(+), 145 deletions(-) diff --git a/apps/meteor/app/federation/server/endpoints/dispatch.js b/apps/meteor/app/federation/server/endpoints/dispatch.js index a7ab98accd36..7090f053a22b 100644 --- a/apps/meteor/app/federation/server/endpoints/dispatch.js +++ b/apps/meteor/app/federation/server/endpoints/dispatch.js @@ -296,7 +296,7 @@ const eventHandlers = { const roomUpdater = Rooms.getUpdater(); await notifyUsersOnMessage(denormalizedMessage, room, roomUpdater); if (roomUpdater.hasChanges()) { - await roomUpdater.persist({ _id: room._id }); + await Rooms.updateFromUpdater({ _id: room._id }, roomUpdater); } sendAllNotifications(denormalizedMessage, room); diff --git a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts index 0b80b9bb06df..a05c05b4bb94 100644 --- a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts +++ b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts @@ -188,7 +188,7 @@ callbacks.add( await notifyUsersOnMessage(message, room, roomUpdater); if (roomUpdater.hasChanges()) { - await roomUpdater.persist({ _id: room._id }); + await Rooms.updateFromUpdater({ _id: room._id }, roomUpdater); } return message; diff --git a/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts b/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts index 372704d339bb..07ce7fe08573 100644 --- a/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts +++ b/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts @@ -14,7 +14,7 @@ callbacks.add( const result = await callbacks.run('afterOmnichannelSaveMessage', message, { room, roomUpdater: updater }); if (updater.hasChanges()) { - await updater.persist({ _id: room._id }); + await LivechatRooms.updateFromUpdater({ _id: room._id }, updater); } return result; diff --git a/apps/meteor/server/models/dummy/BaseDummy.ts b/apps/meteor/server/models/dummy/BaseDummy.ts index 9ba590151c02..c3052ede9487 100644 --- a/apps/meteor/server/models/dummy/BaseDummy.ts +++ b/apps/meteor/server/models/dummy/BaseDummy.ts @@ -42,7 +42,11 @@ export class BaseDummy< } public getUpdater(): Updater { - return new UpdaterImpl(this.col as unknown as IBaseModel); + return new UpdaterImpl(); + } + + public updateFromUpdater(query: Filter, updater: Updater): Promise { + return this.updateOne(query, updater); } getCollectionName(): string { diff --git a/apps/meteor/server/models/raw/BaseRaw.ts b/apps/meteor/server/models/raw/BaseRaw.ts index 0a41a0fbb3eb..1a3dd1a3eb4c 100644 --- a/apps/meteor/server/models/raw/BaseRaw.ts +++ b/apps/meteor/server/models/raw/BaseRaw.ts @@ -111,7 +111,15 @@ export abstract class BaseRaw< } public getUpdater(): Updater { - return new UpdaterImpl(this.col as unknown as IBaseModel); + return new UpdaterImpl(); + } + + public updateFromUpdater(query: Filter, updater: Updater): Promise { + const updateFilter = updater.getUpdateFilter(); + return this.updateOne(query, updateFilter).catch((e) => { + console.warn(e, updateFilter); + return Promise.reject(e); + }); } private doNotMixInclusionAndExclusionFields(options: FindOptions = {}): FindOptions { diff --git a/packages/model-typings/src/models/IBaseModel.ts b/packages/model-typings/src/models/IBaseModel.ts index 59a5f67273eb..246c3ae253dd 100644 --- a/packages/model-typings/src/models/IBaseModel.ts +++ b/packages/model-typings/src/models/IBaseModel.ts @@ -51,6 +51,7 @@ export interface IBaseModel< getCollectionName(): string; getUpdater(): Updater; + updateFromUpdater(query: Filter, updater: Updater): Promise; findOneAndUpdate(query: Filter, update: UpdateFilter | T, options?: FindOneAndUpdateOptions): Promise>; diff --git a/packages/model-typings/src/updater.ts b/packages/model-typings/src/updater.ts index fe8354479c1f..7743430ad4b8 100644 --- a/packages/model-typings/src/updater.ts +++ b/packages/model-typings/src/updater.ts @@ -1,12 +1,11 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import type { Join, NestedPaths, PropertyType, ArrayElement, NestedPathsOfType, Filter, UpdateFilter } from 'mongodb'; +import type { Join, NestedPaths, PropertyType, ArrayElement, NestedPathsOfType, UpdateFilter } from 'mongodb'; export interface Updater { set

, K extends keyof P>(key: K, value: P[K]): Updater; unset>(key: K): Updater; inc>(key: K, value: number): Updater; addToSet>(key: K, value: ArrayElementType[K]>): Updater; - persist(query: Filter): Promise; hasChanges(): boolean; getUpdateFilter(): UpdateFilter; } diff --git a/packages/models/src/updater.spec.ts b/packages/models/src/updater.spec.ts index ae75400bd9ee..bdae43e338f3 100644 --- a/packages/models/src/updater.spec.ts +++ b/packages/models/src/updater.spec.ts @@ -15,63 +15,67 @@ test('updater typings', () => { e: string; }; e: string[]; - }>({} as any); + }>(); - const omnichannel = new UpdaterImpl({} as any); - omnichannel.addToSet('v.activity', 'asd'); - // @ts-expect-error - omnichannel.addToSet('v.activity', 1); - // @ts-expect-error - omnichannel.addToSet('v.activity', { - asdas: 1, - }); - - // @ts-expect-error - omnichannel.addToSet('v.activity.asd', { - asdas: 1, - }); - - updater.addToSet('e', 'a'); - - // @ts-expect-error - updater.addToSet('e', 1); - // @ts-expect-error - updater.addToSet('a', 'b'); - - // @ts-expect-error - updater.set('njame', 1); - // @ts-expect-error - updater.set('ttes', 1); - // @ts-expect-error + // @ts-expect-error: it should not allow any string to `t` only `l` is allowed updater.set('t', 'a'); + // `l` is allowed updater.set('t', 'l'); - // @ts-expect-error - updater.set('a', 'b'); - // @ts-expect-error - updater.set('c', 'b'); - updater.set('c', 1); - updater.set('a', { - b: 'set', - }); + // `a` is { b: string } + updater.set('a', { b: 'test' }); updater.set('a.b', 'test'); - - // @ts-expect-error + // @ts-expect-error: it should not allow strings to `a`, a is an object containing `b: string` + updater.set('a', 'b'); + // @ts-expect-error: `a` is not optional so unset is not allowed updater.unset('a'); + // @ts-expect-error: strings cannot be incremented + updater.inc('a', 1); + // `c` is number but it should be optional, so unset is allowed updater.unset('c'); + updater.set('c', 1); + // @ts-expect-error: `c` is a number + updater.set('c', 'b'); + // inc is allowed for numbers + updater.inc('c', 1); + // `d` is { e: string } but it should be optional, so unset is allowed updater.unset('d'); + updater.set('d', { e: 'a' }); + // @ts-expect-error: `d` is an object + updater.set('d', 'a'); + + // @ts-expect-error: it should not allow numbers, since e is a string + updater.addToSet('e', 1); + // @ts-expect-error: it should not allow strings, since a is an object + updater.addToSet('a', 'b'); + updater.addToSet('e', 'a'); + // @ts-expect-error: it should not allow `njame` its not specified in the model + updater.set('njame', 1); + + // `d` is { e: string } and also it should be optional, so unset is allowed updater.unset('d.e'); - // @ts-expect-error + // @ts-expect-error: `d` is an object cannot be incremented updater.inc('d', 1); - updater.inc('c', 1); + + // `activity` is a string + const omnichannel = new UpdaterImpl(); + omnichannel.addToSet('v.activity', 'asd'); + // @ts-expect-error: it should not allow numbers, since activity is a string + omnichannel.addToSet('v.activity', 1); + // @ts-expect-error: it should not allow objects, since activity is a string + omnichannel.addToSet('v.activity', { + asdas: 1, + }); + // @ts-expect-error: it should not allow sub properties, since activity is a string + omnichannel.addToSet('v.activity.asd', { + asdas: 1, + }); }); test('updater $set operations', async () => { - const updateOne = jest.fn(); - const updater = new UpdaterImpl<{ _id: string; t: 'l'; @@ -79,29 +83,16 @@ test('updater $set operations', async () => { b: string; }; c?: number; - }>({ - updateOne, - } as any); + }>(); updater.set('a', { b: 'set', }); - await updater.persist({ - _id: 'test', - }); - - expect(updateOne).toBeCalledWith( - { - _id: 'test', - }, - { $set: { a: { b: 'set' } } }, - ); + expect(updater.getUpdateFilter()).toEqual({ $set: { a: { b: 'set' } } }); }); test('updater $unset operations', async () => { - const updateOne = jest.fn(); - const updater = new UpdaterImpl<{ _id: string; t: 'l'; @@ -109,27 +100,12 @@ test('updater $unset operations', async () => { b: string; }; c?: number; - }>({ - updateOne, - } as any); - + }>(); updater.unset('c'); - - await updater.persist({ - _id: 'test', - }); - - expect(updateOne).toBeCalledWith( - { - _id: 'test', - }, - { $unset: { c: 1 } }, - ); + expect(updater.getUpdateFilter()).toEqual({ $unset: { c: 1 } }); }); test('updater inc multiple operations', async () => { - const updateOne = jest.fn(); - const updater = new UpdaterImpl<{ _id: string; t: 'l'; @@ -137,52 +113,27 @@ test('updater inc multiple operations', async () => { b: string; }; c?: number; - }>({ - updateOne, - } as any); + }>(); updater.inc('c', 1); updater.inc('c', 1); - await updater.persist({ - _id: 'test', - }); - - expect(updateOne).toBeCalledWith( - { - _id: 'test', - }, - { $inc: { c: 2 } }, - ); + expect(updater.getUpdateFilter()).toEqual({ $inc: { c: 2 } }); }); test('it should add items to array', async () => { - const updateOne = jest.fn(); const updater = new UpdaterImpl<{ _id: string; a: string[]; - }>({ - updateOne, - } as any); + }>(); updater.addToSet('a', 'b'); updater.addToSet('a', 'c'); - await updater.persist({ - _id: 'test', - }); - - expect(updateOne).toBeCalledWith( - { - _id: 'test', - }, - { $addToSet: { a: { $each: ['b', 'c'] } } }, - ); + expect(updater.getUpdateFilter()).toEqual({ $addToSet: { a: { $each: ['b', 'c'] } } }); }); -test('it should persist only once', async () => { - const updateOne = jest.fn(); - +test('it should getUpdateFilter only once', async () => { const updater = new UpdaterImpl<{ _id: string; t: 'l'; @@ -190,19 +141,12 @@ test('it should persist only once', async () => { b: string; }; c?: number; - }>({ - updateOne, - } as any); + }>(); updater.set('a', { b: 'set', }); - await updater.persist({ - _id: 'test', - }); - - expect(updateOne).toBeCalledTimes(1); - - expect(() => updater.persist({ _id: 'test' })).rejects.toThrow(); + expect(updater.getUpdateFilter()).toEqual({ $set: { a: { b: 'set' } } }); + expect(() => updater.getUpdateFilter()).toThrow(); }); diff --git a/packages/models/src/updater.ts b/packages/models/src/updater.ts index 361e228e65ac..4f7ad271f397 100644 --- a/packages/models/src/updater.ts +++ b/packages/models/src/updater.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import type { IBaseModel, Updater, SetProps, UnsetProps, IncProps, AddToSetProps } from '@rocket.chat/model-typings'; -import type { UpdateFilter, Filter } from 'mongodb'; +import type { Updater, SetProps, UnsetProps, IncProps, AddToSetProps } from '@rocket.chat/model-typings'; +import type { UpdateFilter } from 'mongodb'; type ArrayElementType = T extends (infer E)[] ? E : T; @@ -17,8 +17,6 @@ export class UpdaterImpl implements Updater { private dirty = false; - constructor(private model: IBaseModel) {} - set

, K extends keyof P>(key: K, value: P[K]) { this._set = this._set ?? new Map, any>(); this._set.set(key as Keys, value); @@ -47,31 +45,16 @@ export class UpdaterImpl implements Updater { return this; } - async persist(query: Filter): Promise { - if (this.dirty) { - throw new Error('Updater is not dirty'); - } - - if ((process.env.NODE_ENV === 'development' || process.env.TEST_MODE) && !this.hasChanges()) { - throw new Error('Nothing to update'); - } - - this.dirty = true; - - const update = this.getUpdateFilter(); - try { - await this.model.updateOne(query, update); - } catch (error) { - console.error('Failed to update', JSON.stringify(query), JSON.stringify(update, null, 2)); - throw error; - } + hasChanges() { + const filter = this._getUpdateFilter(); + return this._hasChanges(filter); } - hasChanges() { - return Object.keys(this.getUpdateFilter()).length > 0; + private _hasChanges(filter: UpdateFilter) { + return Object.keys(filter).length > 0; } - getUpdateFilter() { + private _getUpdateFilter() { return { ...(this._set && { $set: Object.fromEntries(this._set) }), ...(this._unset && { $unset: Object.fromEntries([...this._unset.values()].map((k) => [k, 1])) }), @@ -79,6 +62,18 @@ export class UpdaterImpl implements Updater { ...(this._addToSet && { $addToSet: Object.fromEntries([...this._addToSet.entries()].map(([k, v]) => [k, { $each: v }])) }), } as unknown as UpdateFilter; } + + getUpdateFilter() { + if (this.dirty) { + throw new Error('Updater is dirty'); + } + this.dirty = true; + const filter = this._getUpdateFilter(); + if (!this._hasChanges(filter)) { + throw new Error('No changes to update'); + } + return filter; + } } export { Updater }; From f88212491e0ef4e6b3b5f14f51e4f77ad51c9acb Mon Sep 17 00:00:00 2001 From: Debdut Chakraborty Date: Wed, 14 Aug 2024 21:48:45 +0530 Subject: [PATCH 44/80] fix: disable deletion for federated users (#32852) --- .changeset/empty-toys-smell.md | 5 +++++ .../app/lib/server/functions/deleteUser.ts | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 .changeset/empty-toys-smell.md diff --git a/.changeset/empty-toys-smell.md b/.changeset/empty-toys-smell.md new file mode 100644 index 000000000000..043d9c19567d --- /dev/null +++ b/.changeset/empty-toys-smell.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Federated users can no longer be deleted. diff --git a/apps/meteor/app/lib/server/functions/deleteUser.ts b/apps/meteor/app/lib/server/functions/deleteUser.ts index d6457664671a..e66c8c2d5eef 100644 --- a/apps/meteor/app/lib/server/functions/deleteUser.ts +++ b/apps/meteor/app/lib/server/functions/deleteUser.ts @@ -1,5 +1,5 @@ import { api } from '@rocket.chat/core-services'; -import type { IUser } from '@rocket.chat/core-typings'; +import { isUserFederated, type IUser } from '@rocket.chat/core-typings'; import { Integrations, FederationServers, @@ -12,6 +12,7 @@ import { ReadReceipts, LivechatUnitMonitors, ModerationReports, + MatrixBridgedUser, } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; @@ -46,6 +47,19 @@ export async function deleteUser(userId: string, confirmRelinquish = false, dele return; } + if (isUserFederated(user)) { + throw new Meteor.Error('error-not-allowed', 'Deleting federated, external user is not allowed', { + method: 'deleteUser', + }); + } + + const remoteUser = await MatrixBridgedUser.getExternalUserIdByLocalUserId(userId); + if (remoteUser) { + throw new Meteor.Error('error-not-allowed', 'User participated in federation, this user can only be deactivated permanently', { + method: 'deleteUser', + }); + } + const subscribedRooms = await getSubscribedRoomsForUserWithDetails(userId); if (shouldRemoveOrChangeOwner(subscribedRooms) && !confirmRelinquish) { From 1b30512b25d3ab9c8f6a8d808322202dce00ec0d Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 14 Aug 2024 16:15:51 -0300 Subject: [PATCH 45/80] feat: Replaces outdated retention policy warning in favor of `Bubble` (#33044) --- .changeset/large-geese-ring.md | 5 +++++ .../app/theme/client/imports/general/base_old.css | 15 --------------- .../views/room/body/RetentionPolicyWarning.tsx | 15 ++++++--------- apps/meteor/client/views/room/body/RoomBody.tsx | 4 ++-- apps/meteor/client/views/room/body/RoomBodyV2.tsx | 4 ++-- 5 files changed, 15 insertions(+), 28 deletions(-) create mode 100644 .changeset/large-geese-ring.md diff --git a/.changeset/large-geese-ring.md b/.changeset/large-geese-ring.md new file mode 100644 index 000000000000..9b36edf1c02d --- /dev/null +++ b/.changeset/large-geese-ring.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': minor +--- + +Replaces an outdated banner with the Bubble component in order to display retention policy warning diff --git a/apps/meteor/app/theme/client/imports/general/base_old.css b/apps/meteor/app/theme/client/imports/general/base_old.css index 20b023cc61aa..3120d9c05ff0 100644 --- a/apps/meteor/app/theme/client/imports/general/base_old.css +++ b/apps/meteor/app/theme/client/imports/general/base_old.css @@ -776,21 +776,6 @@ padding: 21px 0 10px; } - & .start { - margin-top: 44px; - - text-align: center; - - & .start__purge-warning { - margin-top: -33px; - margin-bottom: 0.5rem; - padding: 1rem; - - border-width: 1px 0 0; - background: linear-gradient(to bottom, var(--rc-color-alert-message-warning-background) 0%, rgba(255, 255, 255, 0) 100%); - } - } - & .editing .body { border-radius: var(--border-radius); } diff --git a/apps/meteor/client/views/room/body/RetentionPolicyWarning.tsx b/apps/meteor/client/views/room/body/RetentionPolicyWarning.tsx index 12fdff976a1f..f4939a261145 100644 --- a/apps/meteor/client/views/room/body/RetentionPolicyWarning.tsx +++ b/apps/meteor/client/views/room/body/RetentionPolicyWarning.tsx @@ -1,5 +1,5 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { Icon } from '@rocket.chat/fuselage'; +import { Bubble, MessageDivider } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; @@ -13,14 +13,11 @@ const RetentionPolicyWarning = ({ room }: { room: IRoom }): ReactElement => { const message = usePruneWarningMessage(room); return ( -

- {message} -
+ + + {message} + + ); }; diff --git a/apps/meteor/client/views/room/body/RoomBody.tsx b/apps/meteor/client/views/room/body/RoomBody.tsx index 31f8440643b7..a592bb1fa2c0 100644 --- a/apps/meteor/client/views/room/body/RoomBody.tsx +++ b/apps/meteor/client/views/room/body/RoomBody.tsx @@ -290,9 +290,9 @@ const RoomBody = (): ReactElement => { {hasMorePreviousMessages ? (
  • {isLoadingMoreMessages ? : null}
  • ) : ( -
  • - {retentionPolicy?.isActive ? : null} +
  • + {retentionPolicy?.isActive ? : null}
  • )} diff --git a/apps/meteor/client/views/room/body/RoomBodyV2.tsx b/apps/meteor/client/views/room/body/RoomBodyV2.tsx index 32b4288b3b0e..cfd6cb94cb51 100644 --- a/apps/meteor/client/views/room/body/RoomBodyV2.tsx +++ b/apps/meteor/client/views/room/body/RoomBodyV2.tsx @@ -262,9 +262,9 @@ const RoomBody = (): ReactElement => { {hasMorePreviousMessages ? (
  • {isLoadingMoreMessages ? : null}
  • ) : ( -
  • - {retentionPolicy?.isActive ? : null} +
  • + {retentionPolicy?.isActive ? : null}
  • )} From ec0cec69e796f92726c87f6545510e7163c9dd50 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 14 Aug 2024 17:00:18 -0300 Subject: [PATCH 46/80] chore: turbo env-mode: loose for dev (#33056) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6f7980d8bfc9..29de436373e2 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "build:services": "turbo run build --filter=rocketchat-services...", "build:ci": "turbo run build:ci", "testunit": "turbo run testunit", - "dev": "turbo run dev --parallel --filter=@rocket.chat/meteor...", - "dsv": "turbo run dsv --filter=@rocket.chat/meteor...", + "dev": "turbo run dev --env-mode=loose --parallel --filter=@rocket.chat/meteor...", + "dsv": "turbo run dsv --env-mode=loose --filter=@rocket.chat/meteor...", "lint": "turbo run lint", "storybook": "yarn workspace @rocket.chat/meteor run storybook", "fuselage": "./fuselage.sh", From 447888779d00bb91d6ee0b234a9f0686c60440be Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 15 Aug 2024 10:23:32 -0300 Subject: [PATCH 47/80] ci: fix external pull requests (#33063) --- .github/actions/build-docker/action.yml | 26 ++++++++++++++++++++++--- .github/workflows/ci-test-e2e.yml | 15 +++++++------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.github/actions/build-docker/action.yml b/.github/actions/build-docker/action.yml index 75673c15bfd6..6f8250d2acd4 100644 --- a/.github/actions/build-docker/action.yml +++ b/.github/actions/build-docker/action.yml @@ -17,13 +17,25 @@ inputs: required: false description: 'Containers to build along with Rocket.Chat' type: string + turbo-cache: + required: false + description: 'Enable turbo cache' + default: 'true' + publish-image: + required: false + description: 'Publish image' + default: 'true' + setup: + required: false + description: 'Setup node.js' + default: 'true' runs: using: composite steps: - name: Login to GitHub Container Registry - if: (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') + if: inputs.publish-image == 'true' &&(github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') uses: docker/login-action@v2 with: registry: ghcr.io @@ -42,17 +54,20 @@ runs: cd /tmp/build tar xzf Rocket.Chat.tar.gz rm Rocket.Chat.tar.gz - - uses: rharkor/caching-for-turbo@v1.5 + # if we are testing a PR from a fork, we already called the turbo cache at this point, so it should be false + if: inputs.turbo-cache == 'true' - name: Setup NodeJS uses: ./.github/actions/setup-node + if: inputs.setup == 'true' with: node-version: ${{ inputs.node-version }} cache-modules: true install: true - run: yarn build + if: inputs.setup == 'true' shell: bash - name: Build Docker images @@ -63,9 +78,14 @@ runs: docker compose -f docker-compose-ci.yml build "${args[@]}" - name: Publish Docker images to GitHub Container Registry - if: (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') + if: inputs.publish-image == 'true' && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') shell: bash run: | args=(rocketchat ${{ inputs.build-containers }}) docker compose -f docker-compose-ci.yml push "${args[@]}" + + - name: Clean up temporary files + shell: bash + run: | + sudo rm -rf /tmp/bundle diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index e8dd480d5b27..31a8bc2ea2b6 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -130,7 +130,9 @@ jobs: node-version: ${{ inputs.node-version }} cache-modules: true install: true + - uses: rharkor/caching-for-turbo@v1.5 + - run: yarn build # if we are testing a PR from a fork, we need to build the docker image at this point - uses: ./.github/actions/build-docker if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository @@ -138,8 +140,11 @@ jobs: CR_USER: ${{ secrets.CR_USER }} CR_PAT: ${{ secrets.CR_PAT }} node-version: ${{ inputs.node-version }} - - - uses: rharkor/caching-for-turbo@v1.5 + # we already called the turbo cache at this point, so it should be false + turbo-cache: false + # the same reason we need to rebuild the docker image at this point is the reason we dont want to publish it + publish-image: false + setup: false - name: Start httpbin container and wait for it to be ready if: inputs.type == 'api' @@ -159,8 +164,6 @@ jobs: exit 1 fi - - run: yarn build - - name: Prepare code coverage directory if: inputs.release == 'ee' run: | @@ -187,10 +190,6 @@ jobs: run: | docker compose -f docker-compose-ci.yml up -d - - name: Clean up temporary files - run: | - sudo rm -rf /tmp/bundle - - name: Cache Playwright binaries if: inputs.type == 'ui' uses: actions/cache@v3 From 77989f51dd6e932344267cdb3b784d9234e8c3de Mon Sep 17 00:00:00 2001 From: Kunal Agrawal <92196937+its-kunal@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:34:56 +0530 Subject: [PATCH 48/80] i18n: more Hindi translation keys added (#30927) Co-authored-by: Douglas Fabris Co-authored-by: Guilherme Gazzo --- packages/i18n/src/locales/hi-IN.i18n.json | 5929 ++++++++++++++++++++- 1 file changed, 5926 insertions(+), 3 deletions(-) diff --git a/packages/i18n/src/locales/hi-IN.i18n.json b/packages/i18n/src/locales/hi-IN.i18n.json index d68f9e2d8d08..1049d8495d86 100644 --- a/packages/i18n/src/locales/hi-IN.i18n.json +++ b/packages/i18n/src/locales/hi-IN.i18n.json @@ -1,9 +1,29 @@ { "500": "आंतरिक सर्वर त्रुटि", + "__agents__agents_and__count__conversations__period__": "{{agents}} एजेंट और {{count}} बातचीत, {{period}}", + "__count__empty_rooms_will_be_removed_automatically": "{{count}} खाली कमरे स्वचालित रूप से हटा दिए जाएंगे।", + "__count__empty_rooms_will_be_removed_automatically__rooms__": "{{count}} खाली कमरे स्वचालित रूप से हटा दिए जाएंगे:
    {{rooms}}।", + "__count__message_pruned": "{{count}} संदेश काट दिया गया", + "__count__conversations__period__": "{{count}} बातचीत, {{period}}", + "__count__tags__and__count__conversations__period__": "{{count}} टैग और {{conversations}} बातचीत, {{period}}", + "__departments__departments_and__count__conversations__period__": "{{departments}} विभाग और {{count}} बातचीत, {{period}}", + "__usersCount__member_joined": "+ {{usersCount}} सदस्य शामिल हुए", + "__usersCount__people_will_be_invited": "{{usersCount}} लोगों को आमंत्रित किया जाएगा", "__username__is_no_longer__role__defined_by__user_by_": "{{username}} is no longer {{role}} by {{user_by}}", "__username__was_set__role__by__user_by_": "{{username}} was set {{role}} by {{user_by}}", + "__count__without__department__": "बिना विभाग के {{count}}", + "__count__without__tags__": "बिना टैग के {{count}}", + "__count__without__assignee__": "{{count}} बिना असाइनी के", + "removed__username__as__role_": "{{username}} को {{role}} के रूप में हटा दिया गया", + "set__username__as__role_": "{{username}} को {{role}} के रूप में सेट करें", + "This_room_encryption_has_been_enabled_by__username_": "इस कमरे का एन्क्रिप्शन {{username}} द्वारा सक्षम किया गया है", + "This_room_encryption_has_been_disabled_by__username_": "इस कमरे का एन्क्रिप्शन {{username}} द्वारा अक्षम कर दिया गया है", + "Third_party_login": "तृतीय-पक्ष लॉगिन", + "Enabled_E2E_Encryption_for_this_room": "इस कमरे के लिए E2E एन्क्रिप्शन सक्षम किया गया", + "disabled": "अक्षम", + "Disabled_E2E_Encryption_for_this_room": "इस कमरे के लिए अक्षम E2E एन्क्रिप्शन", "@username": "@यूज़रनेम", - "@username_message": "@यूज़रनेम ", + "@username_message": "@यूज़रनेम ", "#channel": "#चैनल", "%_of_conversations": "% बातचीत", "0_Errors_Only": "0 - त्रुटियां केवल", @@ -11,18 +31,38 @@ "2_Erros_Information_and_Debug": "2 - त्रुटियां, सूचना और डिबग", "12_Hour": "12-घंटे की घड़ी", "24_Hour": "24-घंटे की घड़ी", + "A_cloud-based_platform_for_those_needing_a_plug-and-play_app": "प्लग-एंड-प्ले ऐप की आवश्यकता वाले लोगों के लिए एक क्लाउड-आधारित प्लेटफ़ॉर्म।", + "A_new_owner_will_be_assigned_automatically_to__count__rooms": "एक नए मालिक को स्वचालित रूप से {{count}} कमरों को सौंपा जाएगा।", + "A_new_owner_will_be_assigned_automatically_to_the__roomName__room": "एक नए मालिक को स्वचालित रूप से {{roomName}} कमरे का कार्यभार सौंपा जाएगा।", + "A_new_owner_will_be_assigned_automatically_to_those__count__rooms__rooms__": "एक नए मालिक को स्वचालित रूप से उन {{count}} कमरों को सौंपा जाएगा:
    {{rooms}}।", + "A_secure_and_highly_private_self-managed_solution_for_conference_calls": "कॉन्फ़्रेंस कॉल के लिए एक सुरक्षित और अत्यधिक निजी स्व-प्रबंधित समाधान।", + "A_workspace_admin_needs_to_install_and_configure_a_conference_call_app": "एक कार्यस्थान व्यवस्थापक को एक कॉन्फ़्रेंस कॉल ऐप इंस्टॉल और कॉन्फ़िगर करने की आवश्यकता होती है।", + "An_app_needs_to_be_installed_and_configured": "एक ऐप इंस्टॉल और कॉन्फ़िगर करना होगा.", + "Accessibility": "सरल उपयोग", + "Accessibility_and_Appearance": "पहुंच एवं उपस्थिति", + "Accessibility_activation": "यहां आप अपने ब्राउज़िंग अनुभव को बेहतर बनाने के लिए कई प्रकार की सुविधाएं सक्रिय कर सकते हैं।", + "Accept_Call": "कॉल लेना", "Accept": "स्वीकार करें", "Accept_incoming_livechat_requests_even_if_there_are_no_online_agents": "यदि कोई ऑनलाइन एजेंट नहीं हैं, तो भी इनकमिंग लाइवचैट अनुरोध स्वीकार करें", + "Accept_new_livechats_when_agent_is_idle": "जब एजेंट निष्क्रिय हो तो नए ओमनीचैनल अनुरोध स्वीकार करें", "Accept_with_no_online_agents": "कोई ऑनलाइन एजेंटों के साथ स्वीकार करें", "Access_not_authorized": "प्रवेश अधिकृत नहीं है", "Access_Token_URL": "एक्सेस टोकन URL", + "Access_Your_Account": "अपने खाते पर पहुंच", + "access_your_basic_information": "अपनी बुनियादी सूचना का आंकलन करें", "access-mailer": "मेलर स्क्रीन एक्सेस करें", "access-mailer_description": "सभी उपयोगकर्ताओं को बड़े पैमाने पर ईमेल भेजने की अनुमति।", + "access-marketplace": "बाज़ार तक पहुंचें", + "access-marketplace_description": "बाज़ार से ऐप्स ब्राउज़ करने और प्राप्त करने की अनुमति", "access-permissions": "अनुमतियाँ स्क्रीन एक्सेस करें", "access-permissions_description": "विभिन्न भूमिकाओं के लिए अनुमतियों को संशोधित करें।", + "access-setting-permissions": "सेटिंग-आधारित अनुमतियाँ संशोधित करें", + "access-setting-permissions_description": "सेटिंग-आधारित अनुमतियों को संशोधित करने की अनुमति", "Accessing_permissions": "अक्सेस्सिंग की अनुमति", "Account_SID": "खाता एसआईडी", + "Account": "खाता", "Accounts": "खाता", + "Accounts_Description": "कार्यस्थान सदस्य खाता सेटिंग संशोधित करें.", "Accounts_Admin_Email_Approval_Needed_Default": "

    The user [name] ([email]) has been registered.

    Please check \"Administration -> Users\" to activate or delete it.

    ", "Accounts_Admin_Email_Approval_Needed_Subject_Default": "एक नया उपयोगकर्ता पंजीकृत है और उसे अनुमोदन की आवश्यकता है", "Accounts_Admin_Email_Approval_Needed_With_Reason_Default": "

    The user [name] ([email]) has been registered.

    Reason: [reason]

    Please check \"Administration -> Users\" to activate or delete it.

    ", @@ -31,12 +71,17 @@ "Accounts_AllowDeleteOwnAccount": "उपयोगकर्ताओं को स्वयं का खाता हटाने की अनुमति दें", "Accounts_AllowedDomainsList": "अनुमत डोमेन सूची", "Accounts_AllowedDomainsList_Description": "अनुमत डोमेन की कोमा-पृथक सूची", + "Accounts_AllowInvisibleStatusOption": "अदृश्य स्थिति विकल्प की अनुमति दें", "Accounts_AllowEmailChange": "ईमेल परिवर्तन की अनुमति दें", + "Accounts_AllowEmailNotifications": "ईमेल सूचनाओं की अनुमति दें", + "Accounts_AllowFeaturePreview": "फ़ीचर पूर्वावलोकन की अनुमति दें", "Accounts_AllowPasswordChange": "पासवर्ड बदलने की अनुमति दें", + "Accounts_AllowPasswordChangeForOAuthUsers": "OAuth उपयोगकर्ताओं के लिए पासवर्ड बदलने की अनुमति दें", "Accounts_AllowRealNameChange": "नाम बदलने की अनुमति दें", "Accounts_AllowUserAvatarChange": "उपयोगकर्ता अवतार परिवर्तन की अनुमति दें", "Accounts_AllowUsernameChange": "उपयोगकर्ता नाम बदलने की अनुमति दें", "Accounts_AllowUserProfileChange": "उपयोगकर्ता प्रोफ़ाइल बदलने की अनुमति दें", + "Accounts_AllowUserStatusMessageChange": "कस्टम स्थिति संदेश की अनुमति दें", "Accounts_AvatarBlockUnauthenticatedAccess": "अपुष्ट एक्सेस को अवतारों से ब्लॉक करें", "Accounts_AvatarCacheTime": "अवतार कैश समय", "Accounts_AvatarCacheTime_description": "HTTP प्रोटोकॉल को अवतार छवियों को कैश करने के लिए सेकंड की संख्या बताई गई है।", @@ -52,11 +97,14 @@ "Accounts_CustomFieldsToShowInUserInfo": "कस्टम फ़ील्ड उपयोगकर्ता जानकारी में दिखाने के लिए", "Accounts_Default_User_Preferences": "डिफ़ॉल्ट उपयोगकर्ता प्राथमिकताएं", "Accounts_Default_User_Preferences_audioNotifications": "ऑडियो सूचनाएं डिफ़ॉल्ट चेतावनी", + "Accounts_Default_User_Preferences_alsoSendThreadToChannel_Description": "उपयोगकर्ताओं को चैनल को भी भेजें व्यवहार का चयन करने की अनुमति दें", "Accounts_Default_User_Preferences_desktopNotifications": "डेस्कटॉप सूचनाएं डिफ़ॉल्ट चेतावनी", "Accounts_Default_User_Preferences_pushNotifications": "मोबाइल सूचनाएं डिफ़ॉल्ट चेतावनी", "Accounts_Default_User_Preferences_not_available": "उपयोगकर्ता प्राथमिकताएँ प्राप्त करने में विफल, क्योंकि वे उपयोगकर्ता द्वारा अभी तक सेट नहीं किए गए हैं", + "Accounts_Default_User_Preferences_showThreadsInMainChannel_Description": "सक्षम होने पर, थ्रेड के अंतर्गत सभी उत्तर भी सीधे मुख्य कक्ष में प्रदर्शित किए जाएंगे। अक्षम होने पर, प्रेषक की पसंद के आधार पर थ्रेड उत्तर प्रदर्शित किए जाएंगे।", "Accounts_DefaultUsernamePrefixSuggestion": "डिफ़ॉल्ट उपयोगकर्ता नाम उपसर्ग सुझाव", "Accounts_denyUnverifiedEmail": "अयोग्य ईमेल अस्वीकार करें", + "Accounts_Directory_DefaultView": "डिफ़ॉल्ट निर्देशिका सूची", "Accounts_Email_Activated": "[name]

    आपका खाता सक्रिय हो गया था।

    ", "Accounts_Email_Activated_Subject": "खाता सक्रिय किया गया", "Accounts_Email_Approved": "[name]

    आपका खाता स्वीकृत हो गया।

    ", @@ -76,18 +124,36 @@ "Accounts_iframe_url": "Iframe URL", "Accounts_LoginExpiration": "दिन में प्रवेश की समाप्ति", "Accounts_ManuallyApproveNewUsers": "नए उपयोगकर्ताओं को मैन्युअल रूप से अनुमोदित करें", + "Accounts_OAuth_Apple": "Apple के साथ साइन इन करें", + "Accounts_OAuth_Apple_Description": "यदि आप चाहते हैं कि Apple लॉगिन केवल मोबाइल पर सक्षम हो, तो आप सभी फ़ील्ड खाली छोड़ सकते हैं।", + "Accounts_OAuth_Custom_Access_Token_Param": "एक्सेस टोकन के लिए परम नाम", "Accounts_OAuth_Custom_Authorize_Path": "पथ अधिकृत करें", + "Accounts_OAuth_Custom_Avatar_Field": "अवतार क्षेत्र", "Accounts_OAuth_Custom_Button_Color": "बटन का रंग", "Accounts_OAuth_Custom_Button_Label_Color": "बटन टेक्स्ट का रंग", "Accounts_OAuth_Custom_Button_Label_Text": "बटन टेक्स्ट", + "Accounts_OAuth_Custom_Channel_Admin": "उपयोगकर्ता डेटा समूह मानचित्र", + "Accounts_OAuth_Custom_Channel_Map": "OAuth समूह चैनल मानचित्र", + "Accounts_OAuth_Custom_Email_Field": "ईमेल फ़ील्ड", "Accounts_OAuth_Custom_Enable": "सक्षम करें", + "Accounts_OAuth_Custom_Groups_Claim": "चैनल मैपिंग के लिए भूमिकाएँ/समूह फ़ील्ड", "Accounts_OAuth_Custom_id": "Id", "Accounts_OAuth_Custom_Identity_Path": "पहचान पथ", - "Accounts_OAuth_Custom_Identity_Token_Sent_Via": "पहचान टोकन भेजा गया", + "Accounts_OAuth_Custom_Identity_Token_Sent_Via": "के जरिए पहचान टोकन भेजा गया", + "Accounts_OAuth_Custom_Key_Field": "कुंजी क्षेत्र", "Accounts_OAuth_Custom_Login_Style": "लॉगिन शैली", + "Accounts_OAuth_Custom_Map_Channels": "भूमिकाओं/समूहों को चैनलों पर मैप करें", + "Accounts_OAuth_Custom_Merge_Roles": "SSO से भूमिकाएँ मर्ज करें", "Accounts_OAuth_Custom_Merge_Users": "उपयोगकर्ताओं को मर्ज करें", + "Accounts_OAuth_Custom_Merge_Users_Distinct_Services": "उपयोगकर्ताओं को अलग-अलग सेवाओं से मर्ज करें", + "Accounts_OAuth_Custom_Merge_Users_Distinct_Services_Description": "जब दिया गया कुंजी फ़ील्ड किसी मौजूदा उपयोगकर्ता से मेल खाता है, तो इस OAuth सेवा के उपयोगकर्ताओं को उनकी मूल सेवा की परवाह किए बिना मौजूदा उपयोगकर्ताओं में विलय करने की अनुमति दें।", + "Accounts_OAuth_Custom_Name_Field": "नाम फ़ील्ड", + "Accounts_OAuth_Custom_Roles_Claim": "भूमिकाएँ/समूह फ़ील्ड नाम", + "Accounts_OAuth_Custom_Roles_To_Sync": "सिंक करने के लिए भूमिकाएँ", + "Accounts_OAuth_Custom_Roles_To_Sync_Description": "उपयोगकर्ता लॉगिन और निर्माण पर सिंक करने के लिए OAuth भूमिकाएँ (अल्पविराम से अलग)।", "Accounts_OAuth_Custom_Scope": "क्षेत्र", "Accounts_OAuth_Custom_Secret": "गुप्त", + "Accounts_OAuth_Custom_Show_Button_On_Login_Page": "लॉगिन पेज पर बटन दिखाएँ", "Accounts_OAuth_Custom_Token_Path": "टोकन पथ", "Accounts_OAuth_Custom_Token_Sent_Via": "के जरिए टोकन भेजा गया", "Accounts_OAuth_Custom_Username_Field": "उपयोगकर्ता नाम फ़ील्ड", @@ -111,6 +177,7 @@ "Accounts_OAuth_Gitlab_callback_url": "GitLab कॉलबैक URL", "Accounts_OAuth_Gitlab_id": "Gitlab Id", "Accounts_OAuth_Gitlab_identity_path": "पहचान पथ", + "Accounts_OAuth_Gitlab_merge_users": "उपयोगकर्ताओं को मर्ज करें", "Accounts_OAuth_Gitlab_secret": "क्लाइंट Secret", "Accounts_OAuth_Google": "Google लॉगिन", "Accounts_OAuth_Google_callback_url": "Google कॉलबैक URL", @@ -125,7 +192,10 @@ "Accounts_OAuth_Meteor_id": "Meteor Id", "Accounts_OAuth_Meteor_secret": "Meteor Secret", "Accounts_OAuth_Nextcloud": "OAuth सक्षम", + "Accounts_OAuth_Nextcloud_callback_url": "नेक्स्टक्लाउड कॉलबैक यूआरएल", + "Accounts_OAuth_Nextcloud_id": "नेक्स्टक्लाउड आईडी", "Accounts_OAuth_Nextcloud_secret": "क्लाइंट Secret", + "Accounts_OAuth_Nextcloud_URL": "नेक्स्टक्लाउड सर्वर यूआरएल", "Accounts_OAuth_Proxy_host": "प्रॉक्सी होस्ट", "Accounts_OAuth_Proxy_services": "प्रॉक्सी सेवाएँ", "Accounts_OAuth_Tokenpass": "Tokenpass लॉगइन", @@ -152,65 +222,5918 @@ "Accounts_Password_Policy_AtLeastOneLowercase_Description": "लागू करें कि पासवर्ड में कम से कम एक लोअरकेस वर्ण हो।", "Accounts_Password_Policy_AtLeastOneNumber": "कम से कम एक नंबर", "Accounts_Password_Policy_AtLeastOneNumber_Description": "लागू करें कि एक पासवर्ड में कम से कम एक संख्यात्मक चरित्र होता है।", + "Accounts_Password_Policy_AtLeastOneSpecialCharacter": "कम से कम एक प्रतीक", + "Accounts_Password_Policy_AtLeastOneSpecialCharacter_Description": "यह सुनिश्चित करें कि पासवर्ड में कम से कम एक विशेष अक्षर हो।", + "Accounts_Password_Policy_AtLeastOneUppercase": "कम से कम एक अपरकेस", "Accounts_Password_Policy_AtLeastOneUppercase_Description": "लागू करें कि पासवर्ड में कम से कम एक लोअरकेस वर्ण हो।", + "Accounts_Password_Policy_Enabled": "पासवर्ड नीति सक्षम करें", + "Accounts_Password_Policy_Enabled_Description": "सक्षम होने पर, उपयोगकर्ता पासवर्ड को निर्धारित नीतियों का पालन करना होगा। ध्यान दें: यह केवल नए पासवर्ड पर लागू होता है, मौजूदा पासवर्ड पर नहीं।", + "Accounts_Password_Policy_ForbidRepeatingCharacters": "अक्षरों को दोहराने से मना करें", + "Accounts_Password_Policy_ForbidRepeatingCharacters_Description": "यह सुनिश्चित करता है कि पासवर्ड में एक-दूसरे के बगल में दोहराए जाने वाले समान अक्षर न हों।", + "Accounts_Password_Policy_ForbidRepeatingCharactersCount": "अधिकतम दोहराव वाले अक्षर", + "Accounts_Password_Policy_ForbidRepeatingCharactersCount_Description": "किसी पात्र को पहले कितनी बार दोहराया जा सकता है इसकी अनुमति नहीं है।", + "Accounts_Password_Policy_MaxLength": "ज्यादा से ज्यादा लंबाई", + "Accounts_Password_Policy_MaxLength_Description": "यह सुनिश्चित करता है कि पासवर्ड में इस संख्या से अधिक अक्षर न हों। अक्षम करने के लिए `-1` का उपयोग करें.", + "Accounts_Password_Policy_MinLength": "न्यूनतम लंबाई", + "Accounts_Password_Policy_MinLength_Description": "यह सुनिश्चित करता है कि पासवर्ड में कम से कम इतने अक्षर होने चाहिए। अक्षम करने के लिए `-1` का उपयोग करें.", + "Accounts_PasswordReset": "पासवर्ड रीसेट", + "Accounts_Registration_AuthenticationServices_Default_Roles": "प्रमाणीकरण सेवाओं के लिए डिफ़ॉल्ट भूमिकाएँ", + "Accounts_Registration_AuthenticationServices_Default_Roles_Description": "प्रमाणीकरण सेवाओं के माध्यम से पंजीकरण करते समय उपयोगकर्ताओं को डिफ़ॉल्ट भूमिकाएँ (अल्पविराम से अलग) दी जाएंगी", + "Accounts_Registration_AuthenticationServices_Enabled": "प्रमाणीकरण सेवाओं के साथ पंजीकरण", + "Accounts_Registration_Users_Default_Roles": "उपयोगकर्ताओं के लिए डिफ़ॉल्ट भूमिकाएँ", + "Accounts_Registration_Users_Default_Roles_Description": "मैन्युअल पंजीकरण (एपीआई सहित) के माध्यम से पंजीकरण करते समय उपयोगकर्ताओं को डिफ़ॉल्ट भूमिकाएं (अल्पविराम से अलग) दी जाएंगी", + "Accounts_Registration_Users_Default_Roles_Enabled": "मैन्युअल पंजीकरण के लिए डिफ़ॉल्ट भूमिकाएँ सक्षम करें", + "Accounts_Registration_InviteUrlType": "आमंत्रण URL प्रकार", "Accounts_Registration_InviteUrlType_Direct": "सीधा", + "Accounts_Registration_InviteUrlType_Proxy": "प्रतिनिधि", "Accounts_RegistrationForm": "पंजीकरण पत्र", "Accounts_RegistrationForm_Disabled": "उपयोग करने की अनुमति नहीं है", + "Accounts_RegistrationForm_LinkReplacementText": "पंजीकरण फॉर्म लिंक प्रतिस्थापन पाठ", "Accounts_RegistrationForm_Public": "जनता", + "Accounts_RegistrationForm_Secret_URL": "गुप्त यूआरएल", + "Accounts_RegistrationForm_SecretURL": "पंजीकरण प्रपत्र गुप्त यूआरएल", + "Accounts_RegistrationForm_SecretURL_Description": "आपको एक यादृच्छिक स्ट्रिंग प्रदान करनी होगी जो आपके पंजीकरण URL में जोड़ी जाएगी। उदाहरण: `https://open.rocket.chat/register/[secret_hash]`", + "Accounts_RequireNameForSignUp": "साइनअप के लिए नाम की आवश्यकता है", + "Accounts_RequirePasswordConfirmation": "पासवर्ड पुष्टिकरण की आवश्यकता है", + "Accounts_RoomAvatarExternalProviderUrl": "कक्ष अवतार बाहरी प्रदाता यूआरएल", + "Accounts_RoomAvatarExternalProviderUrl_Description": "उदाहरण: `https://acme.com/api/v1/{roomId}`", + "Accounts_SearchFields": "खोज में विचार करने योग्य फ़ील्ड", + "Accounts_Send_Email_When_Activating": "उपयोगकर्ता सक्रिय होने पर उपयोगकर्ता को ईमेल भेजें", + "Accounts_Send_Email_When_Deactivating": "उपयोगकर्ता के निष्क्रिय होने पर उपयोगकर्ता को ईमेल भेजें", + "Accounts_Set_Email_Of_External_Accounts_as_Verified": "बाहरी खातों के ईमेल को सत्यापित के रूप में सेट करें", + "Accounts_Set_Email_Of_External_Accounts_as_Verified_Description": "एलडीएपी, ओएथ आदि जैसी बाहरी सेवाओं से बनाए गए खातों के ईमेल स्वचालित रूप से सत्यापित हो जाएंगे", + "Accounts_SetDefaultAvatar": "डिफ़ॉल्ट अवतार सेट करें", + "Accounts_SetDefaultAvatar_Description": "OAuth खाते या Gravatar के आधार पर डिफ़ॉल्ट अवतार निर्धारित करने का प्रयास करता है", + "Accounts_ShowFormLogin": "डिफ़ॉल्ट लॉगिन फॉर्म दिखाएँ", + "Accounts_TwoFactorAuthentication_By_TOTP_Enabled": "टीओटीपी के माध्यम से दो कारक प्रमाणीकरण सक्षम करें", + "Accounts_TwoFactorAuthentication_By_TOTP_Enabled_Description": "उपयोगकर्ता Google Authenticator या Authy जैसे किसी भी TOTP ऐप का उपयोग करके अपना टू फैक्टर ऑथेंटिकेशन सेटअप कर सकते हैं।", + "Accounts_TwoFactorAuthentication_By_Email_Auto_Opt_In": "ईमेल के माध्यम से टू फैक्टर के लिए नए उपयोगकर्ताओं को ऑटो ऑप्ट इन करें", + "Accounts_TwoFactorAuthentication_By_Email_Auto_Opt_In_Description": "नए उपयोगकर्ताओं के पास ईमेल के माध्यम से दो कारक प्रमाणीकरण डिफ़ॉल्ट रूप से सक्षम होगा। वे इसे अपने प्रोफ़ाइल पृष्ठ में अक्षम कर सकेंगे.", + "Accounts_TwoFactorAuthentication_By_Email_Code_Expiration": "ईमेल के माध्यम से भेजे गए कोड को सेकंडों में समाप्त करने का समय", + "Accounts_TwoFactorAuthentication_By_Email_Enabled": "ईमेल के माध्यम से दो कारक प्रमाणीकरण सक्षम करें", + "Accounts_TwoFactorAuthentication_By_Email_Enabled_Description": "जिन उपयोगकर्ताओं का ईमेल सत्यापित है और उनके प्रोफ़ाइल पृष्ठ में विकल्प सक्षम है, उन्हें कुछ कार्यों जैसे लॉगिन, प्रोफ़ाइल सहेजना आदि को अधिकृत करने के लिए एक अस्थायी कोड के साथ एक ईमेल प्राप्त होगा।", + "Accounts_TwoFactorAuthentication_Enabled": "दो कारक प्रमाणीकरण सक्षम करें", + "Accounts_TwoFactorAuthentication_Enabled_Description": "निष्क्रिय होने पर, यह सेटिंग सभी दो कारक प्रमाणीकरण को निष्क्रिय कर देगी।\nउपयोगकर्ताओं को दो कारक प्रमाणीकरण का उपयोग करने के लिए बाध्य करने के लिए, व्यवस्थापक को इसे लागू करने के लिए 'उपयोगकर्ता' भूमिका को कॉन्फ़िगर करना होगा।", + "Accounts_TwoFactorAuthentication_Enforce_Password_Fallback": "पासवर्ड फ़ॉलबैक लागू करें", + "Accounts_TwoFactorAuthentication_Enforce_Password_Fallback_Description": "यदि उस उपयोगकर्ता के लिए कोई अन्य दो कारक प्रमाणीकरण विधि सक्षम नहीं है और उसके लिए एक पासवर्ड सेट किया गया है, तो महत्वपूर्ण कार्यों के लिए उपयोगकर्ताओं को अपना पासवर्ड दर्ज करने के लिए मजबूर किया जाएगा।", "Accounts_TwoFactorAuthentication_MaxDelta": "soochna", + "Accounts_TwoFactorAuthentication_MaxDelta_Description": "अधिकतम डेल्टा यह निर्धारित करता है कि किसी भी समय कितने टोकन वैध हैं। टोकन हर 30 सेकंड में उत्पन्न होते हैं, और (30 * अधिकतम डेल्टा) सेकंड के लिए वैध होते हैं।\nउदाहरण: अधिकतम डेल्टा 10 पर सेट होने पर, प्रत्येक टोकन का उपयोग उसके टाइमस्टैम्प से 300 सेकंड पहले या बाद तक किया जा सकता है। यह तब उपयोगी होता है जब क्लाइंट की घड़ी सर्वर के साथ ठीक से समन्वयित नहीं होती है।", + "Accounts_TwoFactorAuthentication_RememberFor": "(सेकंड) के लिए दो कारक याद रखें", + "Accounts_TwoFactorAuthentication_RememberFor_Description": "यदि दो कारक प्राधिकरण कोड पहले ही दिए गए समय में प्रदान किया गया हो तो उसका अनुरोध न करें।", + "Accounts_UseDefaultBlockedDomainsList": "डिफ़ॉल्ट अवरुद्ध डोमेन सूची का उपयोग करें", + "Accounts_UseDNSDomainCheck": "DNS डोमेन जाँच का उपयोग करें", + "API_EmbedDisabledFor": "उपयोगकर्ताओं के लिए एंबेड अक्षम करें", + "Accounts_UserAddedEmail_Default": "

    [साइट_नाम] में आपका स्वागत है

    [Site_URL] पर जाएँ और आज उपलब्ध सर्वोत्तम ओपन सोर्स चैट समाधान आज़माएँ!

    आप अपने ईमेल: [ईमेल] और पासवर्ड: [पासवर्ड] का उपयोग करके लॉगिन कर सकते हैं। आपको अपने पहले लॉगिन के बाद इसे बदलने की आवश्यकता हो सकती है।", + "Accounts_UserAddedEmail_Description": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं:\n - `[नाम]`, `[fname]`, `[lname]` क्रमशः उपयोगकर्ता के पूर्ण नाम, प्रथम नाम या अंतिम नाम के लिए।\n - `[ईमेल]` उपयोगकर्ता के ईमेल के लिए।\n - उपयोगकर्ता के पासवर्ड के लिए `[पासवर्ड]`।\n - एप्लिकेशन नाम और यूआरएल के लिए क्रमशः `[Site_Name]` और `[Site_URL]`।", + "API_EmbedDisabledFor_Description": "एम्बेडेड लिंक पूर्वावलोकन को अक्षम करने के लिए उपयोगकर्ता नामों की अल्पविराम से अलग की गई सूची।", + "Accounts_UserAddedEmailSubject_Default": "आपको [Site_Name] में जोड़ दिया गया है", + "Accounts_Verify_Email_For_External_Accounts": "सत्यापित बाहरी खातों के लिए ईमेल चिह्नित करें", + "Action": "कार्रवाई", + "Action_required": "कार्रवाई आवश्यक है", + "Action_Available_After_Custom_Content_Added": "कस्टम सामग्री जोड़े जाने के बाद यह क्रिया उपलब्ध हो जाएगी", + "Action_Available_After_Custom_Content_Added_And_Visible": "यह क्रिया कस्टम सामग्री जोड़े जाने और सभी के लिए दृश्यमान होने के बाद उपलब्ध हो जाएगी", + "Activate": "सक्रिय", + "Active": "सक्रिय", + "Active_users": "सक्रिय उपयोगकर्ता", + "Activity": "गतिविधि", + "Add": "जोड़ना", + "Add_a_Message": "कोई संदेश जोड़ें", + "Add_agent": "एजेंट जोड़ें", + "Add_custom_oauth": "कस्टम OAuth जोड़ें", + "Add_Domain": "डोमेन जोड़ें", + "Add_emoji": "इमोजी जोड़ें", + "Add_files_from": "से फ़ाइलें जोड़ें", + "Add_manager": "प्रबंधक जोड़ें", + "Add_monitor": "मॉनिटर जोड़ें", + "Add_Reaction": "प्रतिक्रिया जोड़ें", + "Add_Role": "भूमिका जोड़ें", + "Add_Sender_To_ReplyTo": "प्रेषक को उत्तर-प्रति में जोड़ें", + "Add_Server": "सर्वर जोड़े", + "Add_URL": "यूआरएल जोड़ें", + "Add_user": "उपयोगकर्ता जोड़ें", + "Add_User": "उपयोगकर्ता जोड़ें", + "Add_users": "उपयोगकर्ता जोड़ें", + "Add_members": "सदस्य जोड़ें", + "add-all-to-room": "सभी उपयोगकर्ताओं को एक कमरे में जोड़ें", + "add-all-to-room_description": "सभी उपयोगकर्ताओं को एक कमरे में जोड़ने की अनुमति", + "add-livechat-department-agents": "विभागों में ओमनीचैनल एजेंट जोड़ें", + "add-livechat-department-agents_description": "विभागों में ओमनीचैनल एजेंटों को जोड़ने की अनुमति", + "add-oauth-service": "OAuth सेवा जोड़ें", + "add-oauth-service_description": "नई OAuth सेवा जोड़ने की अनुमति", + "bypass-time-limit-edit-and-delete": "समय सीमा को बायपास करें", + "bypass-time-limit-edit-and-delete_description": "संदेशों को संपादित करने और हटाने के लिए समय सीमा को बायपास करने की अनुमति", + "add-team-channel": "टीम चैनल जोड़ें", + "add-team-channel_description": "किसी टीम में चैनल जोड़ने की अनुमति", + "add-team-member": "टीम सदस्य जोड़ें", + "add-team-member_description": "किसी टीम में सदस्यों को जोड़ने की अनुमति", + "add-user": "उपयोगकर्ता जोड़ें", + "add-user_description": "उपयोगकर्ता स्क्रीन के माध्यम से सर्वर पर नए उपयोगकर्ता जोड़ने की अनुमति", + "add-user-to-any-c-room": "किसी भी सार्वजनिक चैनल में उपयोगकर्ता जोड़ें", + "add-user-to-any-c-room_description": "किसी उपयोगकर्ता को किसी सार्वजनिक चैनल में जोड़ने की अनुमति", + "add-user-to-any-p-room": "किसी भी निजी चैनल में उपयोगकर्ता जोड़ें", + "add-user-to-any-p-room_description": "किसी निजी चैनल में उपयोगकर्ता जोड़ने की अनुमति", + "add-user-to-joined-room": "किसी भी जुड़े हुए चैनल में उपयोगकर्ता जोड़ें", + "add-user-to-joined-room_description": "किसी उपयोगकर्ता को वर्तमान में शामिल चैनल में जोड़ने की अनुमति", + "added__roomName__to_team": "इस टीम में #{{roomName}} जोड़ा गया", + "Added__username__to_team": "इस टीम में @{{user_added}} जोड़ा गया", + "added__roomName__to_this_team": "इस टीम में #{{roomName}} जोड़ा गया", + "Apps_Framework_enabled": "ऐप फ़्रेमवर्क सक्षम करें", + "Added__username__to_this_team": "इस टीम में @{{user_added}} जोड़ा गया", + "Adding_OAuth_Services": "OAuth सेवाएँ जोड़ना", + "Adding_permission": "अनुमति जोड़ी जा रही है", + "Adjustable_layout": "समायोज्य लेआउट", + "Adding_user": "उपयोगकर्ता जोड़ा जा रहा है", + "Additional_emails": "अतिरिक्त ईमेल", "Additional_Feedback": "अतिरिक्त प्रतिक्रिया", + "additional_integrations_Bots": "यदि आप यह खोज रहे हैं कि अपने स्वयं के बॉट को कैसे एकीकृत किया जाए, तो हमारे हबोट एडॉप्टर के अलावा कहीं और न देखें। https://github.com/RocketChat/hubot-rocketchat", + "Admin_disabled_encryption": "आपके व्यवस्थापक ने E2E एन्क्रिप्शन सक्षम नहीं किया है.", + "Admin_Info": "व्यवस्थापक जानकारी", + "admin-no-active-video-conf-provider": "**कॉन्फ़्रेंस कॉल सक्षम नहीं है**: इस कार्यस्थान पर उपलब्ध कराने के लिए कॉन्फ़्रेंस कॉल कॉन्फ़िगर करें।", + "admin-video-conf-provider-not-configured": "**कॉन्फ़्रेंस कॉल सक्षम नहीं है**: इस कार्यस्थान पर उपलब्ध कराने के लिए कॉन्फ़्रेंस कॉल कॉन्फ़िगर करें।", + "admin-no-videoconf-provider-app": "**कॉन्फ्रेंस कॉल सक्षम नहीं**: कॉन्फ्रेंस कॉल ऐप्स रॉकेट.चैट मार्केटप्लेस में उपलब्ध हैं।", + "Administration": "प्रशासन", + "Address": "पता", + "Adjustable_font_size": "समायोज्य फ़ॉन्ट आकार", + "Adjustable_font_size_description": "उन लोगों के लिए डिज़ाइन किया गया है जो बेहतर पठनीयता के लिए बड़े या छोटे पाठ को पसंद करते हैं। यह लचीलापन उपयोगकर्ताओं को सॉफ़्टवेयर इंटरफ़ेस को उनकी विशिष्ट आवश्यकताओं के अनुरूप बनाने के लिए सशक्त बनाकर समावेशिता को बढ़ावा देता है।", + "Adult_images_are_not_allowed": "वयस्क छवियों की अनुमति नहीं है", + "Aerospace_and_Defense": "विमानन व रक्षा", + "After_OAuth2_authentication_users_will_be_redirected_to_this_URL": "OAuth2 प्रमाणीकरण के बाद, उपयोगकर्ताओं को इस सूची के एक URL पर पुनः निर्देशित किया जाएगा। आप प्रति पंक्ति एक URL जोड़ सकते हैं.", + "After_guest_registration": "अतिथि पंजीकरण के बाद", + "Agent": "प्रतिनिधि", + "Agent_added": "एजेंट जोड़ा गया", + "Agent_Info": "एजेंट की जानकारी", + "Agent_messages": "एजेंट संदेश", + "Agent_Name": "एजेंट का नाम", + "Agent_Name_Placeholder": "कृपया एजेंट का नाम दर्ज करें...", + "Agent_removed": "एजेंट हटा दिया गया", + "Agent_deactivated": "एजेंट निष्क्रिय कर दिया गया", + "Agent_Without_Extensions": "एक्सटेंशन के बिना एजेंट", + "Agents": "एजेंटों", + "Agree": "सहमत", + "Alerts": "अलर्ट", + "Alias": "उपनाम", + "Alias_Format": "अन्य प्रारूप", + "Alias_Format_Description": "उपनाम के साथ स्लैक से संदेश आयात करें; %s को उपयोक्ता के उपयोक्तानाम से बदल दिया जाता है। यदि खाली है, तो किसी उपनाम का उपयोग नहीं किया जाएगा।", + "Alias_Set": "उपनाम सेट", + "AutoLinker_Email": "ऑटोलिंकर ईमेल", + "Aliases": "उपनाम", + "AutoLinker_Phone": "ऑटोलिंकर फ़ोन", + "AutoLinker_Phone_Description": "फ़ोन नंबरों के लिए स्वचालित रूप से लिंक किया गया. जैसे `(123)456-7890`", + "All": "सभी", + "AutoLinker_StripPrefix": "ऑटोलिंकर स्ट्रिप उपसर्ग", + "All_Apps": "सभी एप्लीकेशन", + "AutoLinker_StripPrefix_Description": "लघु प्रदर्शन. जैसे https://rocket.chat => रॉकेट.चैट", + "All_added_tokens_will_be_required_by_the_user": "उपयोगकर्ता को सभी जोड़े गए टोकन की आवश्यकता होगी", + "All_categories": "सब वर्ग", + "AutoLinker_Urls_Scheme": "ऑटोलिंकर योजना: // यूआरएल", + "All_channels": "सभी चैनल", + "AutoLinker_Urls_TLD": "ऑटोलिंकर टीएलडी यूआरएल", + "All_closed_chats_have_been_removed": "सभी बंद चैट हटा दिए गए हैं", + "AutoLinker_Urls_www": "ऑटोलिंक 'www' यूआरएल", + "All_logs": "सभी लॉग", + "AutoLinker_UrlsRegExp": "ऑटोलिंकर यूआरएल नियमित अभिव्यक्ति", + "All_messages": "सभी संदेश", + "All_Prices": "सभी कीमतें", + "All_status": "सभी स्थिति", + "All_users": "सभी उपयोगकर्ता", + "All_users_in_the_channel_can_write_new_messages": "चैनल के सभी उपयोगकर्ता नए संदेश लिख सकते हैं", + "Allow_collect_and_store_HTTP_header_informations": "HTTP हेडर जानकारी एकत्र करने और संग्रहीत करने की अनुमति दें", + "Allow_collect_and_store_HTTP_header_informations_description": "यह सेटिंग निर्धारित करती है कि क्या लाइवचैट को HTTP हेडर डेटा से एकत्र की गई जानकारी, जैसे आईपी पता, उपयोगकर्ता-एजेंट, आदि को संग्रहीत करने की अनुमति है।", + "Allow_Invalid_SelfSigned_Certs": "अमान्य स्व-हस्ताक्षरित प्रमाणपत्र की अनुमति दें", + "Allow_Invalid_SelfSigned_Certs_Description": "लिंक सत्यापन और पूर्वावलोकन के लिए अमान्य और स्व-हस्ताक्षरित एसएसएल प्रमाणपत्र की अनुमति दें।", + "Allow_Marketing_Emails": "मार्केटिंग ईमेल की अनुमति दें", + "Allow_Online_Agents_Outside_Business_Hours": "व्यावसायिक घंटों के बाहर ऑनलाइन एजेंटों को अनुमति दें", + "Allow_Online_Agents_Outside_Office_Hours": "कार्यालय समय के बाहर ऑनलाइन एजेंटों को अनुमति दें", + "Allow_Save_Media_to_Gallery": "मीडिया को गैलरी में सहेजने की अनुमति दें", + "Allow_switching_departments": "आगंतुक को विभाग बदलने की अनुमति दें", + "Almost_done": "लगभग हो गया", + "Alphabetical": "वर्णमाला", + "bold": "बोल्ड", + "Also_send_thread_message_to_channel_behavior": "चैनल व्यवहार के लिए थ्रेड संदेश भी भेजें", + "Also_send_to_channel": "चैनल को भी भेजें", + "Always_open_in_new_window": "हमेशा नई विंडो में खोलें", + "Always_show_thread_replies_in_main_channel": "थ्रेड उत्तरों को हमेशा मुख्य चैनल में दिखाएं", + "Analytic_reports": "विश्लेषणात्मक रिपोर्ट", + "Analytics": "एनालिटिक्स", + "Analytics_Description": "देखें कि उपयोगकर्ता आपके कार्यक्षेत्र के साथ कैसे इंटरैक्ट करते हैं।", + "Analytics_features_enabled": "सुविधाएँ सक्षम", + "Analytics_features_messages_Description": "उपयोगकर्ता द्वारा संदेशों पर की जाने वाली कार्रवाइयों से संबंधित कस्टम ईवेंट को ट्रैक करता है।", + "Analytics_features_rooms_Description": "किसी चैनल या समूह पर गतिविधियों से संबंधित कस्टम ईवेंट को ट्रैक करता है (बनाएं, छोड़ें, हटाएं)।", + "Analytics_features_users_Description": "उपयोगकर्ताओं से संबंधित कार्यों से संबंधित कस्टम ईवेंट को ट्रैक करता है (पासवर्ड रीसेट समय, प्रोफ़ाइल चित्र परिवर्तन, आदि)।", + "Analytics_Google": "गूगल विश्लेषिकी", + "Analytics_Google_id": "ट्रैकिंग आईडी", + "Analytics_page_briefing_first_paragraph": "Rocket.Chat सभी के लिए उत्पाद को बेहतर बनाने के लिए अनाम उपयोग डेटा, जैसे सुविधा उपयोग और सत्र की लंबाई, एकत्र करता है।", + "Analytics_page_briefing_second_paragraph": "हम कभी भी व्यक्तिगत या संवेदनशील डेटा एकत्र न करके आपकी गोपनीयता की रक्षा करते हैं। यह अनुभाग दिखाता है कि क्या एकत्र किया गया है, जो पारदर्शिता और विश्वास के प्रति हमारी प्रतिबद्धता को मजबूत करता है।", + "Analyze_practical_usage": "उपयोगकर्ताओं, संदेशों और चैनलों के बारे में व्यावहारिक उपयोग के आँकड़ों का विश्लेषण करें", + "and": "और", + "And_more": "और {{length}} और भी", + "Animals_and_Nature": "पशु और प्रकृति", + "Announcement": "घोषणा", + "Anonymous": "गुमनाम", + "Answer_call": "कॉल का उत्तर दें", + "API": "एपीआई", + "API_Add_Personal_Access_Token": "नया व्यक्तिगत एक्सेस टोकन जोड़ें", + "API_Allow_Infinite_Count": "सब कुछ पाने की अनुमति दें", + "API_Allow_Infinite_Count_Description": "क्या REST API पर कॉल को एक कॉल में सब कुछ वापस करने की अनुमति दी जानी चाहिए?", + "API_Analytics": "एनालिटिक्स", + "API_CORS_Origin": "कॉर्स उत्पत्ति", + "API_Apply_permission_view-outside-room_on_users-list": "एपीआई `users.list` पर `view-outside-room` अनुमति लागू करें", + "API_Apply_permission_view-outside-room_on_users-list_Description": "अनुमति लागू करने के लिए अस्थायी सेटिंग. अनुमति को हमेशा लागू करने के लिए परिवर्तन के अंतर्गत अगली प्रमुख रिलीज़ पर हटा दिया जाएगा", + "API_Default_Count": "डिफ़ॉल्ट count", + "API_Default_Count_Description": "यदि उपभोक्ता ने कोई प्रदान नहीं किया है तो REST API परिणामों के लिए डिफ़ॉल्ट गणना।", + "API_Drupal_URL": "ड्रूपल सर्वर यूआरएल", + "API_Drupal_URL_Description": "उदाहरण: `https://domain.com` (अनुगामी स्लैश को छोड़कर)", + "API_Embed": "लिंक पूर्वावलोकन एम्बेड करें", + "API_Embed_Description": "जब कोई उपयोगकर्ता किसी वेबसाइट पर लिंक पोस्ट करता है तो एम्बेडेड लिंक पूर्वावलोकन सक्षम होते हैं या नहीं।", + "API_EmbedIgnoredHosts": "उपेक्षित होस्ट एम्बेड करें", + "API_EmbedIgnoredHosts_Description": "होस्ट या सीआईडीआर पतों की अल्पविराम से अलग की गई सूची, उदाहरण के लिए। लोकलहोस्ट, 127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16", + "API_EmbedSafePorts": "सुरक्षित बंदरगाह", + "API_EmbedSafePorts_Description": "पूर्वावलोकन के लिए अनुमति प्राप्त बंदरगाहों की अल्पविराम से अलग की गई सूची।", + "API_Embed_UserAgent": "एंबेड अनुरोध उपयोगकर्ता एजेंट", + "API_EmbedCacheExpirationDays": "एंबेड कैश समाप्ति दिवस", + "API_Enable_CORS": "CORS सक्षम करें", + "API_Enable_Direct_Message_History_EndPoint": "सीधा संदेश इतिहास समापन बिंदु सक्षम करें", + "API_Enable_Direct_Message_History_EndPoint_Description": "यह `/api/v1/im.history.others` को सक्षम करता है जो अन्य उपयोगकर्ताओं द्वारा भेजे गए सीधे संदेशों को देखने की अनुमति देता है जिनका कॉलर हिस्सा नहीं है।", + "API_Enable_Personal_Access_Tokens": "REST API में व्यक्तिगत एक्सेस टोकन सक्षम करें", + "API_Enable_Personal_Access_Tokens_Description": "REST API के साथ उपयोग के लिए व्यक्तिगत एक्सेस टोकन सक्षम करें", + "API_Enable_Rate_Limiter": "दर सीमक सक्षम करें", + "API_Enable_Rate_Limiter_Dev": "विकास में दर सीमक सक्षम करें", + "API_Enable_Rate_Limiter_Dev_Description": "क्या विकास परिवेश में कॉल की मात्रा को अंतिम बिंदुओं तक सीमित किया जाना चाहिए?", + "API_Enable_Rate_Limiter_Limit_Calls_Default": "रेट लिमिटर पर डिफ़ॉल्ट नंबर कॉल", + "API_Enable_Rate_Limiter_Limit_Calls_Default_Description": "REST API के प्रत्येक समापन बिंदु के लिए डिफ़ॉल्ट कॉल की संख्या, नीचे परिभाषित समय सीमा के भीतर अनुमत है", + "API_Enable_Rate_Limiter_Limit_Time_Default": "दर सीमक के लिए डिफ़ॉल्ट समय सीमा (एमएस में)", + "API_Enable_Rate_Limiter_Limit_Time_Default_Description": "REST API के प्रत्येक समापन बिंदु पर कॉल की संख्या सीमित करने के लिए डिफ़ॉल्ट टाइमआउट (एमएस में)", + "API_Enable_Shields": "शील्ड्स सक्षम करें", + "API_Enable_Shields_Description": "`/api/v1/shield.svg` पर उपलब्ध शील्ड सक्षम करें", + "API_GitHub_Enterprise_URL": "सर्वर यूआरएल", + "API_GitHub_Enterprise_URL_Description": "उदाहरण: `https://domain.com` (अनुगामी स्लैश को छोड़कर)", + "API_Gitlab_URL": "गिटलैब यूआरएल", + "API_Personal_Access_Token_Generated": "पर्सनल एक्सेस टोकन सफलतापूर्वक जनरेट हुआ", + "API_Personal_Access_Token_Generated_Text_Token_s_UserId_s": "कृपया अपना टोकन सावधानी से सहेजें क्योंकि इसके बाद आप इसे नहीं देख पाएंगे।
    टोकन: {{token}}
    आपकी उपयोगकर्ता आईडी: {{userId}}", + "API_Personal_Access_Token_Name": "व्यक्तिगत पहुँच टोकन नाम", + "API_Personal_Access_Tokens_Regenerate_It": "टोकन पुन: उत्पन्न करें", + "API_Personal_Access_Tokens_Regenerate_Modal": "यदि आपने अपना टोकन खो दिया है या भूल गए हैं, तो आप इसे पुन: उत्पन्न कर सकते हैं, लेकिन याद रखें कि इस टोकन का उपयोग करने वाले सभी एप्लिकेशन को अपडेट किया जाना चाहिए", + "API_Personal_Access_Tokens_Remove_Modal": "क्या आप वाकई इस व्यक्तिगत एक्सेस टोकन को हटाना चाहते हैं?", + "API_Personal_Access_Tokens_To_REST_API": "REST API तक व्यक्तिगत पहुंच टोकन", + "API_Rate_Limiter": "एपीआई दर सीमक", + "API_Shield_Types": "ढाल के प्रकार", + "API_Shield_Types_Description": "अल्पविराम से अलग की गई सूची के रूप में सक्षम करने के लिए शील्ड के प्रकार, सभी के लिए `ऑनलाइन`, `चैनल` या `*` में से चुनें", + "Apps_Framework_Development_Mode": "विकास मोड सक्षम करें", + "API_Shield_user_require_auth": "उपयोगकर्ता शील्ड के लिए प्रमाणीकरण की आवश्यकता है", + "API_Token": "एपीआई टोकन", + "Apps_Framework_Development_Mode_Description": "डेवलपमेंट मोड उन ऐप्स को इंस्टॉल करने की अनुमति देता है जो Rocket.Chat के मार्केटप्लेस से नहीं हैं।", + "API_Tokenpass_URL": "टोकनपास सर्वर यूआरएल", + "API_Tokenpass_URL_Description": "उदाहरण: `https://domain.com` (अनुगामी स्लैश को छोड़कर)", + "API_Upper_Count_Limit": "अधिकतम रिकार्ड राशि", + "API_Upper_Count_Limit_Description": "REST API को अधिकतम कितने रिकॉर्ड लौटाने चाहिए (जब असीमित न हो)?", + "API_Use_REST_For_DDP_Calls": "उल्का कॉल के लिए वेबसोकेट के बजाय REST का उपयोग करें", + "API_User_Limit": "सभी उपयोगकर्ताओं को चैनल में जोड़ने के लिए उपयोगकर्ता सीमा", + "API_Wordpress_URL": "वर्डप्रेस यूआरएल", + "api-bypass-rate-limit": "REST API के लिए बाईपास दर सीमा", + "api-bypass-rate-limit_description": "दर सीमा के बिना एपीआई कॉल करने की अनुमति", + "Apiai_Key": "एपीआई.एआई कुंजी", + "Apiai_Language": "एपीआई.एआई भाषा", + "APIs": "शहद की मक्खी", + "App_author_homepage": "लेखक मुखपृष्ठ", + "App_Details": "ऐप विवरण", + "App_Info": "अनुप्रयोग की जानकारी", + "App_Information": "ऐप की जानकारी", + "App_Installation": "ऐप इंस्टालेशन", + "App_not_enabled": "ऐप सक्षम नहीं है", + "App_not_found": "ऐप नहीं मिला", "App_status_auto_enabled": "सक्रिय", + "App_status_constructed": "निर्माण", "App_status_disabled": "उपयोग करने की अनुमति नहीं है", + "App_status_error_disabled": "अक्षम: ध्यान में न आई त्रुटि", + "App_status_initialized": "प्रारंभ", + "App_status_invalid_license_disabled": "विकलांग: अमान्य लाइसेंस", + "App_status_invalid_settings_disabled": "अक्षम: कॉन्फ़िगरेशन की आवश्यकता है", + "App_status_manually_disabled": "अक्षम: मैन्युअल रूप से", "App_status_manually_enabled": "सक्रिय", + "App_status_unknown": "अज्ञात", + "App_Store": "ऐप स्टोर", + "App_support_url": "यूआरएल का समर्थन करें", + "App_Url_to_Install_From": "यूआरएल से इंस्टॉल करें", + "App_Url_to_Install_From_File": "फ़ाइल से इंस्टॉल करें", + "App_user_not_allowed_to_login": "ऐप उपयोगकर्ताओं को सीधे लॉग इन करने की अनुमति नहीं है।", "Appearance": "दिखावट", + "Application_added": "एप्लिकेशन जोड़ा गया", + "Application_delete_warning": "आप इस एप्लिकेशन को पुनर्प्राप्त नहीं कर पाएंगे!", + "Application_Name": "आवेदन का नाम", + "Application_updated": "एप्लिकेशन अपडेट किया गया", + "Apply": "आवेदन करना", + "Apply_and_refresh_all_clients": "सभी ग्राहकों को लागू करें और ताज़ा करें", + "Apps": "ऐप्स", + "Apps_context_explore": "अन्वेषण करना", + "Apps_context_installed": "स्थापित", + "Apps_context_requested": "का अनुरोध किया", + "Apps_context_private": "निजी ऐप्स", + "Apps_context_premium": "अधिमूल्य", + "Apps_Count_Enabled": "{{count}} ऐप सक्षम", + "Private_Apps_Count_Enabled": "{{count}} निजी ऐप सक्षम", + "Apps_Count_Enabled_tooltip": "सामुदायिक कार्यस्थान अधिकतम {{number}} {{context}} ऐप्स सक्षम कर सकते हैं", + "Apps_disabled_when_Premium_trial_ended": "प्रीमियम योजना का परीक्षण समाप्त होने पर ऐप्स अक्षम हो गए", + "Apps_disabled_when_Premium_trial_ended_description": "समुदाय पर कार्यस्थानों में अधिकतम 5 मार्केटप्लेस ऐप्स और 3 निजी ऐप्स सक्षम हो सकते हैं। अपने कार्यक्षेत्र व्यवस्थापक से ऐप्स को पुनः सक्षम करने के लिए कहें।", + "Apps_disabled_when_Premium_trial_ended_description_admin": "समुदाय पर कार्यस्थानों में अधिकतम 5 मार्केटप्लेस ऐप्स और 3 निजी ऐप्स सक्षम हो सकते हैं। आपके लिए आवश्यक ऐप्स को पुनः सक्षम करें.", + "Apps_Engine_Version": "ऐप्स इंजन संस्करण", + "Apps_Error_private_app_install_disabled": "इस कार्यक्षेत्र में निजी ऐप इंस्टॉलेशन और अपडेट अक्षम हैं", + "Apps_Essential_Alert": "यह ऐप निम्नलिखित घटनाओं के लिए आवश्यक है:", + "Apps_Essential_Disclaimer": "यदि यह ऐप अक्षम है तो ऊपर सूचीबद्ध ईवेंट बाधित हो जाएंगे। यदि आप चाहते हैं कि Rocket.Chat इस ऐप की कार्यक्षमता के बिना काम करे, तो आपको इसे अनइंस्टॉल करना होगा", + "Apps_Framework_Source_Package_Storage_Type": "ऐप्स का स्रोत पैकेज संग्रहण प्रकार", + "Apps_Framework_Source_Package_Storage_Type_Description": "चुनें कि सभी ऐप्स का स्रोत कोड कहाँ संग्रहीत किया जाएगा। प्रत्येक ऐप का आकार कई मेगाबाइट हो सकता है।", + "Apps_Framework_Source_Package_Storage_Type_Alert": "ऐप्स को संग्रहीत करने का स्थान बदलने से वहां पहले से इंस्टॉल किए गए ऐप्स में अस्थिरता उत्पन्न हो सकती है", + "Apps_Framework_Source_Package_Storage_FileSystem_Path": "ऐप्स स्रोत पैकेज संग्रहीत करने के लिए निर्देशिका", + "Apps_Framework_Source_Package_Storage_FileSystem_Path_Description": "ऐप्स के स्रोत कोड को संग्रहीत करने के लिए फ़ाइल सिस्टम में पूर्ण पथ (ज़िप फ़ाइल प्रारूप में)", + "Apps_Framework_Source_Package_Storage_FileSystem_Alert": "सुनिश्चित करें कि चुनी गई निर्देशिका मौजूद है और Rocket.Chat उस तक पहुंच सकता है (उदाहरण के लिए पढ़ने/लिखने की अनुमति)", + "Apps_Game_Center": "खेल केंद्र", + "Apps_Game_Center_Back": "गेम सेंटर पर वापस जाएँ", + "Apps_Game_Center_Invite_Friends": "शामिल होने के लिए अपने दोस्तों को आमंत्रित कीजिए", + "Apps_Game_Center_Play_Game_Together": "@यहाँ आइए एक साथ {{name}} खेलें!", + "Apps_Interface_IPostExternalComponentClosed": "किसी बाहरी घटक के बंद होने के बाद होने वाली घटना", + "Apps_Interface_IPostExternalComponentOpened": "किसी बाहरी घटक के खुलने के बाद होने वाली घटना", + "Apps_Interface_IPostMessageDeleted": "संदेश हटाए जाने के बाद होने वाली घटना", + "Apps_Interface_IPostMessageSent": "संदेश भेजे जाने के बाद होने वाली घटना", + "Apps_Interface_IPostMessageUpdated": "किसी संदेश के अद्यतन होने के बाद होने वाली घटना", + "Apps_Interface_IPostRoomCreate": "रूम बनने के बाद होने वाला इवेंट", + "Apps_Interface_IPostRoomDeleted": "एक कमरा हटाए जाने के बाद होने वाली घटना", + "Apps_Interface_IPostRoomUserJoined": "किसी उपयोगकर्ता के कमरे में शामिल होने के बाद होने वाली घटना (निजी समूह, सार्वजनिक चैनल)", + "Apps_Interface_IPreMessageDeletePrevent": "संदेश हटाए जाने से पहले होने वाली घटना", + "Apps_Interface_IPreMessageSentExtend": "संदेश भेजे जाने से पहले होने वाली घटना", + "Apps_Interface_IPreMessageSentModify": "संदेश भेजे जाने से पहले होने वाली घटना", + "Apps_Interface_IPreMessageSentPrevent": "संदेश भेजे जाने से पहले होने वाली घटना", + "Apps_Interface_IPreMessageUpdatedExtend": "किसी संदेश के अपडेट होने से पहले होने वाली घटना", + "Apps_Interface_IPreMessageUpdatedModify": "किसी संदेश के अपडेट होने से पहले होने वाली घटना", + "Apps_Interface_IPreMessageUpdatedPrevent": "किसी संदेश के अपडेट होने से पहले होने वाली घटना", + "Apps_Interface_IPreRoomCreateExtend": "रूम बनने से पहले होने वाली घटना", + "Apps_Interface_IPreRoomCreateModify": "रूम बनने से पहले होने वाली घटना", + "Apps_Interface_IPreRoomCreatePrevent": "रूम बनने से पहले होने वाली घटना", + "Apps_Interface_IPreRoomDeletePrevent": "किसी कमरे को हटाए जाने से पहले होने वाली घटना", + "Apps_Interface_IPreRoomUserJoined": "किसी उपयोगकर्ता के कमरे में शामिल होने से पहले होने वाली घटना (निजी समूह, सार्वजनिक चैनल)", + "Apps_License_Message_appId": "इस ऐप के लिए लाइसेंस जारी नहीं किया गया है", + "Apps_License_Message_bundle": "ऐसे बंडल के लिए लाइसेंस जारी किया गया जिसमें ऐप शामिल नहीं है", + "Apps_License_Message_expire": "लाइसेंस अब वैध नहीं है और इसे नवीनीकृत करने की आवश्यकता है", + "Apps_License_Message_maxSeats": "लाइसेंस सक्रिय उपयोगकर्ताओं की वर्तमान संख्या को समायोजित नहीं करता है। कृपया सीटों की संख्या बढ़ाएँ", + "Apps_License_Message_publicKey": "लाइसेंस को डिक्रिप्ट करने का प्रयास करते समय एक त्रुटि हुई है। कृपया अपने कार्यक्षेत्र को कनेक्टिविटी सेवाओं में सिंक करें और पुनः प्रयास करें", + "Apps_License_Message_renewal": "लाइसेंस समाप्त हो गया है और नवीनीकरण की आवश्यकता है", + "Apps_License_Message_seats": "सक्रिय उपयोगकर्ताओं की वर्तमान संख्या को समायोजित करने के लिए लाइसेंस में पर्याप्त सीटें नहीं हैं। कृपया सीटों की संख्या बढ़ाएँ", + "Apps_Logs_TTL": "ऐप्स से लॉग संग्रहीत रखने के लिए दिनों की संख्या", + "Apps_Logs_TTL_7days": "7 दिन", + "Apps_Logs_TTL_14days": "14 दिन", + "Apps_Logs_TTL_30days": "तीस दिन", + "Apps_Logs_TTL_Alert": "लॉग संग्रह के आकार के आधार पर, इस सेटिंग को बदलने से कुछ क्षणों के लिए धीमापन आ सकता है", + "Apps_Marketplace_Deactivate_App_Prompt": "क्या आप वाकई इस ऐप को अक्षम करना चाहते हैं?", + "Apps_Marketplace_Login_Required_Description": "Rocket.Chat मार्केटप्लेस से ऐप्स खरीदने के लिए आपके कार्यक्षेत्र को पंजीकृत करने और लॉग इन करने की आवश्यकता होती है।", + "Apps_Marketplace_Login_Required_Title": "मार्केटप्लेस लॉगिन आवश्यक", + "Apps_Marketplace_Modify_App_Subscription": "सदस्यता संशोधित करें", + "Apps_Marketplace_pricingPlan_monthly": "{{price}} /माह", + "Apps_Marketplace_pricingPlan_monthly_perUser": "{{price}} / प्रति उपयोगकर्ता माह", + "Apps_Marketplace_pricingPlan_monthly_trialDays": "{{price}} / माह-{{trialDays}}-दिन का परीक्षण", + "Apps_Marketplace_pricingPlan_monthly_perUser_trialDays": "{{price}}/माह प्रति उपयोगकर्ता-{{trialDays}}-दिन का परीक्षण", + "Apps_Marketplace_pricingPlan_+*_monthly": " {{price}}+* /माह", + "Apps_Marketplace_pricingPlan_+*_monthly_trialDays": " {{price}}+* / माह-{{trialDays}}-दिन का परीक्षण", + "Apps_Marketplace_pricingPlan_+*_monthly_perUser": " {{price}}+* / प्रति उपयोगकर्ता माह", + "Apps_Marketplace_pricingPlan_+*_monthly_perUser_trialDays": " {{price}}+* / प्रति उपयोगकर्ता माह-{{trialDays}}-दिन का परीक्षण", + "Apps_Marketplace_pricingPlan_+*_yearly": " {{price}}+* / वर्ष", + "Apps_Marketplace_pricingPlan_+*_yearly_trialDays": " {{price}}+* / वर्ष-{{trialDays}}-दिन का परीक्षण", + "Apps_Marketplace_pricingPlan_+*_yearly_perUser": " {{price}}+* / वर्ष प्रति उपयोगकर्ता", + "Apps_Marketplace_pricingPlan_+*_yearly_perUser_trialDays": " {{price}}+* / वर्ष प्रति उपयोगकर्ता-{{trialDays}}-दिन का परीक्षण", + "Apps_Marketplace_pricingPlan_yearly_trialDays": "{{price}} / वर्ष-{{trialDays}}-दिन का परीक्षण", + "Apps_Marketplace_pricingPlan_yearly_perUser_trialDays": "{{price}} / वर्ष प्रति उपयोगकर्ता-{{trialDays}}-दिन का परीक्षण", + "Apps_Marketplace_Uninstall_App_Prompt": "क्या आप वाकई इस ऐप को अनइंस्टॉल करना चाहते हैं?", + "Apps_Marketplace_Uninstall_Subscribed_App_Anyway": "फिर भी इसे अनइंस्टॉल करें", + "Apps_Marketplace_Uninstall_Subscribed_App_Prompt": "इस ऐप की सक्रिय सदस्यता है और अनइंस्टॉल करने से यह रद्द नहीं होगी। यदि आप ऐसा करना चाहते हैं, तो कृपया अनइंस्टॉल करने से पहले अपनी सदस्यता संशोधित करें।", + "Apps_Permissions_Review_Modal_Title": "आवश्यक अनुमतियाँ", + "Apps_Permissions_Review_Modal_Subtitle": "यह ऐप निम्नलिखित अनुमतियों तक पहुंच चाहता है। क्या आप सहमत हैं?", + "Apps_Permissions_No_Permissions_Required": "ऐप को अतिरिक्त अनुमतियों की आवश्यकता नहीं है", + "Apps_Permissions_cloud_workspace-token": "इस सर्वर की ओर से क्लाउड सेवाओं के साथ बातचीत करें", + "Apps_Permissions_user_read": "उपयोगकर्ता जानकारी तक पहुंचें", + "Apps_Permissions_user_write": "उपयोगकर्ता जानकारी संशोधित करें", + "Apps_Permissions_upload_read": "इस सर्वर पर अपलोड की गई एक्सेस फ़ाइलें", + "Apps_Permissions_upload_write": "इस सर्वर पर फ़ाइलें अपलोड करें", + "Apps_Permissions_server-setting_read": "इस सर्वर में सेटिंग्स तक पहुंचें", + "Apps_Permissions_server-setting_write": "इस सर्वर में सेटिंग्स संशोधित करें", + "Apps_Permissions_room_read": "कमरे की जानकारी तक पहुंचें", + "Apps_Permissions_room_write": "कमरे बनाएं और संशोधित करें", + "Apps_Permissions_message_read": "संदेशों तक पहुंचें", + "Apps_Permissions_message_write": "संदेश भेजें और संशोधित करें", + "Apps_Permissions_livechat-status_read": "लाइवचैट स्थिति की जानकारी तक पहुंचें", + "Apps_Permissions_livechat-custom-fields_write": "लाइवचैट कस्टम फ़ील्ड कॉन्फ़िगरेशन को संशोधित करें", + "Apps_Permissions_livechat-visitor_read": "लाइवचैट विज़िटर जानकारी तक पहुंचें", + "Apps_Permissions_livechat-visitor_write": "लाइवचैट विज़िटर जानकारी संशोधित करें", + "Apps_Permissions_livechat-message_read": "लाइवचैट संदेश जानकारी तक पहुंचें", + "Apps_Permissions_livechat-message_write": "लाइवचैट संदेश जानकारी संशोधित करें", + "Apps_Permissions_livechat-room_read": "लाइवचैट रूम की जानकारी तक पहुंचें", + "Apps_Permissions_livechat-room_write": "लाइवचैट रूम की जानकारी संशोधित करें", + "Apps_Permissions_livechat-department_read": "लाइवचैट विभाग की जानकारी तक पहुंचें", + "Apps_Permissions_livechat-department_multiple": "कई लाइवचैट विभागों की जानकारी तक पहुंच", + "Apps_Permissions_livechat-department_write": "लाइवचैट विभाग की जानकारी संशोधित करें", + "Apps_Permissions_slashcommand": "नए स्लैश कमांड पंजीकृत करें", + "Apps_Permissions_api": "नए HTTP समापनबिंदु पंजीकृत करें", + "Apps_Permissions_env_read": "इस सर्वर वातावरण के बारे में न्यूनतम जानकारी तक पहुँचें", + "Apps_Permissions_networking": "इस सर्वर नेटवर्क तक पहुंच", + "Apps_Permissions_persistence": "डेटाबेस में आंतरिक डेटा संग्रहीत करें", + "Apps_Permissions_scheduler": "निर्धारित नौकरियों को पंजीकृत करें और बनाए रखें", + "Apps_Permissions_ui_interact": "यूआई के साथ इंटरैक्ट करें", + "Apps_Settings": "ऐप की सेटिंग्स", + "Apps_Manual_Update_Modal_Title": "यह ऐप पहले से इंस्टॉल है", + "Apps_Manual_Update_Modal_Body": "क्या आप इसे अपडेट करना चाहते हैं?", + "Apps_User_Already_Exists": "उपयोक्तानाम \"{{username}}\" पहले से ही प्रयोग किया जा रहा है। इस ऐप को इंस्टॉल करने के लिए इसका उपयोग करने वाले उपयोगकर्ता का नाम बदलें या उसे हटा दें", + "AutoLinker": "ऑटोलिंकर", + "Apps_WhatIsIt": "ऐप्स: वे क्या हैं?", + "Apps_WhatIsIt_paragraph1": "प्रशासन क्षेत्र में एक नया आइकन! इसका क्या मतलब है और ऐप्स क्या हैं?", + "Apps_WhatIsIt_paragraph2": "सबसे पहले, इस संदर्भ में ऐप्स का तात्पर्य मोबाइल एप्लिकेशन से नहीं है। वास्तव में, प्लगइन्स या उन्नत एकीकरण के संदर्भ में उनके बारे में सोचना सबसे अच्छा होगा।", + "Apps_WhatIsIt_paragraph3": "दूसरे, वे गतिशील स्क्रिप्ट या पैकेज हैं जो आपको कोडबेस को फोर्क किए बिना अपने रॉकेट.चैट इंस्टेंस को अनुकूलित करने की अनुमति देंगे। लेकिन ध्यान रखें, यह एक नया फीचर सेट है और इसके कारण यह 100% स्थिर नहीं हो सकता है। साथ ही, हम अभी भी फीचर सेट विकसित कर रहे हैं इसलिए इस समय हर चीज को अनुकूलित नहीं किया जा सकता है। किसी ऐप को विकसित करना शुरू करने के बारे में अधिक जानकारी के लिए, यहां जाकर पढ़ें:", + "Apps_WhatIsIt_paragraph4": "लेकिन इसके साथ ही, यदि आप इस सुविधा को सक्षम करने और इसे आज़माने में रुचि रखते हैं तो ऐप्स सिस्टम को सक्षम करने के लिए यहां इस बटन पर क्लिक करें।", + "Archive": "पुरालेख", + "Archived": "संग्रहीत", + "archive-room": "पुरालेख कक्ष", + "archive-room_description": "किसी चैनल को संग्रहित करने की अनुमति", + "are_typing": "टाइप कर रहे हैं", + "are_playing": "खेल रहे हैं", + "is_playing": "खेल रहे है", + "are_uploading": "अपलोड कर रहे हैं", + "are_recording": "रिकॉर्डिंग कर रहे हैं", + "is_uploading": "अपलोड कर रहा है", + "is_recording": "रिकॉर्डिंग कर रहा है", + "Are_you_sure": "क्या आपको यकीन है?", + "Are_you_sure_delete_department": "क्या आप वाकई इस विभाग को हटाना चाहते हैं? इस एक्शन को वापस नहीं किया जा सकता। पुष्टि करने के लिए कृपया विभाग का नाम दर्ज करें।", + "Are_you_sure_you_want_to_clear_all_unread_messages": "क्या आप वाकई सभी अपठित संदेशों को साफ़ करना चाहते हैं?", + "Are_you_sure_you_want_to_close_this_chat": "क्या आप वाकई इस चैट को बंद करना चाहते हैं?", + "Are_you_sure_you_want_to_delete_this_record": "क्या आप वाकई यह रिकॉर्ड हटाना चाहते हैं?", + "Are_you_sure_you_want_to_delete_your_account": "क्या आप इस खाते को हटाने के लिए सुनिश्चित हैं?", + "Are_you_sure_you_want_to_disable_Facebook_integration": "क्या आप वाकई फेसबुक एकीकरण को अक्षम करना चाहते हैं?", + "Are_you_sure_you_want_to_reset_the_name_of_all_priorities": "क्या आप वाकई सभी प्राथमिकताओं का नाम रीसेट करना चाहते हैं?", + "Assets": "संपत्ति", + "Assets_Description": "अपने कार्यक्षेत्र का लोगो, आइकन, फ़ेविकॉन और बहुत कुछ संशोधित करें।", + "Asset_preview": "संपत्ति पूर्वावलोकन", + "Assign_admin": "व्यवस्थापक नियुक्त करना", + "Assign_new_conversations_to_bot_agent": "बॉट एजेंट को नई बातचीत सौंपें", + "Assign_new_conversations_to_bot_agent_description": "रूटिंग सिस्टम किसी मानव एजेंट को नई बातचीत को संबोधित करने से पहले एक बॉट एजेंट को खोजने का प्रयास करेगा।", + "assign-admin-role": "व्यवस्थापक भूमिका निर्दिष्ट करें", + "assign-admin-role_description": "अन्य उपयोगकर्ताओं को व्यवस्थापक भूमिका सौंपने की अनुमति", + "assign-roles": "भूमिकाएँ सौंपें", + "assign-roles_description": "अन्य उपयोगकर्ताओं को भूमिकाएँ आवंटित करने की अनुमति", + "Associate": "संबंद्ध करना", + "Associate_Agent": "सहयोगी एजेंट", + "Associate_Agent_to_Extension": "एक्सटेंशन के लिए एसोसिएट एजेंट", + "at": "पर", + "At_least_one_added_token_is_required_by_the_user": "उपयोगकर्ता को कम से कम एक अतिरिक्त टोकन की आवश्यकता है", + "AtlassianCrowd": "एटलसियन भीड़", + "AtlassianCrowd_Description": "एटलसियन भीड़ को एकीकृत करें।", + "Attachment_File_Uploaded": "फ़ाइल अपलोड की गई", + "Attribute_handling": "विशेषता प्रबंधन", + "Audio": "ऑडियो", + "Audio_message": "ऑडियो संदेश", + "Audio_Notification_Value_Description": "कोई भी कस्टम ध्वनि या डिफ़ॉल्ट ध्वनि हो सकती है: बीप, चेले, डिंग, ड्रॉपलेट, हाईबेल, सीज़न", "Audio_Notifications_Default_Alert": "ऑडियो सूचनाएं डिफ़ॉल्ट चेतावनी", + "Audio_Notifications_Value": "डिफ़ॉल्ट संदेश अधिसूचना ऑडियो", + "Audio_record": "ऑडियो रिकॉर्ड", + "Audios": "ऑडियो", + "Audit": "अंकेक्षण", + "Auditing": "लेखा परीक्षा", + "Auth": "प्रमाणीकरण", + "Auth_Token": "प्रामाणिक टोकन", + "Authentication": "प्रमाणीकरण", + "Author": "लेखक", + "Author_Information": "लेखक की जानकारी", + "Author_Site": "लेखक साइट", + "Authorization_URL": "प्राधिकरण यूआरएल", + "Authorize": "अधिकृत", + "Authorize_access_to_your_account": "अपने खाते तक पहुंच अधिकृत करें", + "Automatic_translation_not_available": "स्वचालित अनुवाद उपलब्ध नहीं है", + "Automatic_translation_not_available_info": "इस कमरे में E2E एन्क्रिप्शन सक्षम है, अनुवाद एन्क्रिप्टेड संदेशों के साथ काम नहीं कर सकता है", + "Auto_Load_Images": "छवियाँ स्वतः लोड करें", + "Auto_Selection": "स्वतः चयन", + "Auto_Translate": "ऑटो का अनुवाद", + "auto-translate": "स्वतः अनुवाद", + "auto-translate_description": "ऑटो ट्रांसलेशन टूल का उपयोग करने की अनुमति", + "Automatic_Translation": "स्वचालित अनुवाद", + "AutoTranslate": "ऑटो का अनुवाद", + "AutoTranslate_APIKey": "एपीआई कुंजी", + "AutoTranslate_Change_Language_Description": "ऑटो-अनुवाद भाषा बदलने से पिछले संदेशों का अनुवाद नहीं होता है।", + "AutoTranslate_DeepL": "डीपएल", + "AutoTranslate_Disabled_for_room": "#{{roomName}} के लिए स्वतः-अनुवाद अक्षम किया गया", + "AutoTranslate_Enabled": "स्वतः-अनुवाद सक्षम करें", + "AutoTranslate_Enabled_Description": "ऑटो-ट्रांसलेशन सक्षम करने से 'ऑटो-ट्रांसलेट' अनुमति वाले लोगों को सभी संदेशों को स्वचालित रूप से उनकी चयनित भाषा में अनुवाद करने की अनुमति मिल जाएगी। शुल्क लागू हो सकता है.", + "AutoTranslate_Enabled_for_room": "#{{roomName}} के लिए स्वतः-अनुवाद सक्षम किया गया", + "AutoTranslate_AutoEnableOnJoinRoom": "गैर-डिफ़ॉल्ट भाषा सदस्यों के लिए स्वचालित अनुवाद", + "AutoTranslate_AutoEnableOnJoinRoom_Description": "सक्षम होने पर, जब भी कार्यस्थान डिफ़ॉल्ट से भिन्न भाषा प्राथमिकता वाला कोई उपयोगकर्ता किसी कमरे में शामिल होता है, तो यह स्वचालित रूप से उनके लिए अनुवादित हो जाएगा।", + "AutoTranslate_Google": "गूगल", + "AutoTranslate_language_set_to": "स्वतः-अनुवाद भाषा को {{language}} पर सेट किया गया", + "AutoTranslate_Microsoft": "माइक्रोसॉफ्ट", + "AutoTranslate_Microsoft_API_Key": "Ocp-एपिम-सदस्यता-कुंजी", + "AutoTranslate_ServiceProvider": "सेवा प्रदाता", + "Available": "उपलब्ध", + "Available_agents": "उपलब्ध एजेंट", + "Available_departments": "उपलब्ध विभाग", + "Avatar": "अवतार", + "Avatars": "अवतारों", + "Avatar_changed_successfully": "अवतार सफलतापूर्वक बदला गया", + "Avatar_URL": "अवतार यूआरएल", + "Avatar_format_invalid": "अवैध प्रारूप। केवल छवि प्रकार की अनुमति है", + "Avatar_url_invalid_or_error": "प्रदान किया गया यूआरएल अमान्य है या पहुंच योग्य नहीं है। कृपया पुनः प्रयास करें, लेकिन एक अलग यूआरएल के साथ।", + "Avg_chat_duration": "चैट period का औसत", + "Avg_first_response_time": "प्रथम प्रतिक्रिया समय का औसत", + "Avg_of_abandoned_chats": "छोड़ी गई चैट का औसत", + "Avg_of_available_service_time": "सेवा उपलब्ध समय का औसत", + "Avg_of_chat_duration_time": "चैट period का औसत समय", + "Avg_of_service_time": "सेवा समय का औसत", + "Avg_of_waiting_time": "प्रतीक्षा समय का औसत", + "Avg_reaction_time": "प्रतिक्रिया समय का औसत", + "Avg_response_time": "प्रतिक्रिया समय का औसत", + "away": "दूर", + "Away": "दूर", + "Back": "पीछे", + "Back_to_applications": "अनुप्रयोगों पर वापस जाएँ", + "Back_to_calendar": "कैलेंडर पर वापस जाएँ", + "Back_to_chat": "चैट पर वापस जाएँ", + "Back_to_imports": "आयात पर वापस जाएँ", + "Back_to_integration_detail": "एकीकरण विवरण पर वापस जाएँ", + "Back_to_integrations": "एकीकरण पर वापस जाएँ", + "Back_to_login": "लॉगिन पर वापस जाएं", + "Back_to_Manage_Apps": "ऐप्स प्रबंधित करने के लिए वापस जाएं", + "Back_to_permissions": "अनुमतियों पर वापस जाएँ", + "Back_to_room": "कक्ष में वापस", + "Back_to_threads": "धागों पर वापस जाएँ", + "Backup_codes": "बैकअप कोड", + "ban-user": "प्रतिबंध उपयोगकर्ता", + "ban-user_description": "किसी उपयोगकर्ता को किसी चैनल से प्रतिबंधित करने की अनुमति", + "BBB_End_Meeting": "बैठक समाप्त", + "BBB_Enable_Teams": "टीमों के लिए सक्षम करें", + "BBB_Join_Meeting": "बैठक में शामिल", + "BBB_Start_Meeting": "मीटिंग प्रारंभ करें", + "BBB_Video_Call": "बीबीबी वीडियो कॉल", + "BBB_You_have_no_permission_to_start_a_call": "आपको कॉल शुरू करने की कोई अनुमति नहीं है", + "Be_the_first_to_join": "शामिल होने वाले पहले व्यक्ति बनें", + "Belongs_To": "से संबंधित", + "Best_first_response_time": "सर्वोत्तम प्रथम प्रतिक्रिया समय", + "Beta_feature_Depends_on_Video_Conference_to_be_enabled": "बीटा सुविधा. सक्षम होने के लिए वीडियो कॉन्फ़्रेंस पर निर्भर करता है।", + "Better": "बेहतर", + "Bio": "वह था", + "Bio_Placeholder": "बायो प्लेसहोल्डर", + "Block": "अवरोध पैदा करना", + "Block_Multiple_Failed_Logins_Attempts_Until_Block_By_Ip": "आईपी एड्रेस को ब्लॉक करने से पहले असफल प्रयासों की मात्रा", + "Block_Multiple_Failed_Logins_Attempts_Until_Block_by_User": "उपयोगकर्ता को ब्लॉक करने से पहले विफल प्रयासों की मात्रा", + "Block_Multiple_Failed_Logins_By_Ip": "आईपी द्वारा विफल लॉगिन प्रयासों को ब्लॉक करें", + "Block_Multiple_Failed_Logins_By_User": "उपयोगकर्ता नाम द्वारा विफल लॉगिन प्रयासों को ब्लॉक करें", + "Block_Multiple_Failed_Logins_Enable_Collect_Login_data_Description": "लॉग इन प्रयासों से लेकर डेटाबेस पर संग्रह तक आईपी और उपयोगकर्ता नाम संग्रहीत करता है", + "Block_Multiple_Failed_Logins_Enabled": "लॉग इन डेटा एकत्रित करना सक्षम करें", + "Block_Multiple_Failed_Logins_Ip_Whitelist": "आईपी श्वेतसूची", + "Block_Multiple_Failed_Logins_Ip_Whitelist_Description": "श्वेतसूचीबद्ध आईपी की अल्पविराम से अलग की गई सूची", + "Block_Multiple_Failed_Logins_Time_To_Unblock_By_Ip_In_Minutes": "आईपी एड्रेस ब्लॉक की period (मिनटों में)", + "Block_Multiple_Failed_Logins_Time_To_Unblock_By_Ip_In_Minutes_Description": "यह वह समय है जब आईपी एड्रेस को ब्लॉक किया जाता है, और वह समय जिसमें काउंटर रीसेट होने से पहले असफल प्रयास हो सकते हैं", + "Block_Multiple_Failed_Logins_Time_To_Unblock_By_User_In_Minutes": "उपयोगकर्ता ब्लॉक की period (मिनटों में)", + "Block_Multiple_Failed_Logins_Time_To_Unblock_By_User_In_Minutes_Description": "यह वह समय है जब उपयोगकर्ता को ब्लॉक किया जाता है, और वह समय जिसमें काउंटर रीसेट होने से पहले विफल प्रयास हो सकते हैं", + "Block_Multiple_Failed_Logins_Notify_Failed": "विफल लॉगिन प्रयासों की सूचना दें", + "Block_Multiple_Failed_Logins_Notify_Failed_Channel": "सूचनाएं भेजने के लिए चैनल", + "Block_Multiple_Failed_Logins_Notify_Failed_Channel_Desc": "यहीं पर सूचनाएं प्राप्त होंगी. सुनिश्चित करें कि चैनल मौजूद है. चैनल के नाम में # चिन्ह शामिल नहीं होना चाहिए", + "Block_User": "खंड उपयोगकर्ता", + "Blockchain": "ब्लॉकचेन", + "block-ip-device-management": "आईपी डिवाइस प्रबंधन को ब्लॉक करें", + "block-ip-device-management_description": "आईपी एड्रेस को ब्लॉक करने की अनुमति", + "Block_IP_Address": "आईपी एड्रेस को ब्लॉक करें", + "Blocked_IP_Addresses": "अवरुद्ध आईपी पते", + "Blockstack": "ब्लॉकस्टैक", + "Blockstack_Description": "कार्यक्षेत्र के सदस्यों को किसी तीसरे पक्ष या दूरस्थ सर्वर पर भरोसा किए बिना साइन इन करने की क्षमता दें।", + "Blockstack_Auth_Description": "प्रामाणिक विवरण", + "Blockstack_ButtonLabelText": "बटन लेबल टेक्स्ट", + "Blockstack_Generate_Username": "उपयोक्तानाम उत्पन्न करें", + "Body": "शरीर", + "Bold": "बोल्ड", + "bot_request": "बॉट अनुरोध", + "BotHelpers_userFields": "उपयोगकर्ता फ़ील्ड", + "BotHelpers_userFields_Description": "उपयोगकर्ता फ़ील्ड का CSV जिसे बॉट्स सहायक विधियों द्वारा एक्सेस किया जा सकता है।", + "Bot": "बीओटी", + "Bots": "बॉट", + "Bots_Description": "वे फ़ील्ड सेट करें जिन्हें बॉट विकसित करते समय संदर्भित और उपयोग किया जा सकता है।", + "Branch": "शाखा", + "Broadcast": "प्रसारण", + "Broadcast_channel": "प्रसारण चैनल", + "Broadcast_channel_Description": "केवल अधिकृत उपयोगकर्ता ही नए संदेश लिख सकते हैं, लेकिन अन्य उपयोगकर्ता उत्तर दे सकेंगे", + "Broadcast_Connected_Instances": "कनेक्टेड इंस्टेंस प्रसारित करें", + "Broadcasting_api_key": "प्रसारण एपीआई कुंजी", + "Broadcasting_client_id": "प्रसारण क्लाइंट आईडी", + "Broadcasting_client_secret": "प्रसारण ग्राहक रहस्य", + "Broadcasting_enabled": "प्रसारण सक्षम", + "Broadcasting_media_server_url": "प्रसारण मीडिया सर्वर यूआरएल", + "Browse_Files": "फ़ाइलों को ब्राउज़ करें", + "Browser_does_not_support_audio_element": "आपका ब्राउजर में ऑडियो तत्व समर्थित नहीं है।", + "Browser_does_not_support_video_element": "आपका ब्राउज़र वीडियो तत्व का समर्थन नहीं करता.", + "Browser_does_not_support_recording_video": "आपका ब्राउज़र वीडियो रिकॉर्ड करने का समर्थन नहीं करता", + "Bugsnag_api_key": "बगस्नाग एपीआई कुंजी", + "Build_Environment": "पर्यावरण का निर्माण करें", + "bulk-register-user": "थोक में उपयोगकर्ता बनाएँ", + "bulk-register-user_description": "बड़ी संख्या में उपयोगकर्ता बनाने की अनुमति", + "Bundles": "बंडल", + "Busiest_day": "सबसे व्यस्त दिन", + "Busiest_time": "व्यस्ततम समय", + "Business_Hour": "व्यवसाय का समय", + "Business_Hour_Removed": "व्यावसायिक समय हटा दिया गया", + "Business_Hours": "काम करने के घंटे", + "Business_hours_enabled": "व्यावसायिक घंटे सक्षम", + "Business_hours_updated": "व्यावसायिक घंटे अपडेट किए गए", + "busy": "व्यस्त", + "Busy": "व्यस्त", + "Buy": "खरीदना", + "By": "द्वारा", + "by": "द्वारा", + "cache_cleared": "कैश साफ़ किया गया", + "Calendar_MeetingUrl_Regex": "मीटिंग यूआरएल रेगुलर एक्सप्रेशन", + "Calendar_MeetingUrl_Regex_Description": "घटना विवरण में मीटिंग यूआरएल का पता लगाने के लिए अभिव्यक्ति का उपयोग किया जाता है। वैध यूआरएल वाले पहले मिलान समूह का उपयोग किया जाएगा। HTML एन्कोडेड यूआरएल स्वचालित रूप से डीकोड हो जाएंगे।", + "Calendar_settings": "कैलेंडर सेटिंग", + "Call": "पुकारना", + "Call_again": "दोबारा फोन करें", + "Call_back": "वापस बुलाओ", + "Call_not_found": "कॉल नहीं मिली", + "Call_not_found_error": "ऐसा तब हो सकता है जब कॉल यूआरएल मान्य नहीं है, या आपको कनेक्शन संबंधी समस्याएं आ रही हैं। कृपया कॉल यूआरएल के स्रोत की जांच करें और पुनः प्रयास करें, या यदि समस्या बनी रहती है तो अपने कार्यक्षेत्र व्यवस्थापक से बात करें", + "Calling": "कॉलिंग", + "Call_Center": "आवाज चैनल", + "Call_Center_Description": "रॉकेट.चैट के वॉयस चैनल कॉन्फ़िगर करें", + "Call_ended": "कॉल समाप्त", + "Calls": "कॉल", + "Calls_in_queue": "{{calls}} कतार में कॉल करें", + "Call_declined": "कॉल अस्वीकृत!", + "Call_history_provides_a_record_of_when_calls_took_place_and_who_joined": "कॉल इतिहास इस बात का रिकॉर्ड प्रदान करता है कि कॉल कब हुई और कौन शामिल हुआ।", + "Call_Information": "कॉल सूचना", + "Call_provider": "कॉल प्रदाता", + "Call_Already_Ended": "कॉल पहले ही समाप्त हो चुकी है", + "Call_number": "कॉल नंबर", + "Call_number_premium_only": "कॉल नंबर (केवल प्रीमियम प्लान)", + "call-management": "कॉल प्रबंधन", + "call-management_description": "बैठक शुरू करने की अनुमति", + "Call_ongoing": "कॉल जारी है", + "Call_started": "कॉल शुरू हुई", + "Call_unavailable_for_federation": "फ़ेडरेटेड रूम के लिए कॉल उपलब्ध नहीं है", + "Call_was_not_answered": "कॉल का उत्तर नहीं दिया गया", + "Caller": "कोलर", + "Caller_Id": "कॉलर आईडी", + "Camera_access_not_allowed": "कैमरा एक्सेस की अनुमति नहीं थी, कृपया अपनी ब्राउज़र सेटिंग जांचें।", + "Cam_on": "कैम ऑन", + "Cam_off": "कैम बंद", + "can-audit": "ऑडिट कर सकते हैं", + "can-audit_description": "ऑडिट तक पहुंचने की अनुमति", + "can-audit-log": "ऑडिट लॉग कर सकते हैं", + "can-audit-log_description": "ऑडिट लॉग तक पहुंचने की अनुमति", "Cancel": "रद्द करना", "Cancel_message_input": "रद्द करना", + "Canceled": "रद्द", + "Canned_Response_Created": "डिब्बाबंद प्रतिक्रिया बनाई गई", + "Canned_Response_Updated": "डिब्बाबंद प्रतिक्रिया अद्यतन की गई", + "Canned_Response_Delete_Warning": "डिब्बाबंद प्रतिक्रिया को हटाना पूर्ववत नहीं किया जा सकता।", + "Canned_Response_Removed": "डिब्बाबंद प्रतिक्रिया हटा दी गई", + "Canned_Response_Sharing_Department_Description": "चयनित विभाग में कोई भी इस डिब्बाबंद प्रतिक्रिया तक पहुंच सकता है", + "Canned_Response_Sharing_Private_Description": "केवल आप और ओमनीचैनल प्रबंधक ही इस डिब्बाबंद प्रतिक्रिया तक पहुंच सकते हैं", + "Canned_Response_Sharing_Public_Description": "कोई भी इस डिब्बाबंद प्रतिक्रिया तक पहुंच सकता है", + "Canned_Responses": "डिब्बाबंद प्रतिक्रियाएं", + "Canned_Responses_Enable": "डिब्बाबंद प्रत्युत्तर सक्षम करें", + "Create_department": "विभाग बनाएं", + "Create_direct_message": "सीधा संदेश बनाएं", + "Create_tag": "टैग बनाएं", + "Create_trigger": "ट्रिगर बनाएं", + "Create_SLA_policy": "SLA नीति बनाएं", + "Cannot_invite_users_to_direct_rooms": "उपयोगकर्ताओं को सीधे रूम में आमंत्रित नहीं किया जा सकता", + "Cannot_open_conversation_with_yourself": "अपने आप से सीधे संदेश नहीं भेजा जा सकता", + "Cannot_share_your_location": "आपका स्थान साझा नहीं किया जा सकता...", + "Cannot_disable_while_on_call": "कॉल के दौरान स्थिति नहीं बदल सकते", + "Cant_join": "शामिल नहीं हो सकते", + "CAS": "कैस", + "CAS_Description": "केंद्रीय प्रमाणीकरण सेवा सदस्यों को कई प्रोटोकॉल पर कई साइटों पर साइन इन करने के लिए क्रेडेंशियल्स के एक सेट का उपयोग करने की अनुमति देती है।", + "CAS_autoclose": "लॉगिन पॉपअप स्वतः बंद करें", + "CAS_base_url": "एसएसओ बेस यूआरएल", + "CAS_base_url_Description": "आपकी बाहरी SSO सेवा का आधार URL जैसे: `https://sso.example.undef/sso/`", + "CAS_button_color": "लॉगिन बटन पृष्ठभूमि रंग", + "CAS_button_label_color": "लॉगिन बटन टेक्स्ट का रंग", + "CAS_button_label_text": "लॉगिन बटन लेबल", + "CAS_Creation_User_Enabled": "उपयोगकर्ता निर्माण की अनुमति दें", + "CAS_Creation_User_Enabled_Description": "CAS टिकट द्वारा उपलब्ध कराए गए डेटा से CAS उपयोगकर्ता निर्माण की अनुमति दें।", "CAS_enabled": "सक्रिय", + "CAS_Login_Layout": "CAS लॉगिन लेआउट", + "CAS_login_url": "एसएसओ लॉगिन यूआरएल", + "CAS_login_url_Description": "आपकी बाहरी SSO सेवा का लॉगिन URL जैसे: `https://sso.example.undef/sso/login`", + "CAS_popup_height": "लॉगिन पॉपअप ऊंचाई", + "CAS_popup_width": "लॉगिन पॉपअप चौड़ाई", + "CAS_Sync_User_Data_Enabled": "उपयोगकर्ता डेटा को हमेशा सिंक करें", + "CAS_Sync_User_Data_Enabled_Description": "लॉगिन पर बाहरी CAS उपयोगकर्ता डेटा को हमेशा उपलब्ध विशेषताओं में सिंक्रनाइज़ करें। ध्यान दें: खाता बनाते समय विशेषताएँ हमेशा समन्वयित होती हैं।", + "CAS_Sync_User_Data_FieldMap": "गुण मानचित्र", + "CAS_Sync_User_Data_FieldMap_Description": "बाहरी विशेषताओं (मान) से आंतरिक विशेषताएँ (कुंजी) बनाने के लिए इस JSON इनपुट का उपयोग करें। '%' के साथ संलग्न बाहरी विशेषता नाम मूल्य स्ट्रिंग में प्रक्षेपित होंगे।\nउदाहरण, `{\"ईमेल\":\"%ईमेल%\", \"नाम\":\"%पहला नाम%, %अंतिमनाम%\"}`\n \nविशेषता मानचित्र हमेशा प्रक्षेपित होता है। CAS 1.0 में केवल `उपयोगकर्ता नाम` विशेषता उपलब्ध है। उपलब्ध आंतरिक विशेषताएँ हैं: उपयोगकर्ता नाम, नाम, ईमेल, कमरे; रूम उपयोगकर्ता के निर्माण पर शामिल होने के लिए कमरों की एक अल्पविराम से अलग की गई सूची है, उदाहरण के लिए: `{\"rooms\": \"%team%,%department%\"}` निर्माण पर CAS उपयोगकर्ताओं को उनकी टीम और विभाग चैनल में शामिल करेगा।", + "CAS_trust_username": "CAS उपयोगकर्ता नाम पर भरोसा करें", + "CAS_trust_username_description": "सक्षम होने पर, Rocket.Chat को भरोसा होगा कि CAS का कोई भी उपयोगकर्ता नाम Rocket.Chat पर उसी उपयोगकर्ता का है।\nयदि किसी उपयोगकर्ता का नाम CAS पर बदला जाता है तो इसकी आवश्यकता हो सकती है, लेकिन यह लोगों को अपने CAS उपयोगकर्ताओं का नाम बदलकर Rocket.Chat खातों पर नियंत्रण लेने की अनुमति भी दे सकता है।", + "CAS_version": "कैस संस्करण", + "CAS_version_Description": "केवल आपकी CAS SSO सेवा द्वारा समर्थित CAS संस्करण का उपयोग करें।", + "Categories": "श्रेणियाँ", + "Categories*": "श्रेणियाँ*", + "CDN_JSCSS_PREFIX": "जेएस/सीएसएस के लिए सीडीएन उपसर्ग", + "CDN_PREFIX": "सीडीएन उपसर्ग", + "CDN_PREFIX_ALL": "सभी संपत्तियों के लिए सीडीएन उपसर्ग का उपयोग करें", + "Certificates_and_Keys": "प्रमाणपत्र और चाबियाँ", + "changed_room_announcement_to__room_announcement_": "कमरे की घोषणा को इसमें बदला गया: {{room_announcement}}", + "changed_room_description_to__room_description_": "कमरे के विवरण को इसमें बदल दिया गया: {{room_description}}", + "change-livechat-room-visitor": "लाइवचैट रूम विज़िटर बदलें", + "change-livechat-room-visitor_description": "लाइवचैट रूम विज़िटर के लिए अतिरिक्त जानकारी जोड़ने की अनुमति", + "Change_Room_Type": "कमरे का प्रकार बदलना", + "Changing_email": "ईमेल बदलना", + "channel": "चैनल", + "Channel": "चैनल", + "Channel_already_exist": "चैनल `#%s` पहले से मौजूद है।", + "Channel_already_exist_static": "चैनल पहले से मौजूद है.", + "Channel_already_Unarchived": "`#%s` नाम वाला चैनल पहले से ही अनारक्षित स्थिति में है", + "Channel_Archived": "`#%s` नाम वाला चैनल सफलतापूर्वक संग्रहीत किया गया है", + "Channel_created": "चैनल `#%s` बनाया गया.", + "Channel_doesnt_exist": "चैनल `#%s` मौजूद नहीं है।", + "Channel_Export": "चैनल निर्यात", + "Channel_name": "चैनल का नाम", + "Channel_Name_Placeholder": "कृपया चैनल का नाम दर्ज करें...", + "Channel_to_listen_on": "सुनने के लिए चैनल", + "Channel_Unarchived": "`#%s` नाम वाला चैनल सफलतापूर्वक अनारक्षित कर दिया गया है", + "Channels": "चैनल", + "Channels_added": "चैनल सफलतापूर्वक जोड़े गए", + "Channels_are_where_your_team_communicate": "चैनल वे हैं जहां आपकी टीम संवाद करती है", + "Channels_list": "सार्वजनिक चैनलों की सूची", + "Channel_what_is_this_channel_about": "यह चैनल किस बारे में है?", + "Chart": "चार्ट", + "Chat_button": "चैट बटन", + "Chat_close": "चैट बंद करें", + "Chat_closed": "चैट बंद", + "Chat_closed_by_agent": "एजेंट द्वारा चैट बंद कर दी गई", + "Chat_closed_successfully": "चैट सफलतापूर्वक बंद हुई", + "Chat_History": "चैट का इतिहास", + "Chat_Now": "अभी बातचीत करें", + "chat_on_hold_due_to_inactivity": "निष्क्रियता के कारण यह चैट रुकी हुई है", + "Chat_On_Hold": "चैट ऑन-होल्ड", + "Chat_On_Hold_Successfully": "इस चैट को सफलतापूर्वक ऑन-होल्ड पर रखा गया था", + "Chat_queued": "चैट पंक्तिबद्ध", + "Chat_removed": "चैट हटा दी गई", + "Chat_resumed": "चैट फिर से शुरू हुई", + "Chat_start": "चैट प्रारंभ", + "Chat_started": "चैट शुरू हुई", + "Chat_taken": "चैट लिया गया", + "Chat_window": "चैट विंडो", + "Chatops_Enabled": "चैटॉप्स सक्षम करें", + "Chatops_Title": "चैटॉप्स पैनल", + "Chatops_Username": "चैटॉप्स उपयोगकर्ता नाम", + "Chat_Duration": "चैट की period", + "Chats_removed": "चैट हटा दी गईं", + "Check_All": "सभी चेक करें", + "Check_if_the_spelling_is_correct": "जांचें कि क्या वर्तनी सही है", + "Check_Progress": "प्रगति की जाँच करें", + "Check_device_activity": "डिवाइस गतिविधि की जाँच करें", + "Choose_a_room": "एक कमरा चुनें", + "Choose_messages": "संदेश चुनें", + "Choose_the_alias_that_will_appear_before_the_username_in_messages": "वह उपनाम चुनें जो संदेशों में उपयोगकर्ता नाम से पहले दिखाई देगा।", + "Choose_the_username_that_this_integration_will_post_as": "वह उपयोक्तानाम चुनें जिसके रूप में यह एकीकरण पोस्ट किया जाएगा.", + "Choose_users": "उपयोगकर्ता चुनें", + "Clean_History_unavailable_for_federation": "महासंघ के लिए स्वच्छ इतिहास अनुपलब्ध है", + "Clean_Usernames": "उपयोक्तानाम साफ़ करें", + "clean-channel-history": "स्वच्छ चैनल इतिहास", + "clean-channel-history_description": "चैनलों से इतिहास साफ़ करने की अनुमति", + "clear": "स्पष्ट", + "Clear_all_unreads_question": "सभी अपठित साफ़ करें?", + "clear_cache_now": "अभी कैश साफ़ करें", + "Clear_filters": "फ़िल्टर साफ़ करें", + "clear_history": "इतिहास मिटा दें", + "Clear_livechat_session_when_chat_ended": "चैट समाप्त होने पर अतिथि सत्र साफ़ करें", + "clear-oembed-cache": "OEmbed कैश साफ़ करें", + "clear-oembed-cache_description": "OEmbed कैश साफ़ करने की अनुमति", + "Click_here": "यहाँ क्लिक करें", + "Click_here_for_more_details_or_contact_sales_for_a_new_license": "अधिक जानकारी के लिए यहां क्लिक करें या नए लाइसेंस के लिए {{email}} से संपर्क करें।", + "Click_here_for_more_info": "अधिक जानकारी के लिए यहां क्लिक करें", + "Click_here_to_clear_the_selection": "चयन साफ़ करने के लिए यहां क्लिक करें", + "Click_here_to_enter_your_encryption_password": "अपना एन्क्रिप्शन पासवर्ड दर्ज करने के लिए यहां क्लिक करें", + "Click_here_to_view_and_copy_your_password": "अपना पासवर्ड देखने और कॉपी करने के लिए यहां क्लिक करें।", + "Click_the_messages_you_would_like_to_send_by_email": "उन संदेशों पर क्लिक करें जिन्हें आप ई-मेल द्वारा भेजना चाहते हैं", + "Click_to_join": "शामिल होने के लिए क्लिक करें!", + "Click_to_load": "लोड करने के लिए क्लिक करें", + "Client_ID": "ग्राहक ID", "Client_Secret": "क्लाइंट Secret", + "Client": "ग्राहक", + "Clients_will_refresh_in_a_few_seconds": "ग्राहक कुछ ही सेकंड में ताज़ा हो जाएंगे", + "close": "बंद करना", + "Close": "बंद करना", + "Close_chat": "चैट बंद करें", + "Close_room_description": "आप इस चैट को बंद करने वाले हैं. क्या आप वाकई जारी रखना चाहते हैं?", + "close-livechat-room": "ओमनीचैनल कक्ष बंद करें", + "close-livechat-room_description": "वर्तमान ओमनीचैनल कक्ष को बंद करने की अनुमति", + "close-others-livechat-room": "अन्य ओमनीचैनल कक्ष बंद करें", + "close-others-livechat-room_description": "अन्य ओमनीचैनल कमरों को बंद करने की अनुमति", + "Close_Window": "विंडो बंद", + "Closed": "बंद किया हुआ", + "Closed_At": "पर बंद हुआ", + "Closed_automatically": "सिस्टम द्वारा स्वचालित रूप से बंद कर दिया गया", + "Closed_automatically_because_chat_was_onhold_for_seconds": "स्वचालित रूप से बंद हो गया क्योंकि चैट {{onHoldTime}} सेकंड के लिए होल्ड पर थी", + "Closed_automatically_chat_queued_too_long": "सिस्टम द्वारा स्वचालित रूप से बंद (कतार का अधिकतम समय पार हो गया)", + "Closed_by_visitor": "आगंतुक द्वारा बंद कर दिया गया", + "Wrap_up_conversation": "बातचीत समाप्त करें", + "These_options_affect_this_conversation_only_To_set_default_selections_go_to_My_Account_Omnichannel": "ये विकल्प केवल इस वार्तालाप को प्रभावित करते हैं. डिफ़ॉल्ट चयन सेट करने के लिए, मेरा खाता > ओमनीचैनल पर जाएँ।", + "This_option_affect_this_conversation_only_To_set_default_selection_go_to_My_Account_Omnichannel": "यह विकल्प केवल इस वार्तालाप को प्रभावित करता है. डिफ़ॉल्ट चयन सेट करने के लिए, मेरा खाता > ओमनीचैनल पर जाएँ।", + "Closing_chat": "चैट बंद हो रही है", + "Closing_chat_message": "चैट बंद करने का संदेश", + "Cloud": "बादल", + "Cloud_Apply_Offline_License": "ऑफ़लाइन लाइसेंस लागू करें", + "Cloud_Change_Offline_License": "ऑफ़लाइन लाइसेंस बदलें", + "Cloud_License_applied_successfully": "लाइसेंस सफलतापूर्वक लागू हो गया!", + "Cloud_Invalid_license": "अवैध लाइसेंस!", + "Cloud_Apply_license": "लाइसेंस लागू करें", + "Cloud_connectivity": "क्लाउड कनेक्टिविटी", + "Cloud_address_to_send_registration_to": "अपना क्लाउड पंजीकरण ईमेल भेजने का पता।", + "Cloud_click_here": "टेक्स्ट कॉपी करने के बाद, [क्लाउड कंसोल (यहां क्लिक करें)]({{cloudConsoleUrl}}) पर जाएं।", + "Cloud_console": "क्लाउड कंसोल", + "Cloud_error_code": "कोड: {{errorCode}}", + "Cloud_error_in_authenticating": "प्रमाणीकरण करते समय त्रुटि प्राप्त हुई", + "Cloud_Info": "क्लाउड जानकारी", + "Cloud_login_to_cloud": "Rocket.Chat क्लाउड में लॉग इन करें", + "Cloud_logout": "रॉकेट.चैट क्लाउड से लॉगआउट करें", + "Cloud_manually_input_token": "क्लाउड कंसोल से प्राप्त टोकन दर्ज करें।", + "Cloud_register_error": "आपके अनुरोध को संसाधित करने का प्रयास करते समय एक त्रुटि हुई है। कृपया बाद में पुन: प्रयास करें।", + "Cloud_Register_manually": "ऑफ़लाइन पंजीकरण करें", + "Cloud_register_offline_finish_helper": "क्लाउड कंसोल में पंजीकरण प्रक्रिया पूरी करने के बाद आपको कुछ टेक्स्ट प्रस्तुत किया जाना चाहिए। पंजीकरण समाप्त करने के लिए कृपया इसे यहां पेस्ट करें।", + "Cloud_register_offline_helper": "यदि एयरगैप या नेटवर्क पहुंच प्रतिबंधित है तो कार्यस्थानों को मैन्युअल रूप से पंजीकृत किया जा सकता है। प्रक्रिया को पूरा करने के लिए नीचे दिए गए टेक्स्ट को कॉपी करें और हमारे क्लाउड कंसोल पर जाएं।", + "Cloud_register_success": "आपका कार्यक्षेत्र सफलतापूर्वक पंजीकृत हो गया है!", + "Cloud_registration_required": "पंजीकरण आवश्यक", + "Cloud_registration_required_description": "ऐसा लगता है कि सेटअप के दौरान आपने अपना कार्यक्षेत्र पंजीकृत करना नहीं चुना।", + "Cloud_registration_required_link_text": "अपना कार्यक्षेत्र पंजीकृत करने के लिए यहां क्लिक करें।", + "Cloud_resend_email": "ईमेल दुबारा भेजें", + "Cloud_Service_Agree_PrivacyTerms": "क्लाउड सेवा गोपनीयता शर्तें अनुबंध", + "Cloud_Service_Agree_PrivacyTerms_Description": "मैं [शर्तें](https://rocket.chat/terms) और [गोपनीयता नीति](https://rocket.chat/privacy) से सहमत हूं", + "Cloud_Service_Agree_PrivacyTerms_Login_Disabled_Warning": "आपको अपने क्लाउड कार्यक्षेत्र से जुड़ने के लिए क्लाउड गोपनीयता शर्तों (सेटअप विज़ार्ड > क्लाउड जानकारी > क्लाउड सेवा गोपनीयता शर्तें अनुबंध) को स्वीकार करना चाहिए", + "Cloud_status_page_description": "यदि किसी विशेष क्लाउड सेवा में समस्या आ रही है तो आप हमारे स्थिति पृष्ठ पर ज्ञात समस्याओं की जांच कर सकते हैं", + "Cloud_token_instructions": "अपने कार्यक्षेत्र को पंजीकृत करने के लिए क्लाउड कंसोल पर जाएं। लॉग इन करें या एक खाता बनाएं और स्व-प्रबंधित रजिस्टर पर क्लिक करें। नीचे दिए गए टोकन को चिपकाएँ", + "Cloud_troubleshooting": "समस्या निवारण", + "Cloud_update_email": "ईमेल अपडेट करें", + "Cloud_what_is_it": "यह क्या है?", + "Copy_Link": "लिंक की प्रतिलिपि करें", + "Copy_password": "पासवर्ड कॉपी करें", + "Cloud_what_is_it_additional": "इसके अलावा आप Rocket.Chat क्लाउड कंसोल से लाइसेंस, बिलिंग और समर्थन का प्रबंधन करने में सक्षम होंगे।", + "Cloud_what_is_it_description": "Rocket.Chat क्लाउड कनेक्ट आपको अपने स्व-होस्ट किए गए Rocket.Chat वर्कस्पेस को हमारे क्लाउड में प्रदान की जाने वाली सेवाओं से कनेक्ट करने की अनुमति देता है।", + "Cloud_what_is_it_services_like": "सेवाएँ जैसे:", + "Cloud_workspace_connected": "आपका कार्यक्षेत्र Rocket.Chat Cloud से जुड़ा है। यहां अपने Rocket.Chat क्लाउड खाते में लॉग इन करने से आप मार्केटप्लेस जैसी कुछ सेवाओं के साथ बातचीत कर सकेंगे।", + "Cloud_workspace_connected_plus_account": "आपका कार्यक्षेत्र अब Rocket.Chat क्लाउड से जुड़ा है और एक खाता संबद्ध है।", + "Cloud_workspace_connected_without_account": "आपका कार्यक्षेत्र अब Rocket.Chat क्लाउड से कनेक्ट हो गया है। यदि आप चाहें, तो आप Rocket.Chat क्लाउड में लॉग इन कर सकते हैं और अपने कार्यक्षेत्र को अपने क्लाउड खाते से जोड़ सकते हैं।", + "Cloud_workspace_disconnect": "यदि आप अब क्लाउड सेवाओं का उपयोग नहीं करना चाहते हैं तो आप अपने कार्यक्षेत्र को Rocket.Chat Cloud से डिस्कनेक्ट कर सकते हैं।", + "Cloud_workspace_support": "यदि आपको क्लाउड सेवा में परेशानी हो रही है, तो कृपया पहले सिंक करने का प्रयास करें। यदि समस्या बनी रहती है, तो कृपया क्लाउड कंसोल में एक सहायता टिकट खोलें।", + "Collaborative": "सहयोगात्मक", + "Collapse": "गिर जाना", + "Collapse_Embedded_Media_By_Default": "एंबेडेड मीडिया को डिफ़ॉल्ट रूप से संक्षिप्त करें", + "color": "रंग", + "Color": "रंग", + "Colors": "रंग की", + "Commands": "आदेश", + "Comment_to_leave_on_closing_session": "समापन सत्र पर जाने के लिए टिप्पणी करें", + "Comment": "टिप्पणी", + "Common_Access": "सामान्य पहुंच", + "Commit": "प्रतिबद्ध", + "Community": "समुदाय", + "Free_Edition": "निशुल्क संस्करण", + "Composer_not_available_phone_calls": "फ़ोन कॉल पर संदेश उपलब्ध नहीं हैं", + "Condensed": "संघनित", + "Condition": "स्थिति", + "Commit_details": "प्रतिबद्ध विवरण", + "Completed": "पुरा होना।", + "Computer": "कंप्यूटर", + "Conference_call_apps": "कॉन्फ़्रेंस कॉल ऐप्स", + "Conference_call_has_ended": "_कॉल समाप्त हो गया है._", + "Conference_name": "सम्मेलन का नाम", + "Configure_Incoming_Mail_IMAP": "इनकमिंग मेल कॉन्फ़िगर करें (IMAP)", + "Configure_Outgoing_Mail_SMTP": "आउटगोइंग मेल कॉन्फ़िगर करें (एसएमटीपी)", + "Configure_video_conference_to_make_it_available_on_this_workspace": "इसे इस कार्यक्षेत्र पर उपलब्ध कराने के लिए वीडियो कॉन्फ़्रेंस कॉन्फ़िगर करें", + "Confirm": "पुष्टि करना", + "Confirm_new_encryption_password": "नये एन्क्रिप्शन पासवर्ड की पुष्टि करें", + "Confirm_new_password": "नए पासवर्ड की पुष्टि करें", + "Confirm_New_Password_Placeholder": "कृपया नया पासवर्ड दोबारा दर्ज करें...", + "Confirm_password": "पासवर्ड की पुष्टि कीजिये", + "Confirm_your_password": "अपने पासवर्ड की पुष्टि करें", + "Confirm_configuration_update_description": "पहचान डेटा और क्लाउड कनेक्शन डेटा बरकरार रखा जाएगा।

    चेतावनी : यदि यह वास्तव में एक नया कार्यक्षेत्र है, तो कृपया वापस जाएं और संचार विवादों से बचने के लिए नए कार्यक्षेत्र विकल्प का चयन करें।", + "Confirm_configuration_update": "कॉन्फ़िगरेशन अद्यतन की पुष्टि करें", + "Confirm_new_workspace_description": "पहचान डेटा और क्लाउड कनेक्शन डेटा रीसेट कर दिया जाएगा।

    चेतावनी : कार्यक्षेत्र यूआरएल बदलने पर लाइसेंस प्रभावित हो सकता है।", + "Confirm_new_workspace": "नए कार्यक्षेत्र की पुष्टि करें", + "Confirmation": "पुष्टीकरण", + "Configure_video_conference": "कॉन्फ़्रेंस कॉल कॉन्फ़िगर करें", + "Configuration_update_confirmed": "कॉन्फ़िगरेशन अद्यतन की पुष्टि की गई", + "Configuration_update": "कॉन्फ़िगरेशन अद्यतन", + "Connect": "जोड़ना", + "Connected": "जुड़े हुए", + "Connect_SSL_TLS": "एसएसएल/टीएलएस से जुड़ें", + "Connection_Closed": "कनेक्शन बंद", + "Connection_Reset": "सम्बन्ध फिरसे बनाना", + "Connection_error": "संपर्क त्रुटि", + "Connection_failed": "एलडीएपी कनेक्शन विफल", + "Connectivity_Services": "कनेक्टिविटी सेवाएँ", + "Consulting": "CONSULTING", + "Consumer_Packaged_Goods": "उपभोक्ता के लिए पैक की गई वस्तुएं", + "Contact": "संपर्क", + "Contacts": "संपर्क", + "Contact_Name": "संपर्क नाम", + "Contact_Center": "संपर्क केंद्र", + "Contact_Chat_History": "संपर्क चैट इतिहास", + "Contains_Security_Fixes": "सुरक्षा सुधार शामिल हैं", + "Contact_Manager": "प्रबंधक से संपर्क करें", + "Contact_not_found": "संपर्क नहीं मिला", + "Contact_Profile": "प्रोफ़ाइल से संपर्क करें", + "Contact_Info": "संपर्क जानकारी", + "Content": "सामग्री", + "Continue": "जारी रखना", + "Continuous_sound_notifications_for_new_livechat_room": "नए ओमनीचैनल कक्ष के लिए निरंतर ध्वनि सूचनाएं", + "convert-team": "टीम परिवर्तित करें", + "convert-team_description": "टीम को चैनल में बदलने की अनुमति", + "Conversation": "बातचीत", + "Conversation_closed": "बातचीत बंद: {{comment}}.", + "Conversation_closed_without_comment": "बातचीत बंद", + "Conversation_closing_tags": "वार्तालाप समापन टैग", + "Conversation_closing_tags_description": "समापन टैग स्वचालित रूप से समापन पर वार्तालापों को असाइन किए जाएंगे।", + "Conversation_finished": "बातचीत ख़त्म", + "Conversation_finished_message": "बातचीत समाप्त संदेश", + "Conversation_finished_text": "बातचीत समाप्त पाठ", + "conversation_with_s": "%s के साथ बातचीत", + "Conversations": "बात चिट", + "Conversations_per_day": "प्रति दिन बातचीत", + "Convert": "बदलना", + "Convert_Ascii_Emojis": "ASCII को इमोजी में बदलें", + "Convert_to_channel": "चैनल में कनवर्ट करें", + "Converting_channel_to_a_team": "आप इस चैनल को एक टीम में परिवर्तित कर रहे हैं। सभी सदस्यों को रखा जाएगा.", + "Converted__roomName__to_team": "#{{roomName}} को एक टीम में परिवर्तित किया गया", + "Converted__roomName__to_channel": "#{{roomName}} को एक चैनल में परिवर्तित किया गया", + "Converted__roomName__to_a_team": "#{{roomName}} को एक टीम में परिवर्तित किया गया", + "Converted__roomName__to_a_channel": "#{{roomName}} को चैनल में परिवर्तित किया गया", + "Converting_team_to_channel": "टीम को चैनल में परिवर्तित करना", + "Copied": "कॉपी किया गया", + "Copy": "प्रतिलिपि", + "Copy_text": "पाठ कॉपी करें", + "Copy_to_clipboard": "क्लिपबोर्ड पर कॉपी करें", + "COPY_TO_CLIPBOARD": "क्लिपबोर्ड पर कॉपी करें", + "could-not-access-webdav": "WebDAV तक नहीं पहुंच सका", + "Count": "count करना", + "Counters": "काउंटर", + "Country": "देश", + "Country_Afghanistan": "अफ़ग़ानिस्तान", + "Country_Albania": "अल्बानिया", + "Country_Algeria": "एलजीरिया", + "Country_American_Samoa": "अमेरिकी समोआ", + "Country_Andorra": "एंडोरा", + "Country_Angola": "अंगोला", + "Country_Anguilla": "एंगुइला", + "Country_Antarctica": "अंटार्कटिका", + "Country_Antigua_and_Barbuda": "अण्टीगुआ और बारबूडा", + "Country_Argentina": "अर्जेंटीना", + "Country_Armenia": "आर्मीनिया", + "Country_Aruba": "अरूबा", + "Country_Australia": "ऑस्ट्रेलिया", + "Country_Austria": "ऑस्ट्रिया", + "Country_Azerbaijan": "आज़रबाइजान", + "Country_Bahamas": "बहामा", + "Country_Bahrain": "बहरीन", + "Country_Bangladesh": "बांग्लादेश", + "Country_Barbados": "बारबाडोस", + "Country_Belarus": "बेलोरूस", + "Country_Belgium": "बेल्जियम", + "Country_Belize": "बेलीज़", + "Country_Benin": "बेनिन", + "Country_Bermuda": "बरमूडा", + "Country_Bhutan": "भूटान", + "Country_Bolivia": "बोलीविया", + "Country_Bosnia_and_Herzegovina": "बोस्निया और हर्जेगोविना", + "Country_Botswana": "बोत्सवाना", + "Country_Bouvet_Island": "बाउवेट द्वीप", + "Country_Brazil": "ब्राज़िल", + "Country_British_Indian_Ocean_Territory": "ब्रिटेन और भारतीय समुद्री क्षेत्र", + "Country_Brunei_Darussalam": "ब्रूनेइ्र दारएस्सलाम", + "Country_Bulgaria": "बुल्गारिया", + "Country_Burkina_Faso": "बुर्किना फासो", + "Country_Burundi": "बुस्र्न्दी", + "Country_Cambodia": "कंबोडिया", + "Country_Cameroon": "कैमरून", + "Country_Canada": "कनाडा", + "Country_Cape_Verde": "केप वर्ड", + "Country_Cayman_Islands": "केमन द्वीपसमूह", + "Country_Central_African_Republic": "केन्द्रीय अफ़्रीकी गणराज्य", + "Country_Chad": "काग़ज़ का टुकड़ा", + "Country_Chile": "चिली", + "Country_China": "चीन", + "Country_Christmas_Island": "क्रिसमस द्वीप", + "Country_Cocos_Keeling_Islands": "कोकोस (कीलिंग) द्वीप समूह", + "Country_Colombia": "कोलंबिया", + "Country_Comoros": "कोमोरोस", + "Country_Congo": "कांगो", + "Country_Congo_The_Democratic_Republic_of_The": "कांगो, लोकतांत्रिक गणराज्य", + "Country_Cook_Islands": "कुक द्वीपसमूह", + "Country_Costa_Rica": "कोस्टा रिका", + "Country_Cote_Divoire": "हाथीदांत का किनारा", + "Country_Croatia": "क्रोएशिया", + "Country_Cuba": "क्यूबा", + "Country_Cyprus": "साइप्रस", + "Country_Czech_Republic": "चेक रिपब्लिक", + "Country_Denmark": "डेनमार्क", + "Country_Djibouti": "ज़िबूटी", + "Country_Dominica": "डोमिनिका", + "Country_Dominican_Republic": "डोमिनिकन गणराज्य", + "Country_Ecuador": "इक्वेडोर", + "Country_Egypt": "मिस्र", + "Country_El_Salvador": "अल साल्वाडोर", + "Country_Equatorial_Guinea": "भूमध्यवर्ती गिनी", + "Country_Eritrea": "इरिट्रिया", + "Country_Estonia": "एस्तोनिया", + "Country_Ethiopia": "इथियोपिया", + "Country_Falkland_Islands_Malvinas": "फ़ॉकलैंड द्वीप समूह (माल्विनास)", + "Country_Faroe_Islands": "फ़ैरो द्वीप", + "Country_Fiji": "फ़िजी", + "Country_Finland": "फिनलैंड", + "Country_France": "फ्रांस", + "Country_French_Guiana": "फ्रेंच गयाना", + "Country_French_Polynesia": "फ़्रेंच पोलिनेशिया", + "Country_French_Southern_Territories": "दक्षिणी फ्राँसिसी क्षेत्र", + "Country_Gabon": "गैबॉन", + "Country_Gambia": "गाम्बिया", + "Country_Georgia": "जॉर्जिया", + "Country_Germany": "जर्मनी", + "Country_Ghana": "घाना", + "Country_Gibraltar": "जिब्राल्टर", + "Country_Greece": "यूनान", + "Country_Greenland": "ग्रीनलैंड", + "Country_Grenada": "ग्रेनेडा", + "Country_Guadeloupe": "ग्वाडेलोप", + "Country_Guam": "गुआम", + "Country_Guatemala": "ग्वाटेमाला", + "Country_Guinea": "गिनी", + "Country_Guinea_bissau": "गिनी-बिसाऊ", + "Country_Guyana": "गुयाना", + "Country_Haiti": "हैती", + "Country_Heard_Island_and_Mcdonald_Islands": "हर्ड द्वीप और मैकडोनाल्ड द्वीप समूह", + "Country_Holy_See_Vatican_City_State": "होली सी (वेटिकन सिटी राज्य)", + "Country_Honduras": "होंडुरस", + "Country_Hong_Kong": "हांगकांग", + "Country_Hungary": "हंगरी", + "Country_Iceland": "आइसलैंड", + "Country_India": "भारत", + "Country_Indonesia": "इंडोनेशिया", + "Country_Iran_Islamic_Republic_of": "ईरान (इस्लामिक रिपब्लिक ऑफ", + "Country_Iraq": "इराक", + "Country_Ireland": "आयरलैंड", + "Country_Israel": "इजराइल", + "Country_Italy": "इटली", + "Country_Jamaica": "जमैका", + "Country_Japan": "जापान", + "Country_Jordan": "जॉर्डन", + "Country_Kazakhstan": "कजाखस्तान", + "Country_Kenya": "केन्या", + "Country_Kiribati": "किरिबाती", + "Country_Korea_Democratic_Peoples_Republic_of": "कोरिया प्रजातात्रिक जनवादी गणतंत्र", + "Country_Korea_Republic_of": "कोरिया गणराज्य", + "Country_Kuwait": "कुवैट", + "Country_Kyrgyzstan": "किर्गिज़स्तान", + "Country_Lao_Peoples_Democratic_Republic": "लाओ पीपुल्स डेमोक्रेटिक रिपब्लिक", + "Country_Latvia": "लातविया", + "Country_Lebanon": "लेबनान", + "Country_Lesotho": "लिसोटो", + "Country_Liberia": "लाइबेरिया", + "Country_Libyan_Arab_Jamahiriya": "लीबिया का अरब जमहिरिया", + "Country_Liechtenstein": "लिकटेंस्टाइन", + "Country_Lithuania": "लिथुआनिया", + "Country_Luxembourg": "लक्समबर्ग", + "Country_Macao": "मकाओ", + "Country_Macedonia_The_Former_Yugoslav_Republic_of": "मैसेडोनिया, पूर्व यूगोस्लाव गणराज्य", + "Country_Madagascar": "मेडागास्कर", + "Country_Malawi": "मलावी", + "Country_Malaysia": "मलेशिया", + "Country_Maldives": "मालदीव", + "Country_Mali": "वे थे", + "Country_Malta": "माल्टा", + "Country_Marshall_Islands": "मार्शल द्वीपसमूह", + "Country_Martinique": "मार्टीनिक", + "Country_Mauritania": "मॉरिटानिया", + "Country_Mauritius": "मॉरीशस", + "Country_Mayotte": "मैयट", + "Country_Mexico": "मेक्सिको", + "Country_Micronesia_Federated_States_of": "माइक्रोनेशिया, संघीय राज्य", + "Country_Moldova_Republic_of": "मोल्दोवा, गणराज्य", + "Country_Monaco": "मोनाको", + "Country_Mongolia": "मंगोलिया", + "Country_Montserrat": "मोंटेसेराट", + "Country_Morocco": "मोरक्को", + "Country_Mozambique": "मोज़ाम्बिक", + "Country_Myanmar": "म्यांमार", + "Country_Namibia": "नामिबिया", + "Country_Nauru": "नाउरू", + "Country_Nepal": "नेपाल", + "Country_Netherlands": "नीदरलैंड", + "Country_Netherlands_Antilles": "नीदरलैंड्स एंटाइल्स", + "If_you_dont_have_one_send_an_email_to_omni_rocketchat_to_get_yours": "यदि आपके पास कोई नहीं है तो अपना पाने के लिए [omni@rocket.chat](mailto:omni@rocket.chat) पर एक ईमेल भेजें।", + "Country_New_Caledonia": "नया केलडोनिया", + "Country_New_Zealand": "न्यूज़ीलैंड", + "Country_Nicaragua": "निकारागुआ", + "Country_Niger": "नाइजर", + "Country_Nigeria": "नाइजीरिया", + "Country_Niue": "नियू", + "Country_Norfolk_Island": "नॉरफ़ॉक द्वीप", + "Country_Northern_Mariana_Islands": "उत्तरी मरीयाना द्वीप समूह", + "Country_Norway": "नॉर्वे", + "Country_Oman": "अपने मन", + "Country_Pakistan": "पाकिस्तान", + "Country_Palau": "पलाउ", + "Country_Palestinian_Territory_Occupied": "अधिकृत फ़िलिस्तीन क्षेत्र", + "Country_Panama": "पनामा", + "Country_Papua_New_Guinea": "पापुआ न्यू गिनी", + "Country_Paraguay": "परागुआ", + "Country_Peru": "पेरू", + "Country_Philippines": "फिलिपींस", + "Country_Pitcairn": "पिटकेर्न", + "Country_Poland": "पोलैंड", + "Country_Portugal": "पुर्तगाल", + "Country_Puerto_Rico": "प्यूर्टो रिको", + "Country_Qatar": "कतर", + "Country_Reunion": "रीयूनियन", + "Country_Romania": "रोमानिया", + "Country_Russian_Federation": "रूसी संघ", + "Country_Rwanda": "रवांडा", + "Country_Saint_Helena": "Saint Helena", + "Country_Saint_Kitts_and_Nevis": "संत किट्ट्स और नेविस", + "Country_Saint_Lucia": "सेंट लूसिया", + "Country_Saint_Pierre_and_Miquelon": "सेंट पियरे और मिकेलॉन", + "Country_Saint_Vincent_and_The_Grenadines": "संत विंसेंट अँड थे ग्रेनडीनेस", + "Country_Samoa": "समोआ", + "Country_San_Marino": "सैन मारिनो", + "Country_Sao_Tome_and_Principe": "साओ टोमे और प्रिंसिपे", + "Country_Saudi_Arabia": "सऊदी अरब", + "Country_Senegal": "सेनेगल", + "Country_Serbia_and_Montenegro": "सर्बिया और मोंटेनेग्रो", + "inline_code": "इनलाइन कोड", + "Country_Seychelles": "सेशल्स", + "Country_Sierra_Leone": "सेरा लिओन", + "Country_Singapore": "सिंगापुर", + "Country_Slovakia": "स्लोवाकिया", + "Country_Slovenia": "स्लोवेनिया", + "Country_Solomon_Islands": "सोलोमन इस्लैंडस", + "Country_Somalia": "सोमालिया", + "Country_South_Africa": "दक्षिण अफ्रीका", + "Country_South_Georgia_and_The_South_Sandwich_Islands": "दक्षिण जॉर्जिया और दक्षिण सैंडविच द्वीप समूह", + "Country_Spain": "स्पेन", + "Country_Sri_Lanka": "श्रीलंका", + "Country_Sudan": "सूडान", + "Country_Suriname": "सूरीनाम", + "Country_Svalbard_and_Jan_Mayen": "स्वालबार्ड और जान मायेन", + "Country_Swaziland": "स्वाजीलैंड", + "Country_Sweden": "स्वीडन", + "Country_Switzerland": "स्विट्ज़रलैंड", + "Country_Syrian_Arab_Republic": "सीरियाई अरब गणराज्य", + "Country_Taiwan_Province_of_China": "ताइवान, चीन प्रांत", + "Country_Tajikistan": "तजाकिस्तान", + "Country_Tanzania_United_Republic_of": "तंजानिया, संयुक्त गणराज्य", + "Country_Thailand": "थाईलैंड", + "Country_Timor_leste": "तिमोर ने पढ़ा", + "Country_Togo": "चल देना", + "Country_Tokelau": "टोकेलाऊ", + "Country_Tonga": "पहुँचा", + "Country_Trinidad_and_Tobago": "त्रिनिदाद और टोबैगो", + "Country_Tunisia": "ट्यूनीशिया", + "Country_Turkey": "टर्की", + "Country_Turkmenistan": "तुर्कमेनिस्तान", + "Country_Turks_and_Caicos_Islands": "तुर्क और कैकोस द्वीप समूह", + "Country_Tuvalu": "तुवालू", + "Country_Uganda": "युगांडा", + "Country_Ukraine": "यूक्रेन", + "Country_United_Arab_Emirates": "संयुक्त अरब अमीरात", + "Country_United_Kingdom": "यूनाइटेड किंगडम", + "Country_United_States": "संयुक्त राज्य अमेरिका", + "Country_United_States_Minor_Outlying_Islands": "संयुक्त राज्य अमेरिका के छोटे दूरस्थ द्वीपसमूह", + "Country_Uruguay": "उरुग्वे", + "Country_Uzbekistan": "उज़्बेकिस्तान", + "Country_Vanuatu": "वानुअतु", + "Country_Venezuela": "वेनेज़ुएला", + "Country_Viet_Nam": "वियतनाम", + "Country_Virgin_Islands_British": "वर्जिन द्वीप समूह, ब्रिटिश", + "Country_Virgin_Islands_US": "वर्जिन द्वीप समूह, यू.एस.", + "Country_Wallis_and_Futuna": "वाली और फ़्युटुना", + "Country_Western_Sahara": "पश्चिमी सहारा", + "Country_Yemen": "यमन", + "Country_Zambia": "जाम्बिया", + "Country_Zimbabwe": "ज़िम्बाब्वे", + "Create": "बनाएं", + "Create_canned_response": "डिब्बाबंद प्रतिक्रिया बनाएँ", + "Create_custom_field": "कस्टम फ़ील्ड बनाएं", + "Create_channel": "चैनल बनाएं", + "Create_channels": "चैनल बनाएं", + "Create_a_public_channel_that_new_workspace_members_can_join": "एक सार्वजनिक चैनल बनाएं जिसमें नए कार्यक्षेत्र सदस्य शामिल हो सकें।", + "Create_A_New_Channel": "एक नया चैनल बनाएं", + "Create_new": "नया निर्माण", + "Create_new_members": "नए सदस्य बनाएं", + "Create_unique_rules_for_this_channel": "इस चैनल के लिए अद्वितीय नियम बनाएं", + "Create_unit": "इकाई बनाएं", + "create-c": "सार्वजनिक चैनल बनाएं", + "create-c_description": "सार्वजनिक चैनल बनाने की अनुमति", + "create-d": "सीधे संदेश बनाएं", + "create-d_description": "सीधे संदेश प्रारंभ करने की अनुमति", + "create-invite-links": "आमंत्रण लिंक बनाएं", + "create-invite-links_description": "चैनलों के लिए आमंत्रण लिंक बनाने की अनुमति", + "create-p": "निजी चैनल बनाएं", + "create-p_description": "निजी चैनल बनाने की अनुमति", + "create-personal-access-tokens": "व्यक्तिगत एक्सेस टोकन बनाएं", + "create-personal-access-tokens_description": "व्यक्तिगत एक्सेस टोकन बनाने की अनुमति", + "create-team": "टीम बनाएं", + "create-team_description": "टीमें बनाने की अनुमति", + "create-user": "उपयोगकर्ता बनाइये", + "create-user_description": "उपयोगकर्ता बनाने की अनुमति", + "Created": "बनाया था", + "Created_as": "के रूप में बनाया गया", + "Created_at": "पर बनाया गया", + "Created_at_s_by_s": "%s द्वारा % s पर बनाया गया", + "Created_at_s_by_s_triggered_by_s": "%s द्वारा %s पर बनाया गया , %s द्वारा ट्रिगर किया गया", + "Created_by": "के द्वारा बनाई गई", + "CRM_Integration": "सीआरएम एकीकरण", + "CROWD_Allow_Custom_Username": "Rocket.Chat में कस्टम उपयोगकर्ता नाम की अनुमति दें", + "CROWD_Reject_Unauthorized": "अनधिकृत अस्वीकार करें", + "Crowd_Remove_Orphaned_Users": "अनाथ उपयोगकर्ताओं को हटाएँ", + "Crowd_sync_interval_Description": "तुल्यकालन के बीच का अंतराल. उदाहरण `हर 24 घंटे` या `सप्ताह के पहले दिन`, अधिक उदाहरण [क्रोन टेक्स्ट पार्सर](http://bunkat.github.io/later/parsers.html#text) पर", + "Current_Chats": "वर्तमान चैट", + "Current_File": "मौजूदा फ़ाइल", + "Current_Import_Operation": "वर्तमान आयात परिचालन", + "Current_Status": "वर्तमान स्थिति", + "Currently_we_dont_support_joining_servers_with_this_many_people": "वर्तमान में हम इतने सारे लोगों के साथ सर्वर से जुड़ने का समर्थन नहीं करते हैं", "Custom": "कस्टम", + "Custom CSS": "कस्टम सीएसएस", + "Custom_agent": "कस्टम एजेंट", + "Custom_dates": "कस्टम तिथियाँ", + "Custom_Emoji": "कस्टम इमोजी", + "Custom_Emoji_Add": "नया इमोजी जोड़ें", + "Custom_Emoji_Added_Successfully": "कस्टम इमोजी सफलतापूर्वक जोड़ा गया", + "Custom_Emoji_Delete_Warning": "किसी इमोजी को हटाना पूर्ववत नहीं किया जा सकता.", + "Custom_Emoji_Error_Invalid_Emoji": "अमान्य इमोजी", + "Custom_Emoji_Error_Name_Or_Alias_Already_In_Use": "कस्टम इमोजी या उसका कोई उपनाम पहले से ही उपयोग में है।", + "Custom_Emoji_Error_Same_Name_And_Alias": "कस्टम इमोजी नाम और उनके उपनाम अलग-अलग होने चाहिए.", + "Custom_Emoji_Has_Been_Deleted": "कस्टम इमोजी हटा दिया गया है.", + "Custom_Emoji_Info": "कस्टम इमोजी जानकारी", + "Custom_Emoji_Updated_Successfully": "कस्टम इमोजी सफलतापूर्वक अपडेट किया गया", + "Custom_Fields": "तटकर क्षेत्र", + "Custom_Field_Removed": "कस्टम फ़ील्ड हटा दी गई", + "Custom_Field_Not_Found": "कस्टम फ़ील्ड नहीं मिला", + "Custom_Integration": "कस्टम एकीकरण", + "Custom_OAuth_has_been_added": "कस्टम OAuth जोड़ा गया है", + "Custom_OAuth_has_been_removed": "कस्टम OAuth हटा दिया गया है", + "Custom_oauth_helper": "अपना OAuth प्रदाता स्थापित करते समय, आपको एक कॉलबैक URL सूचित करना होगा। उपयोग

     %एस
    .", + "Custom_oauth_unique_name": "कस्टम OAuth अद्वितीय नाम", + "Custom_roles": "कस्टम भूमिकाएँ", + "Custom_roles_upsell_add_custom_roles_workspace": "अपने कार्यक्षेत्र के अनुरूप कस्टम भूमिकाएँ जोड़ें", + "Custom_roles_upsell_add_custom_roles_workspace_description": "कस्टम भूमिकाएँ आपको अपने कार्यक्षेत्र में लोगों के लिए अनुमतियाँ सेट करने की अनुमति देती हैं। यह सुनिश्चित करने के लिए कि लोगों को काम करने के लिए सुरक्षित वातावरण मिले, सभी भूमिकाएँ निर्धारित करें।", + "Custom_Script_Logged_In": "लॉग इन उपयोगकर्ताओं के लिए कस्टम स्क्रिप्ट", + "Custom_Script_Logged_In_Description": "कस्टम स्क्रिप्ट जो हमेशा और लॉग इन किए गए किसी भी उपयोगकर्ता पर चलेगी। (जब भी आप चैट में प्रवेश करते हैं और आप लॉग इन होते हैं)", + "Custom_Script_Logged_Out": "लॉग आउट उपयोगकर्ताओं के लिए कस्टम स्क्रिप्ट", + "Custom_Script_Logged_Out_Description": "कस्टम स्क्रिप्ट जो हमेशा चलेगी और किसी भी उपयोगकर्ता के लिए जो लॉग इन नहीं है। (जब भी आप लॉगिन पेज दर्ज करें)", + "Custom_Script_On_Logout": "लॉगआउट फ़्लो के लिए कस्टम स्क्रिप्ट", + "Custom_Script_On_Logout_Description": "कस्टम स्क्रिप्ट जो केवल निष्पादन लॉगआउट प्रवाह पर चलेगी", + "Custom_Scripts": "कस्टम स्क्रिप्ट", + "Custom_Sound_Add": "कस्टम ध्वनि जोड़ें", + "Custom_Sound_Delete_Warning": "किसी ध्वनि को हटाना पूर्ववत नहीं किया जा सकता.", + "Custom_Sound_Edit": "कस्टम ध्वनि संपादित करें", + "Custom_Sound_Error_Invalid_Sound": "अमान्य ध्वनि", + "Custom_Sound_Error_Name_Already_In_Use": "कस्टम ध्वनि नाम पहले से ही उपयोग में है.", + "Custom_Sound_Has_Been_Deleted": "कस्टम ध्वनि हटा दी गई है.", + "Custom_Sound_Info": "कस्टम ध्वनि जानकारी", + "Custom_Sound_Saved_Successfully": "कस्टम ध्वनि सफलतापूर्वक सहेजी गई", + "Custom_Status": "कस्टम स्थिति", + "Custom_Translations": "कस्टम अनुवाद", + "Custom_Translations_Description": "एक वैध JSON होना चाहिए जहां कुंजी ऐसी भाषाएं हैं जिनमें कुंजी और अनुवाद का शब्दकोश होता है। उदाहरण: `{\"en\": {\"चैनल\": \"कमरे\"},\"pt\": {\"चैनल\": \"सलास\"}}`", + "Custom_User_Status": "कस्टम उपयोगकर्ता स्थिति", + "Custom_User_Status_Add": "कस्टम उपयोगकर्ता स्थिति जोड़ें", + "Custom_User_Status_Added_Successfully": "कस्टम उपयोगकर्ता स्थिति सफलतापूर्वक जोड़ी गई", + "Custom_User_Status_Delete_Warning": "कस्टम उपयोगकर्ता स्थिति को हटाना पूर्ववत नहीं किया जा सकता।", + "Custom_User_Status_Edit": "कस्टम उपयोगकर्ता स्थिति संपादित करें", + "Custom_User_Status_Error_Invalid_User_Status": "अमान्य उपयोगकर्ता स्थिति", + "Custom_User_Status_Error_Name_Already_In_Use": "कस्टम उपयोगकर्ता स्थिति नाम पहले से ही उपयोग में है।", + "Custom_User_Status_Has_Been_Deleted": "कस्टम उपयोगकर्ता स्थिति हटा दी गई है", + "Custom_User_Status_Info": "कस्टम उपयोगकर्ता स्थिति जानकारी", + "Custom_User_Status_Updated_Successfully": "कस्टम उपयोगकर्ता स्थिति सफलतापूर्वक अपडेट की गई", + "Customer_without_registered_email": "ग्राहक के पास पंजीकृत ईमेल पता नहीं है", + "Customize": "अनुकूलित करें", + "Customize_Content": "सामग्री को अनुकूलित करें", + "CustomSoundsFilesystem": "कस्टम ध्वनि फ़ाइल सिस्टम", + "CustomSoundsFilesystem_Description": "निर्दिष्ट करें कि कस्टम ध्वनियाँ कैसे संग्रहीत की जाती हैं।", + "Daily_Active_Users": "दैनिक सक्रिय उपयोगकर्ता", + "Dashboard": "डैशबोर्ड", + "Data_modified": "डेटा संशोधित", + "Data_processing_consent_text": "डेटा प्रोसेसिंग सहमति पाठ", + "Data_processing_consent_text_description": "इस सेटिंग का उपयोग यह समझाने के लिए करें कि आप बातचीत के दौरान ग्राहक की व्यक्तिगत जानकारी एकत्र, संग्रहीत और संसाधित कर सकते हैं।", + "Date": "तारीख", + "Date_From": "से", + "Date_to": "को", + "DAU_value": "डीएयू {{price}}", + "days": "दिन", + "Days": "दिन", + "DB_Migration": "डेटाबेस माइग्रेशन", + "DB_Migration_Date": "डेटाबेस माइग्रेशन तिथि", + "DDP_Rate_Limiter": "डीडीपी दर सीमा", + "DDP_Rate_Limit_Connection_By_Method_Enabled": "प्रति विधि कनेक्शन द्वारा सीमा: सक्षम", + "DDP_Rate_Limit_Connection_By_Method_Interval_Time": "प्रति विधि कनेक्शन द्वारा सीमा: अंतराल समय", + "DDP_Rate_Limit_Connection_By_Method_Requests_Allowed": "प्रति विधि कनेक्शन द्वारा सीमा: अनुरोधों की अनुमति है", + "DDP_Rate_Limit_Connection_Enabled": "कनेक्शन द्वारा सीमा: सक्षम", + "DDP_Rate_Limit_Connection_Interval_Time": "कनेक्शन द्वारा सीमा: अंतराल समय", + "DDP_Rate_Limit_Connection_Requests_Allowed": "कनेक्शन द्वारा सीमा: अनुरोधों की अनुमति है", + "DDP_Rate_Limit_IP_Enabled": "आईपी द्वारा सीमा: सक्षम", + "DDP_Rate_Limit_IP_Interval_Time": "आईपी द्वारा सीमा: अंतराल समय", + "DDP_Rate_Limit_IP_Requests_Allowed": "आईपी द्वारा सीमा: अनुरोधों की अनुमति है", + "DDP_Rate_Limit_User_By_Method_Enabled": "प्रति विधि उपयोगकर्ता द्वारा सीमा: सक्षम", + "DDP_Rate_Limit_User_By_Method_Interval_Time": "प्रति विधि उपयोगकर्ता द्वारा सीमा: अंतराल समय", + "DDP_Rate_Limit_User_By_Method_Requests_Allowed": "प्रति विधि उपयोगकर्ता द्वारा सीमा: अनुरोधों की अनुमति है", + "DDP_Rate_Limit_User_Enabled": "उपयोगकर्ता द्वारा सीमा: सक्षम", + "DDP_Rate_Limit_User_Interval_Time": "उपयोगकर्ता द्वारा सीमा: अंतराल समय", + "DDP_Rate_Limit_User_Requests_Allowed": "उपयोगकर्ता द्वारा सीमा: अनुरोधों की अनुमति है", + "Deactivate": "निष्क्रिय करें", + "Decline": "गिरावट", + "default": "गलती करना", + "Default": "गलती करना", + "Default_provider": "डिफ़ॉल्ट प्रदाता", + "Default_value": "डिफ़ॉल्ट मान", + "Delete": "मिटाना", + "Deleting": "हटाया जा रहा है", + "Delete_account": "खाता हटा दो", + "Delete_account?": "खाता हटा दो?", + "Delete_all_closed_chats": "सभी बंद चैट हटाएं", + "Delete_Department?": "विभाग हटाएं?", + "Delete_File_Warning": "किसी फ़ाइल को हटाने से वह हमेशा के लिए हट जाएगी. इसे असंपादित नहीं किया जा सकता है।", + "Delete_message": "संदेश को हटाएं", + "Delete_my_account": "मेरा एकाउंट हटा दो", + "Delete_Role_Warning": "इसे असंपादित नहीं किया जा सकता है", + "Delete_Room_Warning": "किसी रूम को हटाने से रूम के भीतर पोस्ट किए गए सभी संदेश हट जाएंगे। इसे असंपादित नहीं किया जा सकता है।", + "Delete_User_Warning": "किसी उपयोगकर्ता को हटाने से उस उपयोगकर्ता के सभी संदेश भी हट जाएंगे। इसे असंपादित नहीं किया जा सकता है।", + "Delete_User_Warning_Delete": "किसी उपयोगकर्ता को हटाने से उस उपयोगकर्ता के सभी संदेश भी हट जाएंगे। इसे असंपादित नहीं किया जा सकता है।", + "Delete_User_Warning_Keep": "उपयोगकर्ता को हटा दिया जाएगा, लेकिन उनके संदेश दृश्यमान रहेंगे. इसे असंपादित नहीं किया जा सकता है।", + "Delete_User_Warning_Unlink": "किसी उपयोगकर्ता को हटाने से उनके सभी संदेशों से उपयोगकर्ता नाम हटा दिया जाएगा। इसे असंपादित नहीं किया जा सकता है।", + "delete-c": "सार्वजनिक चैनल हटाएँ", + "delete-c_description": "सार्वजनिक चैनलों को हटाने की अनुमति", + "delete-d": "सीधे संदेश हटाएँ", + "delete-d_description": "सीधे संदेशों को हटाने की अनुमति", + "delete-message": "संदेश को हटाएं", + "delete-message_description": "एक कमरे के भीतर एक संदेश को हटाने की अनुमति", + "delete-own-message": "स्वयं का संदेश हटाएँ", + "delete-own-message_description": "स्वयं का संदेश हटाने की अनुमति", + "delete-p": "निजी चैनल हटाएँ", + "delete-p_description": "निजी चैनल हटाने की अनुमति", + "delete-team": "टीम हटाएँ", + "delete-team_description": "टीमों को हटाने की अनुमति", + "delete-user": "उपभोक्ता मिटायें", + "delete-user_description": "उपयोगकर्ताओं को हटाने की अनुमति", + "Deleted": "हटा दिया गया!", + "Deleted_user": "हटाया हुआ उपयोगकर्ता", + "Deleted__roomName__": "#{{roomName}} हटा दिया गया", + "Deleted__roomName__room": "#{{roomName}} हटा दिया गया", + "Department": "विभाग", + "Department_archived": "विभाग संग्रहीत", + "Department_name": "विभाग का नाम", + "Department_not_found": "विभाग नहीं मिला", + "Department_removed": "विभाग हटा दिया गया", + "Department_Removal_Disabled": "व्यवस्थापक द्वारा हटाएं विकल्प अक्षम कर दिया गया है", + "Department_unarchived": "विभाग अनारक्षित", + "Departments": "विभागों", + "Deployment_ID": "परिनियोजन आईडी", + "Deployment": "तैनाती", + "Description": "विवरण", + "Desktop": "डेस्कटॉप", + "Desktop_apps": "डेस्कटॉप ऐप्स", + "Desktop_Notification_Test": "डेस्कटॉप अधिसूचना परीक्षण", + "Desktop_Notifications": "डेस्कटॉप सूचनाएं", "Desktop_Notifications_Default_Alert": "डेस्कटॉप सूचनाएं डिफ़ॉल्ट चेतावनी", + "Desktop_Notifications_Disabled": "डेस्कटॉप सूचनाएं अक्षम हैं. यदि आपको सूचनाएं सक्षम करने की आवश्यकता है तो अपनी ब्राउज़र प्राथमिकताएं बदलें।", + "Desktop_Notifications_Duration": "डेस्कटॉप अधिसूचना period", + "Desktop_Notifications_Duration_Description": "डेस्कटॉप अधिसूचना प्रदर्शित करने के लिए सेकंड। यह OS X अधिसूचना केंद्र को प्रभावित कर सकता है। डिफ़ॉल्ट ब्राउज़र सेटिंग्स का उपयोग करने और ओएस एक्स अधिसूचना केंद्र को प्रभावित न करने के लिए 0 दर्ज करें।", + "Desktop_Notifications_Enabled": "डेस्कटॉप सूचनाएं सक्षम हैं", + "Desktop_Notifications_Not_Enabled": "डेस्कटॉप सूचनाएं सक्षम नहीं हैं", + "Unselected_by_default": "डिफ़ॉल्ट रूप से अचयनित", + "Unseen_features": "अनदेखी विशेषताएं", + "Details": "विवरण", + "Device_Changes_Not_Available": "इस ब्राउज़र में डिवाइस परिवर्तन उपलब्ध नहीं हैं. गारंटीकृत उपलब्धता के लिए, कृपया Rocket.Chat के आधिकारिक डेस्कटॉप ऐप का उपयोग करें।", + "Device_Changes_Not_Available_Insecure_Context": "डिवाइस परिवर्तन केवल सुरक्षित संदर्भों पर उपलब्ध हैं (जैसे https://)", + "Device_Management": "डिवाइस प्रबंधन", + "Device_Management_Allow_Login_Email_preference": "कार्यस्थान सदस्यों को लॉगिन पहचान ईमेल बंद करने की अनुमति दें", + "Device_Management_Allow_Login_Email_preference_Description": "व्यक्तिगत सदस्य अपनी प्राथमिकता निर्धारित कर सकते हैं। तब उपयोगी जब बार-बार लॉगिन समाप्ति तिथि निर्धारित की जाती है जिससे सदस्यों को बार-बार लॉगिन करना पड़ता है।", + "Device_Management_Client": "ग्राहक", + "Device_Management_Description": "सुरक्षा और पहुंच नियंत्रण नीतियां कॉन्फ़िगर करें.", + "Device_Management_Device": "उपकरण", + "line": "रेखा", + "Device_Management_Device_Unknown": "अज्ञात", + "Device_Management_Email_Subject": "[साइट_नाम] - लॉगिन का पता चला", + "Device_Management_Email_Body": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं: `

    {लॉगिन_डिटेक्टेड}

    [नाम] ([उपयोगकर्ता नाम]) {Logged_In_Via}

    {डिवाइस_मैनेजमेंट_क्लाइंट}: [ब्राउज़रइन्फो]
    {डिवाइस_मैनेजमेंट_ओएस}: [osInfo]
    {डिवाइस_मैनेजमेंट_डिवाइस}: [डिवाइसइन्फो]
    {डिवाइस_मैनेजमेंट_आईपी}: [आईपीइन्फो]

    [उपयोगकर्ता एजेंट]

    {अपने खाते पर पहुंच}

    {Or_Copy_And_Paste_This_URL_Into_A_Tab_Of_Your_Browser}
    [साइट URL]

    {Thank_You_For_Choosing_RocketChat}

    `", + "Device_Management_Enable_Login_Emails": "लॉगिन पहचान ईमेल सक्षम करें", + "Device_Management_Enable_Login_Emails_Description": "कार्यस्थल के सदस्यों को हर बार उनके खातों में नए लॉगिन का पता चलने पर ईमेल भेजे जाते हैं।", + "Device_Management_IP": "आई पी", + "Device_Management_OS": "आप", + "Device_ID": "डिवाइस आईडी", + "Device_Info": "डिवाइस जानकारी", + "Device_Logged_Out": "डिवाइस लॉग आउट हो गया", + "Device_Logout_Text": "डिवाइस कार्यक्षेत्र से लॉग आउट हो जाएगा और वर्तमान सत्र समाप्त हो जाएगा। उपयोगकर्ता उसी डिवाइस से दोबारा लॉग इन कर सकेगा।", + "Devices": "उपकरण", + "Devices_Set": "डिवाइस सेट", + "Device_settings": "उपकरण सेटिंग्स", + "Dialed_number_doesnt_exist": "डायल किया गया नंबर मौजूद नहीं है", + "Dialed_number_is_incomplete": "डायल किया गया नंबर पूरा नहीं है", + "Different_Style_For_User_Mentions": "उपयोगकर्ता उल्लेखों के लिए अलग शैली", + "Livechat_Facebook_API_Key": "ओमनीचैनल एपीआई कुंजी", + "Direct": "प्रत्यक्ष", + "Direction": "दिशा", + "Livechat_Facebook_API_Secret": "ओमनीचैनल एपीआई रहस्य", + "Direct_Message": "सीधा संदेश", + "Livechat_Facebook_Enabled": "फेसबुक एकीकरण सक्षम", + "Direct_message_creation_description": "आप एकाधिक उपयोगकर्ताओं के साथ चैट बनाने वाले हैं. जिन लोगों से आप बात करना चाहते हैं, उन सभी को सीधे संदेशों का उपयोग करके एक ही स्थान पर जोड़ें।", + "Direct_message_someone": "किसी को सीधा संदेश भेजें", + "Direct_message_you_have_joined": "आप एक नए डायरेक्ट मैसेज से जुड़े हैं", + "Direct_Messages": "सीधे संदेश", + "Direct_Reply": "सीधा उत्तर", + "Direct_Reply_Advice": "आप सीधे इस ईमेल का उत्तर दे सकते हैं. थ्रेड में पिछले ईमेल को संशोधित न करें.", + "Direct_Reply_Debug": "सीधा उत्तर डिबग करें", + "Direct_Reply_Debug_Description": "[सावधान] डिबग मोड सक्षम करने से आपका 'प्लेन टेक्स्ट पासवर्ड' एडमिन कंसोल में प्रदर्शित होगा।", + "Direct_Reply_Delete": "ईमेल हटाएँ", + "Direct_Reply_Delete_Description": "[ध्यान दें!] यदि यह विकल्प सक्रिय है, तो सभी अपठित संदेश अपरिवर्तनीय रूप से हटा दिए जाते हैं, यहां तक कि वे भी जो सीधे उत्तर नहीं हैं। कॉन्फ़िगर किया गया ई-मेल मेलबॉक्स हमेशा खाली रहता है और इसे मनुष्यों द्वारा \"समानांतर\" में संसाधित नहीं किया जा सकता है।", + "Direct_Reply_Enable": "सीधा उत्तर सक्षम करें", + "Direct_Reply_Enable_Description": "[ध्यान दें!] यदि \"डायरेक्ट रिप्लाई\" सक्षम है, तो Rocket.Chat कॉन्फ़िगर किए गए ईमेल मेलबॉक्स को नियंत्रित करेगा। सभी अपठित ई-मेल पुनर्प्राप्त किए जाते हैं, पढ़े गए के रूप में चिह्नित किए जाते हैं और संसाधित किए जाते हैं। \"डायरेक्ट रिप्लाई\" केवल तभी सक्रिय किया जाना चाहिए जब उपयोग किया गया मेलबॉक्स विशेष रूप से Rocket.Chat द्वारा पहुंच के लिए है और मनुष्यों द्वारा \"समानांतर में\" पढ़ा/संसाधित नहीं किया गया है।", + "Direct_Reply_Frequency": "ईमेल जाँच आवृत्ति", + "Direct_Reply_Frequency_Description": "(मिनटों में, डिफ़ॉल्ट/न्यूनतम 2)", + "Direct_Reply_Host": "डायरेक्ट रिप्लाई होस्ट", + "Direct_Reply_IgnoreTLS": "टीएलएस पर ध्यान न दें", + "Direct_Reply_Password": "पासवर्ड", + "Direct_Reply_Port": "डायरेक्ट_रिप्लाई_पोर्ट", + "Direct_Reply_Protocol": "प्रत्यक्ष उत्तर प्रोटोकॉल", + "Direct_Reply_Separator": "सेपरेटर", + "Direct_Reply_Separator_Description": "[केवल तभी परिवर्तन करें जब आप ठीक-ठीक जानते हों कि आप क्या कर रहे हैं, दस्तावेज़ देखें]\nईमेल के आधार और टैग भाग के बीच विभाजक", + "Direct_Reply_Username": "उपयोगकर्ता नाम", + "Direct_Reply_Username_Description": "कृपया संपूर्ण ईमेल का उपयोग करें, टैगिंग की अनुमति नहीं है, इसे अधिक लिखा जाएगा", + "Directory": "निर्देशिका", + "Disable": "अक्षम करना", + "Disable_Facebook_integration": "फेसबुक एकीकरण अक्षम करें", + "Disable_Notifications": "नोटीफिकेशन निष्क्रिय किया गया", + "Disable_two-factor_authentication": "TOTP के माध्यम से दो-कारक प्रमाणीकरण अक्षम करें", + "Disable_two-factor_authentication_email": "ईमेल के माध्यम से दो-कारक प्रमाणीकरण अक्षम करें", "Disabled": "उपयोग करने की अनुमति नहीं है", + "Disallow_reacting": "प्रतिक्रिया करने की अनुमति न दें", + "Disallow_reacting_Description": "प्रतिक्रिया करने की अनुमति नहीं देता", + "Discard": "खारिज करना", + "Disconnect": "डिस्कनेक्ट", + "Discover_public_channels_and_teams_in_the_workspace_directory": "कार्यक्षेत्र निर्देशिका में सार्वजनिक चैनल और टीमें खोजें।", + "Discussion": "बहस", + "Discussion_Description": "चर्चाएँ वार्तालापों को व्यवस्थित करने का एक अतिरिक्त तरीका है जो बाहरी चैनलों के उपयोगकर्ताओं को विशिष्ट वार्तालापों में भाग लेने के लिए आमंत्रित करने की अनुमति देता है।", + "Discussion_description": "क्या हो रहा है इसका अवलोकन रखने में सहायता करें! एक चर्चा बनाने से, आपके द्वारा चुने गए चैनल का एक उप-चैनल बनाया जाता है और दोनों लिंक हो जाते हैं।", + "Discussion_first_message_disabled_due_to_e2e": "आप इसके निर्माण के बाद इस चर्चा में एंड-टू-एंड एन्क्रिप्टेड संदेश भेजना शुरू कर सकते हैं।", + "Discussion_first_message_title": "आपका संदेश", + "Discussion_name": "चर्चा का नाम", + "Discussion_start": "चर्चा प्रारंभ करें", + "Discussion_target_channel": "मूल चैनल या समूह", + "Discussion_target_channel_description": "एक चैनल चुनें जो आप जो पूछना चाहते हैं उससे संबंधित हो", + "Discussion_target_channel_prefix": "आप एक चर्चा बना रहे हैं", + "Discussion_title": "चर्चा बनाएं", + "Discussions_unavailable_for_federation": "फेडरेटेड रूम के लिए चर्चाएँ उपलब्ध नहीं हैं", + "discussion-created": "{{message}}", + "Discussions": "चर्चाएँ", + "Display": "प्रदर्शन", + "Display_avatars": "अवतार प्रदर्शित करें", + "Display_Avatars_Sidebar": "साइडबार में अवतार प्रदर्शित करें", + "Display_chat_permissions": "चैट अनुमतियाँ प्रदर्शित करें", + "Display_mentions_counter": "केवल प्रत्यक्ष उल्लेख के लिए बैज प्रदर्शित करें", + "Display_offline_form": "ऑफ़लाइन फॉर्म प्रदर्शित करें", + "Display_setting_permissions": "सेटिंग्स बदलने के लिए अनुमतियाँ प्रदर्शित करें", + "Display_unread_counter": "अपठित संदेश होने पर रूम को अपठित के रूप में प्रदर्शित करें", + "Displays_action_text": "क्रिया पाठ प्रदर्शित करता है", + "Do_It_Later": "इसे बाद में करें", + "Do_not_display_unread_counter": "इस चैनल का कोई भी काउंटर प्रदर्शित न करें", + "Do_not_provide_this_code_to_anyone": "यह कोड किसी को न दें.", + "Do_Nothing": "कुछ भी नहीं है", + "Do_you_have_any_notes_for_this_conversation": "क्या आपके पास इस बातचीत के लिए कोई नोट्स हैं?", + "Do_you_want_to_accept": "क्या आप स्वीकार करना चाहते हैं?", + "Do_you_want_to_change_to_s_question": "क्या आप %s में बदलना चाहते हैं?", + "Documentation": "प्रलेखन", + "Document_Domain": "दस्तावेज़ डोमेन", + "Domain": "कार्यक्षेत्र", + "Domain_added": "डोमेन जोड़ा गया", + "Domain_removed": "डोमेन हटाया गया", + "Domains": "डोमेन", + "Domains_allowed_to_embed_the_livechat_widget": "लाइवचैट विजेट को एम्बेड करने की अनुमति वाले डोमेन की अल्पविराम से अलग की गई सूची। सभी डोमेन को अनुमति देने के लिए खाली छोड़ें।", + "Done": "हो गया", + "Dont_ask_me_again": "मुझसे दोबारा मत पूछो!", + "Dont_ask_me_again_list": "मुझसे दुबारा सूची मत पूछो", + "Download": "डाउनलोड करना", + "Download_Destkop_App": "डेस्कटॉप ऐप डाउनलोड करें", + "Download_Info": "जानकारी डाउनलोड करें", + "Download_My_Data": "मेरा डेटा डाउनलोड करें (HTML)", + "Download_Pending_Avatars": "लंबित अवतार डाउनलोड करें", + "Download_Pending_Files": "लंबित फ़ाइलें डाउनलोड करें", + "Download_Snippet": "डाउनलोड करना", + "Downloading_file_from_external_URL": "बाहरी URL से फ़ाइल डाउनलोड हो रही है", + "Drop_to_upload_file": "फ़ाइल अपलोड करने के लिए छोड़ें", + "Dry_run": "पूर्वाभ्यास", + "Dry_run_description": "प्रेषक के समान पते पर केवल एक ईमेल भेजा जाएगा। ईमेल किसी वैध उपयोगकर्ता का होना चाहिए.", + "Duplicate_archived_channel_name": "`#%s` नाम से एक संग्रहीत चैनल मौजूद है", + "Markdown_Headers": "संदेशों में मार्कडाउन हेडर की अनुमति दें", + "Markdown_Marked_Breaks": "चिह्नित ब्रेक सक्षम करें", + "Duplicate_archived_private_group_name": "'%s' नाम से एक संग्रहीत निजी समूह मौजूद है", + "Duplicate_channel_name": "'%s' नाम का एक चैनल मौजूद है", + "Markdown_Marked_GFM": "चिह्नित जीएफएम सक्षम करें", + "Duplicate_file_name_found": "डुप्लिकेट फ़ाइल नाम मिला.", + "Markdown_Marked_Pedantic": "चिह्नित पेडेंटिक सक्षम करें", + "Markdown_Marked_SmartLists": "चिह्नित स्मार्ट सूचियाँ सक्षम करें", + "Duplicate_private_group_name": "'%s' नाम से एक निजी समूह मौजूद है", + "Markdown_Marked_Smartypants": "चिह्नित स्मार्टपैंट सक्षम करें", + "Duplicated_Email_address_will_be_ignored": "डुप्लिकेट ईमेल पते पर ध्यान नहीं दिया जाएगा.", + "Markdown_Marked_Tables": "चिह्नित तालिकाएँ सक्षम करें", + "duplicated-account": "डुप्लिकेट खाता", + "E2E Encryption": "E2E एन्क्रिप्शन", + "E2E_Encryption_enabled_for_room": "#{{roomName}} के लिए एंड-टू-एंड एन्क्रिप्शन सक्षम किया गया", + "E2E_Encryption_disabled_for_room": "#{{roomName}} के लिए एंड-टू-एंड एन्क्रिप्शन अक्षम किया गया", + "Markdown_Parser": "मार्कडाउन पार्सर", + "Markdown_SupportSchemesForLink": "लिंक के लिए मार्कडाउन सहायता योजनाएँ", + "E2E Encryption_Description": "बातचीत को निजी रखें, यह सुनिश्चित करते हुए कि केवल प्रेषक और इच्छित प्राप्तकर्ता ही उन्हें पढ़ सकें।", + "Markdown_SupportSchemesForLink_Description": "अनुमत योजनाओं की अल्पविराम से अलग की गई सूची", + "E2E_enable": "E2E सक्षम करें", + "E2E_disable": "E2E अक्षम करें", + "E2E_Enable_alert": "यह विशेषता अभी बीटा संस्करण में है! कृपया github.com/RocketChat/Rocket.Chat/issues पर बग की रिपोर्ट करें और इनसे अवगत रहें:
    - एन्क्रिप्टेड रूम के एन्क्रिप्टेड संदेश सर्च ऑपरेशन से नहीं मिलेंगे।
    - मोबाइल ऐप्स एन्क्रिप्टेड संदेशों का समर्थन नहीं कर सकते (वे इसे लागू कर रहे हैं)।
    - बॉट एन्क्रिप्टेड संदेशों को तब तक नहीं देख पाएंगे जब तक वे इसके लिए समर्थन लागू नहीं करते।
    - इस संस्करण में अपलोड एन्क्रिप्टेड नहीं होंगे.", + "E2E_Enable_description": "एन्क्रिप्टेड समूह बनाने का विकल्प सक्षम करें और समूहों को बदलने और एन्क्रिप्ट किए जाने वाले संदेशों को निर्देशित करने में सक्षम हों", + "E2E_Enabled": "E2E सक्षम", + "E2E_Enabled_Default_DirectRooms": "डिफ़ॉल्ट रूप से डायरेक्ट रूम के लिए एन्क्रिप्शन सक्षम करें", + "E2E_Enabled_Default_PrivateRooms": "निजी कमरों के लिए डिफ़ॉल्ट रूप से एन्क्रिप्शन सक्षम करें", + "E2E_Encryption_Password_Change": "एन्क्रिप्शन पासवर्ड बदलें", + "E2E_Encryption_Password_Explanation": "अब आप एन्क्रिप्टेड निजी समूह और सीधे संदेश बना सकते हैं। आप मौजूदा निजी समूहों या डीएम को एन्क्रिप्टेड में भी बदल सकते हैं।

    यह एंड-टू-एंड एन्क्रिप्शन है इसलिए आपके संदेशों को एनकोड/डीकोड करने की कुंजी सर्वर पर सहेजी नहीं जाएगी। इस कारण से आपको अपना पासवर्ड किसी सुरक्षित स्थान पर संग्रहीत करना होगा। आपको इसे अन्य डिवाइसों पर दर्ज करना होगा जिन पर आप e2e एन्क्रिप्शन का उपयोग करना चाहते हैं।", + "E2E_key_reset_email": "E2E कुंजी रीसेट अधिसूचना", + "E2E_message_encrypted_placeholder": "यह संदेश एंड-टू-एंड एन्क्रिप्टेड है. इसे देखने के लिए, आपको अपनी खाता सेटिंग में अपनी एन्क्रिप्शन कुंजी दर्ज करनी होगी।", + "E2E_password_request_text": "अपने एन्क्रिप्टेड निजी समूहों और सीधे संदेशों तक पहुंचने के लिए, अपना एन्क्रिप्शन पासवर्ड दर्ज करें।
    आपके द्वारा उपयोग किए जाने वाले प्रत्येक क्लाइंट पर अपने संदेशों को एनकोड/डीकोड करने के लिए आपको यह पासवर्ड दर्ज करना होगा, क्योंकि कुंजी सर्वर पर संग्रहीत नहीं है।", + "E2E_password_reveal_text": "एंड-टू-एंड एन्क्रिप्शन के साथ सुरक्षित निजी कमरे और सीधे संदेश बनाएं।

    अपना पासवर्ड सुरक्षित रूप से सहेजें, क्योंकि आपके संदेशों को एन्कोड/डीकोड करने की कुंजी सर्वर पर सहेजी नहीं जाएगी। e2e एन्क्रिप्शन का उपयोग करने के लिए आपको इसे अन्य डिवाइस पर दर्ज करना होगा। और अधिक जानें

    अपना पासवर्ड किसी भी ब्राउज़र से, जिस पर आपने दर्ज किया है, कभी भी बदलें। इस संदेश को ख़ारिज करने से पहले अपना पासवर्ड संग्रहीत करना याद रखें।

    आपका पासवर्ड है: {{randomPassword}}", + "E2E_Reset_Email_Content": "आप स्वचालित रूप से लॉग आउट हो गए हैं. जब आप दोबारा लॉगिन करते हैं, तो Rocket.Chat एक नई कुंजी उत्पन्न करेगा और किसी भी एन्क्रिप्टेड कमरे तक आपकी पहुंच बहाल करेगा जिसमें एक या अधिक सदस्य ऑनलाइन हैं। E2E एन्क्रिप्शन की प्रकृति के कारण, Rocket.Chat किसी भी एन्क्रिप्टेड कमरे तक पहुंच बहाल करने में सक्षम नहीं होगा जिसमें कोई भी सदस्य ऑनलाइन नहीं है।", + "E2E_Reset_Key_Explanation": "यह विकल्प आपकी वर्तमान E2E कुंजी को हटा देगा और आपको लॉग आउट कर देगा।
    जब आप दोबारा लॉगिन करते हैं, तो Rocket.Chat आपके लिए एक नई कुंजी उत्पन्न करेगा और किसी भी एन्क्रिप्टेड कमरे तक आपकी पहुंच बहाल करेगा जिसमें एक या अधिक सदस्य ऑनलाइन हैं।
    E2E एन्क्रिप्शन की प्रकृति के कारण, Rocket.Chat किसी भी एन्क्रिप्टेड कमरे तक पहुंच बहाल करने में सक्षम नहीं होगा जिसमें कोई भी सदस्य ऑनलाइन नहीं है।", + "E2E_Reset_Other_Key_Warning": "वर्तमान E2E कुंजी को रीसेट करने से उपयोगकर्ता लॉग आउट हो जाएगा। जब उपयोगकर्ता दोबारा लॉगिन करेगा, तो Rocket.Chat एक नई कुंजी उत्पन्न करेगा और उपयोगकर्ता को किसी भी एन्क्रिप्टेड कमरे तक पहुंच बहाल करेगा जिसमें एक या अधिक सदस्य ऑनलाइन होंगे। E2E एन्क्रिप्शन की प्रकृति के कारण, Rocket.Chat किसी भी एन्क्रिप्टेड कमरे तक पहुंच बहाल करने में सक्षम नहीं होगा जिसमें कोई भी सदस्य ऑनलाइन नहीं है।", + "E2E_unavailable_for_federation": "E2E फ़ेडरेटेड कमरों के लिए उपलब्ध नहीं है", + "ECDH_Enabled": "डेटा परिवहन के लिए दूसरी परत एन्क्रिप्शन सक्षम करें", + "Edit": "संपादन करना", + "Edit_Business_Hour": "व्यावसायिक समय संपादित करें", + "Edit_Canned_Response": "डिब्बाबंद प्रतिक्रिया संपादित करें", + "Edit_Canned_Responses": "डिब्बाबंद प्रतिक्रियाएँ संपादित करें", + "Edit_Custom_Field": "कस्टम फ़ील्ड संपादित करें", + "Edit_Department": "विभाग संपादित करें", + "Edit_Federated_User_Not_Allowed": "फ़ेडरेटेड उपयोगकर्ता को संपादित करना संभव नहीं है", + "Message_AllowSnippeting": "संदेश स्निपेटिंग की अनुमति दें", + "Edit_Invite": "आमंत्रण संपादित करें", + "Edit_previous_message": "`%s` - पिछला संदेश संपादित करें", + "Edit_Priority": "प्राथमिकता संपादित करें", + "Edit_SLA_Policy": "SLA नीति संपादित करें", "Edit_Status": "स्थिति संपादित करें", + "Edit_Tag": "टैग संपादित करें", + "Edit_Trigger": "ट्रिगर संपादित करें", + "Edit_Unit": "इकाई संपादित करें", + "Message_Attachments_GroupAttach": "समूह अनुलग्नक बटन", + "Message_Attachments_GroupAttachDescription": "यह आइकनों को एक विस्तार योग्य मेनू के अंतर्गत समूहित करता है। कम स्क्रीन स्पेस लेता है.", + "Edit_User": "यूजर को संपादित करो", + "edit-livechat-room-customfields": "लाइवचैट रूम कस्टम फ़ील्ड संपादित करें", + "edit-livechat-room-customfields_description": "लाइवचैट रूम के कस्टम फ़ील्ड को संपादित करने की अनुमति", + "edit-message": "संदेश संपादित करें", + "edit-message_description": "एक कमरे के भीतर किसी संदेश को संपादित करने की अनुमति", + "edit-other-user-active-status": "अन्य उपयोगकर्ता सक्रिय स्थिति संपादित करें", + "edit-other-user-active-status_description": "अन्य खातों को सक्षम या अक्षम करने की अनुमति", + "edit-other-user-avatar": "अन्य उपयोगकर्ता अवतार संपादित करें", + "edit-other-user-avatar_description": "अन्य उपयोगकर्ता का अवतार बदलने की अनुमति.", + "edit-other-user-e2ee": "अन्य उपयोगकर्ता E2E एन्क्रिप्शन संपादित करें", + "edit-other-user-e2ee_description": "अन्य उपयोगकर्ता के E2E एन्क्रिप्शन को संशोधित करने की अनुमति।", + "edit-other-user-info": "अन्य उपयोगकर्ता जानकारी संपादित करें", + "edit-other-user-info_description": "अन्य उपयोगकर्ता का नाम, उपयोगकर्ता नाम या ईमेल पता बदलने की अनुमति।", + "edit-other-user-password": "अन्य उपयोगकर्ता पासवर्ड संपादित करें", + "edit-other-user-password_description": "अन्य उपयोगकर्ता के पासवर्ड को संशोधित करने की अनुमति। अन्य-उपयोगकर्ता-जानकारी संपादित करने की अनुमति की आवश्यकता है।", + "edit-other-user-totp": "अन्य उपयोगकर्ता दो कारक TOTP संपादित करें", + "edit-other-user-totp_description": "अन्य उपयोगकर्ता के टू फैक्टर टीओटीपी को संपादित करने की अनुमति", + "edit-privileged-setting": "विशेषाधिकार प्राप्त सेटिंग संपादित करें", + "edit-privileged-setting_description": "सेटिंग्स संपादित करने की अनुमति", + "edit-team": "टीम संपादित करें", + "edit-team_description": "टीमों को संपादित करने की अनुमति", + "edit-team-channel": "टीम चैनल संपादित करें", + "edit-team-channel_description": "किसी टीम के चैनल को संपादित करने की अनुमति", + "edit-team-member": "टीम सदस्य संपादित करें", + "edit-team-member_description": "किसी टीम के सदस्यों को संपादित करने की अनुमति", + "edit-room": "कक्ष संपादित करें", + "edit-room_description": "किसी कमरे का नाम, विषय, प्रकार (निजी या सार्वजनिक स्थिति) और स्थिति (सक्रिय या संग्रहीत) संपादित करने की अनुमति", + "edit-room-avatar": "कक्ष अवतार संपादित करें", + "edit-room-avatar_description": "किसी कमरे का अवतार संपादित करने की अनुमति.", + "edit-room-retention-policy": "कक्ष की अवधारण नीति संपादित करें", + "edit-room-retention-policy_description": "किसी कमरे की अवधारण नीति को संपादित करने, उसमें मौजूद संदेशों को स्वचालित रूप से हटाने की अनुमति", + "edit-omnichannel-contact": "ओमनीचैनल संपर्क संपादित करें", + "Use_Legacy_Message_Template": "लीगेसी संदेश टेम्पलेट का उपयोग करें", + "multi_line": "मल्टी लाइन", + "edit-omnichannel-contact_description": "ओमनीचैनल संपर्क को संपादित करने की अनुमति", + "Edit_Contact_Profile": "संपर्क प्रोफ़ाइल संपादित करें", + "edited": "संपादित", + "Editing_room": "संपादन कक्ष", + "Editing_user": "उपयोगकर्ता का संपादन", + "Editor": "संपादक", + "Message_ShowEditedStatus": "संपादित स्थिति दिखाएँ", + "Education": "शिक्षा", + "Message_ShowFormattingTips": "फ़ॉर्मेटिंग युक्तियाँ दिखाएँ", + "Email": "ईमेल", + "Email_Description": "Rocket.Chat के अंदर से प्रसारण ईमेल भेजने के लिए कॉन्फ़िगरेशन।", + "Email_address_to_send_offline_messages": "ऑफ़लाइन संदेश भेजने के लिए ईमेल पता", + "Email_already_exists": "ईमेल पहले से ही मौजूद है", + "Email_body": "ईमेल बॉडी", + "Email_Change_Disabled": "आपके Rocket.Chat व्यवस्थापक ने ईमेल बदलना अक्षम कर दिया है", + "Email_Changed_Description": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं:\n - `[ईमेल]` उपयोगकर्ता के ईमेल के लिए।\n- एप्लिकेशन नाम और यूआरएल के लिए क्रमशः `[Site_Name]` और `[Site_URL]`।", + "Email_Changed_Email_Subject": "[साइट_नाम] - ईमेल पता बदल दिया गया है", + "Email_changed_section": "ईमेल पता बदल गया", + "Email_Footer_Description": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं:\n - एप्लिकेशन नाम और यूआरएल के लिए क्रमशः `[Site_Name]` और `[Site_URL]`।", + "Email_from": "से", + "Email_Header_Description": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं:\n - एप्लिकेशन नाम और यूआरएल के लिए क्रमशः `[Site_Name]` और `[Site_URL]`।", + "Email_Inbox": "ईमेल इनबॉक्स", + "Email_Inboxes": "ईमेल इनबॉक्स", + "Email_Inbox_has_been_added": "ईमेल इनबॉक्स जोड़ा गया है", + "Email_Inbox_has_been_removed": "ईमेल इनबॉक्स हटा दिया गया है", + "Email_Notification_Mode": "ऑफ़लाइन ईमेल सूचनाएं", + "Email_Notification_Mode_All": "प्रत्येक उल्लेख/डीएम", "Email_Notification_Mode_Disabled": "उपयोग करने की अनुमति नहीं है", + "Email_notification_show_message": "ईमेल अधिसूचना में संदेश दिखाएँ", + "Email_Notifications_Change_Disabled": "आपके Rocket.Chat व्यवस्थापक ने ईमेल सूचनाएं अक्षम कर दी हैं", + "Email_or_username": "ईमेल या उपयोगकर्ता का नाम", + "Email_Placeholder": "कृपया अपना ईमेल एड्रेस इंटर करें...", + "Email_Placeholder_any": "कृपया ईमेल पते दर्ज करें...", + "email_plain_text_only": "केवल सादा पाठ ईमेल भेजें", + "email_style_description": "नेस्टेड चयनकर्ताओं से बचें", + "email_style_label": "ईमेल शैली", + "Email_subject": "ईमेल विषय", + "Email_verified": "ईमेल सत्यापित हुआ", + "Email_sent": "ईमेल भेजा", + "Emoji": "इमोजी", + "Emoji_picker": "इमोजी पिकर", + "EmojiCustomFilesystem": "कस्टम इमोजी फ़ाइल सिस्टम", + "EmojiCustomFilesystem_Description": "निर्दिष्ट करें कि इमोजी कैसे संग्रहीत किए जाते हैं।", + "Empty_no_agent_selected": "खाली, कोई एजेंट चयनित नहीं", + "Empty_title": "ख़ाली शीर्षक", "Enable": "सक्षम करें", + "Enable_Auto_Away": "ऑटो अवे सक्षम करें", + "Enable_CSP": "सामग्री-सुरक्षा-नीति सक्षम करें", + "Enable_CSP_Description": "इस विकल्प को तब तक अक्षम न करें जब तक आपके पास कोई कस्टम बिल्ड न हो और इनलाइन-स्क्रिप्ट के कारण समस्याएँ न आ रही हों", + "Extra_CSP_Domains": "अतिरिक्त सीएसपी डोमेन", + "Extra_CSP_Domains_Description": "सामग्री-सुरक्षा-नीति में जोड़ने के लिए अतिरिक्त डोमेन", + "Enable_Desktop_Notifications": "डेस्कटॉप सूचनाएं सक्षम करें", + "Enable_inquiry_fetch_by_stream": "स्ट्रीम का उपयोग करके सर्वर से पूछताछ डेटा लाने में सक्षम करें", + "Enable_omnichannel_auto_close_abandoned_rooms": "आगंतुक द्वारा छोड़े गए कमरों को स्वचालित रूप से बंद करने में सक्षम करें", + "Enable_Password_History": "पासवर्ड इतिहास सक्षम करें", + "Enable_Password_History_Description": "सक्षम होने पर, उपयोगकर्ता अपने पासवर्ड को अपने हाल ही में उपयोग किए गए कुछ पासवर्डों में अपडेट नहीं कर पाएंगे।", + "Enable_Svg_Favicon": "एसवीजी फ़ेविकॉन सक्षम करें", + "Enable_two-factor_authentication": "TOTP के माध्यम से दो-कारक प्रमाणीकरण सक्षम करें", + "Enable_two-factor_authentication_email": "ईमेल के माध्यम से दो-कारक प्रमाणीकरण सक्षम करें", + "Enable_unlimited_apps": "असीमित ऐप्स सक्षम करें", "Enabled": "सक्रिय", + "Encrypted": "कूट रूप दिया गया", + "Encrypted_channel_Description": "एंड-टू-एंड एन्क्रिप्टेड चैनल। खोज एन्क्रिप्टेड चैनलों के साथ काम नहीं करेगी और सूचनाएं संदेश सामग्री नहीं दिखा सकती हैं।", + "Encrypted_key_title": "इस चैनल के लिए एंड-टू-एंड एन्क्रिप्शन अक्षम करने के लिए यहां क्लिक करें (e2ee-अनुमति की आवश्यकता है)", + "Encrypted_message": "एन्क्रिप्टेड संदेश", + "Encrypted_setting_changed_successfully": "एन्क्रिप्टेड सेटिंग सफलतापूर्वक बदल दी गई", + "Encrypted_not_available": "सार्वजनिक चैनलों के लिए उपलब्ध नहीं है", + "Encryption_key_saved_successfully": "आपकी एन्क्रिप्शन कुंजी सफलतापूर्वक सहेजी गई थी.", + "EncryptionKey_Change_Disabled": "आप अपनी एन्क्रिप्शन कुंजी के लिए पासवर्ड सेट नहीं कर सकते क्योंकि आपकी निजी कुंजी इस क्लाइंट पर मौजूद नहीं है। नया पासवर्ड सेट करने के लिए आपको अपने मौजूदा पासवर्ड का उपयोग करके अपनी निजी कुंजी लोड करनी होगी या किसी क्लाइंट का उपयोग करना होगा जहां कुंजी पहले से ही लोड है।", + "End": "अंत", + "End_suspicious_sessions": "किसी भी संदिग्ध सत्र को समाप्त करें", + "End_call": "कॉल समाप्त करें", + "End_conversation": "बातचीत समाप्त करें", + "Expand_view": "दृश्य का विस्तार करें", + "Explore": "अन्वेषण करना", + "Explore_marketplace": "बाज़ार का अन्वेषण करें", + "Explore_the_marketplace_to_find_awesome_apps": "Rocket.Chat के लिए शानदार ऐप्स ढूंढने के लिए बाज़ार का अन्वेषण करें", + "Export": "निर्यात", + "End_Call": "कॉल समाप्त करें", + "End_OTR": "ओटीआर समाप्त करें", + "Engagement": "सगाई", + "Engagement_Dashboard": "सगाई डैशबोर्ड", + "Enrich_your_workspace": "सहभागिता डैशबोर्ड के साथ अपने कार्यक्षेत्र परिप्रेक्ष्य को समृद्ध करें। अपने उपयोगकर्ताओं, संदेशों और चैनलों के बारे में व्यावहारिक उपयोग आंकड़ों का विश्लेषण करें। प्रीमियम योजनाओं में शामिल.", + "Ensure_secure_workspace_access": "कार्यस्थल तक सुरक्षित पहुंच सुनिश्चित करें", + "Enter": "प्रवेश करना", + "Enter_a_custom_message": "एक कस्टम संदेश दर्ज करें", + "Enter_a_department_name": "विभाग का नाम दर्ज करें", + "Enter_a_name": "नाम डालें", + "Enter_a_regex": "रेगेक्स दर्ज करें", + "Enter_a_room_name": "कमरे का नाम दर्ज करें", + "Enter_a_tag": "एक टैग दर्ज करें", + "Enter_a_username": "एक उपयोगकर्ता नाम दर्ज करें", + "Enter_Alternative": "वैकल्पिक मोड (एंटर + Ctrl/Alt/Shift/CMD के साथ भेजें)", + "Enter_authentication_code": "प्रमाणीकरण कोड दर्ज करें", + "Enter_Behaviour": "कुंजी व्यवहार दर्ज करें", + "Enter_Behaviour_Description": "यदि एंटर कुंजी एक संदेश भेजेगी या लाइन ब्रेक करेगी तो यह बदल जाएगा", + "Enter_E2E_password": "E2E पासवर्ड दर्ज करें", + "Enter_name_here": "यहां नाम दर्ज करें", + "Enter_Normal": "सामान्य मोड (एंटर के साथ भेजें)", + "Enter_to": "में दर्ज", + "Enter_your_E2E_password": "अपना E2E पासवर्ड दर्ज करें", + "Enter_your_password_to_delete_your_account": "अपना खाता हटाने के लिए अपना पासवर्ड दर्ज करें। इसे असंपादित नहीं किया जा सकता है।", + "Enter_your_username_to_delete_your_account": "अपना खाता हटाने के लिए अपना उपयोगकर्ता नाम दर्ज करें। इसे असंपादित नहीं किया जा सकता है।", + "Premium_capabilities": "प्रीमियम क्षमताएं", + "Premium_Departments_title": "ग्राहकों को कतार में लगाएं और एजेंट उत्पादकता में सुधार करें", + "Premium_Departments_description_upgrade": "समुदाय पर कार्यस्थान केवल एक विभाग बना सकते हैं। सीमाएं हटाने और अपने कार्यक्षेत्र को सुपरचार्ज करने के लिए प्रीमियम योजना में अपग्रेड करें।", + "Premium_Departments_description_free_trial": "समुदाय पर कार्यस्थान एक विभाग बना सकते हैं। अनेक विभाग बनाने के लिए आज ही निःशुल्क प्रीमियम परीक्षण प्रारंभ करें!", + "Premium_License": "प्रीमियम लाइसेंस", + "Premium_only": "केवल प्रीमियम", + "Entertainment": "मनोरंजन", + "Error": "गलती", + "Error_something_went_wrong": "उफ़! कुछ गलत हो गया। कृपया पृष्ठ पुनः लोड करें या किसी व्यवस्थापक से संपर्क करें।", + "Error_404": "त्रुटि 404", + "Error_changing_password": "पासवर्ड बदलने में त्रुटि", + "Error_loading_pages": "पेज लोड करने में त्रुटि", + "Error_login_blocked_for_ip": "इस आईपी के लिए लॉगिन अस्थायी रूप से अवरुद्ध कर दिया गया है", + "Error_login_blocked_for_user": "इस उपयोगकर्ता के लिए लॉगिन अस्थायी रूप से अवरुद्ध कर दिया गया है", + "Error_RocketChat_requires_oplog_tailing_when_running_in_multiple_instances": "त्रुटि: रॉकेट.चैट को कई उदाहरणों में चलाने पर ओप्लॉग टेलिंग की आवश्यकता होती है", + "Error_RocketChat_requires_oplog_tailing_when_running_in_multiple_instances_details": "कृपया सुनिश्चित करें कि आपका MongoDB रेप्लिकासेट मोड पर है और MONGO_OPLOG_URL पर्यावरण चर एप्लिकेशन सर्वर पर सही ढंग से परिभाषित है", + "Error_sending_livechat_offline_message": "ओमनीचैनल ऑफ़लाइन संदेश भेजने में त्रुटि", + "Error_sending_livechat_transcript": "ओमनीचैनल प्रतिलेख भेजने में त्रुटि", + "Error_Site_URL": "अमान्य साइट_यूआरएल", + "Error_Site_URL_description": "कृपया, अपनी \"साइट_यूआरएल\" सेटिंग अपडेट करें और अधिक जानकारी पाएं [यहां](https://go.rocket.chat/i/invalid-site-url)", + "error-action-not-allowed": "{{action}} की अनुमति नहीं है", + "error-agent-offline": "एजेंट ऑफ़लाइन है", + "error-agent-status-service-offline": "एजेंट की स्थिति ऑफ़लाइन है या ओमनीचैनल सेवा सक्रिय नहीं है", + "error-application-not-found": "अनुप्रयोग नहीं मिला", + "error-archived-duplicate-name": "'{{room_name}}' नाम से एक संग्रहीत चैनल है", + "error-avatar-invalid-url": "अमान्य अवतार URL: {{url}}", + "error-avatar-url-handling": "{{username}} के लिए URL ({{url}}) से अवतार सेटिंग को संभालते समय त्रुटि", + "error-business-hours-are-closed": "व्यावसायिक घंटे बंद हैं", + "error-business-hour-finish-time-before-start-time": "समाप्ति का समय प्रारंभ समय के बाद का होना चाहिए", + "error-business-hour-finish-time-equals-start-time": "प्रारंभ और समाप्ति का समय एक समान नहीं हो सकता", + "error-blocked-username": "{{field}} अवरुद्ध है और इसका उपयोग नहीं किया जा सकता!", + "error-canned-response-not-found": "डिब्बाबंद प्रतिक्रिया नहीं मिली", + "error-cannot-delete-app-user": "ऐप उपयोगकर्ता को हटाने की अनुमति नहीं है, इसे हटाने के लिए संबंधित ऐप को अनइंस्टॉल करें।", + "error-cant-add-federated-users": "फ़ेडरेटेड उपयोगकर्ताओं को गैर-फ़ेडरेटेड रूम में नहीं जोड़ा जा सकता", + "error-cant-invite-for-direct-room": "उपयोगकर्ता को सीधे रूम में आमंत्रित नहीं किया जा सकता", + "error-channels-setdefault-is-same": "चैनल की डिफ़ॉल्ट सेटिंग वही है जिसमें इसे बदला जाएगा।", + "error-channels-setdefault-missing-default-param": "बॉडीपरम 'डिफ़ॉल्ट' आवश्यक है", + "error-could-not-change-email": "ईमेल नहीं बदला जा सका", + "error-could-not-change-name": "नाम नहीं बदला जा सका", + "error-could-not-change-username": "उपयोक्तानाम नहीं बदला जा सका", + "error-comment-is-required": "टिप्पणी आवश्यक है", + "error-custom-field-name-already-exists": "कस्टम फ़ील्ड नाम पहले से मौजूद है", + "error-delete-protected-role": "संरक्षित भूमिका को हटाया नहीं जा सकता", + "error-department-not-found": "विभाग नहीं मिला", + "error-department-removal-disabled": "विभाग निष्कासन प्रशासन द्वारा अक्षम कर दिया गया है, कृपया अपने व्यवस्थापक से संपर्क करें", + "error-direct-message-file-upload-not-allowed": "सीधे संदेशों में फ़ाइल साझाकरण की अनुमति नहीं है", + "error-duplicate-channel-name": "'{{channel_name}}' नाम से एक चैनल मौजूद है", + "error-duplicate-priority-name": "समान नाम वाली प्राथमिकता पहले से मौजूद है", + "error-edit-permissions-not-allowed": "संपादन अनुमति की अनुमति नहीं है", + "error-email-domain-blacklisted": "ईमेल डोमेन ब्लैकलिस्टेड है", + "error-email-body-not-initialized": "ईमेल का मुख्य भाग प्रारंभ नहीं किया गया. रिच ईमेल भेजने से पहले ईमेल सेटिंग्स पर ईमेल के हेडर और फुटर को सेटअप करें", + "error-email-send-failed": "ईमेल भेजने का प्रयास करने में त्रुटि: {{message}}", + "error-essential-app-disabled": "त्रुटि: एक Rocket.Chat ऐप जो इसके लिए आवश्यक है, अक्षम है। कृपया अपने व्यवस्थापक से संपर्क करें", + "error-failed-to-delete-department": "विभाग हटाने में विफल", + "error-field-unavailable": "{{field}} पहले से ही उपयोग में है :(", + "error-file-too-large": "फ़ाइल बहुत बड़ी है", + "error-forwarding-chat": "चैट अग्रेषित करते समय कुछ गलत हो गया, कृपया बाद में पुनः प्रयास करें।", + "error-forwarding-chat-same-department": "चयनित विभाग और वर्तमान कक्ष विभाग समान हैं", + "error-forwarding-department-target-not-allowed": "लक्ष्य विभाग को अग्रेषित करने की अनुमति नहीं है.", + "error-guests-cant-have-other-roles": "अतिथि उपयोगकर्ताओं की कोई अन्य भूमिका नहीं हो सकती.", + "error-import-file-extract-error": "आयात फ़ाइल निकालने में विफल.", + "error-import-file-is-empty": "आयातित फ़ाइल खाली प्रतीत होती है.", + "error-import-file-missing": "आयात की जाने वाली फ़ाइल निर्दिष्ट पथ पर नहीं मिली।", + "error-importer-not-defined": "आयातक को सही ढंग से परिभाषित नहीं किया गया था, इसमें आयात वर्ग गुम है।", + "error-input-is-not-a-valid-field": "{{input}} मान्य {{field}} नहीं है", + "error-insufficient-permission": "गलती! आपके पास इस ऑपरेशन को करने के लिए आवश्यक '{{permission}}' अनुमति नहीं है", + "error-inquiry-taken": "पूछताछ हो चुकी है", + "error-invalid-account": "अवैध खाता", + "error-invalid-actionlink": "अमान्य क्रिया लिंक", + "error-invalid-arguments": "अमान्य तर्क", + "error-invalid-asset": "अमान्य संपत्ति", + "error-invalid-channel": "अमान्य चैनल.", + "error-invalid-channel-start-with-chars": "अमान्य चैनल. @ या # से प्रारंभ करें", + "error-invalid-custom-field": "अमान्य कस्टम फ़ील्ड", + "error-invalid-custom-field-name": "अमान्य कस्टम फ़ील्ड नाम. केवल अक्षरों, संख्याओं, हाइफ़न और अंडरस्कोर का उपयोग करें।", + "error-invalid-custom-field-value": "{{field}} फ़ील्ड के लिए अमान्य मान", + "error-invalid-date": "अमान्य दिनांक प्रदान की गई.", + "error-invalid-dates": "दिनांक से दिनांक के बाद नहीं हो सकता", + "error-invalid-description": "अमान्य विवरण", + "error-invalid-domain": "अमान्य डोमेन", + "error-invalid-email": "अमान्य ईमेल {{email}}", + "error-invalid-email-address": "अमान्य ईमेल पता", + "error-invalid-email-inbox": "अमान्य ईमेल इनबॉक्स", + "error-email-inbox-not-found": "ईमेल इनबॉक्स नहीं मिला", + "error-invalid-file-height": "अमान्य फ़ाइल ऊंचाई", + "error-invalid-file-type": "अमान्य फ़ाइल प्रकार", + "error-invalid-file-width": "अमान्य फ़ाइल चौड़ाई", + "error-invalid-from-address": "आपने एक अमान्य FROM पता सूचित किया.", + "error-invalid-inquiry": "अमान्य पूछताछ", + "error-invalid-integration": "अमान्य एकीकरण", + "error-invalid-message": "अमान्य संदेश", + "error-invalid-method": "अमान्य विधि", + "error-invalid-name": "अमान्य नाम", + "error-invalid-password": "अवैध पासवर्ड", + "error-invalid-param": "अमान्य पैरामीटर", + "error-invalid-params": "अमान्य पैरामीटर", + "error-invalid-permission": "अमान्य अनुमति", + "error-invalid-port-number": "अमान्य पोर्ट नंबर", + "error-invalid-priority": "अमान्य प्राथमिकता", + "error-invalid-redirectUri": "अमान्य रीडायरेक्टयूरी", + "error-invalid-role": "अमान्य भूमिका", + "error-invalid-room": "अमान्य कमरा", + "error-invalid-room-name": "{{room_name}} कमरे का वैध नाम नहीं है", + "error-invalid-room-type": "{{type}} मान्य कमरे का प्रकार नहीं है।", + "error-invalid-settings": "अमान्य सेटिंग्स प्रदान की गईं", + "error-invalid-subscription": "अमान्य सदस्यता", + "error-invalid-token": "अमान्य टोकन", + "error-invalid-triggerWords": "अमान्य ट्रिगर शब्द", + "error-invalid-urls": "अमान्य यूआरएल", + "error-invalid-user": "अमान्य उपयोगकर्ता", + "error-invalid-username": "अमान्य उपयोगकर्ता नाम", + "error-invalid-value": "अमान्य मूल्य", + "error-invalid-webhook-response": "वेबहुक यूआरएल ने 200 के अलावा किसी अन्य स्थिति के साथ प्रतिक्रिया दी", + "error-license-user-limit-reached": "उपयोगकर्ताओं की अधिकतम संख्या तक पहुँच गया है.", + "error-logged-user-not-in-room": "आप `%s` कमरे में नहीं हैं", + "error-max-departments-number-reached": "आप अपने लाइसेंस द्वारा अनुमत विभागों की अधिकतम संख्या तक पहुँच गए। नए लाइसेंस के लिए sales@rocket.chat से संपर्क करें।", + "error-max-guests-number-reached": "आप अपने लाइसेंस द्वारा अनुमत अतिथि उपयोगकर्ताओं की अधिकतम संख्या तक पहुँच गए हैं। नए लाइसेंस के लिए sales@rocket.chat से संपर्क करें।", + "error-max-number-simultaneous-chats-reached": "प्रति एजेंट एक साथ चैट की अधिकतम संख्या तक पहुंच गई है।", + "error-max-rooms-per-guest-reached": "प्रति अतिथि कमरों की अधिकतम संख्या तक पहुँच गई है।", + "error-mac-limit-reached": "इस कार्यक्षेत्र के लिए मासिक सक्रिय संपर्कों की अधिकतम संख्या तक पहुंच गई है।", + "error-message-deleting-blocked": "संदेश हटाना अवरुद्ध है", + "error-message-editing-blocked": "संदेश संपादन अवरुद्ध है", + "error-message-size-exceeded": "संदेश का आकार Message_MaxAllowedSize से अधिक है", + "error-missing-unsubscribe-link": "आपको [सदस्यता समाप्त करें] लिंक प्रदान करना होगा।", + "error-no-tokens-for-this-user": "इस उपयोगकर्ता के लिए कोई टोकन नहीं हैं", + "error-no-agents-online-in-department": "विभाग में कोई एजेंट ऑनलाइन नहीं है", + "error-no-message-for-unread": "अपठित चिह्नित करने के लिए कोई संदेश नहीं हैं", + "error-not-allowed": "अनुमति नहीं", + "error-not-authorized": "अधिकृत नहीं हैं", + "error-office-hours-are-closed": "कार्यालय समय बंद है.", + "Estimated_due_time": "अनुमानित नियत समय", + "error-password-in-history": "दर्ज किया गया पासवर्ड पहले इस्तेमाल किया जा चुका है", + "error-password-policy-not-met": "पासवर्ड सर्वर की नीति के अनुरूप नहीं है", + "Estimated_due_time_in_minutes": "अनुमानित नियत समय (मिनटों में समय)", + "error-password-policy-not-met-maxLength": "पासवर्ड सर्वर की अधिकतम लंबाई की नीति के अनुरूप नहीं है (पासवर्ड बहुत लंबा है)", + "error-password-policy-not-met-minLength": "पासवर्ड सर्वर की न्यूनतम लंबाई की नीति को पूरा नहीं करता (पासवर्ड बहुत छोटा है)", + "error-password-policy-not-met-oneLowercase": "पासवर्ड सर्वर की कम से कम एक लोअरकेस वर्ण की नीति को पूरा नहीं करता है", + "error-password-policy-not-met-oneNumber": "पासवर्ड सर्वर की कम से कम एक संख्यात्मक वर्ण की नीति को पूरा नहीं करता है", + "error-password-policy-not-met-oneSpecial": "पासवर्ड सर्वर की कम से कम एक विशेष वर्ण की नीति को पूरा नहीं करता है", + "Please_go_to_the_Administration_page_then_Livechat_Facebook": "कृपया प्रशासन पृष्ठ पर जाएं, फिर ओमनीचैनल > फेसबुक पर जाएं", + "error-password-policy-not-met-oneUppercase": "पासवर्ड सर्वर की कम से कम एक बड़े अक्षर की नीति को पूरा नहीं करता है", + "error-password-policy-not-met-repeatingCharacters": "पासवर्ड सर्वर की वर्जित दोहराए जाने वाले वर्णों की नीति के अनुरूप नहीं है (आपके पास एक-दूसरे के बगल में समान वर्णों के बहुत सारे हैं)", + "error-password-same-as-current": "वर्तमान पासवर्ड के समान ही दर्ज किया गया पासवर्ड", + "error-personal-access-tokens-are-current-disabled": "व्यक्तिगत एक्सेस टोकन वर्तमान में अक्षम हैं", + "error-pinning-message": "संदेश पिन नहीं किया जा सका", + "error-push-disabled": "पुश अक्षम है", + "error-remove-last-owner": "यह आखिरी मालिक है. कृपया इसे हटाने से पहले एक नया स्वामी निर्धारित करें।", + "error-returning-inquiry": "पूछताछ को कतार में लौटाने में त्रुटि", + "error-role-in-use": "भूमिका को हटाया नहीं जा सकता क्योंकि यह उपयोग में है", + "error-role-name-required": "भूमिका का नाम आवश्यक है", + "error-room-does-not-exist": "यह कमरा मौजूद नहीं है", + "error-role-already-present": "इस नाम की एक भूमिका पहले से मौजूद है", + "error-room-already-closed": "कमरा पहले से ही बंद है", + "error-room-is-not-closed": "कमरा बंद नहीं है", + "error-room-onHold": "गलती! कमरा रुका हुआ है", + "error-room-is-already-on-hold": "गलती! कमरा पहले से ही होल्ड पर है", + "error-room-not-on-hold": "गलती! कमरा होल्ड पर नहीं है", + "error-selected-agent-room-agent-are-same": "चयनित एजेंट और रूम एजेंट समान हैं", + "error-starring-message": "संदेश को घूरा नहीं जा सका", + "error-tags-must-be-assigned-before-closing-chat": "चैट बंद करने से पहले टैग असाइन किया जाना चाहिए", + "error-the-field-is-required": "फ़ील्ड {{field}} आवश्यक है.", + "error-this-is-not-a-livechat-room": "यह एक ओमनीचैनल कक्ष नहीं है", + "error-this-is-a-premium-feature": "यह एक प्रीमियम फीचर से है", + "error-token-already-exists": "इस नाम का एक टोकन पहले से मौजूद है", + "error-token-does-not-exists": "टोकन मौजूद नहीं है", + "error-too-many-requests": "त्रुटि, बहुत सारे अनुरोध. कृप्या धीरें करो। दोबारा प्रयास करने से पहले आपको {{seconds}} सेकंड तक प्रतीक्षा करनी होगी।", + "error-transcript-already-requested": "प्रतिलिपि का अनुरोध पहले ही किया जा चुका है", + "error-unpinning-message": "संदेश अनपिन नहीं किया जा सका", + "error-user-deactivated": "उपयोगकर्ता सक्रिय नहीं है", + "error-user-has-no-roles": "उपयोगकर्ता की कोई भूमिका नहीं है", + "error-user-is-not-activated": "उपयोगकर्ता सक्रिय नहीं है", + "error-user-is-not-agent": "उपयोगकर्ता एक ओमनीचैनल एजेंट नहीं है", + "error-user-is-offline": "उपयोगकर्ता ऑफ़लाइन है", + "error-user-limit-exceeded": "आप जिन उपयोगकर्ताओं को #channel_name पर आमंत्रित करने का प्रयास कर रहे हैं, उनकी संख्या व्यवस्थापक द्वारा निर्धारित सीमा से अधिक है", + "error-user-not-belong-to-department": "उपयोगकर्ता इस विभाग से संबंधित नहीं है", + "error-user-not-in-room": "उपयोगकर्ता इस कमरे में नहीं है", + "error-user-registration-disabled": "उपयोगकर्ता पंजीकरण अक्षम है", + "error-user-registration-secret": "उपयोगकर्ता पंजीकरण की अनुमति केवल गुप्त यूआरएल के माध्यम से है", + "error-validating-department-chat-closing-tags": "जब विभाग को बातचीत बंद करने के लिए टैग की आवश्यकता होती है तो कम से कम एक समापन टैग की आवश्यकता होती है।", + "error-no-permission-team-channel": "आपको इस चैनल को टीम में जोड़ने की अनुमति नहीं है", + "error-no-owner-channel": "केवल मालिक ही इस चैनल को टीम में जोड़ सकते हैं", + "error-unable-to-update-priority": "प्राथमिकता अद्यतन करने में असमर्थ", + "error-you-are-last-owner": "आप आखिरी मालिक हैं. कृपया कमरा छोड़ने से पहले नए मालिक का चयन करें।", + "error-saving-sla": "SLA सहेजते समय एक त्रुटि उत्पन्न हुई", + "error-duplicated-sla": "समान नाम या नियत समय वाला एक SLA पहले से मौजूद है", + "error-cannot-place-chat-on-hold": "आप चैट को होल्ड पर नहीं रख सकते", + "error-contact-sent-last-message-so-cannot-place-on-hold": "जब संपर्क ने आखिरी संदेश भेज दिया हो तो आप चैट को होल्ड पर नहीं रख सकते", + "error-unserved-rooms-cannot-be-placed-onhold": "परोसे जाने से पहले कमरे को होल्ड पर नहीं रखा जा सकता", + "Workspace_exceeded_MAC_limit_disclaimer": "कार्यक्षेत्र सक्रिय संपर्कों की मासिक सीमा को पार कर गया है. इस समस्या के समाधान के लिए अपने कार्यक्षेत्र व्यवस्थापक से बात करें।", + "You_do_not_have_permission_to_do_this": "तुमको यह करने की इजाजत नहीं है", + "You_do_not_have_permission_to_execute_this_command": "आपके पास कमांड निष्पादित करने के लिए पर्याप्त अनुमतियाँ नहीं हैं: `/{{command}}`", + "You_have_reached_the_limit_active_costumers_this_month": "आप इस महीने सक्रिय ग्राहकों की सीमा तक पहुंच गए हैं", + "Errors_and_Warnings": "त्रुटियाँ और चेतावनियाँ", + "Esc_to": "Esc को", + "Estimated_wait_time": "अनुमानित प्रतीक्षा समय", + "Estimated_wait_time_in_minutes": "अनुमानित प्रतीक्षा समय (मिनटों में समय)", + "Event_notifications": "घटना सूचनाएं", + "Event_notifications_description": "इस सेटिंग को अक्षम करके आप ऐप को आगामी घटनाओं के बारे में सूचित करने से रोकेंगे।", + "Event_Trigger": "इवेंट ट्रिगर", + "Event_Trigger_Description": "चुनें कि किस प्रकार का ईवेंट इस आउटगोइंग वेबहुक इंटीग्रेशन को ट्रिगर करेगा", + "every_5_minutes": "हर 5 मिनट में एक बार", + "every_10_seconds": "हर 10 सेकंड में एक बार", + "every_30_seconds": "हर 30 सेकंड में एक बार", + "every_10_minutes": "हर 10 मिनट में एक बार", + "every_30_minutes": "हर 30 मिनट में एक बार", + "every_day": "हर दिन एक बार", + "every_hour": "हर घंटे में एक बार", + "every_minute": "हर मिनट में एक बार", + "every_second": "हर सेकंड एक बार", + "every_six_hours": "हर छह घंटे में एक बार", + "every_12_hours": "हर 12 घंटे में एक बार", + "every_24_hours": "हर 24 घंटे में एक बार", + "every_48_hours": "हर 48 घंटे में एक बार", + "Everyone_can_access_this_channel": "हर कोई इस चैनल तक पहुंच सकता है", + "Exact": "एकदम सही", + "Example_payload": "उदाहरण पेलोड", + "Example_s": "उदाहरण: %s", + "except_pinned": "(उन्हें छोड़कर जिन्हें पिन किया गया है)", + "Exclude_Botnames": "बॉट्स को बाहर निकालें", + "Exclude_Botnames_Description": "उन बॉट्स से संदेशों का प्रचार-प्रसार न करें जिनका नाम उपरोक्त रेगुलर एक्सप्रेशन से मेल खाता हो। यदि खाली छोड़ दिया जाए, तो बॉट्स के सभी संदेश प्रसारित हो जाएंगे।", + "Exclude_pinned": "पिन किए गए संदेशों को बाहर निकालें", + "Execute_Synchronization_Now": "अभी सिंक्रोनाइज़ेशन निष्पादित करें", + "Exit_Full_Screen": "पूर्ण स्क्रीन से बाहर निकलें", + "Expand": "बढ़ाना", + "Experimental_Feature_Alert": "यह एक प्रायोगिक सुविधा है! कृपया ध्यान रखें कि यह भविष्य में बिना किसी सूचना के बदल सकता है, टूट सकता है या हटाया भी जा सकता है।", + "Expired": "खत्म हो चुका", + "Expiration": "समय सीमा समाप्ति", + "Expiration_(Days)": "समाप्ति (दिन)", + "Export_as_file": "फ़ाइल के रूप में निर्यात करें", + "Export_Messages": "संदेश निर्यात करें", + "Export_My_Data": "मेरा डेटा निर्यात करें (JSON)", + "expression": "अभिव्यक्ति", + "Extended": "विस्तारित", + "Extensions": "एक्सटेंशन", + "Extension_Number": "विस्तारण क्रमांक", + "Extension_Status": "विस्तार स्थिति", + "External": "बाहरी", + "External_Domains": "बाहरी डोमेन", + "External_Queue_Service_URL": "बाहरी कतार सेवा यूआरएल", + "External_Service": "बाह्य सेवा", + "External_Users": "बाहरी उपयोगकर्ताओं", + "Extremely_likely": "बहुत ज्यादा संभावना", + "Facebook": "फेसबुक", + "Facebook_Page": "फेसबुक पेज", + "Failed": "असफल", + "Failed_to_activate_invite_token": "आमंत्रण टोकन सक्रिय करने में विफल", + "Failed_to_add_monitor": "मॉनिटर जोड़ने में विफल", + "Failed_To_Download_Files": "फ़ाइलें डाउनलोड करने में विफल", + "Failed_to_generate_invite_link": "आमंत्रण लिंक जनरेट करने में विफल", + "Failed_To_Load_Import_Data": "आयात डेटा लोड करने में विफल", + "Failed_To_Load_Import_History": "आयात इतिहास लोड करने में विफल", + "Failed_To_Load_Import_Operation": "आयात कार्रवाई लोड करने में विफल", + "Failed_To_Start_Import": "आयात कार्रवाई प्रारंभ करने में विफल", + "Failed_to_validate_invite_token": "आमंत्रण टोकन सत्यापित करने में विफल", + "Failure": "असफलता", + "False": "असत्य", + "Fallback_forward_department": "अग्रेषण के लिए फ़ॉलबैक विभाग", + "Fallback_forward_department_description": "आपको एक फ़ॉलबैक विभाग को परिभाषित करने की अनुमति देता है जो इस समय कोई ऑनलाइन एजेंट न होने की स्थिति में इस पर अग्रेषित चैट प्राप्त करेगा", + "Favorite": "पसंदीदा", + "Favorite_Rooms": "पसंदीदा कमरे सक्षम करें", + "Favorites": "पसंदीदा", + "Feature_preview": "फ़ीचर पूर्वावलोकन", + "Feature_preview_page_description": "फीचर पूर्वावलोकन पृष्ठ पर आपका स्वागत है! यहां, आप नवीनतम अत्याधुनिक सुविधाओं को सक्षम कर सकते हैं जो वर्तमान में विकास के अधीन हैं और अभी तक आधिकारिक तौर पर जारी नहीं की गई हैं।\n\nकृपया ध्यान दें कि ये कॉन्फ़िगरेशन अभी भी परीक्षण चरण में हैं और स्थिर या पूरी तरह कार्यात्मक नहीं हो सकते हैं।", + "featured": "प्रदर्शित", + "Featured": "प्रदर्शित", + "Feature_depends_on_selected_call_provider_to_be_enabled_from_administration_settings": "यह सुविधा प्रशासन सेटिंग्स (एडमिन -> वीडियो कॉन्फ्रेंस) से सक्षम होने के लिए उपरोक्त चयनित कॉल प्रदाता पर निर्भर करती है।", + "Feature_Depends_on_Livechat_Visitor_navigation_as_a_message_to_be_enabled": "यह सुविधा सक्षम होने के लिए \"विज़िटर नेविगेशन इतिहास को संदेश के रूप में भेजें\" पर निर्भर करती है।", + "Feature_Limiting": "सुविधा सीमित करना", + "Features": "विशेषताएँ", + "Federation": "फेडरेशन", + "Federation_Description": "फ़ेडरेशन असीमित संख्या में कार्यस्थानों को एक-दूसरे के साथ संचार करने की अनुमति देता है।", + "Federation_Enable": "फ़ेडरेशन सक्षम करें", + "Federation_Example_matrix_server": "उदाहरण: मैट्रिक्स.ऑर्ग", + "Federation_Federated_room_search": "फ़ेडरेटेड कमरे की खोज", + "Federation_Public_key": "सार्वजनिक कुंजी", + "Federation_Search_federated_rooms": "फ़ेडरेटेड कमरे खोजें", + "Federation_slash_commands": "फेडरेशन का आदेश", + "FEDERATION_Discovery_Method": "खोज विधि", + "FEDERATION_Discovery_Method_Description": "आप अपने DNS रिकॉर्ड पर हब या SRV और TXT प्रविष्टि का उपयोग कर सकते हैं।", + "FEDERATION_Domain": "कार्यक्षेत्र", + "FEDERATION_Domain_Alert": "सुविधा सक्षम करने के बाद इसे न बदलें, हम अभी तक डोमेन परिवर्तनों को संभाल नहीं सकते हैं।", + "FEDERATION_Domain_Description": "वह डोमेन जोड़ें जिससे यह सर्वर लिंक होना चाहिए - उदाहरण के लिए: @rocket.chat.", + "FEDERATION_Enabled": "फेडरेशन समर्थन को एकीकृत करने का प्रयास।", + "FEDERATION_Enabled_Alert": "फेडरेशन सपोर्ट का कार्य प्रगति पर है। इस समय उत्पादन प्रणाली पर उपयोग की अनुशंसा नहीं की जाती है।", + "FEDERATION_Public_Key": "सार्वजनिक कुंजी", + "FEDERATION_Public_Key_Description": "यह वह कुंजी है जिसे आपको अपने साथियों के साथ साझा करने की आवश्यकता है।", + "FEDERATION_Status": "स्थिति", + "FEDERATION_Test_Setup": "परीक्षण व्यवस्था", + "FEDERATION_Test_Setup_Error": "आपके सेटअप का उपयोग करके आपका सर्वर नहीं मिल सका, कृपया अपनी सेटिंग्स की समीक्षा करें।", + "FEDERATION_Test_Setup_Success": "आपका फ़ेडरेशन सेटअप काम कर रहा है और अन्य सर्वर आपको ढूंढ सकते हैं!", + "Retry_Count": "count पुनः प्रयास करें", + "Federation_Matrix": "फेडरेशन V2", "Federation_Matrix_enabled": "सक्रिय", + "Federation_Matrix_Enabled_Alert": "मैट्रिक्स फेडरेशन समर्थन के बारे में अधिक जानकारी यहां पाई जा सकती है (किसी भी कॉन्फ़िगरेशन के बाद, परिवर्तनों को प्रभावी करने के लिए पुनः आरंभ करना आवश्यक है)", + "Federation_Matrix_Federated": "संघीय", + "Federation_Matrix_Federated_Description": "फ़ेडरेटेड रूम बनाकर आप न तो एन्क्रिप्शन सक्षम कर पाएंगे और न ही प्रसारण", + "Federation_Matrix_Federated_Description_disabled": "फ़ेडरेशन वर्तमान में इस कार्यक्षेत्र में अक्षम है.", + "Federation_Matrix_id": "ऐपसेवा आईडी", + "Federation_Matrix_hs_token": "होमसर्वर टोकन", + "Federation_Matrix_as_token": "ऐपसर्विस टोकन", + "Federation_Matrix_homeserver_url": "होमसर्वर यूआरएल", + "Federation_Matrix_homeserver_url_alert": "हम अपने फेडरेशन के साथ उपयोग करने के लिए एक नए, खाली होमसर्वर की अनुशंसा करते हैं", + "Federation_Matrix_homeserver_domain": "होमसर्वर डोमेन", + "Federation_Matrix_homeserver_domain_alert": "किसी भी उपयोगकर्ता को केवल रॉकेट.चैट के अलावा तीसरे पक्ष के ग्राहकों के साथ होमसर्वर से नहीं जुड़ना चाहिए", + "Federation_Matrix_bridge_url": "ब्रिज यूआरएल", + "Federation_Matrix_bridge_localpart": "ऐपसर्विस उपयोगकर्ता लोकलपार्ट", + "Federation_Matrix_registration_file": "पंजीकरण फ़ाइल", + "Federation_Matrix_registration_file_Alert": "महत्वपूर्ण: अल्पकालिक घटनाओं को सक्षम करने से सर्वर उन सभी सर्वरों से सभी उपयोगकर्ताओं की टाइपिंग स्थिति प्राप्त कर लेगा जिनसे आप जुड़े हुए हैं। इसे सक्षम करने के लिए, कृपया अपनी पंजीकरण फ़ाइल (.yaml फ़ाइल जिसे आप Rocket.Chat को पंजीकृत करने के लिए उपयोग कर रहे हैं) अपडेट करें। अपने होम सर्वर पर), निम्नलिखित जोड़ें:
    de.sorunome.msc2409.push_epheral: true", + "Federation_Matrix_error_applying_room_roles": "फ़ेडरेटेड नेटवर्क पर रूम भूमिकाएँ लागू करते समय कुछ गलत हो गया", + "Federation_Matrix_giving_same_permission_warning": "आप इस उपयोगकर्ता को अपने जैसे ही विशेषाधिकार दे रहे हैं, आप इस परिवर्तन को पूर्ववत नहीं कर पाएंगे। क्या आपकी आगे बढ़ने की इच्छा है?", + "Federation_Matrix_losing_privileges": "विशेषाधिकार खोना", + "Federation_Matrix_losing_privileges_warning": "आप इस कार्रवाई को पूर्ववत नहीं कर पाएंगे, क्योंकि आप स्वयं को पदावनत कर रहे हैं। यदि आप अंतिम विशेषाधिकार प्राप्त उपयोगकर्ता हैं तो आप यह विशेषाधिकार पुनः प्राप्त नहीं कर पाएंगे। क्या आप अब भी आगे बढ़ना चाहते हैं?", + "Federation_Matrix_not_allowed_to_change_moderator": "आपको मॉडरेटर बदलने की अनुमति नहीं है", + "Federation_Matrix_not_allowed_to_change_owner": "आपको स्वामी बदलने की अनुमति नहीं है", + "Federation_Matrix_join_public_rooms_is_premium": "फ़ेडरेटेड रूम से जुड़ें एक प्रीमियम सुविधा है", + "Federation_Matrix_max_size_of_public_rooms_users": "किसी दूरस्थ सर्वर में सार्वजनिक कक्ष से जुड़ने पर उपयोगकर्ताओं की अधिकतम संख्या", + "Federation_Matrix_max_size_of_public_rooms_users_desc": "किसी दूरस्थ सर्वर में सार्वजनिक कक्ष से जुड़ने पर अधिकतम उपयोगकर्ताओं की संख्या। अधिक उपयोगकर्ताओं वाले सार्वजनिक कमरों को शामिल होने वाले सार्वजनिक कमरों की सूची में नजरअंदाज कर दिया जाएगा।", + "Federation_Matrix_max_size_of_public_rooms_users_Alert": "ध्यान रखें, आप उपयोगकर्ताओं को शामिल होने के लिए जितना बड़ा कमरा देंगे, उस कमरे में शामिल होने में उतना ही अधिक समय लगेगा, साथ ही इसमें संसाधन की मात्रा भी उपयोग होगी। और पढ़ें", + "Field": "मैदान", + "Field_removed": "फ़ील्ड हटा दिया गया", + "Field_required": "आवश्यक क्षेत्र", + "File": "फ़ाइल", + "File_Downloads_Started": "फ़ाइल डाउनलोड प्रारंभ हो गए", + "File_exceeds_allowed_size_of_bytes": "फ़ाइल स्वीकृत आकार {{size}} से अधिक है।", + "File_name_Placeholder": "फ़ाइल ढूंढो...", + "File_not_allowed_direct_messages": "सीधे संदेशों में फ़ाइल साझाकरण की अनुमति नहीं है.", + "File_Path": "दस्तावेज पथ", + "file_pruned": "फ़ाइल की छँटाई की गई", + "File_removed_by_automatic_prune": "स्वचालित छँटाई द्वारा फ़ाइल हटा दी गई", + "File_removed_by_prune": "फ़ाइल को प्रून द्वारा हटा दिया गया", + "File_Type": "फाइल का प्रकार", + "File_type_is_not_accepted": "फ़ाइल प्रकार स्वीकार नहीं किया जाता है.", + "File_uploaded": "फ़ाइल अपलोड की गई", + "File_Upload_Disabled": "फ़ाइल अपलोड अक्षम किया गया", + "File_uploaded_successfully": "फ़ाइल सफलतापूर्वक अपलोड की गई", + "File_URL": "फ़ाइल यूआरएल", + "FileType": "फाइल का प्रकार", + "files": "फ़ाइलें", + "Files": "फ़ाइलें", + "Files_only": "केवल संलग्न फ़ाइलें हटाएँ, संदेश रखें", + "FileSize_Bytes": "{{fileSize}} बाइट्स", + "FileSize_KB": "{{fileSize}} केबी", + "FileSize_MB": "{{fileSize}} एमबी", + "FileUpload": "फाइल अपलोड", + "FileUpload_Description": "फ़ाइल अपलोड और भंडारण कॉन्फ़िगर करें.", + "FileUpload_Cannot_preview_file": "फ़ाइल का पूर्वावलोकन नहीं किया जा सकता", + "FileUpload_Disabled": "फ़ाइल अपलोड अक्षम हैं.", + "FileUpload_Enable_json_web_token_for_files": "फ़ाइल अपलोड करने के लिए Json वेब टोकन सुरक्षा सक्षम करें", + "FileUpload_Enable_json_web_token_for_files_description": "अपलोड की गई फ़ाइलों के यूआरएल में एक JWT जोड़ता है", + "FileUpload_Restrict_to_room_members": "फ़ाइलों को कमरों के सदस्यों तक ही सीमित रखें", + "FileUpload_Restrict_to_room_members_Description": "कमरों पर अपलोड की गई फ़ाइलों की पहुंच केवल कमरों के सदस्यों तक ही सीमित रखें", + "FileUpload_Enabled": "फ़ाइल अपलोड सक्षम", + "FileUpload_Enabled_Direct": "सीधे संदेशों में फ़ाइल अपलोड सक्षम", + "FileUpload_Error": "फ़ाइल अपलोड करने में त्रुटि", + "FileUpload_File_Empty": "फ़ाइल खाली", + "FileUpload_FileSystemPath": "सिस्टम पथ", + "FileUpload_GoogleStorage_AccessId": "Google संग्रहण एक्सेस आईडी", + "FileUpload_GoogleStorage_AccessId_Description": "एक्सेस आईडी आम तौर पर ईमेल प्रारूप में होती है, उदाहरण के लिए: \"`example-test@example.iam.gserviceaccount.com`\"", + "FileUpload_GoogleStorage_Bucket": "Google संग्रहण बकेट नाम", + "FileUpload_GoogleStorage_Bucket_Description": "बकेट का नाम जिस पर फ़ाइलें अपलोड की जानी चाहिए.", + "FileUpload_GoogleStorage_ProjectId": "प्रोजेक्ट आईडी", + "FileUpload_GoogleStorage_ProjectId_Description": "Google डेवलपर कंसोल से प्रोजेक्ट आईडी", + "FileUpload_GoogleStorage_Proxy_Avatars": "प्रॉक्सी अवतार", + "FileUpload_GoogleStorage_Proxy_Avatars_Description": "प्रॉक्सी अवतार फ़ाइल संपत्ति के यूआरएल तक सीधी पहुंच के बजाय आपके सर्वर के माध्यम से प्रसारित होती है", + "FileUpload_GoogleStorage_Proxy_Uploads": "प्रॉक्सी अपलोड", + "FileUpload_GoogleStorage_Proxy_Uploads_Description": "संपत्ति के यूआरएल तक सीधी पहुंच के बजाय आपके सर्वर के माध्यम से प्रॉक्सी अपलोड फ़ाइल ट्रांसमिशन", + "FileUpload_GoogleStorage_Secret": "गूगल स्टोरेज सीक्रेट", + "FileUpload_GoogleStorage_Secret_Description": "कृपया [इन निर्देशों](https://github.com/CulturalMe/meteor-slingshot#google-cloud) का पालन करें और परिणाम यहां पेस्ट करें।", + "FileUpload_json_web_token_secret_for_files": "फ़ाइल अपलोड JSON वेब टोकन रहस्य", + "FileUpload_json_web_token_secret_for_files_description": "फ़ाइल अपलोड JSON वेब टोकन सीक्रेट (प्रमाणीकरण के बिना अपलोड की गई फ़ाइलों तक पहुँचने में सक्षम होने के लिए उपयोग किया जाता है)", + "FileUpload_MaxFileSize": "अधिकतम फ़ाइल अपलोड आकार (बाइट्स में)", + "FileUpload_MaxFileSizeDescription": "फ़ाइल आकार की सीमा को हटाने के लिए इसे -1 पर सेट करें।", + "FileUpload_MediaType_NotAccepted__type__": "मीडिया प्रकार स्वीकृत नहीं: {{type}}", + "FileUpload_MediaType_NotAccepted": "मीडिया प्रकार स्वीकृत नहीं", + "FileUpload_MediaTypeBlackList": "अवरुद्ध मीडिया प्रकार", + "FileUpload_MediaTypeBlackListDescription": "मीडिया प्रकारों की अल्पविराम से अलग की गई सूची। इस सेटिंग को स्वीकृत मीडिया प्रकारों पर प्राथमिकता है।", + "FileUpload_MediaTypeWhiteList": "स्वीकृत मीडिया प्रकार", + "FileUpload_MediaTypeWhiteListDescription": "मीडिया प्रकारों की अल्पविराम से अलग की गई सूची। सभी मीडिया प्रकारों को स्वीकार करने के लिए इसे खाली छोड़ दें।", + "FileUpload_ProtectFiles": "अपलोड की गई फ़ाइलों को सुरक्षित रखें", + "FileUpload_ProtectFilesDescription": "केवल प्रमाणित उपयोगकर्ताओं को ही पहुंच प्राप्त होगी", + "FileUpload_ProtectFilesEnabled_JWTNotSet": "अपलोड की गई फ़ाइलें सुरक्षित हैं, लेकिन JWT एक्सेस सेटअप नहीं है, मीडिया संदेश भेजने के लिए ट्विलियो के लिए यह आवश्यक है। सेटिंग्स में सेटअप -> फ़ाइल अपलोड करें", + "FileUpload_RotateImages": "अपलोड पर छवियाँ घुमाएँ", + "FileUpload_RotateImages_Description": "इस सेटिंग को सक्षम करने से छवि गुणवत्ता हानि हो सकती है", + "FileUpload_S3_Acl": "एसीएल", + "FileUpload_S3_AWSAccessKeyId": "प्रवेश की चाबी", + "FileUpload_S3_AWSSecretAccessKey": "गुप्त कुंजी", + "FileUpload_S3_Bucket": "बाल्टी का नाम", + "FileUpload_S3_BucketURL": "बकेट यूआरएल", + "FileUpload_S3_CDN": "डाउनलोड के लिए सीडीएन डोमेन", + "FileUpload_S3_ForcePathStyle": "बल पथ शैली", + "FileUpload_S3_Proxy_Avatars": "प्रॉक्सी अवतार", + "FileUpload_S3_Proxy_Avatars_Description": "प्रॉक्सी अवतार फ़ाइल संपत्ति के यूआरएल तक सीधी पहुंच के बजाय आपके सर्वर के माध्यम से प्रसारित होती है", + "FileUpload_S3_Proxy_Uploads": "प्रॉक्सी अपलोड", + "FileUpload_S3_Proxy_Uploads_Description": "संपत्ति के यूआरएल तक सीधी पहुंच के बजाय आपके सर्वर के माध्यम से प्रॉक्सी अपलोड फ़ाइल ट्रांसमिशन", + "FileUpload_S3_Region": "क्षेत्र", + "FileUpload_S3_SignatureVersion": "हस्ताक्षर संस्करण", + "FileUpload_S3_URLExpiryTimeSpan": "यूआरएल समाप्ति समय period", + "FileUpload_S3_URLExpiryTimeSpan_Description": "वह समय जिसके बाद Amazon S3 द्वारा जेनरेट किए गए URL मान्य नहीं होंगे (सेकंड में)। यदि 5 सेकंड से कम पर सेट किया जाता है, तो इस फ़ील्ड को अनदेखा कर दिया जाएगा।", + "FileUpload_Storage_Type": "भण्डारण प्रकार", + "FileUpload_Webdav_Password": "वेबडीएवी पासवर्ड", + "FileUpload_Webdav_Proxy_Avatars": "प्रॉक्सी अवतार", + "FileUpload_Webdav_Proxy_Avatars_Description": "प्रॉक्सी अवतार फ़ाइल संपत्ति के यूआरएल तक सीधी पहुंच के बजाय आपके सर्वर के माध्यम से प्रसारित होती है", + "FileUpload_Webdav_Proxy_Uploads": "प्रॉक्सी अपलोड", + "FileUpload_Webdav_Proxy_Uploads_Description": "संपत्ति के यूआरएल तक सीधी पहुंच के बजाय आपके सर्वर के माध्यम से प्रॉक्सी अपलोड फ़ाइल ट्रांसमिशन", + "FileUpload_Webdav_Server_URL": "WebDAV सर्वर एक्सेस यूआरएल", + "FileUpload_Webdav_Upload_Folder_Path": "फ़ोल्डर पथ अपलोड करें", + "FileUpload_Webdav_Upload_Folder_Path_Description": "WebDAV फ़ोल्डर पथ जिस पर फ़ाइलें अपलोड की जानी चाहिए", + "FileUpload_Webdav_Username": "वेबडीएवी उपयोगकर्ता नाम", + "Filter": "फ़िल्टर", + "Filter_by_category": "श्रेणी के अनुसार फ़िल्टर करें", + "Filter_by_Custom_Fields": "कस्टम फ़ील्ड द्वारा फ़िल्टर करें", + "Filter_By_Price": "कीमत के अनुसार फ़िल्टर करें", + "Filter_By_Status": "स्थिति के अनुसार फ़िल्टर करें", "Filters": "फिल्टर", + "Filters_applied": "फ़िल्टर लागू किए गए", + "Financial_Services": "वित्तीय सेवाएं", + "Finish": "खत्म करना", + "Finish_Registration": "पंजीकरण समाप्त करें", + "First_Channel_After_Login": "लॉगिन के बाद पहला चैनल", + "First_response_time": "प्रथम प्रतिक्रिया समय", + "Flags": "झंडे", + "Follow_message": "संदेश का पालन करें", + "Follow_social_profiles": "हमारे सामाजिक प्रोफाइल का अनुसरण करें, हमें जीथब पर फोर्क करें और हमारे ट्रेलो बोर्ड पर रॉकेट.चैट ऐप के बारे में अपने विचार साझा करें।", + "Following": "अगले", + "Fonts": "फोंट्स", + "Food_and_Drink": "भोजन पेय", + "Footer": "फ़ुटबाल", + "Footer_Direct_Reply": "प्रत्यक्ष उत्तर सक्षम होने पर पादलेख", + "For_more_details_please_check_our_docs": "अधिक जानकारी के लिए कृपया हमारे दस्तावेज़ देखें।", + "For_your_security_you_must_enter_your_current_password_to_continue": "आपकी सुरक्षा के लिए, जारी रखने के लिए आपको अपना वर्तमान पासवर्ड दर्ज करना होगा", + "Force_Disable_OpLog_For_Cache": "कैश के लिए ओपलॉग को बलपूर्वक अक्षम करें", + "Force_Disable_OpLog_For_Cache_Description": "कैश उपलब्ध होने पर भी उसे सिंक करने के लिए OpLog का उपयोग नहीं किया जाएगा", + "Force_Screen_Lock": "बलपूर्वक स्क्रीन लॉक करें", + "Force_Screen_Lock_After": "इसके बाद फोर्स स्क्रीन लॉक करें", + "Force_Screen_Lock_After_description": "नवीनतम सत्र की समाप्ति के बाद दोबारा पासवर्ड का अनुरोध करने का समय, सेकंड में।", + "Force_Screen_Lock_description": "सक्षम होने पर, आप अपने उपयोगकर्ताओं को ऐप को अनलॉक करने के लिए पिन/बायोमेट्री/फेसआईडी का उपयोग करने के लिए बाध्य करेंगे।", + "Force_SSL": "एसएसएल को बाध्य करें", + "Force_SSL_Description": "*सावधान!* _Force SSL_ का उपयोग कभी भी रिवर्स प्रॉक्सी के साथ नहीं किया जाना चाहिए। यदि आपके पास रिवर्स प्रॉक्सी है, तो आपको वहां रीडायरेक्ट करना चाहिए। यह विकल्प हेरोकू जैसे परिनियोजन के लिए मौजूद है, जो रिवर्स प्रॉक्सी पर रीडायरेक्ट कॉन्फ़िगरेशन की अनुमति नहीं देता है।", + "Force_visitor_to_accept_data_processing_consent": "विज़िटर को डेटा प्रोसेसिंग सहमति स्वीकार करने के लिए बाध्य करें", + "Force_visitor_to_accept_data_processing_consent_description": "आगंतुकों को सहमति के बिना चैटिंग शुरू करने की अनुमति नहीं है।", + "Force_visitor_to_accept_data_processing_consent_enabled_alert": "डेटा प्रोसेसिंग के साथ समझौता प्रोसेसिंग के कारण की पारदर्शी समझ पर आधारित होना चाहिए। इस वजह से, आपको नीचे दी गई सेटिंग भरनी होगी जो आपकी व्यक्तिगत जानकारी एकत्र करने और संसाधित करने के कारण बताने के लिए उपयोगकर्ताओं को प्रदर्शित की जाएगी।", + "force-delete-message": "संदेश को बलपूर्वक हटाएं", + "force-delete-message_description": "सभी प्रतिबंधों को दरकिनार करते हुए किसी संदेश को हटाने की अनुमति", + "Font_size": "फ़ॉन्ट आकार", + "Forgot_password": "अपना कूट शब्द भूल गए?", + "Forgot_Password_Description": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं:\n - पासवर्ड पुनर्प्राप्ति URL के लिए `[Forgot_Password_Url]`।\n - `[नाम]`, `[fname]`, `[lname]` क्रमशः उपयोगकर्ता के पूर्ण नाम, प्रथम नाम या अंतिम नाम के लिए।\n - `[ईमेल]` उपयोगकर्ता के ईमेल के लिए।\n - एप्लिकेशन नाम और यूआरएल के लिए क्रमशः `[Site_Name]` और `[Site_URL]`।", + "Forgot_Password_Email": "अपना पासवर्ड रीसेट करने के लिए यहां क्लिक करें।", + "Forgot_Password_Email_Subject": "[साइट_नाम] - पासवर्ड पुनर्प्राप्ति", + "Forgot_password_section": "पासवर्ड भूल गए", + "Format": "प्रारूप", + "Forward": "आगे", + "Forward_chat": "चैट अग्रेषित करें", + "Forward_message": "अग्रेषित संदेश", + "Forward_to_department": "विभाग को अग्रेषित करें", + "Forward_to_user": "उपयोगकर्ता को अग्रेषित करें", + "Forwarding": "अग्रेषित करना", + "Free": "मुक्त", + "Free_Extension_Numbers": "निःशुल्क एक्सटेंशन नंबर", + "Free_Apps": "मुक्त एप्लिकेशन्स", + "Frequently_Used": "बहुधा प्रयुक्त", + "Friday": "शुक्रवार", + "From": "से", + "From_Email": "ई - मेल से", + "From_email_warning": "चेतावनी : फ़ील्ड आपकी मेल सर्वर सेटिंग्स के अधीन है।", + "Full_Name": "पूरा नाम", + "Full_Screen": "पूर्ण स्क्रीन", + "Gaming": "जुआ", + "General": "सामान्य", + "General_Description": "सामान्य कार्यस्थान सेटिंग्स कॉन्फ़िगर करें.", + "General_Settings": "सामान्य सेटिंग्स", + "Generate_new_key": "एक नई कुंजी जनरेट करें", + "Generate_New_Link": "नया लिंक जनरेट करें", + "Generating_key": "कुंजी उत्पन्न करना", + "Copy_link": "लिंक की प्रतिलिपि करें", + "get-password-policy-forbidRepeatingCharacters": "पासवर्ड में दोहराए जाने वाले अक्षर नहीं होने चाहिए", + "get-password-policy-forbidRepeatingCharactersCount": "पासवर्ड में {{forbidRepeatingCharactersCount}} से अधिक दोहराव वाले अक्षर नहीं होने चाहिए", + "get-password-policy-maxLength": "पासवर्ड अधिकतम {{maxLength}} अक्षर लंबा होना चाहिए", + "get-password-policy-minLength": "पासवर्ड न्यूनतम {{minLength}} अक्षर लंबा होना चाहिए", + "get-password-policy-mustContainAtLeastOneLowercase": "पासवर्ड में कम से कम एक लोअरकेस अक्षर होना चाहिए", + "get-password-policy-mustContainAtLeastOneNumber": "पासवर्ड में कम से कम एक नंबर होना चाहिए", + "get-password-policy-mustContainAtLeastOneSpecialCharacter": "पासवर्ड में कम से कम एक विशेष अक्षर होना चाहिए", + "get-password-policy-mustContainAtLeastOneUppercase": "पासवर्ड में कम से कम एक बड़ा अक्षर होना चाहिए", + "get-password-policy-minLength-label": "कम से कम {{limit}} अक्षर", + "get-password-policy-maxLength-label": "अधिकतम {{limit}} अक्षर", + "get-password-policy-forbidRepeatingCharactersCount-label": "अधिकतम. {{limit}} दोहराए जाने वाले अक्षर", + "get-password-policy-mustContainAtLeastOneLowercase-label": "कम से कम एक छोटा अक्षर", + "get-password-policy-mustContainAtLeastOneUppercase-label": "कम से कम एक बड़ा अक्षर", + "get-password-policy-mustContainAtLeastOneNumber-label": "कम से कम एक नंबर", + "get-password-policy-mustContainAtLeastOneSpecialCharacter-label": "कम से कम एक प्रतीक", + "get-server-info": "सर्वर जानकारी प्राप्त करें", + "get-server-info_description": "सर्वर जानकारी प्राप्त करने की अनुमति", + "github_no_public_email": "आपके GitHub खाते में सार्वजनिक ईमेल के रूप में कोई ईमेल नहीं है", + "github_HEAD": "सिर", + "Give_a_unique_name_for_the_custom_oauth": "कस्टम OAuth के लिए एक अद्वितीय नाम दें", + "strike": "हड़ताल", + "Give_the_application_a_name_This_will_be_seen_by_your_users": "एप्लिकेशन को एक नाम दें. यह आपके उपयोगकर्ताओं को दिखाई देगा.", + "Global": "वैश्विक", + "Global Policy": "वैश्विक नीति", + "Global_purge_override_warning": "एक वैश्विक अवधारण नीति लागू है। यदि आप \"ओवरराइड ग्लोबल रिटेंशन पॉलिसी\" को बंद कर देते हैं, तो आप केवल वही पॉलिसी लागू कर सकते हैं जो ग्लोबल पॉलिसी से अधिक सख्त है।", + "Global_Search": "वैश्विक खोज", + "Go_to_your_workspace": "अपने कार्यस्थल पर जाएँ", + "Go_to_accessibility_and_appearance": "पहुंच और उपस्थिति पर जाएं", + "Google_Meet_Premium_only": "Google मीट (केवल प्रीमियम)", + "Google_Play": "गूगल प्ले", + "Hold_Call": "कॉल होल्ड करें", + "Hold_Call_Premium_only": "कॉल होल्ड करें (केवल प्रीमियम प्लान)", + "GoogleCloudStorage": "गूगल क्लाउड स्टोरेज", + "GoogleNaturalLanguage_ServiceAccount_Description": "सेवा खाता कुंजी JSON फ़ाइल. अधिक जानकारी [यहां] (https://cloud.google.com/प्राकृतिक-भाषा/docs/common/auth#set_up_a_service_account) पाई जा सकती है", + "GoogleTagManager_id": "Google टैग प्रबंधक आईडी", + "Got_it": "समझ गया", + "Government": "सरकार", + "Grandfathered_app": "दादाजी ऐप - ऐप सीमा में गिना जाता है लेकिन इस ऐप पर सीमा लागू नहीं होती है", + "Graphql_CORS": "ग्राफक्यूएल कॉर्स", + "Graphql_Enabled": "ग्राफक्यूएल सक्षम", + "Graphql_Subscription_Port": "ग्राफक्यूएल सदस्यता पोर्ट", + "Grid_view": "जालक दृश्य", + "Snippet_Messages": "स्निपेट संदेश", + "Group": "समूह", + "Group_by": "द्वारा समूह बनाएं", + "Group_by_Type": "प्रकार के अनुसार समूह बनाएं", + "snippet-message": "स्निपेट संदेश", + "snippet-message_description": "स्निपेट संदेश बनाने की अनुमति", + "Group_discussions": "समूह चर्चा", + "Group_favorites": "समूह पसंदीदा", + "Group_mentions_disabled_x_members": "समूह का उल्लेख है कि `@all` और `@here` को उन कमरों के लिए अक्षम कर दिया गया है जिनमें {{total}} से अधिक सदस्य हैं।", + "Group_mentions_only": "समूह का केवल उल्लेख है", + "Grouping": "समूहन", + "Guest": "अतिथि", + "Hash": "हैश", + "Header": "हैडर", + "Header_and_Footer": "शीर्षक और पृष्ठांक", + "Pharmaceutical": "फार्मास्युटिकल", + "Healthcare": "स्वास्थ्य देखभाल", + "Helpers": "सहायकों", + "Here_is_your_authentication_code": "यहां आपका प्रमाणीकरण कोड है:", + "Hex_Color_Preview": "हेक्स रंग पूर्वावलोकन", + "Hi": "नमस्ते", + "Hi_username": "नमस्ते [नाम]", + "Hidden": "छिपा हुआ", + "Hide": "छिपाना", + "Hide_counter": "काउंटर छुपाएं", + "Hide_flextab": "प्रासंगिक बार के बाहर क्लिक करके उसे छिपाएँ", + "Hide_Group_Warning": "क्या आप वाकई समूह \"%s\" को छिपाना चाहते हैं?", + "Hide_Livechat_Warning": "क्या आप वाकई \"%s\" के साथ चैट छिपाना चाहते हैं?", + "Hide_On_Workspace": "कार्यस्थल पर छुपें", + "Hide_Private_Warning": "क्या आप वाकई \"%s\" के साथ चर्चा छिपाना चाहते हैं?", + "Hide_roles": "भूमिकाएँ छिपाएँ", + "Hide_room": "छिपाना", + "Hide_Room_Warning": "क्या आप वाकई चैनल \"%s\" को छिपाना चाहते हैं?", + "Hide_System_Messages": "सिस्टम संदेश छिपाएँ", + "Hide_Unread_Room_Status": "अपठित कक्ष की स्थिति छिपाएँ", + "Hide_usernames": "उपयोक्तानाम छिपाएँ", + "Hide_video": "वीडियो छिपाएँ", + "High": "उच्च", + "Highest": "उच्चतम", + "Highlights": "हाइलाइट", + "Highlights_How_To": "जब कोई किसी शब्द या वाक्यांश का उल्लेख करता है तो उसे सूचित करने के लिए उसे यहां जोड़ें। आप शब्दों या वाक्यांशों को अल्पविराम से अलग कर सकते हैं। हाइलाइट शब्द केस संवेदी नहीं होते.", + "Highlights_List": "शब्दों को हाइलाइट करें", + "History": "इतिहास", + "Hold_Time": "समय पकड़", + "Hold": "पकड़ना", + "Hold_Premium_only": "होल्ड करें (केवल प्रीमियम योजनाएं)", "Home": "होम", + "Homepage": "मुखपृष्ठ", + "Homepage_Custom_Content_Default_Message": "व्यवस्थापक इस सफ़ेद स्थान में प्रस्तुत करने के लिए सामग्री html सम्मिलित कर सकते हैं।", + "Host": "मेज़बान", + "Hospitality_Businness": "खातिरदारी का व्यवसाय", + "hours": "घंटे", + "Hours": "घंटे", + "How_and_why_we_collect_usage_data": "उपयोग डेटा कैसे और क्यों एकत्र किया जाता है", "How_friendly_was_the_chat_agent": "चैट एजेंट कितना दोस्ताना था?", "How_knowledgeable_was_the_chat_agent": "चैट एजेंट कितना जानकार था?", + "How_long_to_wait_after_agent_goes_offline": "एजेंट के ऑफ़लाइन हो जाने के बाद कितनी देर तक प्रतीक्षा करनी होगी", + "How_long_to_wait_to_consider_visitor_abandonment": "आगंतुक परित्याग पर विचार करने के लिए कब तक प्रतीक्षा करनी होगी?", + "How_long_to_wait_to_consider_visitor_abandonment_in_seconds": "आगंतुक परित्याग पर विचार करने के लिए कब तक प्रतीक्षा करनी होगी?", "How_responsive_was_the_chat_agent": "चैट एजेंट कितना उत्तरदायी था?", "How_satisfied_were_you_with_this_chat": "आप इस चैट से कितने संतुष्ट थे?", + "How_to_handle_open_sessions_when_agent_goes_offline": "जब एजेंट ऑफ़लाइन हो जाए तो खुले सत्र को कैसे संभालें", + "Http_timeout": "HTTP टाइमआउट (मिलीसेकंड में)", + "Http_timeout_value": "5000", + "HTML": "एचटीएमएल", + "Icon": "आइकन", + "I_Saved_My_Password": "मैंने अपना पासवर्ड सहेज लिया", + "Idle_Time_Limit": "निष्क्रिय समय सीमा", + "Idle_Time_Limit_Description": "स्थिति बदलने तक की समयावधि। मान सेकंड में होना चाहिए.", + "if_they_are_from": "(यदि वे %s से हैं)", + "If_this_email_is_registered": "यदि यह ईमेल पंजीकृत है, तो हम आपका पासवर्ड रीसेट करने के तरीके पर निर्देश भेजेंगे। यदि आपको शीघ्र ही कोई ईमेल प्राप्त नहीं होता है, तो कृपया वापस आएं और पुनः प्रयास करें।", + "If_you_didnt_ask_for_reset_ignore_this_email": "यदि आपने अपना पासवर्ड रीसेट करने के लिए नहीं कहा है, तो आप इस ईमेल को अनदेखा कर सकते हैं।", + "If_you_didnt_try_to_login_in_your_account_please_ignore_this_email": "यदि आपने अपने खाते में लॉगिन करने का प्रयास नहीं किया है तो कृपया इस ईमेल को अनदेखा करें।", + "Iframe_Integration": "आईफ्रेम एकीकरण", + "Iframe_Integration_receive_enable": "प्राप्त करना सक्षम करें", + "Iframe_Integration_receive_enable_Description": "मूल विंडो को Rocket.Chat पर आदेश भेजने की अनुमति दें।", + "Iframe_Integration_receive_origin": "मूल प्राप्त करें", + "Iframe_Integration_receive_origin_Description": "प्रोटोकॉल उपसर्ग के साथ मूल, अल्पविराम द्वारा अलग किए गए, जिन्हें आदेश प्राप्त करने की अनुमति है जैसे। कहीं से भी प्राप्त करने की अनुमति देने के लिए `https://localhost, http://localhost`, या *।", + "Iframe_Integration_send_enable": "भेजें सक्षम करें", + "Iframe_Integration_send_enable_Description": "ईवेंट को मूल विंडो पर भेजें", + "Iframe_Integration_send_target_origin": "लक्ष्य उत्पत्ति भेजें", + "Iframe_Integration_send_target_origin_Description": "प्रोटोकॉल उपसर्ग के साथ उत्पत्ति, उदाहरण के लिए कौन से आदेश भेजे जाते हैं। `https://localhost`, या * कहीं भी भेजने की अनुमति देने के लिए।", + "Iframe_Restrict_Access": "किसी भी Iframe के अंदर पहुंच प्रतिबंधित करें", + "Iframe_Restrict_Access_Description": "यह सेटिंग किसी भी आईफ्रेम के अंदर आरसी को लोड करने के लिए प्रतिबंधों को सक्षम/अक्षम करती है", + "Iframe_X_Frame_Options": "एक्स-फ़्रेम-विकल्प के विकल्प", + "Iframe_X_Frame_Options_Description": "एक्स-फ़्रेम-विकल्प के विकल्प। [आप यहां सभी विकल्प देख सकते हैं।](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options#Syntax)", + "Ignore": "अनदेखा करना", + "Ignored": "अवहेलना करना", + "Ignore_Two_Factor_Authentication": "टू फैक्टर ऑथेंटिकेशन को नजरअंदाज करें", + "Images": "इमेजिस", + "IMAP_intercepter_already_running": "IMAP इंटरसेप्टर पहले से ही चल रहा है", + "IMAP_intercepter_Not_running": "IMAP इंटरसेप्टर नहीं चल रहा है", + "Impersonate_next_agent_from_queue": "कतार से अगले एजेंट का प्रतिरूपण करें", + "Impersonate_user": "उपयोगकर्ता का प्रतिरूपण करें", + "Impersonate_user_description": "सक्षम होने पर, एकीकरण उस उपयोगकर्ता के रूप में पोस्ट होता है जिसने एकीकरण को ट्रिगर किया है", + "Import": "आयात", + "Import_New_File": "नई फ़ाइल आयात करें", + "Import_requested_successfully": "आयात का सफलतापूर्वक अनुरोध किया गया", + "Import_Type": "आयात प्रकार", + "Importer_Archived": "संग्रहीत", + "Importer_CSV_Information": "CSV आयातक को एक विशिष्ट प्रारूप की आवश्यकता होती है, कृपया अपनी ज़िप फ़ाइल की संरचना कैसे करें, इसके लिए दस्तावेज़ पढ़ें:", + "Importer_done": "आयात पूरा हो गया!", + "Importer_ExternalUrl_Description": "आप सार्वजनिक रूप से पहुंच योग्य फ़ाइल के लिए URL का भी उपयोग कर सकते हैं:", + "Importer_finishing": "आयात समाप्त करना.", + "Importer_From_Description": "Rocket.Chat में {{from}} डेटा आयात करता है।", + "Importer_From_Description_CSV": "Rocket.Chat में CSV डेटा आयात करता है। अपलोड की गई फ़ाइल एक ज़िप फ़ाइल होनी चाहिए.", + "Importer_HipChatEnterprise_BetaWarning": "कृपया ध्यान रखें कि इस आयात पर अभी भी काम चल रहा है, कृपया GitHub में होने वाली किसी भी त्रुटि की रिपोर्ट करें:", + "Importer_HipChatEnterprise_Information": "अपलोड की गई फ़ाइल डिक्रिप्टेड tar.gz होनी चाहिए, कृपया अधिक जानकारी के लिए दस्तावेज़ पढ़ें:", + "Importer_import_cancelled": "आयात रद्द कर दिया गया.", + "Importer_import_failed": "आयात चलाते समय एक त्रुटि उत्पन्न हुई.", + "Importer_importing_channels": "चैनल आयात करना.", + "Importer_importing_files": "फ़ाइलें आयात करना.", + "Importer_importing_messages": "संदेश आयात करना.", + "Importer_importing_started": "आयात प्रारंभ करना.", + "Importer_importing_users": "उपयोगकर्ताओं को आयात करना.", + "Importer_not_in_progress": "आयातक वर्तमान में नहीं चल रहा है.", + "Importer_not_setup": "आयातक सही ढंग से सेटअप नहीं है, क्योंकि उसने कोई डेटा नहीं लौटाया।", + "Importer_Prepare_Restart_Import": "आयात पुनः प्रारंभ करें", + "Importer_Prepare_Start_Import": "आयात करना प्रारंभ करें", + "Importer_Prepare_Uncheck_Archived_Channels": "संग्रहीत चैनल अनचेक करें", + "Importer_Prepare_Uncheck_Deleted_Users": "हटाए गए उपयोगकर्ताओं को अनचेक करें", + "Importer_progress_error": "आयात के लिए प्रगति प्राप्त करने में विफल.", + "Importer_setup_error": "आयातक को सेट करते समय एक त्रुटि उत्पन्न हुई.", + "Importer_Slack_Users_CSV_Information": "अपलोड की गई फ़ाइल स्लैक की उपयोगकर्ता निर्यात फ़ाइल होनी चाहिए, जो एक CSV फ़ाइल है। अधिक जानकारी के लिए यहां देखें:", + "Importer_Source_File": "स्रोत फ़ाइल चयन", + "importer_status_done": "सफलतापूर्वक पूरा", + "importer_status_downloading_file": "फ़ाइल डाउनलोड हो रही है", + "importer_status_file_loaded": "फ़ाइल लोड की गई", + "importer_status_finishing": "लगभग हो गया", + "importer_status_import_cancelled": "रद्द", + "importer_status_import_failed": "गलती", + "importer_status_importing_channels": "चैनल आयात करना", + "importer_status_importing_files": "फ़ाइलें आयात करना", + "importer_status_importing_messages": "संदेश आयात करना", + "importer_status_importing_started": "डेटा आयात करना", + "importer_status_importing_users": "उपयोगकर्ताओं को आयात करना", + "importer_status_new": "शुरू नहीं", + "importer_status_preparing_channels": "चैनल फ़ाइल पढ़ना", + "importer_status_preparing_messages": "संदेश फ़ाइलें पढ़ना", + "importer_status_preparing_started": "फ़ाइलें पढ़ना", + "importer_status_preparing_users": "उपयोगकर्ता फ़ाइल पढ़ना", + "importer_status_uploading": "फ़ाइल अपलोड हो रही है", + "importer_status_user_selection": "क्या आयात करना है यह चुनने के लिए तैयार हैं", + "Importer_Upload_FileSize_Message": "आपकी सर्वर सेटिंग्स {{maxFileSize}} तक किसी भी आकार की फ़ाइलें अपलोड करने की अनुमति देती हैं।", + "Importer_Upload_Unlimited_FileSize": "आपकी सर्वर सेटिंग्स किसी भी आकार की फ़ाइलें अपलोड करने की अनुमति देती हैं।", + "Importing_channels": "चैनल आयात करना", + "Importing_Data": "डेटा आयात करना", + "Importing_messages": "संदेश आयात करना", + "Importing_users": "उपयोगकर्ताओं को आयात करना", + "Inactivity_Time": "निष्क्रियता का समय", + "In_progress": "प्रगति पर है", + "inbound-voip-calls": "इनबाउंड वीओआईपी कॉल", + "inbound-voip-calls_description": "इनबाउंड वीओआईपी कॉल की अनुमति", + "Inbox_Info": "इनबॉक्स जानकारी", + "Include_Offline_Agents": "ऑफ़लाइन एजेंटों को शामिल करें", + "Inclusive": "सहित", + "Incoming": "आने वाली", + "Incoming_call_from": "से आने वाली कॉल", + "Incoming_Livechats": "पंक्तिबद्ध चैट", + "Incoming_WebHook": "आने वाली वेबहुक", + "Industry": "उद्योग", + "Info": "जानकारी", + "initials_avatar": "प्रारंभिक अवतार", + "Inline_code": "इनलाइन कोड", + "Install": "स्थापित करना", + "Install_anyway": "फिर भी इंस्टॉल करें", + "Install_Extension": "एक्सटेंशन इंस्टॉल करें", + "Install_FxOs": "अपने फ़ायरफ़ॉक्स पर Rocket.Chat इंस्टॉल करें", + "Install_FxOs_done": "महान! अब आप अपने होमस्क्रीन पर आइकन के माध्यम से Rocket.Chat का उपयोग कर सकते हैं। रॉकेट.चैट के साथ आनंद लें!", + "Install_FxOs_error": "क्षमा करें, यह इच्छानुसार काम नहीं किया! निम्न त्रुटि दिखाई दी:", + "Install_FxOs_follow_instructions": "कृपया अपने डिवाइस पर ऐप इंस्टॉलेशन की पुष्टि करें (संकेत मिलने पर \"इंस्टॉल करें\" दबाएं)।", + "Installing": "स्थापित कर रहा है", + "Install_package": "पैकेज स्थापित करे", "Installation": "स्थापना", + "Installed": "स्थापित", + "Installed_at": "पर स्थापित किया गया", + "Instance": "उदाहरण", + "Instances": "उदाहरण", + "Instances_health": "उदाहरण स्वास्थ्य", + "Instance_Record": "उदाहरण रिकार्ड", + "Instructions": "निर्देश", + "Instructions_to_your_visitor_fill_the_form_to_send_a_message": "अपने विज़िटर को संदेश भेजने के लिए फ़ॉर्म भरने के निर्देश", + "Insert_Contact_Name": "संपर्क नाम डालें", + "Insert_Placeholder": "प्लेसहोल्डर डालें", + "Install_rocket_chat_on_your_preferred_desktop_platform": "अपने पसंदीदा डेस्कटॉप प्लेटफ़ॉर्म पर Rocket.Chat इंस्टॉल करें।", + "Insurance": "बीमा", + "Integration_added": "एकीकरण जोड़ा गया है", + "Integration_Advanced_Settings": "एडवांस सेटिंग", + "Integration_Delete_Warning": "किसी एकीकरण को हटाना पूर्ववत नहीं किया जा सकता.", + "Integration_disabled": "एकीकरण अक्षम किया गया", + "Integration_History_Cleared": "एकीकरण इतिहास सफलतापूर्वक साफ़ किया गया", + "Integration_Incoming_WebHook": "आने वाली वेबहुक एकीकरण", + "Integration_New": "नया एकीकरण", + "integration-scripts-disabled": "एकीकरण स्क्रिप्ट अक्षम हैं", + "integration-scripts-isolated-vm-disabled": "\"सिक्योर सैंडबॉक्स\" का उपयोग नई या संशोधित स्क्रिप्ट पर नहीं किया जा सकता है।", + "integration-scripts-vm2-disabled": "\"संगत सैंडबॉक्स\" का उपयोग नई या संशोधित स्क्रिप्ट पर नहीं किया जा सकता है।", + "Integration_Outgoing_WebHook": "आउटगोइंग वेबहुक एकीकरण", + "Integration_Outgoing_WebHook_History": "आउटगोइंग वेबहुक एकीकरण इतिहास", + "Integration_Outgoing_WebHook_History_Data_Passed_To_Trigger": "डेटा एकीकरण के लिए पारित किया गया", + "Integration_Outgoing_WebHook_History_Data_Passed_To_URL": "डेटा यूआरएल को भेजा गया", + "Integration_Outgoing_WebHook_History_Error_Stacktrace": "त्रुटि स्टैकट्रेस", + "Integration_Outgoing_WebHook_History_Http_Response": "HTTP प्रतिक्रिया", + "Integration_Outgoing_WebHook_History_Http_Response_Error": "HTTP प्रतिक्रिया त्रुटि", + "Integration_Outgoing_WebHook_History_Messages_Sent_From_Prepare_Script": "तैयारी चरण से भेजे गए संदेश", + "Integration_Outgoing_WebHook_History_Messages_Sent_From_Process_Script": "प्रक्रिया प्रतिक्रिया चरण से भेजे गए संदेश", + "Integration_Outgoing_WebHook_History_Time_Ended_Or_Error": "इसके समाप्त होने या त्रुटि होने का समय", + "Integration_Outgoing_WebHook_History_Time_Triggered": "समय एकीकरण ट्रिगर हुआ", + "Integration_Outgoing_WebHook_History_Trigger_Step": "अंतिम ट्रिगर चरण", + "Integration_Outgoing_WebHook_No_History": "इस निवर्तमान वेबहुक एकीकरण का अभी तक कोई इतिहास दर्ज नहीं किया गया है।", + "Integration_Retry_Count": "count पुनः प्रयास करें", + "Integration_Retry_Count_Description": "यदि यूआरएल पर कॉल विफल हो जाती है तो कितनी बार एकीकरण का प्रयास किया जाना चाहिए?", + "Integration_Retry_Delay": "विलंब पुनः प्रयास करें", + "Integration_Retry_Delay_Description": "पुनः प्रयास करने वालों को किस विलंब एल्गोरिदम का उपयोग करना चाहिए? 10 ^ x या 2 ^ x या x * 2", + "Integration_Retry_Failed_Url_Calls": "विफल यूआरएल कॉल पुनः प्रयास करें", + "Integration_Retry_Failed_Url_Calls_Description": "यदि यूआरएल पर कॉल आउट विफल रहता है तो क्या एकीकरण को उचित समय तक प्रयास करना चाहिए?", + "Integration_Run_When_Message_Is_Edited": "संपादनों पर चलाएँ", + "Integration_Run_When_Message_Is_Edited_Description": "क्या संदेश संपादित होने पर एकीकरण चलना चाहिए? इसे गलत पर सेट करने से एकीकरण केवल **नए** संदेशों पर चलेगा।", + "Integration_updated": "एकीकरण अद्यतन किया गया है.", + "Integration_Word_Trigger_Placement": "कहीं भी शब्द प्लेसमेंट", + "Integration_Word_Trigger_Placement_Description": "क्या शुरुआत के अलावा वाक्य में कहीं भी रखे जाने पर शब्द को ट्रिगर किया जाना चाहिए?", + "Integrations": "एकीकरण", + "Integrations_for_all_channels": "सभी सार्वजनिक चैनलों पर सुनने के लिए all_public_channels , सभी निजी समूहों पर सुनने के लिए all_private_groups , और सभी प्रत्यक्ष संदेशों को सुनने के लिए all_direct_messages दर्ज करें।", + "Integrations_Outgoing_Type_FileUploaded": "फ़ाइल अपलोड की गई", + "Integrations_Outgoing_Type_RoomArchived": "कक्ष संग्रहीत", + "Integrations_Outgoing_Type_RoomCreated": "कक्ष बनाया गया (सार्वजनिक और निजी)", + "Integrations_Outgoing_Type_RoomJoined": "उपयोगकर्ता से जुड़ा कक्ष", + "Integrations_Outgoing_Type_RoomLeft": "उपयोगकर्ता बायां कमरा", + "Integrations_Outgoing_Type_SendMessage": "संदेश भेजा गया", + "Integrations_Outgoing_Type_UserCreated": "उपयोगकर्ता बनाया गया", + "InternalHubot": "आंतरिक धारीदार", + "InternalHubot_EnableForChannels": "सार्वजनिक चैनलों के लिए सक्षम करें", + "InternalHubot_EnableForDirectMessages": "सीधे संदेशों के लिए सक्षम करें", + "InternalHubot_EnableForPrivateGroups": "निजी चैनलों के लिए सक्षम करें", + "InternalHubot_PathToLoadCustomScripts": "स्क्रिप्ट लोड करने के लिए फ़ोल्डर", + "InternalHubot_reload": "स्क्रिप्ट पुनः लोड करें", + "InternalHubot_ScriptsToLoad": "लोड करने के लिए स्क्रिप्ट", + "InternalHubot_ScriptsToLoad_Description": "कृपया अपने कस्टम फ़ोल्डर से लोड करने के लिए स्क्रिप्ट की अल्पविराम से अलग की गई सूची दर्ज करें", + "InternalHubot_Username_Description": "यह आपके सर्वर पर पंजीकृत बॉट का वैध उपयोगकर्ता नाम होना चाहिए।", + "Invalid Canned Response": "अमान्य डिब्बाबंद प्रतिक्रिया", + "Invalid_confirm_pass": "पासवर्ड पुष्टिकरण पासवर्ड से मेल नहीं खाता", + "Invalid_Department": "अमान्य विभाग", + "Invalid_email": "दर्ज किया गया ईमेल अमान्य है", + "Invalid_Export_File": "अपलोड की गई फ़ाइल वैध %s निर्यात फ़ाइल नहीं है.", + "Invalid_field": "फ़ील्ड ख़ाली नहीं होनी चाहिए", + "Invalid_Import_File_Type": "अमान्य आयात फ़ाइल प्रकार.", + "Invalid_name": "नाम खाली नहीं होना चाहिए", + "Invalid_notification_setting_s": "अमान्य अधिसूचना सेटिंग: %s", + "Invalid_OAuth_client": "अमान्य OAuth क्लाइंट", + "Invalid_or_expired_invite_token": "अमान्य या समाप्त आमंत्रण टोकन", + "Invalid_pass": "पासवर्ड खाली नहीं होना चाहिए", + "Invalid_password": "अवैध पासवर्ड", + "Invalid_reason": "शामिल होने का कारण खाली नहीं होना चाहिए", + "Invalid_room_name": "%s मान्य कमरे का नाम नहीं है", + "Invalid_secret_URL_message": "प्रदान किया गया यूआरएल अमान्य है.", + "Invalid_setting_s": "अमान्य सेटिंग: %s", + "Invalid_two_factor_code": "अमान्य दो कारक कोड", + "Invalid_username": "दर्ज किया गया उपयोक्तानाम अमान्य है", + "invisible": "अदृश्य", + "Invisible": "अदृश्य", + "Invitation": "आमंत्रण", + "Invitation_Email_Description": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं:\n - प्राप्तकर्ता ईमेल के लिए `[ईमेल]`।\n - एप्लिकेशन नाम और यूआरएल के लिए क्रमशः `[Site_Name]` और `[Site_URL]`।", + "Invitation_HTML": "आमंत्रण HTML", + "Invitation_HTML_Default": "

    आपको [Site_Name] पर आमंत्रित किया गया है

    [Site_URL] पर जाएँ और आज उपलब्ध सर्वोत्तम ओपन सोर्स चैट समाधान आज़माएँ!

    ", + "Invitation_Subject": "आमंत्रण विषय", + "Invitation_Subject_Default": "आपको [Site_Name] पर आमंत्रित किया गया है", + "Invite": "आमंत्रित करना", + "Invites": "आमंत्रण", + "Invite_and_add_members_to_this_workspace_to_start_communicating": "संचार शुरू करने के लिए इस कार्यक्षेत्र में सदस्यों को आमंत्रित करें और जोड़ें।", + "Invite_Link": "लिंक आमंत्रित करें", + "link": "जोड़ना", + "Invite_link_generated": "आमंत्रण लिंक जनरेट कर दिया गया है", + "Invite_removed": "आमंत्रण सफलतापूर्वक हटा दिया गया", + "Invite_user_to_join_channel": "इस चैनल से जुड़ने के लिए एक उपयोगकर्ता को आमंत्रित करें", + "Invite_user_to_join_channel_all_from": "इस चैनल से जुड़ने के लिए [#चैनल] के सभी उपयोगकर्ताओं को आमंत्रित करें", + "Invite_user_to_join_channel_all_to": "इस चैनल के सभी उपयोगकर्ताओं को [#चैनल] से जुड़ने के लिए आमंत्रित करें", + "Invite_Users": "सदस्यों को आमंत्रित करो", + "IP": "आई पी", + "IP_Address": "आईपी पता", + "IRC_Channel_Join": "JOIN कमांड का आउटपुट।", + "IRC_Channel_Leave": "पार्ट कमांड का आउटपुट।", + "IRC_Channel_Users": "NAMES कमांड का आउटपुट।", + "IRC_Channel_Users_End": "NAMES कमांड के आउटपुट का अंत।", + "IRC_Description": "इंटरनेट रिले चैट (आईआरसी) एक टेक्स्ट-आधारित समूह संचार उपकरण है। उपयोगकर्ता खुली चर्चा के लिए विशिष्ट रूप से नामित चैनलों या कमरों से जुड़ते हैं। आईआरसी व्यक्तिगत उपयोगकर्ताओं और फ़ाइल साझाकरण क्षमताओं के बीच निजी संदेशों का भी समर्थन करता है। यह पैकेज कार्यक्षमता की इन परतों को Rocket.Chat के साथ एकीकृत करता है।", + "IRC_Enabled": "आईआरसी समर्थन को एकीकृत करने का प्रयास। इस मान को बदलने के लिए Rocket.Chat को पुनः आरंभ करने की आवश्यकता है।", + "IRC_Enabled_Alert": "आईआरसी समर्थन का कार्य प्रगति पर है। इस समय उत्पादन प्रणाली पर उपयोग की अनुशंसा नहीं की जाती है।", + "IRC_Federation": "आईआरसी फेडरेशन", + "IRC_Federation_Description": "अन्य आईआरसी सर्वर से कनेक्ट करें।", + "IRC_Federation_Disabled": "आईआरसी फेडरेशन अक्षम है.", + "IRC_Hostname": "कनेक्ट करने के लिए आईआरसी होस्ट सर्वर।", + "IRC_Login_Fail": "आईआरसी सर्वर से कनेक्शन विफल होने पर आउटपुट।", + "IRC_Login_Success": "आईआरसी सर्वर से सफल कनेक्शन पर आउटपुट।", + "IRC_Message_Cache_Size": "आउटबाउंड संदेश प्रबंधन के लिए कैश सीमा।", + "IRC_Port": "आईआरसी होस्ट सर्वर पर बाइंड करने के लिए पोर्ट।", + "IRC_Private_Message": "PRIVMSG कमांड का आउटपुट।", + "IRC_Quit": "आईआरसी सत्र छोड़ने पर आउटपुट।", + "is_typing": "टाइप कर रहा है", + "Issue_Links": "ट्रैकर लिंक जारी करें", + "IssueLinks_Incompatible": "चेतावनी: इसे और 'हेक्स कलर प्रीव्यू' को एक ही समय में सक्षम न करें।", + "IssueLinks_LinkTemplate": "समस्या लिंक के लिए टेम्पलेट", + "IssueLinks_LinkTemplate_Description": "समस्या लिंक के लिए टेम्पलेट; %s को इश्यू नंबर से बदल दिया जाएगा.", + "It_Will_Hide_All_Other_Content_Blocks_In_The_Homepage": "यह मुखपृष्ठ में अन्य सभी सामग्री ब्लॉक छिपा देगा", + "It_Will_Show_All_Other_Content_Blocks_In_The_Homepage": "यह मुखपृष्ठ पर अन्य सभी सामग्री ब्लॉक दिखाएगा", + "It_works": "यह काम करता है", + "It_Security": "आईटी सुरक्षा", + "Italic": "तिरछा", + "italics": "तिर्छा", + "Items_per_page:": "आइटम प्रति पेज:", + "Jitsi_included_with_Community": "जित्सी, समुदाय के साथ शामिल", + "Job_Title": "नौकरी का नाम", + "Join": "जोड़ना", + "Join_with_password": "पासवर्ड के साथ जुड़ें", + "Join_audio_call": "ऑडियो कॉल में शामिल हों", + "Join_call": "कॉल में शामिल हों", + "Join_Chat": "चैट में शामिल हों", + "Join_conference": "सम्मेलन में शामिल हों", + "Join_default_channels": "डिफ़ॉल्ट चैनल से जुड़ें", + "Join_the_Community": "समुदाय में शामिल हों", + "Join_the_given_channel": "दिए गए चैनल से जुड़ें", + "Join_rooms": "कमरों से जुड़ें", + "Join_video_call": "वीडियो कॉल में शामिल हों", + "Join_my_room_to_start_the_video_call": "वीडियो कॉल शुरू करने के लिए मेरे कमरे से जुड़ें", + "join-without-join-code": "बिना जॉइन कोड के शामिल हों", + "join-without-join-code_description": "जॉइन कोड सक्षम वाले चैनलों में जॉइन कोड को बायपास करने की अनुमति", + "Joined": "में शामिल हो गए", + "joined": "में शामिल हो गए", + "Joined_at": "पर शामिल हुए", + "JSON": "JSON", + "Jump": "कूदना", + "Jump_to_first_unread": "पहले अपठित पर जाएँ", + "Jump_to_message": "संदेश पर जाएं", + "Jump_to_recent_messages": "हाल के संदेशों पर जाएँ", + "Just_invited_people_can_access_this_channel": "केवल आमंत्रित लोग ही इस चैनल तक पहुँच सकते हैं।", + "kick-user-from-any-c-room": "किसी भी सार्वजनिक चैनल से उपयोगकर्ता को लात मारो", + "kick-user-from-any-c-room_description": "किसी उपयोगकर्ता को किसी भी सार्वजनिक चैनल से बाहर निकालने की अनुमति", + "kick-user-from-any-p-room": "किसी भी निजी चैनल से उपयोगकर्ता को लात मारो", + "kick-user-from-any-p-room_description": "किसी उपयोगकर्ता को किसी निजी चैनल से बाहर निकालने की अनुमति", + "Katex_Dollar_Syntax": "डॉलर सिंटैक्स की अनुमति दें", + "Katex_Dollar_Syntax_Description": "$$katex ब्लॉक$$ और $inline katex$ सिंटैक्स का उपयोग करने की अनुमति दें", + "Katex_Enabled": "केटेक्स सक्षम", + "Katex_Enabled_Description": "संदेशों में गणित टाइपसेटिंग के लिए [katex](http://खान.github.io/KaTeX/) का उपयोग करने की अनुमति दें", + "Katex_Parenthesis_Syntax": "कोष्ठक सिंटैक्स की अनुमति दें", + "Katex_Parenthesis_Syntax_Description": "\\[katex ब्लॉक\\] और \\(इनलाइन katex\\) सिंटैक्स का उपयोग करने की अनुमति दें", + "Keep_default_user_settings": "डिफ़ॉल्ट सेटिंग्स रखें", + "Keyboard_Shortcuts_Edit_Previous_Message": "पिछला संदेश संपादित करें", + "Keyboard_Shortcuts_Keys_1": "कमांड (या Ctrl) + p या कमांड (या Ctrl) + k", + "Keyboard_Shortcuts_Keys_2": "ऊपर की ओर तीर", + "Keyboard_Shortcuts_Keys_3": "कमांड (या Alt) + बायाँ तीर", + "Keyboard_Shortcuts_Keys_4": "कमांड (या Alt) + ऊपर तीर", + "Keyboard_Shortcuts_Keys_5": "कमांड (या Alt) + दायां तीर", + "Keyboard_Shortcuts_Keys_6": "कमांड (या Alt) + डाउन एरो", + "Keyboard_Shortcuts_Keys_7": "शिफ्ट + एंटर", + "Keyboard_Shortcuts_Keys_8": "शिफ्ट (या Ctrl) + ESC", + "Keyboard_Shortcuts_Mark_all_as_read": "सभी संदेशों को (सभी चैनलों में) पठित के रूप में चिह्नित करें", + "Keyboard_Shortcuts_Move_To_Beginning_Of_Message": "संदेश की शुरुआत में जाएँ", + "Keyboard_Shortcuts_Move_To_End_Of_Message": "संदेश के अंत में जाएँ", + "Keyboard_Shortcuts_New_Line_In_Message": "संदेश लिखें इनपुट में नई पंक्ति", + "Keyboard_Shortcuts_Open_Channel_Slash_User_Search": "चैनल/उपयोगकर्ता खोज खोलें", + "Keyboard_Shortcuts_Title": "कुंजीपटल अल्प मार्ग", + "Knowledge_Base": "ज्ञानधार", + "Label": "लेबल", + "Language": "भाषा", + "Language_Bulgarian": "बल्गेरियाई", + "Language_Chinese": "चीनी", + "Language_Czech": "चेक", + "Language_Danish": "दानिश", + "Language_Dutch": "डच", + "Language_English": "अंग्रेज़ी", + "Language_Estonian": "एस्तोनियावासी", + "Language_Finnish": "फिनिश", + "Language_French": "फ़्रेंच", + "Language_German": "जर्मन", + "Language_Greek": "यूनानी", + "Language_Hungarian": "हंगेरी", + "Language_Italian": "इतालवी", + "Language_Japanese": "जापानी", + "Language_Latvian": "लात्वीयावासी", + "Language_Lithuanian": "लिथुआनियाई", + "Language_Not_set": "कोई विशेष नहीं", + "Language_Polish": "पोलिश", + "Language_Portuguese": "पुर्तगाली", + "Language_Romanian": "रोमानियाई", + "Language_Russian": "रूसी", + "Language_Slovak": "स्लोवाक", + "Language_Slovenian": "स्लोवेनियाई", + "Language_Spanish": "स्पैनिश", + "Language_Swedish": "स्वीडिश", + "Language_Version": "अंग्रेजी संस्करण", + "Last_7_days": "पिछले 7 दिन", + "Last_15_days": "पिछले 15 दिन", + "Last_30_days": "पिछले 30 दिनों में", + "Last_90_days": "पिछले 90 दिन", + "Last_6_months": "पिछले 6 महीने", + "Last_year": "पिछले साल", + "Last_active": "अंतिम सक्रिय", + "Last_Call": "आखिरी कॉल", + "Last_Chat": "आखिरी चैट", + "Last_Heartbeat_Time": "आखिरी दिल की धड़कन का समय", + "Last_login": "आखरी लॉगइन", + "Last_Message": "अंतिम संदेश", + "Last_Message_At": "अंतिम संदेश पर", + "Last_seen": "अंतिम बार देखा गया", + "Last_Status": "अंतिम स्थिति", + "Last_token_part": "अंतिम सांकेतिक भाग", + "Last_Updated": "आखरी अपडेट", + "Launched_successfully": "सफलतापूर्वक लॉन्च किया गया", + "Layout": "लेआउट", + "Layout_Login_Hide_Logo": "लोगो छिपाएँ", + "Layout_Login_Hide_Logo_Description": "लॉगिन पेज पर लोगो छिपाएँ.", + "Layout_Login_Hide_Title": "शीर्षक छिपाएँ", + "Layout_Login_Hide_Title_Description": "लॉगिन पेज पर शीर्षक छिपाएँ.", + "Layout_Login_Hide_Powered_By": "\"इसके द्वारा संचालित\" छुपाएं", + "Layout_Login_Hide_Powered_By_Description": "लॉगिन पेज पर \"संचालित द्वारा\" छुपाएं।", + "Layout_Login_Template": "लॉगिन टेम्प्लेट", + "Layout_Login_Template_Description": "लॉगिन पेज का स्वरूप अनुकूलित करें.", + "Layout_Login_Template_Vertical": "खड़ा", + "Layout_Login_Template_Horizontal": "क्षैतिज", + "Layout_Description": "अपने कार्यक्षेत्र का स्वरूप अनुकूलित करें.", + "Layout_Home_Body": "सामग्री ब्लॉक", + "Layout_Home_Page_Content": "लेआउट/होम पेज सामग्री", + "Layout_Home_Page_Content_Title": "मुख पृष्ठ सामग्री", + "Layout_Home_Title": "गृह शीर्षक", + "Layout_Legal_Notice": "कानूनी नोटिस", + "Layout_Login_Terms": "लॉगिन शर्तें", + "Layout_Login_Terms_Content": "आगे बढ़कर आप हमारी सेवा की शर्तों , गोपनीयता नीति और कानूनी नोटिस से सहमत हैं।", + "Layout_Privacy_Policy": "गोपनीयता नीति", + "Layout_Show_Home_Button": "साइडबार हेडर पर होम पेज बटन दिखाएँ", + "Layout_Custom_Content_Description": "यहां आपकी कस्टम सामग्री है। यदि आप प्रीमियम योजना पर हैं, तो इसे एक सफेद ब्लॉक के अंदर रखा जा सकता है या होमपेज पर उपलब्ध सभी जगह ले सकता है।", + "Layout_Home_Custom_Block_Visible": "मुखपृष्ठ पर कस्टम सामग्री दिखाएं", + "Layout_Custom_Body_Only": "केवल कस्टम सामग्री दिखाएं", + "Layout_Custom_Body_Only_Description": "यह मुखपृष्ठ में अन्य सभी सामग्री ब्लॉक छिपा देगा।", + "Layout_Sidenav_Footer": "साइड नेविगेशन फ़ुटर", + "Layout_Sidenav_Footer_Dark": "साइड नेविगेशन फ़ुटर - डार्क थीम", + "Layout_Sidenav_Footer_description": "फ़ुटर का आकार 260 x 70px है", + "Layout_Sidenav_Footer_Dark_description": "फ़ुटर का आकार 260 x 70px है", + "Layout_Terms_of_Service": "सेवा की शर्तें", + "LDAP": "एलडीएपी", + "LDAP_Description": "लाइटवेट डायरेक्ट्री एक्सेस प्रोटोकॉल किसी को भी आपके सर्वर या कंपनी के बारे में डेटा का पता लगाने में सक्षम बनाता है।", + "LDAP_Documentation": "एलडीएपी दस्तावेज़ीकरण", + "LDAP_Connection": "संबंध", + "LDAP_Connection_Authentication": "प्रमाणीकरण", + "LDAP_Connection_Encryption": "कूटलेखन", + "LDAP_Connection_Timeouts": "समय समाप्ति", + "LDAP_UserSearch": "उपयोगकर्ता खोज", + "LDAP_UserSearch_Filter": "फ़िल्टर खोजें", + "LDAP_UserSearch_GroupFilter": "समूह फ़िल्टर", + "LDAP_DataSync": "डेटा सिंक", + "LDAP_DataSync_DataMap": "मानचित्रण", + "LDAP_DataSync_Avatar": "अवतार", + "LDAP_DataSync_Advanced": "उन्नत सिंक", + "LDAP_DataSync_CustomFields": "कस्टम फ़ील्ड सिंक करें", + "LDAP_DataSync_Roles": "भूमिकाएँ सिंक करें", + "LDAP_DataSync_Channels": "चैनल सिंक करें", + "LDAP_DataSync_Teams": "टीमों को सिंक करें", + "LDAP_DataSync_BackgroundSync": "पृष्ठभूमि समन्वयन", + "LDAP_Server_Type": "सर्वर प्रकार", + "LDAP_Server_Type_AD": "सक्रिय निर्देशिका", + "LDAP_Server_Type_Other": "अन्य", + "LDAP_Name_Field": "नाम फ़ील्ड", + "LDAP_Email_Field": "ईमेल फ़ील्ड", + "LDAP_Update_Data_On_Login": "लॉगिन पर उपयोगकर्ता डेटा अपडेट करें", + "LDAP_Update_Data_On_OAuth_Login": "OAuth सेवाओं के साथ लॉगिन पर उपयोगकर्ता डेटा अपडेट करें", + "LDAP_Advanced_Sync": "उन्नत सिंक", "LDAP_Authentication": "सक्षम करें", + "LDAP_Authentication_Password": "पासवर्ड", + "LDAP_Authentication_UserDN": "उपयोगकर्ता डी.एन", + "LDAP_Authentication_UserDN_Description": "एलडीएपी उपयोगकर्ता जो अन्य उपयोगकर्ताओं के साइन इन करने पर उन्हें प्रमाणित करने के लिए उपयोगकर्ता लुकअप करता है।\n यह आमतौर पर तृतीय-पक्ष एकीकरण के लिए विशेष रूप से बनाया गया एक सेवा खाता है। पूर्णतः योग्य नाम का उपयोग करें, जैसे `cn=Administrator,cn=Users,dc=Example,dc=com`.", + "LDAP_Avatar_Field": "उपयोगकर्ता अवतार फ़ील्ड", + "You_have_to_set_an_API_token_first_in_order_to_use_the_integration": "एकीकरण का उपयोग करने के लिए आपको पहले एक एपीआई टोकन सेट करना होगा।", + "LDAP_Avatar_Field_Description": " उपयोगकर्ताओं के लिए किस फ़ील्ड को *अवतार* के रूप में उपयोग किया जाएगा। पहले `थंबनेलफोटो` और `जेपीईजीफोटो` को फ़ॉलबैक के रूप में उपयोग करने के लिए खाली छोड़ दें।", + "LDAP_Background_Sync": "पृष्ठभूमि समन्वयन", + "LDAP_Background_Sync_Avatars": "अवतार पृष्ठभूमि सिंक", + "LDAP_Background_Sync_Avatars_Description": "उपयोगकर्ता अवतारों को सिंक करने के लिए एक अलग पृष्ठभूमि प्रक्रिया सक्षम करें।", + "LDAP_Background_Sync_Avatars_Interval": "अवतार पृष्ठभूमि सिंक अंतराल", + "LDAP_Background_Sync_Import_New_Users": "पृष्ठभूमि सिंक नए उपयोगकर्ताओं को आयात करें", + "LDAP_Background_Sync_Import_New_Users_Description": "उन सभी उपयोगकर्ताओं को आयात करेगा (आपके फ़िल्टर मानदंड के आधार पर) जो एलडीएपी में मौजूद हैं और रॉकेट.चैट में मौजूद नहीं हैं", + "LDAP_Background_Sync_Interval": "पृष्ठभूमि सिंक अंतराल", + "LDAP_Background_Sync_Interval_Description": "तुल्यकालन के बीच का अंतराल. उदाहरण `हर 24 घंटे` या `सप्ताह के पहले दिन`, अधिक उदाहरण [क्रोन टेक्स्ट पार्सर](http://bunkat.github.io/later/parsers.html#text) पर", + "LDAP_Background_Sync_Keep_Existant_Users_Updated": "मौजूदा उपयोगकर्ताओं का बैकग्राउंड सिंक अपडेट करें", + "LDAP_Background_Sync_Keep_Existant_Users_Updated_Description": "प्रत्येक **सिंक अंतराल** पर पहले से ही एलडीएपी से आयातित सभी उपयोगकर्ताओं के अवतार, फ़ील्ड, उपयोगकर्ता नाम इत्यादि (आपके कॉन्फ़िगरेशन के आधार पर) को सिंक करेगा।", + "LDAP_Background_Sync_Merge_Existent_Users": "बैकग्राउंड सिंक मौजूदा उपयोगकर्ताओं को मर्ज करता है", + "LDAP_Background_Sync_Merge_Existent_Users_Description": "सभी उपयोगकर्ताओं (आपके फ़िल्टर मानदंड के आधार पर) को मर्ज कर देगा जो एलडीएपी में मौजूद हैं और रॉकेट.चैट में भी मौजूद हैं। इसे सक्षम करने के लिए, डेटा सिंक टैब में 'मौजूदा उपयोगकर्ताओं को मर्ज करें' सेटिंग सक्रिय करें।", + "LDAP_BaseDN": "बेस डी.एन", + "LDAP_BaseDN_Description": "एलडीएपी सबट्री का पूर्णतः योग्य विशिष्ट नाम (डीएन) जिसे आप उपयोगकर्ताओं और समूहों के लिए खोजना चाहते हैं। आप जितने चाहें उतने जोड़ सकते हैं; हालाँकि, प्रत्येक समूह को उसी डोमेन आधार में परिभाषित किया जाना चाहिए जिसमें उसके उपयोगकर्ता शामिल हैं। उदाहरण: `ou=उपयोगकर्ता+ou=प्रोजेक्ट्स,dc=उदाहरण,dc=com`। यदि आप प्रतिबंधित उपयोगकर्ता समूह निर्दिष्ट करते हैं, तो केवल उन समूहों से संबंधित उपयोगकर्ता ही दायरे में होंगे। हम अनुशंसा करते हैं कि आप अपने एलडीएपी निर्देशिका ट्री के शीर्ष स्तर को अपने डोमेन आधार के रूप में निर्दिष्ट करें और पहुंच को नियंत्रित करने के लिए खोज फ़िल्टर का उपयोग करें।", + "LDAP_CA_Cert": "सीए सर्टिफिकेट", + "LDAP_Connect_Timeout": "कनेक्शन टाइमआउट (एमएस)", + "LDAP_DataSync_AutoLogout": "ऑटो लॉगआउट निष्क्रिय उपयोगकर्ता", + "LDAP_Default_Domain": "डिफ़ॉल्ट डोमेन", + "LDAP_Default_Domain_Description": "यदि प्रदान किया गया है तो डिफ़ॉल्ट डोमेन का उपयोग उन उपयोगकर्ताओं के लिए एक अद्वितीय ईमेल बनाने के लिए किया जाएगा जहां ईमेल एलडीएपी से आयात नहीं किया गया था। ईमेल को `username@default_domain` या `unique_id@default_domain` के रूप में माउंट किया जाएगा।\n उदाहरण: `रॉकेट.चैट`", "LDAP_Enable": "सक्षम करें", + "LDAP_Enable_Description": "प्रमाणीकरण के लिए एलडीएपी का उपयोग करने का प्रयास करें।", + "LDAP_Enable_LDAP_Groups_To_RC_Teams": "LDAP से Rocket.Chat तक टीम मैपिंग सक्षम करें", + "LDAP_Encryption": "कूटलेखन", + "LDAP_Encryption_Description": "एलडीएपी सर्वर पर संचार सुरक्षित करने के लिए एन्क्रिप्शन विधि का उपयोग किया जाता है। उदाहरणों में `प्लेन` (कोई एन्क्रिप्शन नहीं), `एसएसएल/एलडीएपीएस` (शुरुआत से एन्क्रिप्टेड), और `स्टार्टटीएलएस` (कनेक्ट होने के बाद एन्क्रिप्टेड संचार में अपग्रेड) शामिल हैं।", + "LDAP_Find_User_After_Login": "लॉग इन करने के बाद उपयोगकर्ता ढूंढें", + "LDAP_Find_User_After_Login_Description": "बाइंड के बाद उपयोगकर्ता के डीएन की खोज करेगा ताकि यह सुनिश्चित किया जा सके कि एडी कॉन्फ़िगरेशन द्वारा अनुमति दिए जाने पर बाइंड खाली पासवर्ड के साथ लॉगिन को रोकने में सफल रहा।", + "LDAP_Group_Filter_Enable": "एलडीएपी उपयोगकर्ता समूह फ़िल्टर सक्षम करें", + "LDAP_Group_Filter_Enable_Description": "एलडीएपी समूह में उपयोगकर्ताओं तक पहुंच प्रतिबंधित करें\n समूहों द्वारा पहुंच को प्रतिबंधित करने के लिए *memberOf* फ़िल्टर के बिना OpenLDAP सर्वर को अनुमति देने के लिए उपयोगी", + "LDAP_Group_Filter_Group_Id_Attribute": "समूह आईडी विशेषता", + "LDAP_Group_Filter_Group_Id_Attribute_Description": "जैसे **ओपनएलडीएपी:** `सीएन`", + "LDAP_Group_Filter_Group_Member_Attribute": "समूह सदस्य विशेषता", + "LDAP_Group_Filter_Group_Member_Attribute_Description": "जैसे **ओपनएलडीएपी:** `यूनीकमेम्बर`", + "LDAP_Group_Filter_Group_Member_Format": "समूह सदस्य प्रारूप", + "LDAP_Group_Filter_Group_Member_Format_Description": "जैसे **OpenLDAP:** `uid=#{username},ou=users,o=Company,c=com`", + "LDAP_Group_Filter_Group_Name": "समूह नाम", + "LDAP_Group_Filter_Group_Name_Description": "समूह का नाम जिससे उपयोगकर्ता संबंधित है", + "LDAP_Group_Filter_ObjectClass": "समूह ऑब्जेक्टक्लास", + "LDAP_Group_Filter_ObjectClass_Description": "*ऑब्जेक्टक्लास* जो समूहों की पहचान करता है।\n जैसे **OpenLDAP:** `groupOfUniqueNames`", + "LDAP_Groups_To_Rocket_Chat_Teams": "एलडीएपी से रॉकेट.चैट तक टीम मैपिंग।", + "LDAP_Host": "मेज़बान", + "LDAP_Host_Description": "एलडीएपी होस्ट, उदा. `ldap.example.com` या `10.0.0.30`.", + "LDAP_Idle_Timeout": "निष्क्रिय समयबाह्य (एमएस)", + "LDAP_Idle_Timeout_Description": "नवीनतम एलडीएपी ऑपरेशन के बाद कनेक्शन बंद होने तक कितने मिलीसेकंड प्रतीक्षा करें। (प्रत्येक ऑपरेशन एक नया कनेक्शन खोलेगा)", + "LDAP_Import_Users_Description": "यह ट्रू सिंक प्रक्रिया सभी एलडीएपी उपयोगकर्ताओं को आयात करेगी\n *सावधान!* अतिरिक्त उपयोगकर्ताओं को आयात न करने के लिए खोज फ़िल्टर निर्दिष्ट करें।", + "LDAP_Internal_Log_Level": "आंतरिक लॉग स्तर", + "LDAP_Login_Fallback": "फ़ॉलबैक लॉगिन करें", + "LDAP_Login_Fallback_Description": "यदि एलडीएपी पर लॉगिन सफल नहीं होता है तो डिफ़ॉल्ट/स्थानीय खाता सिस्टम में लॉगिन करने का प्रयास करें। किसी कारण से एलडीएपी डाउन होने पर मदद करता है।", + "LDAP_Merge_Existing_Users": "मौजूदा उपयोगकर्ताओं को मर्ज करें", + "LDAP_Merge_Existing_Users_Description": "*सावधान!* एलडीएपी से एक उपयोगकर्ता आयात करते समय और समान उपयोगकर्ता नाम वाला एक उपयोगकर्ता पहले से मौजूद है तो एलडीएपी जानकारी और पासवर्ड मौजूदा उपयोगकर्ता में सेट किया जाएगा।", + "LDAP_Port": "पत्तन", + "LDAP_Port_Description": "एलडीएपी तक पहुंचने के लिए पोर्ट। उदाहरण के लिए: एलडीएपीएस के लिए `389` या `636`", + "LDAP_Prevent_Username_Changes": "एलडीएपी उपयोगकर्ताओं को अपना Rocket.Chat उपयोगकर्ता नाम बदलने से रोकें", + "LDAP_Query_To_Get_User_Teams": "उपयोगकर्ता समूह प्राप्त करने के लिए एलडीएपी क्वेरी", + "LDAP_Reconnect": "रिकनेक्ट", + "LDAP_Reconnect_Description": "संचालन निष्पादित करते समय किसी कारण से कनेक्शन बाधित होने पर स्वचालित रूप से पुन: कनेक्ट करने का प्रयास करें", + "LDAP_Reject_Unauthorized": "अनधिकृत अस्वीकार करें", + "LDAP_Reject_Unauthorized_Description": "जिन प्रमाणपत्रों को सत्यापित नहीं किया जा सकता, उन्हें अनुमति देने के लिए इस विकल्प को अक्षम करें। आमतौर पर स्व-हस्ताक्षरित प्रमाणपत्रों को काम करने के लिए इस विकल्प को अक्षम करना होगा", + "LDAP_Search_Page_Size": "पृष्ठ आकार खोजें", + "LDAP_Search_Page_Size_Description": "प्रत्येक परिणाम पृष्ठ पर संसाधित होने के लिए प्रविष्टियों की अधिकतम संख्या वापस आएगी", + "LDAP_Search_Size_Limit": "खोज आकार सीमा", + "LDAP_Search_Size_Limit_Description": "वापस आने वाली प्रविष्टियों की अधिकतम संख्या.\n **ध्यान दें** यह संख्या **खोज पृष्ठ आकार** से अधिक होनी चाहिए", + "LDAP_Sync_Custom_Fields": "कस्टम फ़ील्ड सिंक करें", + "LDAP_CustomFieldMap": "कस्टम फ़ील्ड मैपिंग", + "LDAP_Sync_AutoLogout_Enabled": "ऑटो लॉगआउट सक्षम करें", + "LDAP_Sync_AutoLogout_Interval": "ऑटो लॉगआउट अंतराल", + "LDAP_Sync_Now": "अभी सिंक करें", + "LDAP_Sync_Now_Description": "यह अगले शेड्यूल किए गए सिंक की प्रतीक्षा किए बिना, अब **बैकग्राउंड सिंक** ऑपरेशन शुरू कर देगा।\nयह क्रिया अतुल्यकालिक है, कृपया अधिक जानकारी के लिए लॉग देखें।", + "LDAP_Sync_User_Active_State": "उपयोगकर्ता सक्रिय स्थिति सिंक करें", + "LDAP_Sync_User_Active_State_Both": "उपयोगकर्ताओं को सक्षम और अक्षम करें", + "LDAP_Sync_User_Active_State_Description": "एलडीएपी स्थिति के आधार पर निर्धारित करें कि उपयोगकर्ताओं को Rocket.Chat पर सक्षम या अक्षम किया जाना चाहिए या नहीं। 'pwdAccountLockedTime' विशेषता का उपयोग यह निर्धारित करने के लिए किया जाएगा कि उपयोगकर्ता अक्षम है या नहीं।", + "LDAP_Sync_User_Active_State_Disable": "उपयोगकर्ताओं को अक्षम करें", + "LDAP_Sync_User_Active_State_Nothing": "कुछ भी नहीं है", + "LDAP_Sync_User_Avatar": "उपयोगकर्ता अवतार सिंक करें", + "LDAP_Sync_User_Data_Roles": "एलडीएपी समूह सिंक करें", + "LDAP_Sync_User_Data_Channels": "एलडीएपी समूहों को चैनलों के साथ ऑटो सिंक करें", + "LDAP_Sync_User_Data_Channels_Admin": "चैनल व्यवस्थापक", + "LDAP_Sync_User_Data_Channels_Admin_Description": "जब चैनल स्वतः निर्मित होते हैं जो सिंक के दौरान मौजूद नहीं होते हैं, तो यह उपयोगकर्ता स्वचालित रूप से चैनल का व्यवस्थापक बन जाएगा।", + "LDAP_Sync_User_Data_Channels_BaseDN": "एलडीएपी ग्रुप बेसडीएन", + "LDAP_Sync_User_Data_Channels_Description": "उपयोगकर्ताओं को उनके एलडीएपी समूह के आधार पर किसी चैनल में स्वचालित रूप से जोड़ने के लिए इस सुविधा को सक्षम करें। यदि आप भी किसी चैनल से उपयोगकर्ताओं को हटाना चाहते हैं, तो उपयोगकर्ताओं को स्वत: हटाने के बारे में नीचे दिया गया विकल्प देखें।", + "LDAP_Sync_User_Data_Channels_Enforce_AutoChannels": "चैनलों से उपयोगकर्ताओं को स्वतः हटाएँ", + "LDAP_Sync_User_Data_Channels_Enforce_AutoChannels_Description": "**ध्यान दें**: इसे सक्षम करने से चैनल के किसी भी उपयोगकर्ता को हटा दिया जाएगा जिसके पास संबंधित एलडीएपी समूह नहीं है! इसे केवल तभी सक्षम करें यदि आप जानते हैं कि आप क्या कर रहे हैं।", + "LDAP_Sync_User_Data_Channels_Filter": "उपयोगकर्ता समूह फ़िल्टर", + "LDAP_Sync_User_Data_Channels_Filter_Description": "एलडीएपी खोज फ़िल्टर का उपयोग यह जाँचने के लिए किया जाता है कि कोई उपयोगकर्ता किसी समूह में है या नहीं।", + "LDAP_Sync_User_Data_ChannelsMap": "एलडीएपी समूह चैनल मानचित्र", + "LDAP_Sync_User_Data_ChannelsMap_Default": "// उपरोक्त चैनलों के लिए एलडीएपी समूहों को ऑटो सिंक सक्षम करें", + "LDAP_Sync_User_Data_ChannelsMap_Description": "एलडीएपी समूहों को रॉकेट.चैट चैनलों पर मैप करें।\n उदाहरण के तौर पर, `{\"कर्मचारी\":\"सामान्य\"}` एलडीएपी समूह कर्मचारी में किसी भी उपयोगकर्ता को सामान्य चैनल में जोड़ देगा।", + "LDAP_Sync_User_Data_Roles_AutoRemove": "उपयोगकर्ता भूमिकाएँ स्वतः हटाएँ", + "LDAP_Sync_User_Data_Roles_AutoRemove_Description": "**ध्यान दें**: इसे सक्षम करने से उपयोगकर्ता स्वचालित रूप से किसी भूमिका से हटा दिए जाएंगे यदि उन्हें एलडीएपी में असाइन नहीं किया गया है! यह केवल उन भूमिकाओं को स्वचालित रूप से हटा देगा जो नीचे उपयोगकर्ता डेटा समूह मानचित्र के अंतर्गत सेट की गई हैं।", + "LDAP_Sync_User_Data_Roles_BaseDN": "एलडीएपी ग्रुप बेसडीएन", + "LDAP_Sync_User_Data_Roles_BaseDN_Description": "LDAP BaseDN का उपयोग उपयोगकर्ताओं को खोजने के लिए किया जाता है।", + "LDAP_Sync_User_Data_Roles_Filter": "उपयोगकर्ता समूह फ़िल्टर", + "LDAP_Sync_User_Data_Roles_Filter_Description": "एलडीएपी खोज फ़िल्टर का उपयोग यह जाँचने के लिए किया जाता है कि कोई उपयोगकर्ता किसी समूह में है या नहीं।", + "LDAP_Sync_User_Data_RolesMap": "उपयोगकर्ता डेटा समूह मानचित्र", + "LDAP_Sync_User_Data_RolesMap_Description": "LDAP समूहों को Rocket.Chat उपयोगकर्ता भूमिकाओं में मैप करें\n उदाहरण के तौर पर, `{\"रॉकेट-एडमिन\":\"एडमिन\", \"टेक-सपोर्ट\":\"सपोर्ट\", \"मैनेजर\":[\"लीडर\", \"मॉडरेटर\"]}` रॉकेट-एडमिन एलडीएपी ग्रुप को मैप करेगा रॉकेट की \"व्यवस्थापक\" भूमिका.", + "LDAP_Teams_BaseDN": "एलडीएपी टीमें बेसडीएन", + "LDAP_Teams_BaseDN_Description": "एलडीएपी बेसडीएन का उपयोग उपयोगकर्ता टीमों को देखने के लिए किया जाता है।", + "LDAP_Teams_Name_Field": "एलडीएपी टीम का नाम विशेषता", + "LDAP_Teams_Name_Field_Description": "LDAP विशेषता जिसका उपयोग Rocket.Chat को टीम का नाम लोड करने के लिए करना चाहिए। यदि आप उन्हें अल्पविराम से अलग करते हैं तो आप एक से अधिक संभावित विशेषता नाम निर्दिष्ट कर सकते हैं।", + "LDAP_Timeout": "टाइमआउट (एमएस)", + "LDAP_Timeout_Description": "कोई त्रुटि लौटाने से पहले खोज परिणाम के लिए कितने मीलसेकंड प्रतीक्षा करते हैं", + "LDAP_Unique_Identifier_Field": "अद्वितीय पहचानकर्ता फ़ील्ड", + "LDAP_Unique_Identifier_Field_Description": "एलडीएपी उपयोगकर्ता और रॉकेट.चैट उपयोगकर्ता को लिंक करने के लिए किस फ़ील्ड का उपयोग किया जाएगा। आप एलडीएपी रिकॉर्ड से मूल्य प्राप्त करने का प्रयास करने के लिए अल्पविराम से अलग किए गए कई मानों को सूचित कर सकते हैं।\n डिफ़ॉल्ट मान `ऑब्जेक्टGUID,ibm-entryUUID,GUID,dominoUNID,nsuniqueId,uidNumber` है", + "LDAP_User_Found": "एलडीएपी उपयोगकर्ता मिला", + "LDAP_User_Search_AttributesToQuery": "क्वेरी के गुण", + "LDAP_User_Search_AttributesToQuery_Description": "निर्दिष्ट करें कि एलडीएपी प्रश्नों पर कौन सी विशेषताएँ लौटाई जानी चाहिए, उन्हें अल्पविराम से अलग करें। हर चीज़ के लिए डिफ़ॉल्ट. `*` सभी नियमित विशेषताओं का प्रतिनिधित्व करता है और `+` सभी परिचालन विशेषताओं का प्रतिनिधित्व करता है। प्रत्येक Rocket.Chat सिंक विकल्प द्वारा उपयोग की जाने वाली प्रत्येक विशेषता को शामिल करना सुनिश्चित करें।", + "LDAP_User_Search_Field": "खोज क्षेत्र", + "LDAP_User_Search_Field_Description": "एलडीएपी विशेषता जो प्रमाणीकरण का प्रयास करने वाले एलडीएपी उपयोगकर्ता की पहचान करती है। अधिकांश सक्रिय निर्देशिका स्थापनाओं के लिए यह फ़ील्ड `sAMAccountName` होना चाहिए, लेकिन यह अन्य LDAP समाधानों, जैसे OpenLDAP, के लिए `uid` हो सकता है। आप ईमेल या अपनी इच्छित विशेषता के आधार पर उपयोगकर्ताओं की पहचान करने के लिए `मेल` का उपयोग कर सकते हैं।\n आप उपयोगकर्ताओं को उपयोगकर्ता नाम या ईमेल जैसे कई पहचानकर्ताओं का उपयोग करके लॉगिन करने की अनुमति देने के लिए अल्पविराम से अलग किए गए कई मानों का उपयोग कर सकते हैं।", + "LDAP_User_Search_Filter": "फ़िल्टर", + "LDAP_User_Search_Filter_Description": "यदि निर्दिष्ट किया गया है, तो केवल इस फ़िल्टर से मेल खाने वाले उपयोगकर्ताओं को ही लॉग इन करने की अनुमति दी जाएगी। यदि कोई फ़िल्टर निर्दिष्ट नहीं है, तो निर्दिष्ट डोमेन आधार के दायरे में सभी उपयोगकर्ता साइन इन करने में सक्षम होंगे।\n जैसे सक्रिय निर्देशिका के लिए `memberOf=cn=ROCKET_CHAT,ou=सामान्य समूह`।\n जैसे OpenLDAP (एक्स्टेंसिबल मैच सर्च) के लिए `ou:dn:=ROCKET_CHAT`।", "LDAP_User_Search_Scope": "क्षेत्र", + "LDAP_Username_Field": "उपयोक्तानाम फ़ील्ड", + "LDAP_Username_Field_Description": "नए उपयोगकर्ताओं के लिए किस फ़ील्ड का उपयोग *उपयोगकर्ता नाम* के रूप में किया जाएगा. लॉगिन पेज पर सूचित उपयोगकर्ता नाम का उपयोग करने के लिए खाली छोड़ दें।\n आप टेम्प्लेट टैग का भी उपयोग कर सकते हैं, जैसे `#{givenName}.#{sn}`.\n डिफ़ॉल्ट मान `sAMAccountName` है।", + "LDAP_Username_To_Search": "खोजने के लिए उपयोगकर्ता नाम", + "LDAP_Validate_Teams_For_Each_Login": "प्रत्येक लॉगिन के लिए मैपिंग मान्य करें", + "LDAP_Validate_Teams_For_Each_Login_Description": "निर्धारित करें कि क्या हर बार Rocket.Chat पर लॉगिन करने पर उपयोगकर्ताओं की टीमों को अपडेट किया जाना चाहिए। यदि इसे बंद कर दिया जाता है तो टीम को केवल उनके पहले लॉगिन पर ही लोड किया जाएगा।", + "Lead_capture_email_regex": "लीड कैप्चर ईमेल रेगेक्स", + "Lead_capture_phone_regex": "लीड कैप्चर फ़ोन रेगेक्स", + "Learn_more": "और अधिक जानें", + "Learn_more_about_agents": "एजेंटों के बारे में और जानें", + "Learn_more_about_canned_responses": "डिब्बाबंद प्रतिक्रियाओं के बारे में और जानें", + "Learn_more_about_contacts": "संपर्कों के बारे में और जानें", + "Learn_more_about_current_chats": "वर्तमान चैट के बारे में और जानें", + "Learn_more_about_custom_fields": "कस्टम फ़ील्ड के बारे में और जानें", + "Learn_more_about_conversations": "बातचीत के बारे में और जानें", + "Learn_more_about_departments": "विभागों के बारे में और जानें", + "Learn_more_about_managers": "प्रबंधकों के बारे में और जानें", + "Learn_more_about_monitors": "मॉनिटर के बारे में और जानें", + "Learn_more_about_SLA_policies": "SLA नीतियों के बारे में और जानें", + "Learn_more_about_tags": "टैग के बारे में और जानें", + "Learn_more_about_triggers": "ट्रिगर्स के बारे में और जानें", + "Learn_more_about_units": "इकाइयों के बारे में और जानें", + "Learn_more_about_voice_channel": "वॉइस चैनल के बारे में और जानें", + "Least_recent_updated": "कम से कम हाल ही में अद्यतन किया गया", + "Learn_how_to_unlock_the_myriad_possibilities_of_rocket_chat": "जानें कि Rocket.Chat की असंख्य संभावनाओं को कैसे अनलॉक किया जाए।", + "Leave": "छुट्टी", + "Leave_a_comment": "एक टिप्पणी छोड़ें", + "Leave_Group_Warning": "क्या आप वाकई समूह \"%s\" छोड़ना चाहते हैं?", + "Leave_Livechat_Warning": "क्या आप वाकई \"%s\" के साथ ओमनीचैनल छोड़ना चाहते हैं?", + "Leave_Private_Warning": "क्या आप वाकई \"%s\" के साथ चर्चा छोड़ना चाहते हैं?", + "Leave_room": "छुट्टी", + "Leave_Room_Warning": "क्या आप वाकई चैनल \"%s\" छोड़ना चाहते हैं?", + "Leave_the_current_channel": "वर्तमान चैनल छोड़ें", + "Leave_the_description_field_blank_if_you_dont_want_to_show_the_role": "यदि आप भूमिका नहीं दिखाना चाहते तो विवरण फ़ील्ड खाली छोड़ दें", + "leave-c": "चैनल छोड़ें", + "leave-c_description": "चैनल छोड़ने की अनुमति", + "leave-p": "निजी समूह छोड़ें", + "leave-p_description": "निजी समूह छोड़ने की अनुमति", + "Lets_get_you_new_one_": "आइए आपके लिए एक नया लेकर आएं!", + "License": "लाइसेंस", + "Line": "रेखा", + "Link": "जोड़ना", + "Link_Preview": "लिंक पूर्वावलोकन", + "List_of_Channels": "चैनलों की सूची", + "List_of_departments_for_forward": "अग्रेषण हेतु अनुमत विभागों की सूची (वैकल्पिक)", + "List_of_departments_for_forward_description": "उन विभागों की एक प्रतिबंधित सूची सेट करने की अनुमति दें जो इस विभाग से चैट प्राप्त कर सकते हैं", + "List_of_departments_to_apply_this_business_hour": "इस व्यावसायिक घंटे को लागू करने वाले विभागों की सूची", + "List_of_Direct_Messages": "सीधे संदेशों की सूची", + "List_view": "लिस्ट व्यू", + "Livechat": "सीधी बातचीत", + "Livechat_abandoned_rooms_action": "आगंतुक परित्याग को कैसे संभालें", + "Livechat_abandoned_rooms_closed_custom_message": "कस्टम संदेश जब आगंतुक निष्क्रियता के कारण कमरा स्वचालित रूप से बंद हो जाता है", + "Livechat_agents": "ओमनीचैनल एजेंट", + "Livechat_Agents": "एजेंटों", + "Livechat_allow_manual_on_hold": "एजेंटों को चैट को मैन्युअल रूप से होल्ड पर रखने की अनुमति दें", + "Livechat_allow_manual_on_hold_Description": "सक्षम होने पर, एजेंट को चैट को होल्ड पर रखने का विकल्प मिलेगा", + "Livechat_allow_manual_on_hold_upon_agent_engagement_only": "एजेंट संलग्न होने के बाद ही चैट होल्ड पर रहती है", + "Livechat_allow_manual_on_hold_upon_agent_engagement_only_Description": "केवल तभी चैट को होल्ड पर रखने की अनुमति दें यदि एजेंट वही है जिसने बातचीत में अंतिम संदेश भेजा है।", + "Livechat_AllowedDomainsList": "लाइवचैट अनुमत डोमेन", + "Livechat_Appearance": "लाइवचैट उपस्थिति", + "Livechat_auto_close_on_hold_chats_custom_message": "ऑन होल्ड कतार में बंद चैट के लिए कस्टम संदेश", + "Livechat_auto_close_on_hold_chats_custom_message_Description": "जब ऑन-होल्ड कतार में कोई कमरा सिस्टम द्वारा स्वचालित रूप से बंद हो जाता है तो कस्टम संदेश भेजा जाता है", + "Livechat_auto_close_on_hold_chats_timeout": "ऑन होल्ड क्यू में चैट बंद करने से पहले कितनी देर तक इंतजार करना होगा?", + "Livechat_auto_close_on_hold_chats_timeout_Description": "परिभाषित करें कि चैट सिस्टम द्वारा स्वचालित रूप से बंद होने तक ऑन होल्ड कतार में कितनी देर तक रहेगी। समय सेकंड में", + "Livechat_auto_transfer_chat_timeout": "किसी अन्य एजेंट को अनुत्तरित चैट के स्वचालित स्थानांतरण के लिए टाइमआउट (सेकंड में)।", + "Livechat_auto_transfer_chat_timeout_Description": "यह इवेंट तभी होता है जब चैट अभी शुरू हुई हो. निष्क्रियता के लिए पहली बार स्थानांतरण के बाद, कमरे की निगरानी नहीं की जाती है।", + "Livechat_business_hour_type": "व्यावसायिक घंटे का प्रकार (एकल या एकाधिक)", + "Livechat_chat_transcript_sent": "चैट प्रतिलेख भेजा गया: {{transcript}}", + "Livechat_close_chat": "चैट बंद करें", + "Livechat_custom_fields_options_placeholder": "पूर्व-कॉन्फ़िगर मान का चयन करने के लिए अल्पविराम से अलग की गई सूची का उपयोग किया जाता है। तत्वों के बीच रिक्त स्थान स्वीकार नहीं किया जाता है।", + "Livechat_custom_fields_public_description": "सार्वजनिक कस्टम फ़ील्ड बाहरी अनुप्रयोगों, जैसे लाइवचैट, आदि में प्रदर्शित किए जाएंगे।", + "Livechat_Dashboard": "ओमनीचैनल डैशबोर्ड", + "Livechat_DepartmentOfflineMessageToChannel": "इस विभाग के लाइवचैट ऑफ़लाइन संदेशों को एक चैनल पर भेजें", + "Livechat_enable_message_character_limit": "संदेश वर्ण सीमा सक्षम करें", + "Livechat_enabled": "ओमनीचैनल सक्षम", + "Livechat_forward_open_chats": "खुली हुई चैट को अग्रेषित करें", + "Livechat_forward_open_chats_timeout": "चैट अग्रेषित करने के लिए टाइमआउट (सेकंड में)।", + "Livechat_guest_count": "अतिथि काउंटर", + "Livechat_Inquiry_Already_Taken": "ओम्नीचैनल पूछताछ पहले ही ले ली गई है", + "Livechat_Installation": "लाइवचैट इंस्टालेशन", + "Livechat_last_chatted_agent_routing": "अंतिम बार चैट किए गए एजेंट को प्राथमिकता", + "Livechat_last_chatted_agent_routing_Description": "यदि चैट शुरू होने पर एजेंट उपलब्ध है तो लास्ट-चैट एजेंट सेटिंग उस एजेंट को चैट आवंटित करती है जिसने पहले उसी विज़िटर के साथ बातचीत की थी।", + "Livechat_managers": "ओमनीचैनल प्रबंधक", + "Livechat_Managers": "प्रबंधकों", + "Livechat_max_queue_wait_time_action": "अधिकतम प्रतीक्षा समय तक पहुंचने पर कतारबद्ध चैट को कैसे संभालें", + "Livechat_maximum_queue_wait_time": "कतार में अधिकतम प्रतीक्षा समय", + "Livechat_maximum_queue_wait_time_description": "चैट को कतार में रखने का अधिकतम समय (मिनटों में)। -1 का मतलब असीमित है", + "Livechat_message_character_limit": "लाइवचैट संदेश वर्ण सीमा", + "Livechat_monitors": "लाइवचैट मॉनिटर", + "Livechat_Monitors": "पर नज़र रखता है", + "Livechat_offline": "ओमनीचैनल ऑफ़लाइन", + "Livechat_offline_message_sent": "लाइवचैट ऑफ़लाइन संदेश भेजा गया", + "Livechat_OfflineMessageToChannel_enabled": "किसी चैनल पर लाइवचैट ऑफ़लाइन संदेश भेजें", + "Omnichannel_chat_closed_due_to_inactivity": "चैट स्वचालित रूप से बंद हो गई क्योंकि हमें {{timeout}} सेकंड में {{guest}} से कोई उत्तर नहीं मिला", + "Omnichannel_on_hold_chat_resumed": "होल्ड पर चैट फिर से शुरू: {{comment}}", + "Omnichannel_on_hold_chat_automatically": "{{guest}} से एक नया संदेश प्राप्त होने पर चैट स्वचालित रूप से ऑन होल्ड से फिर से शुरू हो गई थी", + "Omnichannel_on_hold_chat_resumed_manually": "चैट को मैन्युअल रूप से ऑन होल्ड से {{user}} द्वारा फिर से शुरू किया गया था", + "Omnichannel_On_Hold_due_to_inactivity": "चैट को स्वचालित रूप से होल्ड पर रखा गया था क्योंकि हमें {{timeout}} सेकंड में {{guest}} से कोई उत्तर नहीं मिला था", + "Omnichannel_On_Hold_manually": "चैट को {{user}} द्वारा मैन्युअल रूप से होल्ड पर रखा गया था", + "Omnichannel_onHold_Chat": "चैट को होल्ड पर रखें", + "Omnichannel_quick_actions": "ओमनीचैनल त्वरित कार्यवाही", + "Omnichannel_sorting_disclaimer": "ओमनीचैनल वार्तालापों को {{sortingMechanism}} द्वारा क्रमबद्ध किया जाता है, लागू करने के लिए एक कक्ष संपादित करें।", + "Livechat_online": "ओमनीचैनल ऑन-लाइन", + "Omnichannel_placed_chat_on_hold": "चैट ऑन होल्ड: {{comment}}", + "Omnichannel_hide_conversation_after_closing": "बंद करने के बाद बातचीत छिपाएँ", + "Omnichannel_hide_conversation_after_closing_description": "बातचीत बंद करने के बाद आपको होम पर रीडायरेक्ट कर दिया जाएगा।", + "Livechat_Queue": "ओमनीचैनल कतार", "Livechat_registration_form": "पंजीकरण ", + "Livechat_registration_form_message": "पंजीकरण प्रपत्र संदेश", + "Livechat_room_count": "ओमनीचैनल कक्ष संख्या", + "Livechat_Routing_Method": "ओमनीचैनल रूटिंग विधि", + "Livechat_status": "लाइवचैट स्थिति", + "Livechat_Take_Confirm": "क्या आप इस ग्राहक को लेना चाहते हैं?", + "Livechat_title": "लाइवचैट शीर्षक", + "Livechat_title_color": "लाइवचैट शीर्षक पृष्ठभूमि रंग", + "Livechat_transcript_already_requested_warning": "इस चैट की प्रतिलेख पहले ही अनुरोध किया जा चुका है और बातचीत समाप्त होते ही भेज दी जाएगी।", + "Livechat_transcript_has_been_requested": "निर्यात का अनुरोध किया गया. इसमें कुछ सेकंड लग सकते हैं.", + "Livechat_email_transcript_has_been_requested": "प्रतिलेख का अनुरोध किया गया है. इसमें कुछ सेकंड लग सकते हैं.", + "Livechat_transcript_request_has_been_canceled": "चैट ट्रांस्क्रिप्शन अनुरोध रद्द कर दिया गया है.", + "Livechat_transcript_sent": "ओमनीचैनल प्रतिलेख भेजा गया", + "Livechat_transfer_return_to_the_queue": "{{from}} ने चैट को कतार में लौटा दिया", + "Livechat_transfer_return_to_the_queue_with_a_comment": "{{from}} ने एक टिप्पणी के साथ चैट को कतार में लौटा दिया: {{comment}}", + "Livechat_transfer_return_to_the_queue_auto_transfer_unanswered_chat": "{{from}} ने चैट को कतार में वापस कर दिया क्योंकि यह {{period}} सेकंड तक अनुत्तरित थी", + "Livechat_transfer_to_agent": "{{from}} ने चैट को {{to}} में स्थानांतरित कर दिया", + "Livechat_transfer_to_agent_with_a_comment": "{{from}} ने एक टिप्पणी के साथ चैट को {{to}} में स्थानांतरित कर दिया: {{comment}}", + "Livechat_transfer_to_agent_auto_transfer_unanswered_chat": "{{from}} ने चैट को {{to}} में स्थानांतरित कर दिया क्योंकि यह {{period}} सेकंड तक अनुत्तरित थी", + "Livechat_transfer_to_department": "{{to}} ने चैट को विभाग में स्थानांतरित कर दिया {{to}}", + "Livechat_transfer_to_department_with_a_comment": "{{to}} ने एक टिप्पणी के साथ चैट को विभाग में स्थानांतरित कर दिया।", + "Livechat_transfer_failed_fallback": "मूल विभाग ({{from}} ) में ऑनलाइन एजेंट नहीं हैं। चैट सफलतापूर्वक {{to}} में स्थानांतरित हो गई", + "Livechat_Triggers": "लाइवचैट ट्रिगर", + "Livechat_user_sent_chat_transcript_to_visitor": "{{agent}} ने चैट ट्रांसक्रिप्ट को {{guest}} को भेजा", + "Livechat_Users": "ओमनीचैनल उपयोगकर्ता", + "Livechat_Calls": "लाइवचैट कॉल", + "Livechat_visitor_email_and_transcript_email_do_not_match": "विज़िटर का ईमेल और प्रतिलेख ईमेल मेल नहीं खाते", + "Livechat_visitor_transcript_request": "{{guest}} ने चैट प्रतिलेख का अनुरोध किया", + "LiveStream & Broadcasting": "लाइवस्ट्रीम और प्रसारण", + "LiveStream & Broadcasting_Description": "Rocket.Chat और YouTube लाइव के बीच यह एकीकरण चैनल मालिकों को एक चैनल के अंदर लाइवस्ट्रीम के लिए अपने कैमरा फ़ीड को लाइव प्रसारित करने की अनुमति देता है।", + "Livestream": "लाइव स्ट्रीम", + "Livestream_close": "लाइवस्ट्रीम बंद करें", + "Livestream_enable_audio_only": "केवल ऑडियो मोड सक्षम करें", + "Livestream_enabled": "लाइवस्ट्रीम सक्षम", + "Livestream_not_found": "लाइवस्ट्रीम उपलब्ध नहीं है", + "Livestream_unavailable_for_federation": "फ़ेडरेटेड कमरों के लिए लिवेस्ट्रम अनुपलब्ध है", + "Livestream_popout": "लाइवस्ट्रीम खोलें", + "Livestream_source_changed_succesfully": "लाइवस्ट्रीम स्रोत सफलतापूर्वक बदला गया", + "Livestream_switch_to_room": "वर्तमान कमरे की लाइवस्ट्रीम पर स्विच करें", + "Livestream_url": "लाइवस्ट्रीम स्रोत यूआरएल", + "Livestream_url_incorrect": "लाइवस्ट्रीम यूआरएल ग़लत है", + "Livestream_live_now": "अब सीधा प्रसारण हो रहा है!", + "Load_Balancing": "भार का संतुलन", + "Load_more": "और लोड करें", + "Load_Rotation": "लोड रोटेशन", + "Loading": "लोड हो रहा है", + "Loading_more_from_history": "इतिहास से और अधिक लोड हो रहा है", + "Loading_suggestion": "सुझाव लोड हो रहे हैं", + "Loading...": "लोड हो रहा है...", + "Local": "स्थानीय", + "Local_Domains": "स्थानीय डोमेन", + "Local_Password": "स्थानीय पासवर्ड", + "Local_Time": "स्थानीय समय", + "Local_Timezone": "स्थानीय समय क्षेत्र", + "Local_Time_time": "स्थानीय समय: {{time}}", + "Localization": "स्थानीयकरण", + "Location": "जगह", + "Log_Exceptions_to_Channel": "चैनल में अपवाद लॉग करें", + "Log_Exceptions_to_Channel_Description": "एक चैनल जो सभी कैप्चर किए गए अपवाद प्राप्त करेगा। अपवादों को नज़रअंदाज करने के लिए खाली छोड़ें।", + "Log_File": "फ़ाइल और लाइन दिखाएँ", + "Log_Level": "छांटने का स्तर", + "Log_Package": "पैकेज दिखाएँ", + "Log_Trace_Methods": "ट्रेस विधि कॉल", + "Log_Trace_Methods_Filter": "ट्रेस विधि फ़िल्टर", + "Log_Trace_Methods_Filter_Description": "यहां टेक्स्ट का मूल्यांकन रेगएक्सपी (`नया रेगएक्सपी('टेक्स्ट')`) के रूप में किया जाएगा। प्रत्येक कॉल का ट्रेस दिखाने के लिए इसे खाली रखें।", + "Log_Trace_Subscriptions": "सदस्यता कॉल ट्रेस करें", + "Log_Trace_Subscriptions_Filter": "सदस्यता फ़िल्टर ट्रेस करें", + "Log_Trace_Subscriptions_Filter_Description": "यहां टेक्स्ट का मूल्यांकन रेगएक्सपी (`नया रेगएक्सपी('टेक्स्ट')`) के रूप में किया जाएगा। प्रत्येक कॉल का ट्रेस दिखाने के लिए इसे खाली रखें।", + "Log_View_Limit": "लॉग दृश्य सीमा", + "Logged_Out_Banner_Text": "आपके कार्यक्षेत्र व्यवस्थापक ने इस उपकरण पर आपका सत्र समाप्त कर दिया। जारी रखने के लिए कृपया दोबारा लॉग इन करें।", + "Logged_out_of_other_clients_successfully": "अन्य ग्राहकों से सफलतापूर्वक लॉग आउट हो गया", + "Login": "लॉग इन करें", + "Log_in_to_sync": "सिंक करने के लिए लॉग इन करें", + "Login_Attempts": "लॉगिन प्रयास विफल", + "Login_Detected": "लॉगिन का पता चला", + "Logged_In_Via": "के माध्यम से लॉग इन किया गया", + "Login_Logs": "लॉगइन लॉग्स", + "Login_Logs_ClientIp": "विफल लॉगिन प्रयास लॉग पर क्लाइंट आईपी दिखाएं", + "Login_Logs_Enabled": "लॉग (कंसोल पर) विफल लॉगिन प्रयास", + "Login_Logs_ForwardedForIp": "विफल लॉगिन प्रयास लॉग पर अग्रेषित आईपी दिखाएं", + "Login_Logs_UserAgent": "विफल लॉगिन प्रयास लॉग पर UserAgent दिखाएं", + "Login_Logs_Username": "विफल लॉगिन प्रयास लॉग पर उपयोगकर्ता नाम दिखाएं", + "Login_with": "%s के साथ लॉगिन करें", + "Logistics": "रसद", + "Logout": "लॉग आउट", + "Logout_Others": "अन्य लॉग इन स्थानों से लॉगआउट करें", + "Logout_Device": "डिवाइस लॉग आउट करें", + "Log_out_devices_remotely": "डिवाइसों को दूरस्थ रूप से लॉग आउट करें", + "logout-device-management": "लॉगआउट डिवाइस प्रबंधन", + "logout-device-management_description": "डिवाइस प्रबंधन डैशबोर्ड से अन्य उपयोगकर्ताओं को लॉगआउट करने की अनुमति", + "logout-other-user": "अन्य उपयोगकर्ता को लॉगआउट करें", + "logout-other-user_description": "अन्य उपयोगकर्ताओं को लॉगआउट करने की अनुमति", + "Logs": "लॉग्स", + "Logs_Description": "कॉन्फ़िगर करें कि सर्वर लॉग कैसे प्राप्त होते हैं।", + "Longest_chat_duration": "सबसे लंबी चैट period", + "Longest_reaction_time": "सबसे लंबा प्रतिक्रिया समय", + "Longest_response_time": "सबसे लंबा प्रतिक्रिया समय", + "Looked_for": "ढ़ूढ़ा", + "Low": "कम", + "Lowest": "निम्नतम", + "Mail_Message_Invalid_emails": "आपने एक या अधिक अमान्य ईमेल प्रदान किए हैं: %s", + "Mail_Message_Missing_subject": "आपको एक ईमेल विषय प्रदान करना होगा.", + "Mail_Message_Missing_to": "आपको एक या अधिक उपयोगकर्ताओं का चयन करना होगा या अल्पविराम से अलग करके एक या अधिक ईमेल पते प्रदान करने होंगे।", + "Mail_Message_No_messages_selected_select_all": "आपने कोई संदेश नहीं चुना है", + "Mail_Messages": "मेल संदेश", + "Mail_Messages_Instructions": "संदेशों पर क्लिक करके चुनें कि आप कौन से संदेश ईमेल के माध्यम से भेजना चाहते हैं", + "Mail_Messages_Subject": "यहां %s संदेशों का चयनित भाग है", + "mail-messages": "मेल संदेश", + "mail-messages_description": "मेल संदेश विकल्प का उपयोग करने की अनुमति", + "Mailer": "मेलर", + "Mailer_body_tags": "आपको अनसब्सक्रिप्शन लिंक के लिए [अनसब्सक्राइब] का उपयोग करना होगा
    आप उपयोगकर्ता के पूर्ण नाम, प्रथम नाम या अंतिम नाम के लिए क्रमशः `[name]`, `[fname]`, `[lname]` का उपयोग कर सकते हैं।
    आप उपयोगकर्ता के ईमेल के लिए [ईमेल] का उपयोग कर सकते हैं।", + "Mailing": "डाक", + "Make_Admin": "एडमिन बनाओ", + "Make_sure_you_have_a_copy_of_your_codes_1": "सुनिश्चित करें कि आपके पास अपने कोड की एक प्रति है:", + "Make_sure_you_have_a_copy_of_your_codes_2": "यदि आप अपने प्रमाणक ऐप तक पहुंच खो देते हैं, तो आप लॉग इन करने के लिए इनमें से किसी एक कोड का उपयोग कर सकते हैं।", + "Manage": "प्रबंधित करना", + "manage-agent-extension-association": "एजेंट एक्सटेंशन एसोसिएशन का प्रबंधन करें", + "manage-agent-extension-association_description": "एजेंट एक्सटेंशन एसोसिएशन को प्रबंधित करने की अनुमति", + "manage-apps": "एप्लिकेशन प्रबंधित", + "manage-apps_description": "सभी ऐप्स को प्रबंधित करने की अनुमति", + "manage-assets": "संपत्ति का प्रबंधन करें", + "manage-assets_description": "सर्वर संपत्तियों को प्रबंधित करने की अनुमति", + "manage-cloud": "बादल प्रबंधित करें", + "manage-cloud_description": "क्लाउड को प्रबंधित करने की अनुमति", + "Manage_Devices": "डिवाइस प्रबंधित करें", + "manage-email-inbox": "ईमेल इनबॉक्स प्रबंधित करें", + "manage-email-inbox_description": "ईमेल इनबॉक्स प्रबंधित करने की अनुमति", + "manage-emoji": "इमोजी प्रबंधित करें", + "manage-emoji_description": "सर्वर इमोजी को प्रबंधित करने की अनुमति", + "messages_pruned": "संदेशों की काट-छाँट की गई", + "manage-incoming-integrations": "आने वाले एकीकरणों को प्रबंधित करें", + "manage-incoming-integrations_description": "सर्वर आने वाली एकीकरणों को प्रबंधित करने की अनुमति", + "manage-integrations": "एकीकरण प्रबंधित करें", + "manage-integrations_description": "सर्वर एकीकरण को प्रबंधित करने की अनुमति", + "manage-livechat-agents": "ओमनीचैनल एजेंटों को प्रबंधित करें", + "manage-livechat-agents_description": "सर्वचैनल एजेंटों को प्रबंधित करने की अनुमति", + "manage-livechat-canned-responses": "ओमनीचैनल डिब्बाबंद प्रतिक्रियाएँ प्रबंधित करें", + "manage-livechat-canned-responses_description": "सर्वचैनल डिब्बाबंद प्रतिक्रियाओं को प्रबंधित करने की अनुमति", + "manage-livechat-departments": "ओमनीचैनल विभागों का प्रबंधन करें", + "manage-livechat-departments_description": "सर्वचैनल विभागों को प्रबंधित करने की अनुमति", + "manage-livechat-managers": "ओमनीचैनल प्रबंधकों को प्रबंधित करें", + "manage-livechat-managers_description": "सर्वचैनल प्रबंधकों को प्रबंधित करने की अनुमति", + "manage-livechat-monitors": "ओमनीचैनल मॉनिटर्स प्रबंधित करें", + "manage-livechat-monitors_description": "ओमनीचैनल मॉनिटर प्रबंधित करने की अनुमति", + "manage-livechat-priorities": "ओमनीचैनल प्राथमिकताएँ प्रबंधित करें", + "manage-livechat-priorities_description": "सर्वचैनल प्राथमिकताओं को प्रबंधित करने की अनुमति", + "manage-livechat-sla": "ओमनीचैनल SLA प्रबंधित करें", + "manage-livechat-sla_description": "सर्वचैनल एसएलए को प्रबंधित करने की अनुमति", + "manage-livechat-tags": "ओमनीचैनल टैग प्रबंधित करें", + "manage-livechat-tags_description": "ओमनीचैनल टैग प्रबंधित करने की अनुमति", + "manage-livechat-units": "ओमनीचैनल इकाइयों का प्रबंधन करें", + "manage-livechat-units_description": "सर्वचैनल इकाइयों को प्रबंधित करने की अनुमति", + "manage-oauth-apps": "OAuth ऐप्स प्रबंधित करें", + "manage-oauth-apps_description": "सर्वर OAuth ऐप्स को प्रबंधित करने की अनुमति", + "manage-outgoing-integrations": "आउटगोइंग एकीकरण प्रबंधित करें", + "manage-outgoing-integrations_description": "सर्वर आउटगोइंग एकीकरणों को प्रबंधित करने की अनुमति", + "manage-own-incoming-integrations": "स्वयं के आने वाले एकीकरणों को प्रबंधित करें", + "manage-own-incoming-integrations_description": "उपयोगकर्ताओं को अपने स्वयं के आने वाले एकीकरण या वेबहुक बनाने और संपादित करने की अनुमति", + "manage-own-integrations": "स्वयं के एकीकरण प्रबंधित करें", + "manage-own-integrations_description": "उपयोगकर्ताओं को अपना स्वयं का एकीकरण या वेबहुक बनाने और संपादित करने की अनुमति", + "manage-own-outgoing-integrations": "स्वयं के आउटगोइंग एकीकरणों को प्रबंधित करें", + "manage-own-outgoing-integrations_description": "उपयोगकर्ताओं को अपने स्वयं के आउटगोइंग एकीकरण या वेबहुक बनाने और संपादित करने की अनुमति", + "manage-selected-settings": "कुछ सेटिंग्स बदलें", + "manage-selected-settings_description": "सेटिंग्स को बदलने की अनुमति जो स्पष्ट रूप से बदलने के लिए दी गई है", + "manage-sounds": "ध्वनियाँ प्रबंधित करें", + "manage-sounds_description": "सर्वर ध्वनियों को प्रबंधित करने की अनुमति", + "manage-the-app": "ऐप प्रबंधित करें", + "manage-user-status": "उपयोगकर्ता स्थिति प्रबंधित करें", + "manage-user-status_description": "सर्वर कस्टम उपयोगकर्ता स्थितियों को प्रबंधित करने की अनुमति", + "manage-voip-call-settings": "वीओआईपी कॉल सेटिंग्स प्रबंधित करें", + "manage-voip-call-settings_description": "वीओआईपी कॉल सेटिंग प्रबंधित करने की अनुमति", + "manage-voip-contact-center-settings": "वीओआईपी संपर्क केंद्र सेटिंग्स प्रबंधित करें", + "manage-voip-contact-center-settings_description": "वीओआईपी संपर्क केंद्र सेटिंग्स को प्रबंधित करने की अनुमति", + "Manage_Omnichannel": "ओमनीचैनल प्रबंधित करें", + "Manage_workspace": "कार्यक्षेत्र प्रबंधित करें", + "Manager_added": "प्रबंधक जोड़ा गया", + "Manager_removed": "मैनेजर को हटा दिया गया", + "Managers": "प्रबंधकों", + "Manage_server_list": "सर्वर सूची प्रबंधित करें", + "Manage_servers": "सर्वर प्रबंधित करें", + "Manage_which_devices": "सुरक्षा सुनिश्चित करने में सहायता के लिए प्रबंधित करें कि कौन से उपकरण इस कार्यक्षेत्र से कनेक्ट हो रहे हैं। डिवाइस आईडी, लॉगिन डेटा जैसी जानकारी शामिल है और डिवाइस को दूरस्थ रूप से लॉग आउट करने की क्षमता भी शामिल है।", + "Management_Server": "तारांकन प्रबंधक इंटरफ़ेस (एएमआई)", + "Managing_assets": "संपत्ति का प्रबंधन", + "Managing_integrations": "एकीकरण का प्रबंधन", + "Manual_Selection": "मैन्युअल चयन", + "Manufacturing": "उत्पादन", + "MapView_Enabled": "मैपव्यू सक्षम करें", + "MapView_Enabled_Description": "मैपव्यू सक्षम करने से चैट इनपुट फ़ील्ड के दाईं ओर एक स्थान साझा बटन प्रदर्शित होगा।", + "MapView_GMapsAPIKey": "गूगल स्टेटिक मैप्स एपीआई कुंजी", + "MapView_GMapsAPIKey_Description": "इसे Google डेवलपर्स कंसोल से निःशुल्क प्राप्त किया जा सकता है।", + "Mark_all_as_read": "`%s` - सभी संदेशों को (सभी चैनलों में) पढ़े गए के रूप में चिह्नित करें", + "Mark_as_read": "पढ़े हुए का चिह्न", + "Mark_as_unread": "अपठित के रूप में चिह्नित करें", + "Mark_read": "पढ़ा हुआ चिह्नित करें", + "Mark_unread": "अपठित चिन्हित करो", + "Marketplace": "बाजार", + "Marketplace_app_last_updated": "अंतिम बार अद्यतन किया गया {{lastUpdated}}", + "Marketplace_view_marketplace": "बाज़ार देखें", + "Marketplace_error": "इंटरनेट से कनेक्ट नहीं हो सकता या आपका कार्यक्षेत्र ऑफ़लाइन इंस्टॉल हो सकता है।", + "MAU_value": "हमेशा {{price}}", + "Max_length_is": "अधिकतम लंबाई %s है", + "Max_number_incoming_livechats_displayed": "कतार में प्रदर्शित वस्तुओं की अधिकतम संख्या", + "Max_number_incoming_livechats_displayed_description": "(वैकल्पिक) आने वाली ओमनीचैनल कतार में प्रदर्शित आइटमों की अधिकतम संख्या।", + "Max_number_of_chats_per_agent": "अधिकतम. एक साथ चैट की संख्या", + "Max_number_of_chats_per_agent_description": "अधिकतम. एक साथ होने वाली चैट की संख्या जिसमें एजेंट भाग ले सकते हैं", + "Max_number_of_uses": "उपयोग की अधिकतम संख्या", + "Max_Retry": "सर्वर से पुनः कनेक्ट करने का अधिकतम प्रयास", + "Maximum": "अधिकतम", + "Maximum_number_of_guests_reached": "सबसे ज्यादा संख्या में मेहमान पहुंचे", + "Me": "मुझे", + "Media": "मिडिया", + "Medium": "मध्यम", + "Members": "सदस्यों", + "Members_List": "सदस्यों की सूची", + "mention-all": "सभी का उल्लेख करें", + "mention-all_description": "@all उल्लेख का उपयोग करने की अनुमति", + "Mentions_all_room_members": "कक्ष के सभी सदस्यों का उल्लेख करता है", + "Mentions_online_room_members": "ऑनलाइन रूम के सदस्यों का उल्लेख करता है", + "Mentions_user": "उपयोगकर्ता का उल्लेख करता है", + "Mentions_channel": "चैनल का उल्लेख है", + "Mentions_you": "आपका जिक्र करता हूं", + "mention-here": "यहां उल्लेख करें", + "mention-here_description": "@यहाँ उल्लेख का उपयोग करने की अनुमति", + "Mentions": "का उल्लेख है", + "Mentions_default": "उल्लेख (डिफ़ॉल्ट)", + "Mentions_only": "केवल उल्लेख है", + "Mentions_with_@_symbol": "@ चिन्ह के साथ उल्लेख", + "Mentions_with_@_symbol_description": "लक्षित संचार की सुविधा प्रदान करते हुए, समूहों या विशिष्ट उपयोगकर्ताओं के लिए संदेशों को सूचित और हाइलाइट किया जाता है।\n\nजब उल्लेख सुविधा में \"@\" प्रतीक का उपयोग किया जाता है तो स्क्रीन रीडर की कार्यक्षमता अनुकूलित हो जाती है। यह सुनिश्चित करता है कि स्क्रीन रीडर पर भरोसा करने वाले उपयोगकर्ता इन उल्लेखों की आसानी से व्याख्या कर सकते हैं और उनसे जुड़ सकते हैं।", + "Merge_Channels": "चैनल मर्ज करें", + "message": "संदेश", + "Message": "संदेश", + "Message_Description": "संदेश सेटिंग कॉन्फ़िगर करें.", + "Message_AllowBadWordsFilter": "संदेश को बुरे शब्दों को फ़िल्टर करने की अनुमति दें", + "Message_AllowConvertLongMessagesToAttachment": "लंबे संदेशों को अनुलग्नक में परिवर्तित करने की अनुमति दें", + "Message_AllowDeleting": "संदेश हटाने की अनुमति दें", + "Message_AllowDeleting_BlockDeleteInMinutes": "(एन) मिनट के बाद संदेश को ब्लॉक करें", + "Message_AllowDeleting_BlockDeleteInMinutes_Description": "अवरोधन अक्षम करने के लिए 0 दर्ज करें.", + "Message_AllowDirectMessagesToYourself": "उपयोगकर्ता को अपने लिए सीधे संदेश भेजने की अनुमति दें", + "Message_AllowEditing": "संदेश संपादन की अनुमति दें", + "Message_AllowEditing_BlockEditInMinutes": "(n) मिनट के बाद संदेश संपादन को ब्लॉक करें", + "Message_AllowEditing_BlockEditInMinutesDescription": "अवरोधन अक्षम करने के लिए 0 दर्ज करें.", + "Message_AllowPinning": "संदेश पिन करने की अनुमति दें", + "Message_AllowPinning_Description": "संदेशों को किसी भी चैनल पर पिन करने की अनुमति दें।", + "Message_AllowStarring": "संदेश को तारांकित करने की अनुमति दें", + "Message_AllowUnrecognizedSlashCommand": "अज्ञात स्लैश कमांड की अनुमति दें", + "Message_Already_Sent": "यह संदेश पहले ही भेजा जा चुका है और सर्वर द्वारा संसाधित किया जा रहा है", + "Message_AlwaysSearchRegExp": "हमेशा RegExp का उपयोग करके खोजें", + "Message_AlwaysSearchRegExp_Description": "यदि आपकी भाषा [MongoDB टेक्स्ट सर्च](https://docs.mongodb.org/manual/reference/text-search-भाषाओं/#text-search-भाषाओं) पर समर्थित नहीं है, तो हम `True` सेट करने की अनुशंसा करते हैं।", + "Message_Attachments": "संदेश अनुलग्नक", + "Message_Attachments_Thumbnails_Enabled": "बैंडविथ को बचाने के लिए छवि थंबनेल सक्षम करें", + "Message_Attachments_Thumbnails_Width": "थंबनेल की अधिकतम चौड़ाई (पिक्सेल में)", + "Message_Attachments_Thumbnails_Height": "थंबनेल की अधिकतम ऊंचाई (पिक्सेल में)", + "Message_with_attachment": "अनुलग्नक के साथ संदेश", + "Report_sent": "सूचना भेजी गई", + "Message_Attachments_Thumbnails_EnabledDesc": "बैंडविथ उपयोग को कम करने के लिए मूल छवि के स्थान पर थंबनेल प्रस्तुत किए जाएंगे। अनुलग्नक के नाम के आगे वाले आइकन का उपयोग करके मूल रिज़ॉल्यूशन वाली छवियां डाउनलोड की जा सकती हैं।", + "Message_Attachments_Strip_Exif": "समर्थित फ़ाइलों से EXIF मेटाडेटा हटाएँ", + "Message_Attachments_Strip_ExifDescription": "छवि फ़ाइलों (jpeg, tiff, आदि) से EXIF मेटाडेटा को हटा देता है। यह सेटिंग पूर्वव्यापी नहीं है, इसलिए अक्षम होने पर अपलोड की गई फ़ाइलों में EXIF डेटा होगा", + "Message_Audio": "ऑडियो संदेश", + "Message_Audio_bitRate": "ऑडियो संदेश बिट दर", + "Message_AudioRecorderEnabled": "ऑडियो रिकॉर्डर सक्षम", + "Message_AudioRecorderEnabled_Description": "'फ़ाइल अपलोड' सेटिंग्स के अंतर्गत 'ऑडियो/एमपी3' फ़ाइलों को एक स्वीकृत मीडिया प्रकार होना आवश्यक है।", + "Message_Audio_Recording_Disabled": "संदेश ऑडियो रिकॉर्डिंग अक्षम की गई", + "Message_auditing": "संदेशों का ऑडिट करें", + "Message_auditing_log": "ऑडिट लॉग", + "Message_BadWordsFilterList": "बुरे शब्दों को काली सूची में जोड़ें", + "Message_BadWordsFilterListDescription": "फ़िल्टर करने के लिए बुरे शब्दों की अल्पविराम से अलग की गई सूची जोड़ें", + "Message_BadWordsWhitelist": "ब्लैकलिस्ट से शब्द हटाएँ", + "Message_BadWordsWhitelistDescription": "फ़िल्टर से हटाए जाने वाले शब्दों की अल्पविराम से अलग की गई सूची जोड़ें", + "Message_Characther_Limit": "संदेश वर्ण सीमा", + "Message_Code_highlight": "कोड हाइलाइटिंग भाषाओं की सूची", + "Message_Code_highlight_Description": "अल्पविराम से अलग की गई भाषाओं की सूची (सभी समर्थित भाषाएं [highlight.js](https://github.com/highlightjs/highlight.js/tree/11.6.0#supported-भाषाएं) पर) जिनका उपयोग कोड ब्लॉक को हाइलाइट करने के लिए किया जाएगा", + "Message_CustomDomain_AutoLink": "ऑटो लिंक के लिए कस्टम डोमेन श्वेतसूची", + "Message_CustomDomain_AutoLink_Description": "यदि आप `https://internaltool.intranet` या `internaltool.intranet` जैसे आंतरिक लिंक को ऑटो लिंक करना चाहते हैं, तो आपको फ़ील्ड में `इंट्रानेट` डोमेन जोड़ना होगा, कई डोमेन को अल्पविराम से अलग करना होगा।", + "message_counter": "{{counter}} संदेश", + "Message_DateFormat": "तारिख का प्रारूप", + "Message_DateFormat_Description": "यह भी देखें: [Moment.js](http://momentjs.com/docs/#/displaying/format/)", + "Message_deleting_blocked": "यह संदेश अब हटाया नहीं जा सकता", + "Message_editing": "संदेश संपादन", + "Message_ErasureType": "संदेश मिटाने का प्रकार", + "Message_ErasureType_Delete": "सभी संदेश हटाएँ", + "Message_ErasureType_Description": "निर्धारित करें कि उन उपयोगकर्ताओं के संदेशों का क्या करना है जो अपना खाता हटाते हैं।\n - **संदेश और उपयोगकर्ता नाम रखें:** उपयोगकर्ता का संदेश और फ़ाइल इतिहास सीधे संदेशों से हटा दिया जाएगा लेकिन अन्य कमरों में रखा जाएगा।\n - **सभी संदेश हटाएं:** उपयोगकर्ता के सभी संदेश और फ़ाइलें डेटाबेस से हटा दी जाएंगी और अब उपयोगकर्ता का पता लगाना संभव नहीं होगा।\n - **उपयोगकर्ता और संदेशों के बीच लिंक हटाएं:** यह विकल्प उपयोगकर्ता के सभी संदेशों और फ़ाइलों को Rocket.Cat बॉट को सौंप देगा और डायरेक्ट संदेश हटा दिए जाएंगे।", + "Message_ErasureType_Keep": "संदेश और उपयोगकर्ता नाम रखें", + "Message_ErasureType_Unlink": "उपयोगकर्ता और संदेशों के बीच लिंक हटाएँ", + "Message_GlobalSearch": "वैश्विक खोज", + "Message_GroupingPeriod": "समूहीकरण period (सेकंड में)", + "Message_GroupingPeriodDescription": "संदेशों को पिछले संदेश के साथ समूहीकृत किया जाएगा यदि दोनों एक ही उपयोगकर्ता के हैं और बीता हुआ समय सेकंड में सूचित समय से कम था।", + "Message_has_been_edited": "संदेश संपादित कर दिया गया है", + "Message_has_been_edited_at": "संदेश को {{date}} पर संपादित किया गया है", + "Message_has_been_edited_by": "संदेश को {{username}} द्वारा संपादित किया गया है", + "Message_has_been_edited_by_at": "संदेश को {{username}} द्वारा {{date}} पर संपादित किया गया है", + "Message_has_been_forwarded": "संदेश अग्रेषित कर दिया गया है", + "Message_has_been_pinned": "संदेश पिन कर दिया गया है", + "Message_has_been_starred": "संदेश तारांकित कर दिया गया है", + "Message_has_been_unpinned": "संदेश अनपिन कर दिया गया है", + "Message_has_been_unstarred": "संदेश अतारांकित कर दिया गया है", + "Message_HideType_au": "\"उपयोगकर्ता द्वारा जोड़े गए\" संदेशों को छिपाएँ", + "Message_HideType_added_user_to_team": "\"उपयोगकर्ता को टीम में जोड़ा गया\" संदेश छिपाएँ", + "Message_HideType_mute_unmute": "\"उपयोगकर्ता द्वारा म्यूट/अनम्यूट किए गए\" संदेशों को छुपाएं", + "Message_HideType_r": "\"कमरे का नाम बदला गया\" संदेश छिपाएँ", + "Message_HideType_rm": "\"संदेश हटाया गया\" संदेश छिपाएँ", + "Message_HideType_room_allowed_reacting": "\"कमरे में प्रतिक्रिया देने की अनुमति है\" संदेश छिपाएँ", + "Message_HideType_room_archived": "\"कक्ष संग्रहीत\" संदेश छिपाएँ", + "Message_HideType_room_changed_avatar": "\"कक्ष का अवतार बदल गया\" संदेश छिपाएँ", + "Message_HideType_room_changed_privacy": "\"कमरे का प्रकार बदल गया\" संदेश छिपाएँ", + "Message_HideType_room_changed_topic": "\"कक्ष का विषय बदल गया\" संदेश छिपाएँ", + "Message_HideType_room_disallowed_reacting": "\"कमरे में प्रतिक्रिया की अनुमति नहीं\" संदेश छिपाएँ", + "Message_HideType_room_enabled_encryption": "\"कक्ष एन्क्रिप्शन सक्षम\" संदेश छिपाएँ", + "Message_HideType_room_disabled_encryption": "\"कक्ष एन्क्रिप्शन अक्षम\" संदेश छिपाएँ", + "Message_HideType_room_set_read_only": "\"रूम सेट केवल पढ़ने के लिए\" संदेश छिपाएँ", + "Message_HideType_room_removed_read_only": "\"कमरा जोड़ा गया लेखन अनुमति\" संदेश छिपाएँ", + "Message_HideType_room_unarchived": "\"कक्ष अनासंग्रहीत\" संदेश छिपाएँ", + "Message_HideType_ru": "\"उपयोगकर्ता द्वारा निकाले गए\" संदेश छिपाएँ", + "Message_HideType_removed_user_from_team": "\"उपयोगकर्ता को टीम से निकाला गया\" संदेश छिपाएँ", + "Message_HideType_subscription_role_added": "\"क्या भूमिका निर्धारित थी\" संदेश छिपाएँ", + "Message_HideType_subscription_role_removed": "\"भूमिका अब परिभाषित नहीं\" संदेश छिपाएँ", + "Message_HideType_uj": "\"उपयोगकर्ता जुड़ें\" संदेश छिपाएँ", + "Message_HideType_ujt": "\"टीम में शामिल उपयोगकर्ता\" संदेश छिपाएँ", + "Message_HideType_ul": "\"उपयोगकर्ता छोड़ें\" संदेश छुपाएं", + "Message_HideType_ult": "\"उपयोगकर्ता बाएँ टीम\" संदेश छिपाएँ", + "Message_HideType_user_added_room_to_team": "\"उपयोगकर्ता द्वारा टीम में जोड़ा गया कमरा\" संदेश छिपाएँ", + "Message_HideType_user_converted_to_channel": "\"उपयोगकर्ता द्वारा एक चैनल में परिवर्तित टीम\" संदेशों को छुपाएं", + "Message_HideType_user_converted_to_team": "\"उपयोगकर्ता द्वारा टीम में परिवर्तित चैनल\" संदेशों को छुपाएं", + "Message_HideType_user_deleted_room_from_team": "\"उपयोगकर्ता द्वारा टीम से हटाया गया कमरा\" संदेश छिपाएँ", + "Message_HideType_user_removed_room_from_team": "\"उपयोगकर्ता ने टीम से कमरा हटा दिया\" संदेश छुपाएं", + "Message_HideType_changed_description": "\"कमरे का विवरण बदल गया\" संदेशों को छिपाएँ", + "Message_HideType_changed_announcement": "\"कक्ष घोषणा परिवर्तित में\" संदेश छिपाएँ", + "Message_HideType_ut": "\"उपयोगकर्ता सम्मिलित वार्तालाप\" संदेश छिपाएँ", + "Message_HideType_wm": "\"स्वागत\" संदेश छिपाएँ", + "Message_Id": "संदेश आईडी", + "Message_Ignored": "इस संदेश को नजरअंदाज कर दिया गया", + "message-impersonate": "अन्य उपयोगकर्ताओं का प्रतिरूपण करें", + "message-impersonate_description": "संदेश उपनाम का उपयोग करके अन्य उपयोगकर्ताओं का प्रतिरूपण करने की अनुमति", + "Message_info": "संदेश जानकारी", + "Message_KeepHistory": "प्रति संदेश संपादन इतिहास रखें", + "Message_MaxAll": "सभी संदेशों के लिए अधिकतम चैनल आकार", + "Message_MaxAllowedSize": "प्रति संदेश अधिकतम अनुमत वर्ण", + "Message_pinning": "संदेश पिन करना", + "message_pruned": "संदेश काट दिया गया", + "Message_QuoteChainLimit": "जंजीरदार उद्धरणों की अधिकतम संख्या", + "Message_Read_Receipt_Enabled": "पढ़ी गई रसीदें दिखाएँ", + "Message_Read_Receipt_Store_Users": "विस्तृत पठन प्राप्तियाँ", + "Message_Read_Receipt_Store_Users_Description": "प्रत्येक उपयोगकर्ता की पढ़ी गई रसीदें दिखाता है", + "Message_removed": "संदेश हटा दिया गया", + "Message_is_removed": "संदेश हटा दिया गया", + "Message_sent_by_email": "ईमेल द्वारा भेजा गया संदेश", + "Message_ShowDeletedStatus": "हटाई गई स्थिति दिखाएँ", + "Message_Formatting_Toolbox": "फ़ॉर्मेटिंग टूलबॉक्स", + "Message_composer_toolbox_primary_actions": "संगीतकार प्राथमिक क्रियाएँ", + "Message_composer_toolbox_secondary_actions": "संगीतकार माध्यमिक क्रियाएँ", + "Message_starring": "संदेश अभिनीत", + "Message_Time": "संदेश का समय", + "Message_TimeAndDateFormat": "समय और दिनांक प्रारूप", + "Message_TimeAndDateFormat_Description": "यह भी देखें: [Moment.js](http://momentjs.com/docs/#/displaying/format/)", + "Message_TimeFormat": "समय स्वरूप", + "Message_TimeFormat_Description": "यह भी देखें: [Moment.js](http://momentjs.com/docs/#/displaying/format/)", + "Message_too_long": "संदेश बहुत लंबा है", + "Message_UserId": "उपयोगकर्ता पहचान", + "Message_view_mode_info": "इससे स्क्रीन पर संदेशों द्वारा ली जाने वाली जगह की मात्रा बदल जाती है।", + "Message_VideoRecorderEnabled": "वीडियो रिकॉर्डर सक्षम", + "Message_Video_Recording_Disabled": "संदेश वीडियो रिकॉर्डिंग अक्षम की गई", + "MessageBox_view_mode": "संदेशबॉक्स दृश्य मोड", + "Message_VideoRecorderEnabledDescription": "'फ़ाइल अपलोड' सेटिंग्स के अंतर्गत 'वीडियो/वेबएम' फ़ाइलों को एक स्वीकृत मीडिया प्रकार होना आवश्यक है।", + "messages": "संदेशों", + "Messages": "संदेशों", + "Messages_selected": "संदेश चयनित", + "Messages_sent": "संदेश भेजे गए", + "Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here": "इनकमिंग वेबहुक पर भेजे गए संदेश यहां पोस्ट किए जाएंगे।", + "Meta": "मेटा", + "Meta_Description": "कस्टम मेटा गुण सेट करें.", + "Meta_custom": "कस्टम मेटा टैग", + "Meta_fb_app_id": "फेसबुक ऐप आईडी", + "Meta_google-site-verification": "Google साइट सत्यापन", + "Meta_language": "भाषा", + "Meta_msvalidate01": "MSValidate.01", + "Meta_robots": "रोबोटों", + "meteor_status_connected": "जुड़े हुए", + "meteor_status_connecting": "कनेक्ट हो रहा है...", + "meteor_status_failed": "सर्वर कनेक्शन विफल रहा", + "meteor_status_offline": "ऑफ़लाइन मोड।", + "meteor_status_reconnect_in": "एक सेकंड में पुनः प्रयास कर रहा हूँ...", + "meteor_status_try_now_offline": "पुनः कनेक्ट करें", + "meteor_status_try_now_waiting": "अब कोशिश करो", + "meteor_status_waiting": "सर्वर कनेक्शन की प्रतीक्षा में,", + "Method": "तरीका", + "Mic_on": "माइक ऑन", + "Microphone": "माइक्रोफ़ोन", + "Microphone_access_not_allowed": "माइक्रोफ़ोन एक्सेस की अनुमति नहीं थी, कृपया अपनी ब्राउज़र सेटिंग जांचें।", + "Mic_off": "माइक बंद", + "Min_length_is": "न्यूनतम लंबाई %s है", + "Minimum": "न्यूनतम", + "Minimum_balance": "न्यूनतम शेष", + "minute": "मिनट", + "minutes": "मिनट", + "Missing_configuration": "अनुपलब्ध कॉन्फ़िगरेशन", + "Mobex_sms_gateway_address": "मोबेक्स एसएमएस गेटवे पता", + "Mobex_sms_gateway_address_desc": "निर्दिष्ट पोर्ट के साथ आपकी मोबेक्स सेवा का आईपी या होस्ट। जैसे `http://192.168.1.1:1401` या `https://www.example.com:1401`", + "Mobex_sms_gateway_from_number": "से", + "Mobex_sms_gateway_from_number_desc": "लाइवचैट क्लाइंट को नया एसएमएस भेजते समय मूल पता/फोन नंबर", + "Mobex_sms_gateway_from_numbers_list": "एसएमएस भेजने के लिए नंबरों की सूची", + "Mobex_sms_gateway_from_numbers_list_desc": "बिल्कुल नए संदेश भेजने में उपयोग करने के लिए संख्याओं की अल्पविराम से अलग की गई सूची, उदाहरण के लिए। 123456789, 123456788, 123456888", + "Mobex_sms_gateway_password": "पासवर्ड", + "Mobex_sms_gateway_restful_address": "मोबेक्स एसएमएस रेस्ट एपीआई पता", + "Mobex_sms_gateway_restful_address_desc": "आपके Mobex REST API का IP या होस्ट। जैसे `http://192.168.1.1:8080` या `https://www.example.com:8080`", + "Mobex_sms_gateway_username": "उपयोगकर्ता नाम", + "Mobile": "गतिमान", + "Mobile_apps": "मोबाइल क्षुधा", + "Mobile_Description": "मोबाइल उपकरणों से अपने कार्यक्षेत्र से जुड़ने के लिए व्यवहार को परिभाषित करें।", + "mobile-upload-file": "मोबाइल उपकरणों पर फ़ाइल अपलोड करने की अनुमति दें", + "mobile-upload-file_description": "मोबाइल उपकरणों पर फ़ाइल अपलोड करने की अनुमति", "Mobile_Push_Notifications_Default_Alert": "मोबाइल सूचनाएं डिफ़ॉल्ट चेतावनी", + "Moderation": "संयम", + "Moderation_Show_reports": "रिपोर्ट दिखाएँ", + "Moderation_Go_to_message": "संदेश पर जाएँ", + "Moderation_Delete_message": "संदेश को हटाएं", + "Moderation_Dismiss_and_delete": "ख़ारिज करें और हटाएं", + "Moderation_Delete_this_message": "इस संदेश को हटा दें", + "Moderation_Message_context_header": "रिपोर्ट किए गए संदेश", + "Moderation_Message_deleted": "संदेश हटा दिया गया और रिपोर्ट खारिज कर दी गईं", + "Moderation_Messages_deleted": "संदेश हटा दिए गए और रिपोर्ट खारिज कर दी गईं", + "Moderation_Action_View_reports": "रिपोर्ट किए गए संदेश देखें", + "Moderation_Hide_reports": "रिपोर्ट छुपाएं", + "Moderation_Dismiss_all_reports": "सभी रिपोर्ट खारिज करें", + "Moderation_Deactivate_User": "उपयोगकर्ता को निष्क्रिय करें", + "Moderation_User_deactivated": "उपयोगकर्ता निष्क्रिय कर दिया गया", + "Moderation_Delete_all_messages": "सभी संदेश हटाएँ", + "Moderation_Dismiss_reports": "रिपोर्ट खारिज करें", + "Moderation_Duplicate_messages": "डुप्लिकेट किए गए संदेश", + "Moderation_Duplicate_messages_warning": "निम्नलिखित में कई कमरों में भेजे गए समान संदेश शामिल हो सकते हैं।", + "Moderation_Report_date": "रिपोर्ट तिथि", + "Moderation_Reported_message": "रिपोर्ट किया गया संदेश", + "Moderation_Reports_dismissed": "रिपोर्ट खारिज कर दी गईं", + "Moderation_Message_already_deleted": "संदेश पहले ही हटा दिया गया है", + "Moderation_Reset_user_avatar": "उपयोगकर्ता अवतार रीसेट करें", + "Moderation_See_messages": "संदेश देखें", + "Moderation_Avatar_reset_success": "अवतार रीसेट", + "Moderation_Dismiss_reports_confirm": "रिपोर्टें हटा दी जाएंगी और रिपोर्ट किया गया संदेश प्रभावित नहीं होगा.", + "Moderation_Dismiss_all_reports_confirm": "सभी रिपोर्टें हटा दी जाएंगी और रिपोर्ट किए गए संदेश प्रभावित नहीं होंगे.", + "Moderation_Are_you_sure_you_want_to_delete_this_message": "यह संदेश उसके संबंधित कक्ष से स्थायी रूप से हटा दिया जाएगा और रिपोर्ट खारिज कर दी जाएगी।", + "Moderation_Are_you_sure_you_want_to_reset_the_avatar": "उपयोगकर्ता अवतार को रीसेट करने से उनका वर्तमान अवतार स्थायी रूप से हट जाएगा।", + "Moderation_Are_you_sure_you_want_to_deactivate_this_user": "पुनः सक्रिय होने तक उपयोगकर्ता लॉग इन नहीं कर पाएगा। सभी रिपोर्ट किए गए संदेशों को उनके संबंधित कमरे से स्थायी रूप से हटा दिया जाएगा।", + "Moderation_Are_you_sure_you_want_to_delete_all_reported_messages_from_this_user": "इस उपयोगकर्ता के सभी रिपोर्ट किए गए संदेशों को उनके संबंधित कमरे से स्थायी रूप से हटा दिया जाएगा और रिपोर्ट खारिज कर दी जाएगी।", + "Moderation_User_deleted_warning": "जिस उपयोगकर्ता ने संदेश भेजा था वह अब मौजूद नहीं है या उसे हटा दिया गया है।", + "Monday": "सोमवार", + "Mongo_storageEngine": "मोंगो स्टोरेज इंजन", + "Mongo_version": "मानगो संस्करण", + "MongoDB": "MongoDB", + "MongoDB_Deprecated": "MongoDB अस्वीकृत", + "MongoDB_version_s_is_deprecated_please_upgrade_your_installation": "MongoDB संस्करण %s अप्रचलित है, कृपया अपना इंस्टालेशन अपग्रेड करें।", + "Monitor_added": "मॉनिटर जोड़ा गया", + "Monitor_new_and_suspicious_logins": "नए और संदिग्ध लॉगिन की निगरानी करें", + "Monitor_history_for_changes_on": "परिवर्तनों के लिए इतिहास की निगरानी करें", + "Monitor_removed": "मॉनिटर हटा दिया गया", + "Monitors": "पर नज़र रखता है", + "Monthly_Active_Users": "मासिक सक्रिय उपयोगकर्ता", + "More": "अधिक", + "More_channels": "अधिक चैनल", + "More_direct_messages": "अधिक प्रत्यक्ष संदेश", + "More_groups": "अधिक निजी समूह", + "More_unreads": "अधिक अपठित", + "More_options": "अधिक विकल्प", + "Most_popular_channels_top_5": "सर्वाधिक लोकप्रिय चैनल (शीर्ष 5)", + "Most_recent_updated": "सबसे ताज़ा अपडेट किया गया", + "Most_recent_requested": "सबसे हाल ही में अनुरोध किया गया", + "Move_beginning_message": "`%s` - संदेश की शुरुआत में जाएँ", + "Move_end_message": "`%s` - संदेश के अंत में जाएँ", + "Move_queue": "कतार में जाएँ", + "Msgs": "संदेश", + "multi": "बहु", + "Multi_line": "मल्टी लाइन", + "Multiple_monolith_instances_alert": "आप सक्रिय प्रीमियम लाइसेंस के बिना कई इंस्टेंसेस का संचालन कर रहे हैं - हो सकता है कि कुछ सुविधाएँ डिज़ाइन के अनुसार व्यवहार न करें", + "Mute": "आवाज़ बंद करना", + "Mute_and_dismiss": "म्यूट करें और ख़ारिज करें", + "Mute_all_notifications": "सभी सूचनाएं म्यूट करें", + "Mute_Focused_Conversations": "केंद्रित वार्तालापों को म्यूट करें", + "Mute_Group_Mentions": "@सभी और @यहां उल्लेखों को म्यूट करें", + "Mute_someone_in_room": "कमरे में किसी को म्यूट करें", + "Mute_user": "उपयोगकर्ता को म्यूट करें", + "Mute_microphone": "माइक्रोफ़ोन म्यूट करें", + "mute-user": "उपयोगकर्ता को म्यूट करें", + "mute-user_description": "उसी चैनल में अन्य उपयोगकर्ताओं को म्यूट करने की अनुमति", + "Muted": "म्यूट किए गए", + "My Data": "मेरी जानकारी", + "My_Account": "मेरा खाता", + "My_location": "मेरा स्थान", + "n_messages": "%s संदेश", + "N_new_messages": "%s नए संदेश", + "Name": "नाम", + "Name_cant_be_empty": "नाम खाली नहीं हो सकता", + "Name_of_agent": "एजेंट का नाम", + "Name_optional": "नाम: (वैकल्पिक)", + "Name_Placeholder": "कृपया अपना नाम दर्ज करें...", + "Navigation": "मार्गदर्शन", + "Navigation_bar": "नेविगेशन पट्टी", + "Navigation_bar_description": "नेविगेशन बार का परिचय - एक उच्च-स्तरीय नेविगेशन जो उपयोगकर्ताओं को उनकी आवश्यकता के अनुसार शीघ्रता से ढूंढने में मदद करने के लिए डिज़ाइन किया गया है। अपने कॉम्पैक्ट डिज़ाइन और सहज संगठन के साथ, यह सुव्यवस्थित साइडबार आवश्यक सॉफ़्टवेयर सुविधाओं और अनुभागों तक आसान पहुँच प्रदान करते हुए स्क्रीन स्थान को अनुकूलित करता है।", + "Navigation_History": "नेविगेशन इतिहास", + "Next": "अगला", + "Never": "कभी नहीं", + "New": "नया", + "New_Application": "नए आवेदन", + "New_Business_Hour": "नया व्यावसायिक घंटा", + "New_Call": "नई कॉल", + "New_Call_Premium_Only": "नई कॉल (केवल प्रीमियम योजनाएं)", + "New_chat_in_queue": "कतार में नई चैट", + "New_chat_priority": "प्राथमिकता बदली गई: {{user}} ने प्राथमिकता को {{priority}} में बदल दिया", + "New_chat_transfer": "नया चैट स्थानांतरण: {{transfer}}", + "New_chat_transfer_fallback": "फ़ॉलबैक विभाग में स्थानांतरित: {{fallback}}", + "New_contact": "नया कॉन्ट्रैक्ट", + "New_Custom_Field": "नया कस्टम फ़ील्ड", + "New_Department": "नया विभाग", + "New_discussion": "नई चर्चा", + "New_discussion_first_message": "आमतौर पर, चर्चा एक प्रश्न से शुरू होती है, जैसे \"मैं एक तस्वीर कैसे अपलोड करूं?\"", + "New_discussion_name": "चर्चा कक्ष के लिए एक सार्थक नाम", + "New_Email_Inbox": "नया ईमेल इनबॉक्स", + "New_encryption_password": "नया एन्क्रिप्शन पासवर्ड", + "New_integration": "नया एकीकरण", + "New_line_message_compose_input": "`%s` - संदेश लिखें इनपुट में नई पंक्ति", + "New_Livechat_offline_message_has_been_sent": "एक नया लाइवचैट ऑफ़लाइन संदेश भेजा गया है", + "New_logs": "नये लॉग", + "New_Message_Notification": "नया संदेश अधिसूचना", "New_messages": "नए संदेश", + "New_OTR_Chat": "नई ओटीआर चैट", + "New_password": "नया पासवर्ड", + "New_Password_Placeholder": "कृपया नया पासवर्ड दर्ज करें...", + "New_Priority": "नई प्राथमिकता", + "New_SLA_Policy": "नई एसएलए नीति", + "New_role": "नयी भूमिका", + "New_Room_Notification": "नये कक्ष की अधिसूचना", + "New_Tag": "नया टैग", + "New_Trigger": "नया ट्रिगर", + "New_Unit": "नई इकाई", + "New_users": "नए उपयोगकर्ता", + "New_version_available_(s)": "नया संस्करण उपलब्ध है (%s)", + "New_videocall_request": "नया वीडियो कॉल अनुरोध", + "New_visitor_navigation": "नया नेविगेशन: {{history}}", + "New_workspace_confirmed": "नए कार्यक्षेत्र की पुष्टि की गई", + "New_workspace": "नया कार्यक्षेत्र", + "Newer_than": "से नया", + "Newer_than_may_not_exceed_Older_than": "\"इससे नया\" \"इससे पुराना\" से अधिक नहीं हो सकता", + "Nickname": "उपनाम", + "Nickname_Placeholder": "अपना उपनाम दर्ज करें...", "No": "नहीं", + "no-active-video-conf-provider": "**कॉन्फ़्रेंस कॉल सक्षम नहीं है**: कार्यस्थान व्यवस्थापक को पहले कॉन्फ़्रेंस कॉल सुविधा सक्षम करने की आवश्यकता है।", + "No_available_agents_to_transfer": "स्थानांतरण के लिए कोई एजेंट उपलब्ध नहीं है", + "No_app_matches": "कोई ऐप मेल नहीं खाता", + "No_app_matches_for": "कोई ऐप इससे मेल नहीं खाता", + "No_apps_installed": "कोई ऐप्स इंस्टॉल नहीं", + "No_Canned_Responses": "कोई डिब्बाबंद प्रतिक्रिया नहीं", + "No_Canned_Responses_Yet": "अभी तक कोई डिब्बाबंद प्रतिक्रिया नहीं", + "No_Canned_Responses_Yet-description": "अक्सर पूछे जाने वाले प्रश्नों के त्वरित और सुसंगत उत्तर प्रदान करने के लिए डिब्बाबंद प्रतिक्रियाओं का उपयोग करें।", + "No_channels_in_team": "इस टीम में कोई चैनल नहीं", + "No_agents_yet": "अभी तक कोई एजेंट नहीं", + "No_agents_yet_description": "अपने दर्शकों से जुड़ने और अनुकूलित ग्राहक सेवा प्रदान करने के लिए एजेंट जोड़ें।", + "No_channels_yet": "आप अभी तक किसी भी चैनल का हिस्सा नहीं हैं", + "No_chats_yet": "अभी तक कोई चैट नहीं", + "No_chats_yet_description": "आपकी सभी चैट यहां दिखाई देंगी.", + "No_calls_yet": "अभी तक कोई कॉल नहीं", + "No_calls_yet_description": "आपकी सभी कॉलें यहां दिखाई देंगी.", + "No_contacts_yet": "अभी तक कोई संपर्क नहीं", + "No_contacts_yet_description": "सभी संपर्क यहां दिखाई देंगे.", + "No_custom_fields_yet": "अभी तक कोई कस्टम फ़ील्ड नहीं", + "No_custom_fields_yet_description": "संपर्क या टिकट विवरण में कस्टम फ़ील्ड जोड़ें या उन्हें नए आगंतुकों के लिए लाइव चैट पंजीकरण फॉर्म पर प्रदर्शित करें।", + "No_departments_yet": "अभी तक कोई विभाग नहीं", + "No_departments_yet_description": "एजेंटों को विभागों में व्यवस्थित करें, टिकट कैसे अग्रेषित किए जाएं यह निर्धारित करें और उनके प्रदर्शन की निगरानी करें।", + "No_managers_yet": "अभी तक कोई प्रबंधक नहीं", + "No_managers_yet_description": "प्रबंधकों के पास सभी ओमनीचैनल नियंत्रणों तक पहुंच होती है, वे निगरानी करने और कार्रवाई करने में सक्षम होते हैं।", + "No_content_was_provided": "कोई सामग्री उपलब्ध नहीं करायी गयी", + "No_data_found": "डाटा प्राप्त नहीं हुआ", + "No_data_available_for_the_selected_period": "चयनित period के लिए कोई डेटा उपलब्ध नहीं है", + "No_direct_messages_yet": "कोई सीधा संदेश नहीं.", + "No_Discussions_found": "कोई चर्चा नहीं मिली", + "No_discussions_yet": "अभी तक कोई चर्चा नहीं", + "No_emojis_found": "कोई इमोजी नहीं मिला", + "No_Encryption": "कोई एन्क्रिप्शन नहीं", + "No_files_found": "कोई फाईल नहीं मिली", + "No_files_left_to_download": "डाउनलोड करने के लिए कोई फ़ाइल नहीं बची", + "No_groups_yet": "आपके पास अभी तक कोई निजी समूह नहीं है.", + "No_history": "कोई इतिहास नहीं", + "No_installed_app_matches": "कोई भी इंस्टॉल किया गया ऐप मेल नहीं खाता", + "No_integration_found": "प्रदत्त आईडी से कोई एकीकरण नहीं मिला।", + "No_Limit": "कोई सीमा नहीं", + "No_livechats": "आपके पास कोई लाइवचैट नहीं है", + "No_marketplace_matches_for": "इसके लिए कोई मार्केटप्लेस मेल नहीं खाता", + "No_members_found": "कोई सदस्य नहीं मिला", + "No_mentions_found": "कोई उल्लेख नहीं मिला", + "No_messages_found_to_prune": "काट-छाँट करने के लिए कोई संदेश नहीं मिला", + "No_messages_yet": "अभी तक कोई संदेश नहीं", + "No_monitors_yet": "अभी तक कोई मॉनिटर नहीं है", + "No_monitors_yet_description": "मॉनिटर्स के पास ओमनीचैनल का आंशिक नियंत्रण होता है। वे विभाग के विश्लेषण और उन्हें सौंपी गई व्यावसायिक इकाइयों की गतिविधियों को देख सकते हैं।", + "No_tags_yet": "अभी तक कोई टैग नहीं", + "No_tags_yet_description": "संबंधित वार्तालापों को व्यवस्थित करना और ढूंढना आसान बनाने के लिए टिकटों में टैग जोड़ें।", + "No_triggers_yet": "अभी तक कोई ट्रिगर नहीं", + "No_triggers_yet_description": "ट्रिगर ऐसी घटनाएँ हैं जो लाइव चैट विजेट को खोलने और स्वचालित रूप से संदेश भेजने का कारण बनती हैं।", + "No_units_yet": "अभी तक कोई इकाई नहीं", + "No_units_yet_description": "विभागों को समूहीकृत करने और उन्हें बेहतर ढंग से प्रबंधित करने के लिए इकाइयों का उपयोग करें।", + "No_pages_yet_Try_hitting_Reload_Pages_button": "अभी तक कोई पेज नहीं. \"रीलोड पेज\" बटन दबाने का प्रयास करें।", + "No_pinned_messages": "कोई पिन किया हुआ संदेश नहीं", + "No_previous_chat_found": "कोई पिछली चैट नहीं मिली", + "No_release_information_provided": "कोई रिलीज़ सूचना नहीं दी गई", + "No_requested_apps": "कोई अनुरोधित ऐप्स नहीं", + "No_requests": "कोई अनुरोध नहीं", + "No_results_found": "कोई परिणाम नहीं मिला", + "No_results_found_for": "इसके लिए कोई परिणाम नहीं मिला:", + "No_SLA_policies_yet": "अभी तक कोई SLA नीति नहीं", + "No_SLA_policies_yet_description": "अनुमानित प्रतीक्षा समय के आधार पर ओमनीचैनल कतारों का क्रम बदलने के लिए SLA नीतियों का उपयोग करें।", + "No_snippet_messages": "कोई स्निपेट नहीं", + "No_starred_messages": "कोई तारांकित संदेश नहीं", + "No_such_command": "ऐसा कोई आदेश नहीं: `/{{command}}`", + "No_Threads": "कोई सूत्र नहीं मिला", + "no-videoconf-provider-app": "**कॉन्फ़्रेंस कॉल उपलब्ध नहीं है**: कॉन्फ़्रेंस कॉल ऐप्स को कार्यस्थल व्यवस्थापक द्वारा रॉकेट.चैट मार्केटप्लेस में इंस्टॉल किया जा सकता है।", + "Nobody_available": "कोई भी उपलब्ध नहीं है", + "Node_version": "नोड संस्करण", + "None": "कोई नहीं", + "Nonprofit": "ग़ैर-लाभकारी", + "Not_authorized": "अधिकृत नहीं हैं", + "Normal": "सामान्य", + "Not_Available": "उपलब्ध नहीं है", + "Not_assigned": "सौंपा नहीं गया है", + "Not_enough_data": "पर्याप्त डेटा नहीं", + "Not_following": "पालन नहीं करते हुए", + "Not_Following": "पालन नहीं करते हुए", + "Not_found_or_not_allowed": "नहीं मिला या अनुमति नहीं है", + "Not_Imported_Messages_Title": "निम्नलिखित संदेश सफलतापूर्वक आयात नहीं किए गए", + "Not_in_channel": "चैनल में नहीं", + "Not_likely": "संभावना नहीं", + "Not_started": "शुरू नहीं", + "Not_verified": "सत्यापित नहीं है", + "Not_Visible_To_Workspace": "कार्यस्थल पर दिखाई नहीं देता", + "Nothing": "कुछ नहीं", + "Nothing_found": "कुछ भी नहीं मिला", + "Notice_that_public_channels_will_be_public_and_visible_to_everyone": "ध्यान दें कि सार्वजनिक चैनल सार्वजनिक होंगे और सभी को दिखाई देंगे।", + "Notification_Desktop_Default_For": "के लिए डेस्कटॉप सूचनाएं दिखाएं", + "Notification_Push_Default_For": "के लिए पुश सूचनाएँ भेजें", + "Notification_RequireInteraction": "डेस्कटॉप अधिसूचना को ख़ारिज करने के लिए सहभागिता की आवश्यकता है", + "Notification_RequireInteraction_Description": "केवल क्रोम ब्राउज़र संस्करण> 50 के साथ काम करता है। जब तक उपयोगकर्ता इसके साथ इंटरैक्ट नहीं करता तब तक डेस्कटॉप अधिसूचना को अनिश्चित काल तक दिखाने के लिए *requireInteraction* पैरामीटर का उपयोग करता है।", + "Notifications": "सूचनाएं", + "Notifications_Max_Room_Members": "सभी संदेश सूचनाओं को अक्षम करने से पहले मैक्स रूम के सदस्य", + "Notifications_Max_Room_Members_Description": "जब सभी संदेशों के लिए सूचनाएं अक्षम हो जाती हैं तो कमरे में सदस्यों की अधिकतम संख्या। उपयोगकर्ता व्यक्तिगत आधार पर सभी सूचनाएं प्राप्त करने के लिए अभी भी प्रति कमरा सेटिंग बदल सकते हैं। (0 अक्षम करने के लिए)", + "Notifications_Muted_Description": "यदि आप सब कुछ म्यूट करना चुनते हैं, तो उल्लेखों को छोड़कर, नए संदेश आने पर आपको सूची में रूम हाइलाइट नहीं दिखाई देगा। सूचनाओं को म्यूट करने से सूचना सेटिंग ओवरराइड हो जाएंगी.", + "Notifications_Preferences": "अधिसूचना प्राथमिकताएँ", + "Notifications_Sound_Volume": "सूचनाएं ध्वनि की मात्रा", + "Notify_active_in_this_room": "इस कक्ष में सक्रिय उपयोगकर्ताओं को सूचित करें", + "Notify_all_in_this_room": "इस कमरे में सभी को सूचित करें", + "Notify_Calendar_Events": "कैलेंडर घटनाओं को सूचित करें", + "Now_Its_Visible_For_Everyone": "अब यह सबके लिए दृश्यमान है", + "Now_Its_Visible_Only_For_Admins": "अब यह केवल व्यवस्थापकों के लिए दृश्यमान है", + "NPS_survey_enabled": "एनपीएस सर्वेक्षण सक्षम करें", + "NPS_survey_enabled_Description": "सभी उपयोगकर्ताओं के लिए एनपीएस सर्वेक्षण चलाने की अनुमति दें। सर्वेक्षण शुरू होने से 2 महीने पहले व्यवस्थापकों को एक अलर्ट प्राप्त होगा", + "NPS_survey_is_scheduled_to-run-at__date__for_all_users": "एनपीएस सर्वेक्षण सभी उपयोगकर्ताओं के लिए {{date}} पर चलने के लिए निर्धारित है। 'एडमिन > जनरल > एनपीएस' पर सर्वेक्षण को बंद करना संभव है", + "Default_Timezone_For_Reporting": "रिपोर्टिंग के लिए डिफ़ॉल्ट समयक्षेत्र", + "Default_Timezone_For_Reporting_Description": "डिफ़ॉल्ट समयक्षेत्र सेट करता है जिसका उपयोग डैशबोर्ड दिखाते समय या ईमेल भेजते समय किया जाएगा", + "Default_Server_Timezone": "सर्वर समय क्षेत्र", + "Default_Custom_Timezone": "कस्टम समय क्षेत्र", + "Default_User_Timezone": "उपयोगकर्ता का वर्तमान समय क्षेत्र", + "Num_Agents": "#एजेंट", + "Number_in_seconds": "सेकंड में नंबर", + "Number_of_events": "घटनाओं की संख्या", + "Number_of_federated_servers": "फ़ेडरेटेड सर्वरों की संख्या", + "Number_of_federated_users": "फ़ेडरेटेड उपयोगकर्ताओं की संख्या", + "Number_of_messages": "संदेशों की संख्या", + "Number_of_most_recent_chats_estimate_wait_time": "अनुमानित प्रतीक्षा समय की गणना करने के लिए हाल की चैट की संख्या", + "Number_of_most_recent_chats_estimate_wait_time_description": "यह संख्या अंतिम सेवा वाले कमरों की संख्या को परिभाषित करती है जिनका उपयोग कतार प्रतीक्षा समय की गणना के लिए किया जाएगा।", + "Number_of_users_autocomplete_suggestions": "उपयोगकर्ताओं के स्वत: पूर्ण सुझावों की संख्या", + "OAuth": "OAuth", + "OAuth_Description": "केवल उपयोगकर्ता नाम और पासवर्ड से परे प्रमाणीकरण विधियों को कॉन्फ़िगर करें।", + "OAuth_Application": "OAuth आवेदन", + "Objects": "वस्तुओं", + "Off": "बंद", + "Off_the_record_conversation": "ऑफ-द-रिकॉर्ड बातचीत", + "Off_the_record_conversation_is_not_available_for_your_browser_or_device": "ऑफ-द-रिकॉर्ड बातचीत आपके ब्राउज़र या डिवाइस के लिए उपलब्ध नहीं है।", + "Office_Hours": "कार्यालय period", + "Office_hours_enabled": "कार्यालय समय सक्षम", + "Office_hours_updated": "कार्यालय समय अद्यतन किया गया", + "offline": "ऑफलाइन", + "Offline": "ऑफलाइन", + "Offline_DM_Email": "सीधा संदेश ईमेल विषय", + "Offline_Email_Subject_Description": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं:\n - एप्लिकेशन नाम, यूआरएल, उपयोगकर्ता नाम और रूमनाम के लिए क्रमशः `[साइट_नाम]`, `[साइट_यूआरएल]`, `[उपयोगकर्ता]` और `[कक्ष]`।", + "Offline_form": "ऑफलाइन फॉर्म", + "Offline_form_unavailable_message": "ऑफ़लाइन फॉर्म अनुपलब्ध संदेश", + "Offline_Link_Message": "संदेश पर जाएँ", + "Offline_Mention_All_Email": "सभी ईमेल विषय का उल्लेख करें", + "Offline_Mention_Email": "ईमेल विषय का उल्लेख करें", + "Offline_message": "ऑफ़लाइन संदेश", + "Offline_Message": "ऑफ़लाइन संदेश", + "Offline_Message_Use_DeepLink": "डीप लिंक यूआरएल फ़ॉर्मेट का उपयोग करें", + "Offline_messages": "ऑफ़लाइन संदेश", + "Offline_success_message": "ऑफ़लाइन सफलता संदेश", + "Offline_unavailable": "ऑफ़लाइन अनुपलब्ध", + "Ok": "ठीक है", + "Old Colors": "पुराने रंग", + "Old Colors (minor)": "पुराने रंग (मामूली)", + "Older_than": "से अधिक पुराना", + "Omnichannel": "सर्वचैनल", + "Omnichannel_Description": "ग्राहकों के साथ एक ही स्थान से संवाद करने के लिए ओमनीचैनल सेट करें, भले ही वे आपके साथ कैसे भी जुड़े हों।", + "Omnichannel_Directory": "ओमनीचैनल निर्देशिका", + "Omnichannel_appearance": "ओम्नीचैनल उपस्थिति", + "Omnichannel_calculate_dispatch_service_queue_statistics": "ओमनीचैनल प्रतीक्षा कतार आँकड़ों की गणना और प्रेषण करें", + "Omnichannel_calculate_dispatch_service_queue_statistics_Description": "स्थिति और अनुमानित प्रतीक्षा समय जैसे प्रतीक्षा कतार आँकड़ों को संसाधित करना और भेजना। यदि *लाइवचैट चैनल* उपयोग में नहीं है, तो इस सेटिंग को अक्षम करने और सर्वर को अनावश्यक प्रक्रियाएं करने से रोकने की अनुशंसा की जाती है।", + "Omnichannel_Contact_Center": "ओमनीचैनल संपर्क केंद्र", + "Omnichannel_contact_manager_routing": "संपर्क प्रबंधक को नई बातचीत सौंपें", + "Omnichannel_contact_manager_routing_Description": "यह सेटिंग असाइन किए गए संपर्क प्रबंधक को एक चैट आवंटित करती है, जब तक कि चैट शुरू होने पर संपर्क प्रबंधक ऑनलाइन होता है", + "Omnichannel_External_Frame": "बाहरी फ़्रेम", + "Omnichannel_External_Frame_Enabled": "बाहरी फ़्रेम सक्षम", + "Omnichannel_External_Frame_Encryption_JWK": "एन्क्रिप्शन कुंजी (JWK)", + "Omnichannel_External_Frame_Encryption_JWK_Description": "यदि प्रदान किया गया है तो यह प्रदान की गई कुंजी के साथ उपयोगकर्ता के टोकन को एन्क्रिप्ट करेगा और बाहरी सिस्टम को टोकन तक पहुंचने के लिए डेटा को डिक्रिप्ट करने की आवश्यकता होगी", + "Omnichannel_External_Frame_URL": "बाहरी फ़्रेम यूआरएल", + "omnichannel_priority_change_history": "प्राथमिकता बदली गई: {{user}} ने प्राथमिकता को {{priority}} में बदल दिया", + "omnichannel_sla_change_history": "SLA नीति परिवर्तित: {{user}} ने SLA नीति को {{sla}} में बदल दिया", + "Omnichannel_enable_department_removal": "विभाग निष्कासन सक्षम करें", + "Omnichannel_enable_department_removal_alert": "हटाए गए विभागों को पुनर्स्थापित नहीं किया जा सकता, हम इसके बजाय विभाग को संग्रहीत करने की अनुशंसा करते हैं।", + "Omnichannel_Reports_Status_Open": "खुला", + "Omnichannel_Reports_Status_Closed": "बंद किया हुआ", + "Omnichannel_Reports_Channels_Empty_Subtitle": "यह चार्ट सबसे अधिक उपयोग किए जाने वाले चैनल दिखाता है.", + "Omnichannel_Reports_Departments_Empty_Subtitle": "यह चार्ट उन विभागों को प्रदर्शित करता है जो सबसे अधिक वार्तालाप प्राप्त करते हैं।", + "Omnichannel_Reports_Status_Empty_Subtitle": "बातचीत शुरू होते ही यह चार्ट अपडेट हो जाएगा.", + "Omnichannel_Reports_Tags_Empty_Subtitle": "यह चार्ट सबसे अधिक उपयोग किये जाने वाले टैग दिखाता है।", + "Omnichannel_Reports_Agents_Empty_Subtitle": "यह चार्ट प्रदर्शित करता है कि कौन से एजेंट सबसे अधिक मात्रा में वार्तालाप प्राप्त करते हैं।", + "Omnichannel_Reports_Summary": "अपने ऑपरेशन के बारे में जानकारी हासिल करें और अपने मेट्रिक्स निर्यात करें।", + "On": "पर", + "on-hold-livechat-room": "ऑन होल्ड ओमनीचैनल रूम", + "on-hold-livechat-room_description": "ओमनीचैनल रूम को होल्ड पर रखने की अनुमति", + "on-hold-others-livechat-room": "अन्य ओम्नीचैनल कक्ष को होल्ड पर रखें", + "on-hold-others-livechat-room_description": "अन्य सर्वचैनल कक्ष को रोकने की अनुमति", + "On_Hold": "होल्ड पर", + "On_Hold_Chats": "होल्ड पर", + "On_Hold_conversations": "बातचीत रुकी हुई है", + "online": "ऑनलाइन", + "Online": "ऑनलाइन", + "Only_authorized_users_can_write_new_messages": "केवल अधिकृत उपयोगकर्ता ही नये संदेश लिख सकते हैं", + "Only_authorized_users_can_react_to_messages": "केवल अधिकृत उपयोगकर्ता ही संदेशों पर प्रतिक्रिया दे सकते हैं", + "Only_from_users": "केवल इन उपयोगकर्ताओं की सामग्री को छाँटें (प्रत्येक की सामग्री को छाँटने के लिए खाली छोड़ दें)", + "Only_Members_Selected_Department_Can_View_Channel": "इस चैनल पर केवल चयनित विभाग के सदस्य ही चैट देख सकते हैं", + "Only_On_Desktop": "डेस्कटॉप मोड (केवल डेस्कटॉप पर एंटर के साथ भेजता है)", + "Only_works_with_chrome_version_greater_50": "केवल Chrome ब्राउज़र संस्करण > 50 के साथ काम करता है", + "Only_you_can_see_this_message": "यह संदेश केवल आप ही देख सकते हैं", + "Only_invited_users_can_acess_this_channel": "केवल आमंत्रित उपयोगकर्ता ही इस चैनल तक पहुंच सकते हैं", + "Oops_page_not_found": "उफ़, पेज नहीं मिला", + "Oops!": "उफ़", + "Person_Or_Channel": "व्यक्ति या चैनल", + "Open": "खुला", + "Open_call": "खुला आवाहन", + "Open_call_in_new_tab": "नए टैब में कॉल खोलें", + "Open_channel_user_search": "`%s` - चैनल/उपयोगकर्ता खोज खोलें", + "Open_conversations": "वार्तालाप खोलें", + "Open_Days": "खुले दिन", + "Open_days_of_the_week": "सप्ताह के खुले दिन", + "Open_Dialpad": "डायलपैड खोलें", + "Open_directory": "निर्देशिका खोलें", + "Open_Livechats": "बातचीत प्रगति पर है", + "Open_Outlook": "आउटलुक खोलें", + "Open_settings": "खुली सेटिंग", + "Open-source_conference_call_solution": "ओपन-सोर्स कॉन्फ़्रेंस कॉल समाधान।", + "Open_thread": "थ्रेड खोलें", + "Opened": "खुल गया", + "Opened_in_a_new_window": "एक नई विंडो में खोला गया.", + "Opens_a_channel_group_or_direct_message": "एक चैनल, समूह या सीधा संदेश खोलता है", + "Optional": "वैकल्पिक", + "optional": "वैकल्पिक", "Options": "विकल्प", + "or": "या", + "Or_Copy_And_Paste_This_URL_Into_A_Tab_Of_Your_Browser": "या इस यूआरएल को कॉपी करके अपने ब्राउज़र के एक टैब में पेस्ट करें", + "Or_talk_as_anonymous": "या गुमनाम बनकर बात करें", + "Order": "आदेश", + "Organization_Email": "संगठन ईमेल", + "Organization_Info": "संगठन की जानकारी", + "Organization_Name": "संगठन का नाम", + "Organization_Type": "संगठन का प्रकार", + "Original": "मूल", + "OS": "आप", + "OS_Arch": "ओएस आर्क", + "OS_Cpus": "ओएस सीपीयू गणना", + "OS_Freemem": "ओएस फ्री मेमोरी", + "OS_Loadavg": "ओएस लोड औसत", + "OS_Platform": "ओएस प्लेटफार्म", + "OS_Release": "ओएस रिलीज", + "OS_Totalmem": "ओएस कुल मेमोरी", + "OS_Type": "ओएस प्रकार", + "OS_Uptime": "ओएस अपटाइम", + "Other": "अन्य", + "others": "अन्य", + "Others": "अन्य", + "OTR": "ओटीआर", + "OTR_unavailable_for_federation": "फ़ेडरेटेड कमरों के लिए ओटीआर उपलब्ध नहीं है", + "OTR_Description": "ऑफ-द-रिकॉर्ड चैट सुरक्षित, निजी होती हैं और समाप्त होने के बाद गायब हो जाती हैं।", + "OTR_Chat_Declined_Title": "ओटीआर चैट आमंत्रण अस्वीकृत", + "OTR_Chat_Declined_Description": "%s ने OTR चैट आमंत्रण अस्वीकार कर दिया. गोपनीयता सुरक्षा के लिए सभी संबंधित सिस्टम संदेशों सहित स्थानीय कैश हटा दिया गया था।", + "OTR_Chat_Error_Title": "कुंजी रीफ़्रेश विफल होने के कारण चैट समाप्त हो गई", + "OTR_Chat_Error_Description": "गोपनीयता सुरक्षा के लिए सभी संबंधित सिस्टम संदेशों सहित स्थानीय कैश हटा दिया गया था।", + "OTR_Chat_Timeout_Title": "ओटीआर चैट आमंत्रण समाप्त हो गया", + "OTR_Chat_Timeout_Description": "%s समय पर ओटीआर चैट आमंत्रण स्वीकार करने में विफल रहा। गोपनीयता सुरक्षा के लिए सभी संबंधित सिस्टम संदेशों सहित स्थानीय कैश हटा दिया गया था।", + "OTR_Enable_Description": "2 उपयोगकर्ताओं के बीच सीधे संदेशों में ऑफ-द-रिकॉर्ड (ओटीआर) संदेशों का उपयोग करने का विकल्प सक्षम करें। ओटीआर संदेशों को सर्वर पर रिकॉर्ड नहीं किया जाता है और दो उपयोगकर्ताओं के बीच सीधे आदान-प्रदान और एन्क्रिप्ट किया जाता है।", + "OTR_message": "ओटीआर संदेश", + "OTR_is_only_available_when_both_users_are_online": "ओटीआर केवल तभी उपलब्ध होता है जब दोनों उपयोगकर्ता ऑनलाइन हों", + "outbound-voip-calls": "आउटबाउंड वीओआईपी कॉल", + "outbound-voip-calls_description": "आउटबाउंड वीओआईपी कॉल की अनुमति", + "Out_of_seats": "सीटों से बाहर", + "Outgoing": "जावक", + "Outgoing_WebHook": "निवर्तमान वेबहुक", + "Outgoing_WebHook_Description": "वास्तविक समय में Rocket.Chat से डेटा प्राप्त करें।", + "Outlook_authentication": "आउटलुक प्रमाणीकरण", + "Outlook_authentication_disabled": "आउटलुक प्रमाणीकरण अक्षम किया गया", + "Outlook_authentication_description": "इस मशीन में संग्रहीत किसी भी आउटलुक क्रेडेंशियल को साफ़ करने के लिए इसे अक्षम करें।", + "Outlook_calendar": "आउटलुक कैलेंडर", + "Outlook_calendar_event": "आउटलुक कैलेंडर इवेंट", + "Outlook_calendar_settings": "आउटलुक कैलेंडर सेटिंग्स", + "Outlook_Calendar": "आउटलुक कैलेंडर", "Outlook_Calendar_Enabled": "सक्रिय", + "Outlook_Calendar_Exchange_Url": "एक्सचेंज यूआरएल", + "Outlook_Calendar_Exchange_Url_Description": "ईडब्ल्यूएस एपीआई के लिए होस्ट यूआरएल।", + "Outlook_Calendar_Outlook_Url": "आउटलुक यूआरएल", + "Outlook_Calendar_Outlook_Url_Description": "आउटलुक वेब ऐप लॉन्च करने के लिए यूआरएल का उपयोग किया जाता है।", + "Output_format": "आउटपुट स्वरूप", + "Outlook_Sync_Failed": "आउटलुक इवेंट लोड करने में विफल.", + "Outlook_Sync_Success": "आउटलुक इवेंट सिंक्रनाइज़।", + "Override_URL_to_which_files_are_uploaded_This_url_also_used_for_downloads_unless_a_CDN_is_given": "जिस URL पर फ़ाइलें अपलोड की गई हैं उसे ओवरराइड करें। इस यूआरएल का उपयोग डाउनलोड के लिए भी किया जाता है जब तक कि सीडीएन न दिया गया हो", + "Override_Destination_Channel": "मुख्य पैरामीटर में गंतव्य चैनल को अधिलेखित करने की अनुमति दें", + "Owner": "मालिक", + "Play": "खेल", + "Page_not_exist_or_not_permission": "पेज मौजूद नहीं है या हो सकता है कि आपके पास एक्सेस की अनुमति न हो", + "Page_not_found": "पृष्ठ नहीं मिला", + "Page_title": "पृष्ठ का शीर्षक", + "Page_URL": "पेज यूआरएल", + "Pages": "पृष्ठों", + "Parent_channel_doesnt_exist": "चैनल मौजूद नहीं है.", + "Participants": "प्रतिभागियों", + "Password": "पासवर्ड", + "Password_Change_Disabled": "आपके Rocket.Chat व्यवस्थापक ने पासवर्ड बदलना अक्षम कर दिया है", + "Password_Changed_Description": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं:\n - अस्थायी पासवर्ड के लिए `[पासवर्ड]`।\n - `[नाम]`, `[fname]`, `[lname]` क्रमशः उपयोगकर्ता के पूर्ण नाम, प्रथम नाम या अंतिम नाम के लिए।\n - `[ईमेल]` उपयोगकर्ता के ईमेल के लिए।\n - एप्लिकेशन नाम और यूआरएल के लिए क्रमशः `[Site_Name]` और `[Site_URL]`।", + "Password_Changed_Email_Subject": "[साइट_नाम] - पासवर्ड बदला गया", + "Password_changed_section": "पासवर्ड बदला गया", + "Password_changed_successfully": "पासवर्ड सफलतापूर्वक बदला गया", + "Password_History": "पासवर्ड इतिहास", + "Password_History_Amount": "पासवर्ड इतिहास की लंबाई", + "Password_History_Amount_Description": "उपयोगकर्ताओं को पुन: उपयोग करने से रोकने के लिए हाल ही में उपयोग किए गए पासवर्ड की मात्रा।", + "Password_must_have": "पासवर्ड होना चाहिए:", + "Password_Policy": "पासवर्ड नीति", + "Password_Policy_Aria_Description": "इसके नीचे पासवर्ड आवश्यकता सत्यापन सूचीबद्ध है", + "Password_must_meet_the_complexity_requirements": "पासवर्ड को जटिलता आवश्यकताओं को पूरा करना होगा।", + "Password_to_access": "प्रवेश हेतु पासवर्ड", + "Passwords_do_not_match": "सांकेतिक शब्द मेल नहीं खाते", + "Past_Chats": "पिछली चैट", + "Paste_here": "यहां चिपकाएं...", + "Paste": "पेस्ट करें", + "Pause": "विराम", + "Paste_error": "क्लिपबोर्ड से पढ़ने में त्रुटि", + "Paid_Apps": "सशुल्क ऐप्स", + "Payload": "पेलोड", + "PDF": "पीडीएफ", + "pdf_success_message": "पीडीएफ प्रतिलेख सफलतापूर्वक तैयार किया गया", + "pdf_error_message": "पीडीएफ प्रतिलेख उत्पन्न करने में त्रुटि", + "Peer_Password": "सहकर्मी पासवर्ड", + "People": "लोग", + "Permalink": "स्थायी लिंक", + "Permissions": "अनुमतियां", + "Personal_Access_Tokens": "व्यक्तिगत पहुँच टोकन", + "Pexip_Premium_only": "पेक्सिप (केवल प्रीमियम)", + "Phone": "फ़ोन", + "Phone_call": "फोन कॉल", + "Phone_Number": "फ़ोन नंबर", + "Thank_you_exclamation_mark": "धन्यवाद!", + "Thank_You_For_Choosing_RocketChat": "रॉकेट.चैट चुनने के लिए धन्यवाद!", + "Phone_already_exists": "फ़ोन पहले से मौजूद है", + "Phone_number": "फ़ोन नंबर", + "PID": "पीआईडी", + "Pin": "नत्थी करना", + "Pin_Message": "संदेश पिन करें", + "pin-message": "संदेश पिन करें", + "pin-message_description": "किसी संदेश को किसी चैनल में पिन करने की अनुमति", + "Pinned_a_message": "एक संदेश पिन किया गया:", + "Pinned_Messages": "पिन किए गए संदेश", + "Pinned_messages_unavailable_for_federation": "फ़ेडरेटेड रूम के लिए पिन किए गए संदेश उपलब्ध नहीं हैं।", + "pinning-not-allowed": "पिन करने की अनुमति नहीं है", + "PiwikAdditionalTrackers": "अतिरिक्त पिविक साइटें", + "PiwikAdditionalTrackers_Description": "यदि आप एक ही डेटा को विभिन्न वेबसाइटों में ट्रैक करना चाहते हैं, तो निम्नलिखित प्रारूप में अतिरिक्त पिविक वेबसाइट यूआरएल और साइटआईडी दर्ज करें: `[ { \"ट्रैकरयूआरएल\": \"https://my.piwik.domain2/\", \"साइटआईडी\": 42 } , { \"trackerURL\" : \"https://my.piwik.domain3/\", \"siteId\" : 15 } ]`", + "PiwikAnalytics_cookieDomain": "सभी उपडोमेन", + "PiwikAnalytics_cookieDomain_Description": "सभी उपडोमेन पर विज़िटर ट्रैक करें", + "PiwikAnalytics_domains": "आउटगोइंग लिंक छुपाएं", + "PiwikAnalytics_domains_Description": "'आउटलिंक्स' रिपोर्ट में, ज्ञात उपनाम यूआरएल पर क्लिक छुपाएं। कृपया प्रति पंक्ति एक डोमेन डालें और किसी विभाजक का उपयोग न करें।", + "PiwikAnalytics_prependDomain": "डोमेन को प्रीपेन्ड करें", + "PiwikAnalytics_prependDomain_Description": "ट्रैकिंग करते समय साइट डोमेन को पृष्ठ शीर्षक से जोड़ें", + "PiwikAnalytics_siteId_Description": "इस साइट की पहचान करने के लिए उपयोग की जाने वाली साइट आईडी। उदाहरण: 17", + "PiwikAnalytics_url_Description": "यूआरएल जहां पिविक स्थित है, उसमें पिछला स्लैश शामिल करना सुनिश्चित करें। उदाहरण: `https://piwik.rocket.chat/`", + "Placeholder_for_email_or_username_login_field": "ईमेल या उपयोगकर्ता नाम लॉगिन फ़ील्ड के लिए प्लेसहोल्डर", + "Placeholder_for_password_login_confirm_field": "पासवर्ड लॉगिन फ़ील्ड के लिए प्लेसहोल्डर की पुष्टि करें", + "Placeholder_for_password_login_field": "पासवर्ड लॉगिन फ़ील्ड के लिए प्लेसहोल्डर", + "Platform_Windows": "खिड़कियाँ", + "Platform_Linux": "लिनक्स", + "Platform_Mac": "मैक", + "Please_add_a_comment": "कृपया एक टिप्पणी जोड़ें", + "Please_add_a_comment_to_close_the_room": "कृपया कमरा बंद करने के लिए एक टिप्पणी जोड़ें", "Please_answer_survey": "कृपया इस चैट के बारे में त्वरित सर्वेक्षण का उत्तर देने के लिए एक क्षण लें", + "Please_enter_usernames": "कृपया उपयोक्तानाम दर्ज करें...", + "please_enter_valid_domain": "कृपया एक मान्य डोमेन दर्ज करें", + "Please_enter_value_for_url": "कृपया अपने अवतार के यूआरएल के लिए एक मान दर्ज करें।", + "Please_enter_your_new_password_below": "कृपया अपना पासवर्ड नीचे डालें:", + "Please_enter_your_password": "अपना पासवर्ड दर्ज करें", + "Please_fill_a_label": "कृपया एक लेबल भरें", + "Please_fill_a_name": "कृपया एक नाम भरें", + "Please_fill_a_token_name": "कृपया एक वैध टोकन नाम भरें", + "Please_fill_a_username": "कृपया एक उपयोक्तानाम भरें", + "Please_fill_all_the_information": "कृपया सारी जानकारी भरें", + "Please_fill_an_email": "कृपया एक ईमेल भरें", "Please_fill_name_and_email": "कृपया नाम और ईमेल भरें", + "Please_fill_out_reason_for_report": "कृपया रिपोर्ट का कारण भरें", + "Please_select_an_user": "कृपया एक उपयोगकर्ता चुनें", + "Please_select_enabled_yes_or_no": "कृपया सक्षम के लिए एक विकल्प चुनें", + "Please_select_visibility": "कृपया एक दृश्यता चुनें", + "Please_wait": "कृपया प्रतीक्षा करें", + "Please_wait_activation": "कृपया प्रतीक्षा करें, इसमें कुछ समय लग सकता है.", + "Please_wait_while_OTR_is_being_established": "कृपया ओटीआर स्थापित होने तक प्रतीक्षा करें", + "Please_wait_while_your_account_is_being_deleted": "कृपया तब तक प्रतीक्षा करें जब तक आपका खाता हटाया जा रहा हो...", + "Please_wait_while_your_profile_is_being_saved": "कृपया तब तक प्रतीक्षा करें जब तक आपकी प्रोफ़ाइल सहेजी जा रही हो...", + "Policies": "नीतियों", + "Pool": "पूल", + "Port": "पत्तन", + "Post_as": "के रूप में पोस्ट करें", + "Post_to": "को पोस्ट", + "Post_to_Channel": "चैनल पर पोस्ट करें", + "Post_to_s_as_s": "%s को %s के रूप में पोस्ट करें", + "post-readonly": "पोस्ट केवल पढ़ने के लिए", + "post-readonly_description": "केवल पढ़ने योग्य चैनल में संदेश पोस्ट करने की अनुमति", + "Powered_by_JoyPixels": "जॉयपिक्सल्स द्वारा संचालित", + "Powered_by_RocketChat": "रॉकेट.चैट द्वारा संचालित", + "powers-of-ten": "दस की शक्तियाँ", + "powers-of-two": "दो की शक्तियाँ", + "increments-of-two": "दो की वृद्धि", + "Preferences": "पसंद", + "Preferences_saved": "प्राथमिकताएँ सहेजी गईं", + "Preparing_data_for_import_process": "आयात प्रक्रिया के लिए डेटा तैयार करना", + "Preparing_list_of_channels": "चैनलों की सूची तैयार की जा रही है", + "Preparing_list_of_messages": "संदेशों की सूची तैयार की जा रही है", + "Preparing_list_of_users": "उपभोक्ताओं की सूची तैयार की जा रही है", + "Presence": "उपस्थिति", + "Preview": "पूर्व दर्शन", + "preview-c-room": "सार्वजनिक चैनल का पूर्वावलोकन करें", + "preview-c-room_description": "शामिल होने से पहले किसी सार्वजनिक चैनल की सामग्री देखने की अनुमति", + "Previous_month": "पिछला महीना", + "Previous_week": "पिछला सप्ताह", + "Price": "कीमत", + "Priorities": "प्राथमिकताओं", + "Priority": "प्राथमिकता", + "Priority_saved": "प्राथमिकता सहेजी गई", + "Priority_removed": "प्राथमिकता हटा दी गई", + "Priorities_restored": "प्राथमिकताएँ बहाल की गईं", + "Privacy": "गोपनीयता", + "Privacy_Policy": "गोपनीयता नीति", + "Privacy_policy": "गोपनीयता नीति", + "Privacy_summary": "गोपनीयता सारांश", + "Private": "निजी", + "private": "निजी", + "Private_channels": "निजी चैनल", + "Private_Apps": "निजी ऐप्स", + "Private_Channel": "निजी चैनल", + "Private_Channels": "निजी चैनल", + "Private_Chats": "निजी चैट", + "Private_Group": "निजी समूह", + "Private_Groups": "निजी समूह", + "Private_Groups_list": "निजी समूहों की सूची", + "Private_Team": "निजी टीम", + "Productivity": "उत्पादकता", + "Profile": "प्रोफ़ाइल", + "Profile_details": "प्रोफ़ाइल विवरण", + "Profile_picture": "प्रोफ़ाइल फोटो", + "Profile_saved_successfully": "प्रोफ़ाइल सफलतापूर्वक सहेजी गई", + "Prometheus": "प्रोमेथियस", + "Prometheus_API_User_Agent": "एपीआई: उपयोगकर्ता एजेंट को ट्रैक करें", + "Prometheus_Garbage_Collector": "नोडजेएस जीसी लीजिए", + "Prometheus_Garbage_Collector_Alert": "निष्क्रिय करने के लिए पुनरारंभ करना आवश्यक है", + "Prometheus_Reset_Interval": "अंतराल रीसेट करें (एमएस)", + "Protocol": "शिष्टाचार", + "Prune": "कांट - छांट", + "Prune_finished": "प्रून ख़त्म", + "Prune_Messages": "संदेशों की छँटाई करें", + "Prune_Modal": "क्या आप वाकई इन संदेशों की काट-छाँट करना चाहते हैं? काटे गए संदेशों को पुनर्प्राप्त नहीं किया जा सकता.", + "Prune_Warning_after": "यह %s के बाद %s में सभी %s को हटा देगा।", + "Prune_Warning_all": "यह %s में सभी %s को हटा देगा!", + "Prune_Warning_before": "यह %s से पहले %s में सभी %s को हटा देगा।", + "Prune_Warning_between": "यह %s में %s और %s के बीच के सभी %s को हटा देगा।", + "Pruning_files": "फ़ाइलें काट-छाँट की जा रही हैं...", + "Pruning_messages": "संदेशों में काट-छाँट की जा रही है...", "Public": "जनता", + "public": "जनता", + "Public_Channel": "सार्वजनिक चैनल", + "Public_Channels": "सार्वजनिक चैनल", + "Public_Community": "सार्वजनिक समुदाय", + "Public_URL": "सार्वजनिक यूआरएल", + "Purchase_for_free": "मुफ़्त में खरीदारी करें", + "Purchase_for_price": "$%s के लिए खरीदारी", + "Purchased": "खरीदी", + "Push": "धकेलना", + "Push_Description": "मोबाइल उपकरणों का उपयोग करने वाले कार्यक्षेत्र सदस्यों के लिए पुश सूचनाओं को सक्षम और कॉन्फ़िगर करें।", + "Push_Notifications": "सूचनाएं धक्का", + "Push_apn_cert": "APN Cert", + "Push_apn_dev_cert": "APN Dev Cert", + "Push_apn_dev_key": "एपीएन देव कुंजी", + "Push_apn_dev_passphrase": "एपीएन देव पासफ़्रेज़", + "Push_apn_key": "एपीएन कुंजी", + "Push_apn_passphrase": "एपीएन पासफ़्रेज़", "Push_enable": "सक्षम करें", + "Push_enable_gateway": "गेटवे सक्षम करें", + "Push_enable_gateway_Description": "**चेतावनी:** आपको इस सेटिंग को सक्षम करने और हमारे गेटवे का उपयोग करने के लिए अपने सर्वर (सेटअप विज़ार्ड> संगठन जानकारी> रजिस्टर सर्वर) और हमारी गोपनीयता शर्तों (सेटअप विज़ार्ड> क्लाउड जानकारी> क्लाउड सेवा गोपनीयता शर्तें अनुबंध) को पंजीकृत करने की आवश्यकता है। भले ही यह सेटिंग उस पर मौजूद हो, यदि सर्वर पंजीकृत नहीं है तो **नहीं** काम करेगा।", + "Push_gateway": "द्वार", + "Push_gateway_description": "एकाधिक गेटवे निर्दिष्ट करने के लिए एकाधिक लाइनों का उपयोग किया जा सकता है", + "Push_gcm_api_key": "जीसीएम एपीआई कुंजी", + "Push_gcm_project_number": "जीसीएम परियोजना संख्या", + "Push_production": "उत्पादन", + "Push_request_content_from_server": "Apple और Google (और सक्षम होने पर गेटवे) से संदेश सामग्री छिपाएँ", + "Push_request_content_from_server_Description": "संदेश सामग्री को पुश अधिसूचना डेटा में शामिल करके Apple/Google के सामने उजागर करने के बजाय, केवल एक संदेश आईडी पुश करें। मोबाइल क्लाइंट गतिशील रूप से सर्वर से सामग्री लाएगा और इसे प्रदर्शित करने से पहले अधिसूचना को अपडेट करेगा। एपीआई त्रुटि की स्थिति में, यह \"आपके पास एक नया संदेश है\" प्रदर्शित करेगा। यह सेटिंग केवल प्रीमियम योजना पर प्रभावी होती है।", + "Push_Setting_Requires_Restart_Alert": "इस मान को बदलने के लिए Rocket.Chat को पुनः आरंभ करने की आवश्यकता है।", + "Push_show_message": "अधिसूचना में संदेश दिखाएँ", + "Push_show_username_room": "अधिसूचना में चैनल/समूह/उपयोगकर्ता नाम दिखाएँ", + "Push_test_push": "परीक्षा", + "Query": "सवाल", + "Query_description": "यह निर्धारित करने के लिए अतिरिक्त शर्तें कि किन उपयोगकर्ताओं को ईमेल भेजना है। सदस्यता समाप्त करने वाले उपयोगकर्ता स्वचालित रूप से क्वेरी से हटा दिए जाते हैं। यह एक वैध JSON होना चाहिए. उदाहरण: \"{\"createdAt\":{\"$gt\":{\"$date\": \"2015-01-01T00:00:00.000Z\"}}}\"", + "Query_is_not_valid_JSON": "क्वेरी मान्य JSON नहीं है", + "Queue": "कतार", + "Queued": "कतारबद्ध", + "Queues": "पूंछ", + "Queue_delay_timeout": "कतार प्रसंस्करण विलंब समयबाह्य", + "Queue_Time": "कतार समय", + "Queue_management": "कतार प्रबंधन", + "Quick_reactions": "त्वरित प्रतिक्रियाएँ", + "Quick_reactions_description": "जब आपका माउस संदेश पर होता है तो सबसे अधिक उपयोग की जाने वाली तीन प्रतिक्रियाओं तक आसान पहुंच मिलती है", + "quote": "उद्धरण", + "Quote": "उद्धरण", + "Random": "Random", + "Rate Limiter": "दर सीमक", + "Rate Limiter_Description": "साइबर हमलों और स्क्रैपिंग को रोकने के लिए अपने सर्वर द्वारा भेजे गए या प्राप्त अनुरोधों की दर को नियंत्रित करें।", + "Rate_Limiter_Limit_RegisterUser": "उपयोगकर्ता को पंजीकृत करने के लिए डिफ़ॉल्ट नंबर दर सीमक पर कॉल करता है", + "Rate_Limiter_Limit_RegisterUser_Description": "एपीआई रेट लिमिटर अनुभाग में परिभाषित समय सीमा के भीतर अनुमत अंतिम बिंदुओं (आरईएसटी और रीयल-टाइम एपीआई) को पंजीकृत करने वाले उपयोगकर्ता के लिए डिफ़ॉल्ट कॉल की संख्या।", + "React_when_read_only": "प्रतिक्रिया करने की अनुमति दें", + "React_when_read_only_changed_successfully": "केवल पढ़ने के लिए सफलतापूर्वक परिवर्तन होने पर प्रतिक्रिया करने की अनुमति दें", + "Reacted_with": "के साथ प्रतिक्रिया व्यक्त की", + "Reactions": "प्रतिक्रियाओं", + "Read_by": "द्वारा पढ़ें", + "Read_only": "केवल पढ़ने के लिए", + "Read_Receipts": "रसीदें पढ़ें", + "Readability": "पठनीयता", + "This_room_is_read_only": "यह कमरा केवल पढ़ने के लिए है", + "Only_people_with_permission_can_send_messages_here": "केवल अनुमति प्राप्त लोग ही यहां संदेश भेज सकते हैं", + "Read_only_changed_successfully": "केवल पढ़ने के लिए सफलतापूर्वक बदला गया", + "Read_only_channel": "केवल पढ़ने के लिए चैनल", + "Read_only_group": "केवल पढ़ने योग्य समूह", + "Real_Estate": "रियल एस्टेट", + "Real_Time_Monitoring": "वास्तविक समय में निगरानी", + "RealName_Change_Disabled": "आपके Rocket.Chat व्यवस्थापक ने नाम बदलना अक्षम कर दिया है", + "Reason_To_Join": "शामिल होने का कारण", + "Receive_alerts": "अलर्ट प्राप्त करें", + "Receive_Group_Mentions": "@सभी और @यहाँ उल्लेख प्राप्त करें", + "Receive_login_notifications": "लॉगिन सूचनाएं प्राप्त करें", + "Receive_Login_Detection_Emails": "लॉगिन पहचान ईमेल प्राप्त करें", + "Receive_Login_Detection_Emails_Description": "हर बार आपके खाते पर नए लॉगिन का पता चलने पर एक ईमेल प्राप्त करें।", + "Recent_Import_History": "हाल का आयात इतिहास", + "Record": "अभिलेख", + "Records": "अभिलेख", + "recording": "रिकॉर्डिंग", + "Redirect_URI": "यूआरआई को पुनर्निर्देशित करें", + "Redirect_URL_does_not_match": "रीडायरेक्ट यूआरएल मेल नहीं खाता", + "Refresh": "ताज़ा करना", + "Refresh_keys": "कुंजियाँ ताज़ा करें", + "Refresh_oauth_services": "OAuth सेवाएँ ताज़ा करें", + "Refresh_your_page_after_install_to_enable_screen_sharing": "स्क्रीन शेयरिंग सक्षम करने के लिए इंस्टॉल के बाद अपने पेज को रीफ्रेश करें", + "Refreshing": "रिफ्रेशिंग", + "Regenerate_codes": "कोड पुन: उत्पन्न करें", + "Regexp_validation": "नियमित अभिव्यक्ति द्वारा सत्यापन", + "Register": "पंजीकरण करवाना", + "Register_new_account": "एक नया खाता रजिस्टर करे", + "Register_Server": "सर्वर पंजीकृत करें", + "Register_Server_Info": "Rocket.Chat Technologies Corp. द्वारा उपलब्ध कराए गए पूर्व-कॉन्फ़िगर गेटवे और प्रॉक्सी का उपयोग करें।", + "Register_Server_Opt_In": "उत्पाद और सुरक्षा अद्यतन", + "Register_Server_Registered": "पहुंच के लिए पंजीकरण करें", + "Register_Server_Registered_I_Agree": "मैं इससे सहमत हूं", + "Register_Server_Registered_Livechat": "लाइवचैट ओमनीचैनल प्रॉक्सी", + "Register_Server_Registered_Marketplace": "ऐप्स बाज़ार", + "Register_Server_Registered_OAuth": "सामाजिक नेटवर्क के लिए OAuth प्रॉक्सी", + "Register_Server_Registered_Push_Notifications": "मोबाइल पुश नोटिफिकेशन गेटवे", + "Register_Server_Standalone": "स्टैंडअलोन रखें, आपको इसकी आवश्यकता होगी", + "Register_Server_Standalone_Own_Certificates": "अपने स्वयं के प्रमाणपत्रों के साथ मोबाइल ऐप्स को पुनः संकलित करें", + "Register_Server_Standalone_Service_Providers": "सेवा प्रदाताओं के साथ खाते बनाएँ", + "Register_Server_Standalone_Update_Settings": "पूर्व-कॉन्फ़िगर की गई सेटिंग्स को अपडेट करें", + "Register_Server_Terms_Alert": "कृपया पंजीकरण पूरा करने की शर्तों से सहमत हों", + "register-on-cloud": "क्लाउड पर रजिस्टर करें", + "register-on-cloud_description": "क्लाउड पर पंजीकरण करने की अनुमति", + "Registration": "पंजीकरण", + "Registration_Succeeded": "पंजीकरण सफल हुआ", + "Registration_via_Admin": "व्यवस्थापक के माध्यम से पंजीकरण", + "Regular_Expressions": "नियमित अभिव्यक्ति", + "Reject_call": "कॉल अस्वीकार करें", + "Release": "मुक्त करना", + "Releases": "विज्ञप्ति", + "Religious": "धार्मिक", + "Reload": "पुनः लोड करें", + "Reload_page": "पृष्ठ पुनः लोड करें", + "Reload_Pages": "पेज पुनः लोड करें", + "Remember_my_credentials": "मेरी साख याद रखें", + "Remove": "निकालना", + "Remove_Admin": "व्यवस्थापक हटाएँ", + "Remove_Association": "एसोसिएशन हटाएँ", + "Remove_as_leader": "नेता पद से हटाओ", + "Remove_as_moderator": "मॉडरेटर के रूप में हटाएँ", + "Remove_as_owner": "स्वामी के रूप में हटाएँ", + "remove-canned-responses": "डिब्बाबंद प्रत्युत्तर हटाएँ", + "remove-canned-responses_description": "डिब्बाबंद प्रत्युत्तरों को हटाने की अनुमति", + "Remove_Channel_Links": "चैनल लिंक हटाएँ", + "Remove_custom_oauth": "कस्टम OAuth हटाएँ", + "Remove_from_room": "कमरे से निकालो", + "Remove_from_team": "टीम से हटाओ", + "Remove_last_admin": "अंतिम व्यवस्थापक को हटाया जा रहा है", + "Remove_someone_from_room": "किसी को कमरे से बाहर निकालें", + "remove-closed-livechat-room": "बंद ओमनीचैनल कक्ष हटाएँ", + "remove-closed-livechat-room_description": "बंद ऑम्नीचैनल रूम को हटाने की अनुमति", + "remove-closed-livechat-rooms": "सभी बंद ओमनीचैनल कमरे हटाएँ", + "remove-closed-livechat-rooms_description": "सभी बंद ओमनीचैनल कमरों को हटाने की अनुमति", + "remove-livechat-department": "ओमनीचैनल विभाग हटाएँ", + "remove-livechat-department_description": "सर्वचैनल विभागों को हटाने की अनुमति", + "remove-slackbridge-links": "स्लैकब्रिज लिंक हटाएँ", + "remove-slackbridge-links_description": "स्लैकब्रिज लिंक हटाने की अनुमति", + "remove-team-channel": "टीम चैनल हटाएँ", + "remove-team-channel_description": "किसी टीम के चैनल को हटाने की अनुमति", + "remove-user": "उपयोगकर्ता को हटाएँ", + "remove-user_description": "किसी उपयोगकर्ता को कमरे से निकालने की अनुमति", + "Removed": "निकाला गया", + "Removed_User": "उपयोगकर्ता को हटा दिया गया", + "Removed__roomName__from_this_team": "इस टीम से #{{roomName}} हटा दिया गया", + "Removed__username__from_team": "@{{user_removed}} को इस टीम से हटा दिया गया", + "Removed__roomName__from_the_team": "इस टीम से #{{roomName}} हटा दिया गया", + "Removed__username__from_the_team": "@{{user_removed}} को इस टीम से हटा दिया गया", + "Replay": "REPLAY", + "Replied_on": "पर उत्तर दिया", + "Replies": "जवाब", + "Reply": "जवाब", + "Reply_in_direct_message": "सीधे संदेश में उत्तर दें", + "Reply_in_thread": "थ्रेड में उत्तर दें", + "Reply_via_Email": "ईमेल के माध्यम से उत्तर दें", + "ReplyTo": "को उत्तर", + "Report": "प्रतिवेदन", + "Reports": "रिपोर्टों", + "Report_Abuse": "दुरुपयोग होने की सूचना दें", + "Report_exclamation_mark": "प्रतिवेदन!", + "Report_has_been_sent": "रिपोर्ट भेज दी गई है", + "Report_Number": "रिपोर्ट संख्या", + "Report_this_message_question_mark": "इस संदेश की रिपोर्ट करें?", + "Report_User": "उपयोगकर्ता को रिपोर्ट करें", + "Reporting": "रिपोर्टिंग", + "Request": "अनुरोध", + "Request_comment_when_closing_conversation": "बातचीत बंद करते समय टिप्पणी का अनुरोध करें", + "Request_comment_when_closing_conversation_description": "यदि सक्षम किया गया है, तो एजेंट को बातचीत बंद होने से पहले एक टिप्पणी सेट करनी होगी।", + "Request_tag_before_closing_chat": "बातचीत बंद करने से पहले टैग का अनुरोध करें", + "request": "अनुरोध", + "requests": "अनुरोध", + "Requests": "अनुरोध", + "Requested": "का अनुरोध किया", + "Requested_apps_will_appear_here": "अनुरोधित ऐप्स यहां दिखाई देंगे", + "request-pdf-transcript": "पीडीएफ प्रतिलेख का अनुरोध करें", + "request-pdf-transcript_description": "किसी दिए गए ओमनीचैनल कक्ष के लिए पीडीएफ प्रतिलेख का अनुरोध करने की अनुमति", + "Requested_At": "पर अनुरोध किया गया", + "Requested_By": "द्वारा अनुरोध किया गया", + "Require": "ज़रूरत होना", + "Required": "आवश्यक", + "required": "आवश्यक", + "Require_all_tokens": "सभी टोकन की आवश्यकता है", + "Require_any_token": "किसी भी टोकन की आवश्यकता है", + "Require_password_change": "पासवर्ड परिवर्तन की आवश्यकता है", + "Resend_verification_email": "सत्यापन ईमेल पुनः भेजे", + "Reset": "रीसेट", + "Reset_priorities": "प्राथमिकताएँ रीसेट करें", + "Reset_Connection": "कनेक्शन रीसेट करें", + "Reset_E2E_Key": "E2E कुंजी रीसेट करें", + "Reset_password": "पासवर्ड रीसेट", + "Reset_section_settings": "डिफॉल्ट्स का पुनःस्थापन", + "Reset_TOTP": "टीओटीपी रीसेट करें", + "reset-other-user-e2e-key": "अन्य उपयोगकर्ता E2E कुंजी रीसेट करें", + "Responding": "जवाब", + "Response_description_post": "खाली बॉडी या खाली टेक्स्ट प्रॉपर्टी वाले बॉडी को आसानी से नजरअंदाज कर दिया जाएगा। गैर-200 प्रतिक्रियाओं का उचित संख्या में पुनः प्रयास किया जाएगा। ऊपर निर्दिष्ट उपनाम और अवतार का उपयोग करके एक प्रतिक्रिया पोस्ट की जाएगी। आप उपरोक्त उदाहरण के अनुसार इन सूचनाओं को ओवरराइड कर सकते हैं।", + "Response_description_pre": "यदि हैंडलर चैनल में प्रतिक्रिया वापस पोस्ट करना चाहता है, तो निम्नलिखित JSON को प्रतिक्रिया के मुख्य भाग के रूप में वापस किया जाना चाहिए:", + "Restart": "पुनः आरंभ करें", + "Restart_the_server": "सर्वर पुनः प्रारंभ करें", + "restart-server": "सर्वर पुनः प्रारंभ करें", + "restart-server_description": "सर्वर को पुनरारंभ करने की अनुमति", + "Results": "परिणाम", + "Resume": "फिर शुरू करना", + "Retail": "खुदरा", + "Retention_setting_changed_successfully": "अवधारण नीति सेटिंग सफलतापूर्वक बदल दी गई", + "RetentionPolicy": "अवधारण नीति", + "RetentionPolicy_Advanced_Precision": "उन्नत अवधारण नीति कॉन्फ़िगरेशन का उपयोग करें", + "RetentionPolicy_Advanced_Precision_Cron": "उन्नत अवधारण नीति क्रॉन का उपयोग करें", + "RetentionPolicy_Advanced_Precision_Cron_Description": "क्रॉन जॉब एक्सप्रेशन द्वारा परिभाषित प्रून टाइमर को कितनी बार चलाना चाहिए। इसे अधिक सटीक मान पर सेट करने से तेज़ रिटेंशन टाइमर वाले चैनल बेहतर काम करते हैं, लेकिन बड़े समुदायों पर अतिरिक्त प्रसंस्करण शक्ति खर्च हो सकती है।", + "RetentionPolicy_AppliesToChannels": "चैनलों पर लागू होता है", + "RetentionPolicy_AppliesToDMs": "सीधे संदेशों पर लागू होता है", + "RetentionPolicy_AppliesToGroups": "निजी समूहों पर लागू होता है", + "RetentionPolicy_Description": "आपके कार्यक्षेत्र में पुराने संदेशों और फ़ाइलों की स्वचालित रूप से छंटाई करें।", + "RetentionPolicy_DoNotPruneDiscussion": "चर्चा संदेशों की काट-छाँट न करें", + "RetentionPolicy_DoNotPrunePinned": "पिन किए गए संदेशों की काट-छांट न करें", + "RetentionPolicy_DoNotPruneThreads": "धागों की काट-छाँट न करें", + "RetentionPolicy_Enabled": "सक्रिय", + "RetentionPolicy_ExcludePinned": "पिन किए गए संदेशों को बाहर निकालें", + "RetentionPolicy_FilesOnly": "केवल फ़ाइलें हटाएँ", + "RetentionPolicy_FilesOnly_Description": "केवल फ़ाइलें हटाई जाएंगी, संदेश स्वयं यथावत रहेंगे।", + "RetentionPolicy_MaxAge": "अधिकतम संदेश आयु", + "RetentionPolicy_MaxAge_Channels": "चैनलों में अधिकतम संदेश आयु", + "RetentionPolicy_MaxAge_Description": "इस मान से पुराने सभी संदेशों को दिनों में छाँटें", + "RetentionPolicy_MaxAge_DMs": "प्रत्यक्ष संदेशों में अधिकतम संदेश आयु", + "RetentionPolicy_MaxAge_Groups": "निजी समूहों में अधिकतम संदेश आयु", + "RetentionPolicy_Precision": "टाइमर परिशुद्धता", + "RetentionPolicy_Precision_Description": "प्रून टाइमर कितनी बार चलना चाहिए. इसे अधिक सटीक मान पर सेट करने से तेज़ रिटेंशन टाइमर वाले चैनल बेहतर काम करते हैं, लेकिन बड़े समुदायों पर अतिरिक्त प्रसंस्करण शक्ति खर्च हो सकती है।", + "RetentionPolicyRoom_Enabled": "पुराने संदेशों को स्वचालित रूप से छाँटें", + "RetentionPolicyRoom_ExcludePinned": "पिन किए गए संदेशों को बाहर निकालें", + "RetentionPolicyRoom_FilesOnly": "केवल फाइलों की छँटाई करें, संदेश रखें", + "RetentionPolicyRoom_MaxAge": "अधिकतम संदेश आयु दिनों में (डिफ़ॉल्ट: {{max}})", + "RetentionPolicyRoom_OverrideGlobal": "वैश्विक प्रतिधारण नीति को ओवरराइड करें", + "RetentionPolicyRoom_ReadTheDocs": "ध्यान रहें! अत्यधिक सावधानी के बिना इन सेटिंग्स में बदलाव करने से सभी संदेश इतिहास नष्ट हो सकते हैं। कृपया यहां सुविधा चालू करने से पहले दस्तावेज़ पढ़ें।", + "Retry": "पुन: प्रयास करें", + "Return_to_home": "घर पर वापस", + "Return_to_previous_page": "पिछले पेज पर लौटें", + "Return_to_the_queue": "कतार में वापस लौटें", + "Review_devices": "समीक्षा करें कि डिवाइस कब और कहाँ से कनेक्ट हो रहे हैं", + "Ringing": "बज", + "Ringtones_and_visual_indicators_notify_people_of_incoming_calls": "रिंगटोन और दृश्य संकेतक लोगों को आने वाली कॉल के बारे में सूचित करते हैं।", + "Robot_Instructions_File_Content": "robots.txt फ़ाइल सामग्री", + "Root": "जड़", + "Required_action": "आवश्यक क्रिया", + "Default_Referrer_Policy": "डिफ़ॉल्ट रेफ़रर नीति", + "Default_Referrer_Policy_Description": "यह 'रेफ़रर' हेडर को नियंत्रित करता है जो अन्य सर्वर से एम्बेडेड मीडिया का अनुरोध करते समय भेजा जाता है। अधिक जानकारी के लिए, [एमडीएन से यह लिंक](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) देखें। याद रखें, इसे प्रभावी बनाने के लिए पूरे पृष्ठ को ताज़ा करना आवश्यक है", + "No_feature_to_preview": "पूर्वावलोकन करने की कोई सुविधा नहीं", + "No_Referrer": "रेफर न करें", + "No_Referrer_When_Downgrade": "डाउनग्रेड करते समय कोई रेफरर नहीं", + "Notes": "टिप्पणियाँ", + "Origin": "मूल", + "Origin_When_Cross_Origin": "उत्पत्ति जब क्रॉस उत्पत्ति", + "Same_Origin": "वही मूल", + "Strict_Origin": "सख्त उत्पत्ति", + "Strict_Origin_When_Cross_Origin": "क्रॉस मूल जब सख्त मूल", + "UIKit_Interaction_Timeout": "ऐप प्रतिक्रिया देने में विफल रहा है. कृपया पुनः प्रयास करें या अपने व्यवस्थापक से संपर्क करें", + "Unsafe_Url": "असुरक्षित यूआरएल", + "Rocket_Chat_Alert": "रॉकेट.चैट अलर्ट", + "Role": "भूमिका", + "Roles": "भूमिकाएँ", + "Role_Editing": "भूमिका संपादन", + "Role_Mapping": "भूमिका मानचित्रण", + "Role_removed": "भूमिका हटा दी गई", + "Room": "कमरा", + "room_allowed_reacting": "{{user_by}} द्वारा प्रतिक्रिया करते हुए कमरे की अनुमति दी गई", + "room_allowed_reactions": "अनुमत प्रतिक्रियाएँ", + "Room_announcement_changed_successfully": "कक्ष की घोषणा सफलतापूर्वक बदल दी गई", + "Room_archivation_state": "राज्य", + "Room_archivation_state_false": "सक्रिय", + "Room_archivation_state_true": "संग्रहीत", + "Room_archived": "कक्ष संग्रहीत", + "room_changed_announcement": "कमरे की घोषणा को बदलकर: {{room_announcement}} द्वारा {{user_by}} कर दिया गया है।", + "room_changed_avatar": "कमरे का अवतार {{user_by}} द्वारा बदला गया", + "room_avatar_changed": "बदला हुआ कमरे का अवतार", + "room_changed_description": "कमरे का विवरण इस प्रकार बदला गया: {{room_description}} द्वारा {{user_by}}", + "room_changed_privacy": "कमरे का प्रकार बदलकर: {{room_type}} द्वारा {{user_by}} कर दिया गया है।", + "room_changed_topic": "कमरे का विषय इस प्रकार बदला गया: {{room_topic}} द्वारा {{user_by}}", + "room_changed_type": "कमरा बदलकर {{room_type}} कर दिया गया", + "room_changed_topic_to": "कमरे का विषय बदलकर {{room_topic}} कर दिया गया", + "Room_default_change_to_private_will_be_default_no_more": "यह एक डिफ़ॉल्ट चैनल है और इसे निजी समूह में बदलने से यह डिफ़ॉल्ट चैनल नहीं रहेगा। क्या आपकी आगे बढ़ने की इच्छा है?", + "Room_description_changed_successfully": "कमरे का विवरण सफलतापूर्वक बदला गया", + "room_disallowed_reacting": "{{user_by}} द्वारा प्रतिक्रिया व्यक्त करते हुए कमरा अस्वीकृत कर दिया गया", + "room_disallowed_reactions": "अस्वीकृत प्रतिक्रियाएँ", + "Room_Edit": "कक्ष संपादित करें", + "Room_has_been_archived": "कमरा संग्रहीत कर लिया गया है", + "Room_has_been_converted": "कमरा परिवर्तित कर दिया गया है", + "Room_has_been_created": "कक्ष बनाया गया है", + "Room_has_been_removed": "कमरा हटा दिया गया है", + "Room_has_been_unarchived": "कमरा अनारक्षित कर दिया गया है", + "Room_Info": "कमरे की जानकारी", + "room_is_blocked": "यह कमरा अवरुद्ध है", + "room_account_deactivated": "यह खाता निष्क्रिय कर दिया गया है", + "room_is_read_only": "यह कमरा केवल पढ़ने के लिए है", + "room_name": "कमरे का नाम", + "Room_name_changed": "कमरे का नाम बदलकर: {{room_name}} द्वारा {{user_by}} कर दिया गया है", + "Room_name_changed_to": "कमरे का नाम बदलकर {{room_name}} कर दिया गया", + "Room_name_changed_successfully": "कमरे का नाम सफलतापूर्वक बदला गया", + "Room_not_exist_or_not_permission": "कमरा मौजूद नहीं है या हो सकता है कि आपके पास प्रवेश की अनुमति न हो", + "Room_not_found": "कमरा नहीं मिला", + "Room_password_changed_successfully": "कमरे का पासवर्ड सफलतापूर्वक बदला गया", + "room_removed_read_only": "कक्ष को लिखने की अनुमति {{user_by}} द्वारा जोड़ी गई", + "room_set_read_only": "{{user_by}} द्वारा कमरे को केवल पढ़ने के लिए सेट किया गया", + "room_removed_read_only_permission": "केवल पढ़ने की अनुमति हटा दी गई", + "room_set_read_only_permission": "केवल पढ़ने के लिए कमरा निर्धारित करें", + "Room_topic_changed_successfully": "कक्ष का विषय सफलतापूर्वक बदला गया", + "Room_type_changed_successfully": "कमरे का प्रकार सफलतापूर्वक बदला गया", + "Room_type_of_default_rooms_cant_be_changed": "यह एक डिफ़ॉल्ट कमरा है और इसका प्रकार बदला नहीं जा सकता, कृपया अपने व्यवस्थापक से परामर्श लें।", + "Room_unarchived": "कमरा अनारक्षित", + "Room_updated_successfully": "कमरा सफलतापूर्वक अपडेट किया गया!", + "Room_uploaded_file_list": "फ़ाइलें सूची", + "Room_uploaded_file_list_empty": "कोई फ़ाइल उपलब्ध नहीं.", + "Rooms": "कमरा", + "Rooms_added_successfully": "कमरे सफलतापूर्वक जोड़े गए", + "Routing": "मार्ग", + "Run_only_once_for_each_visitor": "प्रत्येक आगंतुक के लिए केवल एक बार चलाएँ", + "run-import": "आयात चलाएँ", + "run-import_description": "आयातकों को चलाने की अनुमति", + "run-migration": "माइग्रेशन चलाएँ", + "run-migration_description": "माइग्रेशन चलाने की अनुमति", + "Running_Instances": "चल रहे उदाहरण", + "Runtime_Environment": "क्रम पर्यावरण", + "S_new_messages_since_s": "%s के बाद से %s नये संदेश", + "Same_As_Token_Sent_Via": "\"टोकन के माध्यम से भेजा गया\" के समान", + "Same_Style_For_Mentions": "उल्लेख के लिए वही शैली", + "SAML": "एसएएमएल", + "SAML_Description": "प्रमाणीकरण और प्राधिकरण डेटा के आदान-प्रदान के लिए सुरक्षा अभिकथन मार्कअप भाषा का उपयोग किया जाता है।", + "SAML_Allowed_Clock_Drift": "पहचान प्रदाता से अनुमत क्लॉक ड्रिफ्ट", + "SAML_Allowed_Clock_Drift_Description": "पहचान प्रदाता की घड़ी आपके सिस्टम घड़ियों से थोड़ी आगे बढ़ सकती है। आप थोड़ी मात्रा में घड़ी के बहाव की अनुमति दे सकते हैं। इसका मान कई मिलीसेकंड (एमएस) में दिया जाना चाहिए। दिया गया मान उस वर्तमान समय में जोड़ा जाता है जिस पर प्रतिक्रिया सत्यापित की जाती है।", + "SAML_AuthnContext_Template": "AuthnContext टेम्पलेट", + "SAML_AuthnContext_Template_Description": "आप यहां AuthnRequest टेम्पलेट से किसी भी वेरिएबल का उपयोग कर सकते हैं।\n \n अतिरिक्त ऑथ्न संदर्भ जोड़ने के लिए, {{AuthnContextClassRef}} टैग को डुप्लिकेट करें और {{\\_\\_authnContext\\_\\}} वेरिएबल को नए संदर्भ से बदलें।", + "SAML_AuthnRequest_Template": "AuthnRequest टेम्पलेट", + "SAML_AuthnRequest_Template_Description": "निम्नलिखित चर उपलब्ध हैं:\n- **\\_\\_newId\\_\\_**: यादृच्छिक रूप से उत्पन्न आईडी स्ट्रिंग\n- **\\_\\_तत्काल\\_\\_**: वर्तमान टाइमस्टैम्प\n- **\\_\\_कॉलबैकयूआरएल\\_\\_**: रॉकेट.चैट कॉलबैक यूआरएल।\n- **\\_\\_entryPoint\\_\\_**: {{Custom Entry Point}} सेटिंग का मान।\n- **\\_\\_जारीकर्ता\\_\\_**: {{Custom Issuer}} सेटिंग का मान।\n- **\\_\\_identifierFormatTag\\_\\_**: यदि वैध {{Identifier Format}} कॉन्फ़िगर किया गया है तो {{NameID Policy Template}} की सामग्री कॉन्फ़िगर की गई है।\n- **\\_\\_identifierFormat\\_\\_**: {{Identifier Format}} सेटिंग का मान।\n- **\\_\\_authnContextTag\\_\\_**: यदि वैध {{Custom Authn Context}} कॉन्फ़िगर किया गया है, तो {{AuthnContext Template}} की सामग्री कॉन्फ़िगर की गई है।\n- **\\_\\_authnContextComparison\\_\\_**: {{Authn Context Compare}} सेटिंग का मान।\n- **\\_\\_authnContext\\_\\_**: {{Custom Authn Context}} सेटिंग का मान.", + "SAML_Connection": "संबंध", + "SAML_General": "सामान्य", + "SAML_Custom_Authn_Context": "कस्टम प्रमाणीकरण संदर्भ", + "SAML_Custom_Authn_Context_Comparison": "प्रामाणिक संदर्भ तुलना", + "SAML_Custom_Authn_Context_description": "अनुरोध से प्रामाणिक संदर्भ हटाने के लिए इसे खाली छोड़ दें।\n \n एकाधिक प्रामाणिक संदर्भ जोड़ने के लिए, अतिरिक्त संदर्भों को सीधे {{AuthnContext Template}} सेटिंग में जोड़ें।", + "SAML_Custom_Cert": "कस्टम प्रमाणपत्र", + "SAML_Custom_Debug": "डिबग सक्षम करें", + "SAML_Custom_EMail_Field": "ई-मेल फ़ील्ड का नाम", + "SAML_Custom_Entry_point": "कस्टम प्रवेश बिंदु", + "SAML_Custom_Generate_Username": "उपयोगकर्ता नाम उत्पन्न करें", + "SAML_Custom_IDP_SLO_Redirect_URL": "आईडीपी एसएलओ रीडायरेक्ट यूआरएल", + "SAML_Custom_Immutable_Property": "अपरिवर्तनीय फ़ील्ड नाम", + "SAML_Custom_Immutable_Property_EMail": "ईमेल", + "SAML_Custom_Immutable_Property_Username": "उपयोगकर्ता नाम", + "SAML_Custom_Issuer": "कस्टम जारीकर्ता", + "SAML_Custom_Logout_Behaviour": "लॉगआउट व्यवहार", + "SAML_Custom_Logout_Behaviour_End_Only_RocketChat": "केवल Rocket.Chat से लॉग आउट करें", + "SAML_Custom_Logout_Behaviour_Terminate_SAML_Session": "SAML-सत्र समाप्त करें", + "SAML_Custom_mail_overwrite": "उपयोगकर्ता मेल को अधिलेखित करें (आईडीपी विशेषता का उपयोग करें)", + "SAML_Custom_name_overwrite": "उपयोगकर्ता का पूरा नाम अधिलेखित करें (आईडीपी विशेषता का उपयोग करें)", + "SAML_Custom_Private_Key": "निजी कुंजी सामग्री", + "SAML_Custom_Provider": "कस्टम प्रदाता", + "SAML_Custom_Public_Cert": "सार्वजनिक प्रमाणपत्र सामग्री", + "SAML_Custom_signature_validation_all": "सभी हस्ताक्षर मान्य करें", + "SAML_Custom_signature_validation_assertion": "अभिकथन हस्ताक्षर मान्य करें", + "SAML_Custom_signature_validation_either": "किसी भी हस्ताक्षर को मान्य करें", + "SAML_Custom_signature_validation_response": "मान्य प्रतिक्रिया हस्ताक्षर", + "SAML_Custom_signature_validation_type": "हस्ताक्षर सत्यापन प्रकार", + "SAML_Custom_signature_validation_type_description": "यदि कोई कस्टम प्रमाणपत्र प्रदान नहीं किया गया है तो इस सेटिंग को अनदेखा कर दिया जाएगा।", + "SAML_Custom_user_data_fieldmap": "उपयोगकर्ता डेटा फ़ील्ड मानचित्र", + "SAML_Custom_user_data_fieldmap_description": "कॉन्फ़िगर करें कि एसएएमएल (एक बार मिल जाने पर) में रिकॉर्ड से उपयोगकर्ता खाता फ़ील्ड (जैसे ईमेल) कैसे पॉप्युलेट किए जाते हैं।\nउदाहरण के तौर पर, `{\"name\":\"cn\", \"email\":\"mail\"}` cn विशेषता से किसी व्यक्ति का मानव पठनीय नाम चुनेगा, और मेल विशेषता से उनका ईमेल चुनेगा।\nRocket.Chat में उपलब्ध फ़ील्ड: `नाम`, `ईमेल` और `उपयोगकर्ता नाम`, बाकी सब हटा दिया जाएगा।\n`{\"ईमेल\": \"मेल\",\"उपयोगकर्ता नाम\": {\"फ़ील्डनाम\": \"मेल\",\"रेगेक्स\": \"(.*)@.+$\",\"टेम्पलेट\": \"उपयोगकर्ता-रेगेक्स\"}, \" नाम\": { \"फ़ील्डनाम\": [\"पहला नाम\", \"अंतिम नाम\"], \"टेम्पलेट\": \"{{firstName}} {{lastName}}\"}, \"{{identifier}}\": \"uid\"}`", + "SAML_Custom_user_data_custom_fieldmap": "उपयोगकर्ता डेटा कस्टम फ़ील्ड मानचित्र", + "SAML_Custom_user_data_custom_fieldmap_description": "कॉन्फ़िगर करें कि SAML में रिकॉर्ड से उपयोगकर्ता कस्टम फ़ील्ड कैसे पॉप्युलेट किए जाते हैं (एक बार मिल जाने पर)।", + "SAML_Custom_Username_Field": "उपयोक्तानाम फ़ील्ड नाम", + "SAML_Custom_Username_Normalize": "उपयोक्तानाम सामान्यीकृत करें", + "SAML_Custom_Username_Normalize_Lowercase": "लोअरकेस करने के लिए", + "SAML_Custom_Username_Normalize_None": "कोई सामान्यीकरण नहीं", + "SAML_Default_User_Role": "डिफ़ॉल्ट उपयोगकर्ता भूमिका", + "SAML_Default_User_Role_Description": "आप एकाधिक भूमिकाएँ निर्दिष्ट कर सकते हैं, उन्हें अल्पविराम से अलग कर सकते हैं।", + "SAML_Identifier_Format": "पहचानकर्ता प्रारूप", + "SAML_Identifier_Format_Description": "अनुरोध से NameID नीति को हटाने के लिए इसे खाली छोड़ दें।", + "SAML_LogoutRequest_Template": "लॉगआउट अनुरोध टेम्पलेट", + "SAML_LogoutRequest_Template_Description": "निम्नलिखित चर उपलब्ध हैं:\n- **\\_\\_newId\\_\\_**: यादृच्छिक रूप से उत्पन्न आईडी स्ट्रिंग\n- **\\_\\_तत्काल\\_\\_**: वर्तमान टाइमस्टैम्प\n- **\\_\\_idpSLORedirectURL\\_\\_**: रीडायरेक्ट करने के लिए आईडीपी सिंगल लॉगआउट यूआरएल।\n- **\\_\\_जारीकर्ता\\_\\_**: {{Custom Issuer}} सेटिंग का मान।\n- **\\_\\_identifierFormat\\_\\_**: {{Identifier Format}} सेटिंग का मान।\n- **\\_\\_nameID\\_\\_**: उपयोगकर्ता द्वारा लॉग इन करने पर आईडीपी से प्राप्त NameID।\n- **\\_\\_sessionIndex\\_\\_**: उपयोगकर्ता द्वारा लॉग इन करने पर आईडीपी से सेशन इंडेक्स प्राप्त होता है।", + "SAML_LogoutResponse_Template": "लॉगआउट प्रतिक्रिया टेम्पलेट", + "SAML_LogoutResponse_Template_Description": "निम्नलिखित चर उपलब्ध हैं:\n- **\\_\\_newId\\_\\_**: यादृच्छिक रूप से उत्पन्न आईडी स्ट्रिंग\n- **\\_\\_inResponseToId\\_\\_**: आईडीपी से प्राप्त लॉगआउट अनुरोध की आईडी\n- **\\_\\_तत्काल\\_\\_**: वर्तमान टाइमस्टैम्प\n- **\\_\\_idpSLORedirectURL\\_\\_**: रीडायरेक्ट करने के लिए आईडीपी सिंगल लॉगआउट यूआरएल।\n- **\\_\\_जारीकर्ता\\_\\_**: {{Custom Issuer}} सेटिंग का मान।\n- **\\_\\_identifierFormat\\_\\_**: {{Identifier Format}} सेटिंग का मान।\n- **\\_\\_nameID\\_\\_**: IdP लॉगआउट अनुरोध से प्राप्त NameID।\n- **\\_\\_sessionIndex\\_\\_**: IdP लॉगआउट अनुरोध से प्राप्त sessionIndex।", + "SAML_Metadata_Certificate_Template_Description": "निम्नलिखित चर उपलब्ध हैं:\n- **\\_\\_प्रमाणपत्र\\_\\_**: दावा एन्क्रिप्शन के लिए निजी प्रमाणपत्र।", + "SAML_Metadata_Template": "मेटाडेटा टेम्पलेट", + "SAML_Metadata_Template_Description": "निम्नलिखित चर उपलब्ध हैं:\n- **\\_\\_sloLocation\\_\\_**: रॉकेट.चैट सिंगल लॉगआउट यूआरएल।\n- **\\_\\_जारीकर्ता\\_\\_**: {{Custom Issuer}} सेटिंग का मान।\n- **\\_\\_identifierFormat\\_\\_**: {{Identifier Format}} सेटिंग का मान।\n- **\\_\\_certificateTag\\_\\_**: यदि कोई निजी प्रमाणपत्र कॉन्फ़िगर किया गया है, तो इसमें {{Metadata Certificate Template}} शामिल होगा, अन्यथा इसे अनदेखा कर दिया जाएगा।\n- **\\_\\_कॉलबैकयूआरएल\\_\\_**: रॉकेट.चैट कॉलबैक यूआरएल।", + "SAML_MetadataCertificate_Template": "मेटाडेटा प्रमाणपत्र टेम्पलेट", + "SAML_NameIdPolicy_Template": "NameID नीति टेम्पलेट", + "SAML_NameIdPolicy_Template_Description": "आप यहां अधिकृत अनुरोध टेम्पलेट से किसी भी वेरिएबल का उपयोग कर सकते हैं।", + "SAML_Role_Attribute_Name": "भूमिका विशेषता का नाम", + "SAML_Role_Attribute_Name_Description": "यदि यह विशेषता SAML प्रतिक्रिया पर पाई जाती है, तो इसके मानों का उपयोग नए उपयोगकर्ताओं के लिए भूमिका नाम के रूप में किया जाएगा।", + "SAML_Role_Attribute_Sync": "उपयोगकर्ता भूमिकाएँ सिंक करें", + "SAML_Role_Attribute_Sync_Description": "लॉगिन पर SAML उपयोगकर्ता भूमिकाओं को सिंक करें (स्थानीय उपयोगकर्ता भूमिकाओं को अधिलेखित करता है)।", + "SAML_Section_1_User_Interface": "प्रयोक्ता इंटरफ़ेस", + "SAML_Section_2_Certificate": "प्रमाणपत्र", + "SAML_Section_3_Behavior": "व्यवहार", + "SAML_Section_4_Roles": "भूमिकाएँ", + "SAML_Section_5_Mapping": "मानचित्रण", + "SAML_Section_6_Advanced": "विकसित", + "SAML_Custom_channels_update": "प्रत्येक लॉगिन पर रूम सब्सक्रिप्शन अपडेट करें", + "SAML_Custom_channels_update_description": "यह सुनिश्चित करता है कि उपयोगकर्ता प्रत्येक लॉगिन पर SAML दावे में सभी चैनलों का सदस्य है।", + "SAML_Custom_include_private_channels_update": "रूम सब्सक्रिप्शन में निजी कमरे शामिल करें", + "SAML_Custom_include_private_channels_update_description": "उपयोगकर्ता को SAML दावे में मौजूद किसी भी निजी कमरे में जोड़ता है।", + "Saturday": "शनिवार", + "Save": "बचाना", + "Save_changes": "परिवर्तनों को सुरक्षित करें", + "Save_Mobile_Bandwidth": "मोबाइल बैंडविड्थ सहेजें", + "Save_to_enable_this_action": "इस क्रिया को सक्षम करने के लिए सहेजें", + "Save_To_Webdav": "WebDAV में सहेजें", + "Save_your_encryption_password": "अपना एन्क्रिप्शन पासवर्ड सहेजें", + "save-all-canned-responses": "सभी डिब्बाबंद प्रतिक्रियाएँ सहेजें", + "save-all-canned-responses_description": "सभी डिब्बाबंद प्रतिक्रियाओं को सहेजने की अनुमति", + "save-canned-responses": "डिब्बाबंद प्रतिक्रियाएँ सहेजें", + "save-canned-responses_description": "डिब्बाबंद प्रत्युत्तरों को सहेजने की अनुमति", + "save-department-canned-responses": "विभाग डिब्बाबंद प्रतिक्रियाएँ सहेजें", + "save-department-canned-responses_description": "विभाग द्वारा डिब्बाबंद प्रत्युत्तरों को सहेजने की अनुमति", + "save-others-livechat-room-info": "अन्य ओमनीचैनल कक्ष जानकारी सहेजें", + "save-others-livechat-room-info_description": "अन्य सर्वचैनल कक्षों से जानकारी सहेजने की अनुमति", + "Saved": "बचाया", + "Saving": "सहेजा जा रहा है", + "Scan_QR_code": "Google Authenticator, Authy या Duo जैसे प्रमाणक ऐप का उपयोग करके QR कोड को स्कैन करें। यह 6 अंकों का कोड प्रदर्शित करेगा जिसे आपको नीचे दर्ज करना होगा।", + "Scan_QR_code_alternative_s": "यदि आप क्यूआर कोड को स्कैन नहीं कर सकते हैं, तो आप इसके बजाय मैन्युअल रूप से कोड दर्ज कर सकते हैं:", "Scope": "क्षेत्र", + "Score": "अंक", + "Screen_Lock": "स्क्रीन लॉक है", + "Screen_Share": "स्क्रीन शेयर", + "Script": "लिखी हुई कहानी", + "Script_Enabled": "स्क्रिप्ट सक्षम", + "Script_Engine": "स्क्रिप्ट सैंडबॉक्स", + "Script_Engine_Description": "पुरानी स्क्रिप्ट को ठीक से चलाने के लिए संगत सैंडबॉक्स की आवश्यकता हो सकती है, लेकिन सभी नई स्क्रिप्ट को इसके बजाय सुरक्षित सैंडबॉक्स का उपयोग करने का प्रयास करना चाहिए।", + "Script_Engine_vm2": "संगत सैंडबॉक्स (अस्वीकृत)", + "Script_Engine_isolated_vm": "सुरक्षित सैंडबॉक्स", + "Search": "खोज", + "Searchable": "खोज सकने", + "Search_Apps": "ऐप्स खोजें", + "Search_Installed_Apps": "इंस्टॉल किए गए ऐप्स खोजें", + "Search_Private_apps": "निजी ऐप्स खोजें", + "Search_Requested_Apps": "अनुरोधित ऐप्स खोजें", + "Search_Premium_Apps": "प्रीमियम ऐप्स खोजें", + "Search_by_file_name": "फ़ाइल नाम से खोजें", + "Search_by_username": "उपयोगकर्ता नाम से खोजें", + "Search_by_category": "श्रेणी के आधार पर खोजें", + "Search_Channels": "चैनल खोजें", + "Search_Chat_History": "चैट इतिहास खोजें", + "Search_current_provider_not_active": "वर्तमान खोज प्रदाता सक्रिय नहीं है", + "Search_Description": "कार्यक्षेत्र खोज प्रदाता का चयन करें और खोज संबंधी सेटिंग्स कॉन्फ़िगर करें।", + "Search_Devices_Users": "डिवाइस या उपयोगकर्ता खोजें", + "Search_Files": "फ़ाइल ढूंढो", + "Search_for_a_more_general_term": "अधिक सामान्य शब्द खोजें", + "Search_for_a_more_specific_term": "अधिक विशिष्ट शब्द खोजें", + "Search_Integrations": "एकीकरण खोजें", + "Search_message_search_failed": "खोज अनुरोध विफल रहा", + "Search_Messages": "संदेश खोजें", + "Search_on_marketplace": "मार्केटप्लेस पर खोजें", + "Search_Page_Size": "पृष्ठ आकार", + "Search_Private_Groups": "निजी समूह खोजें", + "Search_Provider": "प्रदाता खोजें", + "Search_rooms": "कमरे खोजें", + "Search_Rooms": "कमरे खोजें", + "Search_Users": "उपयोगकर्ता खोजें", + "Seats_Available": "{{seatsLeft}} सीटें उपलब्ध हैं", + "Seats_usage": "सीटों का उपयोग", + "seconds": "सेकंड", + "Secret_token": "गुप्त टोकन", + "Secure_SaaS_solution": "सुरक्षित SaaS समाधान.", + "Security": "सुरक्षा", + "See_all_themes": "सभी थीम देखें", + "See_documentation": "दस्तावेज़ देखें", + "See_Paid_Plan": "सशुल्क योजना देखें", + "See_Pricing": "मूल्य निर्धारण देखें", + "See_full_profile": "पूरी प्रोफ़ाइल देखें", + "See_history": "इतिहास देखें", + "See_on_Engagement_Dashboard": "एंगेजमेंट डैशबोर्ड पर देखें", "Select_a_department": "एक विभाग का चयन करें", + "Select_a_room": "एक कमरा चुनें", + "Select_a_user": "एक उपयोगकर्ता चुनें", + "Select_a_webdav_server": "एक WebDAV सर्वर चुनें", + "Select_an_avatar": "एक अवतार चुनें", + "Select_an_option": "कोई विकल्प चुनें", + "Select_at_least_one_user": "कम से कम एक उपयोगकर्ता का चयन करें", + "Select_at_least_two_users": "कम से कम दो उपयोगकर्ता चुनें", "Select_department": "एक विभाग का चयन करें", + "Select_file": "फ़ाइल का चयन करें", + "Select_role": "एक भूमिका चुनें", + "Select_service_to_login": "अपनी तस्वीर लोड करने या सीधे अपने कंप्यूटर से अपलोड करने के लिए लॉगिन करने के लिए एक सेवा का चयन करें", + "Select_tag": "एक टैग चुनें", + "Select_the_channels_you_want_the_user_to_be_removed_from": "उन चैनलों का चयन करें जिनसे आप उपयोगकर्ता को हटाना चाहते हैं", + "Select_the_teams_channels_you_would_like_to_delete": "उस टीम के चैनल का चयन करें जिसे आप हटाना चाहते हैं, जिन्हें आप नहीं चुनेंगे उन्हें कार्यक्षेत्र में ले जाया जाएगा।", + "Select_atleast_one_channel_to_forward_the_messsage_to": "संदेश अग्रेषित करने के लिए कम से कम एक चैनल चुनें", + "Select_user": "उपयोगकर्ता का चयन करें", + "Select_users": "उपयोगकर्ताओं का चयन करें", + "Selected_agents": "चयनित एजेंट", + "Selected_by_default": "डिफ़ॉल्ट रूप से चयनित", + "Selected_departments": "चयनित विभाग", + "Selected_first_reply_unselected_following_replies": "पहले उत्तर के लिए चयनित, निम्नलिखित उत्तरों के लिए अचयनित", + "Selected_monitors": "चयनित मॉनिटर्स", + "Selecting_users": "उपयोगकर्ताओं का चयन करना", "Send": "भेजना", + "Send_a_message": "एक संदेश भेजो", + "Send_a_test_mail_to_my_user": "मेरे उपयोगकर्ता को एक परीक्षण मेल भेजें", + "Send_a_test_push_to_my_user": "मेरे उपयोगकर्ता को एक परीक्षण पुश भेजें", + "Send_confirmation_email": "पुष्टिकरण ईमेल भेजें", + "Send_data_into_RocketChat_in_realtime": "वास्तविक समय में Rocket.Chat में डेटा भेजें।", + "Send_email": "ईमेल भेजें", + "Send_Email_SMTP_Warning": "इस ईमेल को भेजने के लिए आपको SMTP ईमेलिंग सर्वर सेटअप करना होगा", + "Send_invitation_email": "आमंत्रण ईमेल भेजें", + "Send_invitation_email_error": "आपने कोई वैध ईमेल पता प्रदान नहीं किया है.", + "Send_invitation_email_info": "आप एक साथ अनेक ईमेल आमंत्रण भेज सकते हैं.", + "Send_invitation_email_success": "आपने निम्नलिखित पते पर सफलतापूर्वक आमंत्रण ईमेल भेज दिया है:", + "Send_it_as_attachment_instead_question": "इसके बजाय इसे अनुलग्नक के रूप में भेजें?", + "Send_me_the_code_again": "मुझे दोबारा कोड भेजें", + "Send_request_on": "पर अनुरोध भेजें", + "Send_request_on_agent_message": "एजेंट संदेशों पर अनुरोध भेजें", + "Send_request_on_chat_close": "चैट बंद करने पर अनुरोध भेजें", + "Send_request_on_chat_queued": "चैट कतार पर अनुरोध भेजें", + "Send_request_on_chat_start": "चैट प्रारंभ पर अनुरोध भेजें", + "Send_request_on_chat_taken": "ली गई चैट पर अनुरोध भेजें", + "Send_request_on_forwarding": "अग्रेषण पर अनुरोध भेजें", + "Send_request_on_lead_capture": "लीड कैप्चर पर अनुरोध भेजें", + "Send_request_on_offline_messages": "ऑफ़लाइन संदेशों पर अनुरोध भेजें", + "Send_request_on_visitor_message": "विज़िटर संदेशों पर अनुरोध भेजें", + "Send_Test": "परीक्षण भेजें", + "Send_Test_Email": "परीक्षण ईमेल भेजें", + "Send_via_email": "ईमेल द्वारा भेजें", + "Send_via_Email_as_attachment": "अनुलग्नक के रूप में ईमेल द्वारा भेजें", + "Export_as_PDF": "पीडीएफ के रूप में निर्यात करें", + "Export_enabled_at_the_end_of_the_conversation": "बातचीत के अंत में निर्यात सक्षम किया गया", + "Send_Visitor_navigation_history_as_a_message": "विज़िटर नेविगेशन इतिहास को संदेश के रूप में भेजें", + "Send_visitor_navigation_history_on_request": "अनुरोध पर विज़िटर नेविगेशन इतिहास भेजें", + "Send_welcome_email": "स्वागत ईमेल भेजें", + "Send_your_JSON_payloads_to_this_URL": "अपने JSON पेलोड इस URL पर भेजें।", + "send-mail": "ईमेल भेजो", + "send-mail_description": "ईमेल भेजने की अनुमति", + "send-many-messages": "अनेक संदेश भेजें", + "send-many-messages_description": "प्रति सेकंड 5 संदेशों की दर सीमा को बायपास करने की अनुमति", + "send-omnichannel-chat-transcript": "ओमनीचैनल वार्तालाप प्रतिलेख भेजें", + "send-omnichannel-chat-transcript_description": "सर्वचैनल वार्तालाप प्रतिलेख भेजने की अनुमति", + "Sender_Info": "चैनल की जानकारी", + "Sending": "भेजना...", + "Sending_Invitations": "निमंत्रण भेजा जा रहा है", + "Sending_your_mail_to_s": "आपका मेल %s पर भेजा जा रहा है", + "Sent_an_attachment": "एक अनुलग्नक भेजा", + "Sent_from": "प्रेषक", + "Separate_multiple_words_with_commas": "एकाधिक शब्दों को अल्पविराम से अलग करें", + "Served_By": "द्वारा सेवा", + "Server": "सर्वर", + "Server_already_added": "सर्वर पहले ही जोड़ा जा चुका है", + "Server_doesnt_exist": "सर्वर मौजूद नहीं है", + "Servers": "सर्वर", + "Server_Configuration": "सर्वर कॉन्फ़िगरेशन", + "Server_File_Path": "सर्वर फ़ाइल पथ", + "Server_Folder_Path": "सर्वर फ़ोल्डर पथ", + "Server_Info": "सर्वर जानकारी", + "Server_name": "सर्वर का नाम", + "Server_Type": "सर्वर प्रकार", + "Service": "सेवा", + "Service_account_key": "सेवा खाता कुंजी", + "Set_as_favorite": "पसंदीदा के रूप में सेट करें", + "Set_as_leader": "नेता के रूप में स्थापित करें", + "Set_as_moderator": "मॉडरेटर के रूप में सेट करें", + "Set_as_owner": "स्वामी के रूप में सेट करें", + "Upload_app": "ऐप अपलोड करें", + "Set_random_password_and_send_by_email": "यादृच्छिक पासवर्ड सेट करें और ईमेल द्वारा भेजें", + "set-leader": "नेता सेट करें", + "set-leader_description": "अन्य उपयोगकर्ताओं को किसी चैनल के लीडर के रूप में सेट करने की अनुमति", + "set-moderator": "मॉडरेटर सेट करें", + "set-moderator_description": "अन्य उपयोगकर्ताओं को किसी चैनल के मॉडरेटर के रूप में सेट करने की अनुमति", + "set-owner": "स्वामी सेट करें", + "set-owner_description": "अन्य उपयोगकर्ताओं को किसी चैनल के स्वामी के रूप में सेट करने की अनुमति", + "set-react-when-readonly": "केवल पढ़ने के लिए प्रतिक्रिया सेट करें", + "set-react-when-readonly_description": "केवल पढ़ने योग्य चैनल में संदेशों पर प्रतिक्रिया करने की क्षमता सेट करने की अनुमति", + "set-readonly": "केवल पढ़ने के लिए सेट करें", + "set-readonly_description": "किसी चैनल को केवल पढ़ने के लिए चैनल सेट करने की अनुमति", + "Settings": "समायोजन", + "Settings_updated": "सेटिंग को अद्यतन किया गया है", + "Setup_SMTP": "एसएमटीपी सेट करें", + "Setup_Wizard": "स्थापना विज़ार्ड", + "Setup_Wizard_Description": "आपके कार्यक्षेत्र के बारे में बुनियादी जानकारी जैसे संगठन का नाम और देश।", + "Setup_Wizard_Info": "हम आपका पहला व्यवस्थापक उपयोगकर्ता स्थापित करने, आपके संगठन को कॉन्फ़िगर करने और निःशुल्क पुश सूचनाएं प्राप्त करने के लिए आपके सर्वर को पंजीकृत करने आदि में आपका मार्गदर्शन करेंगे।", + "Share": "शेयर करना", + "Share_Location_Title": "स्थान साझा करें?", + "Share_screen": "स्क्रीन साझा करना", + "New_CannedResponse": "नई डिब्बाबंद प्रतिक्रिया", + "Edit_CannedResponse": "डिब्बाबंद प्रतिक्रिया संपादित करें", + "Sharing": "शेयरिंग", + "Shared_Location": "साझा स्थान", + "Shared_Secret": "साझा रहस्य", + "Shortcut": "छोटा रास्ता", + "shortcut_name": "शॉर्टकट नाम", + "Should_be_a_URL_of_an_image": "किसी छवि का URL होना चाहिए.", + "Should_exists_a_user_with_this_username": "उपयोगकर्ता पहले से मौजूद होना चाहिए.", + "Show_agent_email": "एजेंट का ईमेल दिखाएँ", + "Show_agent_info": "एजेंट की जानकारी दिखाएँ", + "Show_all": "सब दिखाएं", + "Show_Avatars": "अवतार दिखाएँ", + "Show_counter": "अपठित के रूप में चिह्नित करें", + "Show_default_content": "डिफ़ॉल्ट सामग्री दिखाएँ", + "Show_email_field": "ईमेल फ़ील्ड दिखाएँ", + "Show_mentions": "उल्लेख के लिए बैज दिखाएँ", + "Show_more": "और दिखाओ", + "Show_name_field": "नाम फ़ील्ड दिखाएँ", + "show_offline_users": "ऑफ़लाइन उपयोगकर्ता दिखाएं", + "Show_on_offline_page": "ऑफ़लाइन पेज पर दिखाएं", + "Show_on_registration_page": "पंजीकरण पृष्ठ पर दिखाएँ", + "Show_only_online": "केवल ऑनलाइन दिखाएँ", + "Show_Only_This_Content": "केवल यही सामग्री दिखाएँ", + "Show_preregistration_form": "प्री-रजिस्ट्रेशन फॉर्म दिखाएँ", + "Show_queue_list_to_all_agents": "सभी एजेंटों को कतार सूची दिखाएं", + "Show_room_counter_on_sidebar": "साइडबार पर शो रूम काउंटर", + "Show_Setup_Wizard": "सेटअप विज़ार्ड दिखाएँ", + "Show_the_keyboard_shortcut_list": "कुंजीपटल शॉर्टकट सूची दिखाएँ", + "Show_To_Workspace": "कार्यस्थल पर दिखाएँ", + "Show_video": "वीडियो दिखाओ", + "Showing": "दिखा", + "Showing_archived_results": "

    %s संग्रहीत परिणाम दिखा रहा है

    ", + "Showing_current_of_total": "{{total}} में से {{current}} दिखाया जा रहा है", + "Showing_online_users": "दिखाया जा रहा है: {{total_showing}} , ऑनलाइन: {{online}}, कुल: {{total}} उपयोगकर्ता", + "Showing_results": "

    %s परिणाम दिखा रहा है

    ", + "Showing_results_of": "%s - %s के %s परिणाम दिखा रहा है", + "Show_usernames": "उपयोक्तानाम दिखाएँ", + "Show_roles": "भूमिकाएँ दिखाएँ", + "Show_or_hide_the_user_roles_of_message_authors": "संदेश लेखकों की उपयोगकर्ता भूमिकाएँ दिखाएँ या छिपाएँ।", + "Show_or_hide_the_username_of_message_authors": "संदेश लेखकों का उपयोगकर्ता नाम दिखाएँ या छिपाएँ।", + "Sidebar": "साइड बार", + "Sidebar_list_mode": "साइडबार चैनल सूची मोड", + "Sign_in_to_start_talking": "बातचीत शुरू करने के लिए साइन इन करें", + "Sign_in_with__provider__": "{{provider}} के साथ साइन इन करें", + "since_creation": "%s के बाद से", + "Site_Name": "जगह का नाम", + "Site_Url": "साइट URL", + "Site_Url_Description": "उदाहरण: `https://chat.domain.com/`", + "Size": "आकार", + "Skin_tone": "त्वचा का रंग", "Skip": "छोड़ें", + "SLA_Policy": "एसएलए नीति", + "SLA_Policies": "एसएलए नीतियां", + "SLA_removed": "एसएलए हटा दिया गया", + "Slack_Users": "स्लैक के उपयोगकर्ता सीएसवी", + "SlackBridge_APIToken": "एपीआई टोकन (विरासत)", + "SlackBridge_UseLegacy": "लीगेसी एपीआई टोकन का उपयोग करें", + "SlackBridge_APIToken_Description": "आप प्रति पंक्ति एक एपीआई टोकन जोड़कर एकाधिक स्लैक सर्वर कॉन्फ़िगर कर सकते हैं।", + "SlackBridge_BotToken": "बॉट टोकन", + "SlackBridge_BotToken_Description": "आप प्रति पंक्ति एक बॉट टोकन जोड़कर एकाधिक स्लैक सर्वर कॉन्फ़िगर कर सकते हैं।", + "SlackBridge_AppToken": "ऐप टोकन", + "SlackBridge_AppToken_Description": "आप प्रति पंक्ति एक ऐप टोकन जोड़कर एकाधिक स्लैक सर्वर कॉन्फ़िगर कर सकते हैं।", + "SlackBridge_SigningSecret": "हस्ताक्षर गुप्त", + "SlackBridge_SigningSecret_Description": "आप प्रति पंक्ति एक हस्ताक्षर रहस्य जोड़कर एकाधिक स्लैक सर्वर कॉन्फ़िगर कर सकते हैं।", + "Slackbridge_channel_links_removed_successfully": "स्लैकब्रिज चैनल लिंक सफलतापूर्वक हटा दिए गए हैं।", + "SlackBridge_Description": "स्लैक के साथ सीधे संवाद करने के लिए Rocket.Chat को सक्षम करें।", + "SlackBridge_error": "आपके संदेशों को %s पर आयात करते समय स्लैकब्रिज को एक त्रुटि मिली: %s", + "SlackBridge_finish": "स्लैकब्रिज ने %s पर संदेशों का आयात पूरा कर लिया है। कृपया सभी संदेशों को देखने के लिए पुनः लोड करें।", + "SlackBridge_Out_All": "स्लैकब्रिज आउट ऑल", + "SlackBridge_Out_All_Description": "उन सभी चैनलों से संदेश भेजें जो स्लैक में मौजूद हैं और बॉट शामिल हो गया है", + "SlackBridge_Out_Channels": "स्लैकब्रिज आउट चैनल", + "SlackBridge_Out_Channels_Description": "चुनें कि कौन से चैनल स्लैक को संदेश वापस भेजेंगे", + "SlackBridge_Out_Enabled": "स्लैकब्रिज आउट सक्षम", + "SlackBridge_Out_Enabled_Description": "चुनें कि क्या स्लैकब्रिज को भी आपके संदेश स्लैक को वापस भेजने चाहिए", + "SlackBridge_Remove_Channel_Links_Description": "रॉकेट.चैट चैनलों और स्लैक चैनलों के बीच आंतरिक लिंक हटाएं। बाद में चैनल नामों के आधार पर लिंक फिर से बनाए जाएंगे।", + "SlackBridge_start": "@%s ने `#%s` पर स्लैकब्रिज आयात शुरू किया है। जब यह पूरा हो जाएगा तो हम आपको बताएंगे।", + "Slash_Gimme_Description": "आपके संदेश से पहले ༼ツ ◕_◕ ༽ツ प्रदर्शित करता है", + "Slash_LennyFace_Description": "आपके संदेश के बाद ( ͡° ͜ʖ ͡°) प्रदर्शित होता है", + "Slash_Shrug_Description": "आपके संदेश के बाद ¯\\_(ツ)_/¯ प्रदर्शित करता है", + "Slash_Status_Description": "अपना स्थिति संदेश सेट करें", + "Slash_Status_Params": "स्थिति संदेश", + "Slash_Tableflip_Description": "प्रदर्शित करता है (╯°□°)╯︵ ┻━┻", + "Slash_TableUnflip_Description": "प्रदर्शित करता है ┬─┬ ノ( ゜-゜ノ)", + "Slash_Topic_Description": "विषय निर्धारित करें", + "Slash_Topic_Params": "विषय संदेश", + "Smarsh": "Smarsh", + "Smarsh_Description": "ईमेल संचार को सुरक्षित रखने के लिए कॉन्फ़िगरेशन.", + "Smarsh_Email": "स्मर्श ईमेल", + "Smarsh_Email_Description": ".eml फ़ाइल भेजने के लिए स्मर्श ईमेल पता।", + "Smarsh_Enabled": "स्मर्श सक्षम", + "Smarsh_Enabled_Description": "क्या स्मर्श ईएमएल कनेक्टर सक्षम है या नहीं (ईमेल -> एसएमटीपी के तहत 'ईमेल से' भरने की जरूरत है)।", + "Smarsh_Interval": "स्मर्श अंतराल", + "Smarsh_Interval_Description": "चैट भेजने से पहले प्रतीक्षा करने की मात्रा (ईमेल -> एसएमटीपी के तहत 'ईमेल से' भरने की आवश्यकता है)।", + "Smarsh_MissingEmail_Email": "ईमेल गुम है", + "Smarsh_MissingEmail_Email_Description": "किसी उपयोगकर्ता खाते का ईमेल पता गायब होने पर उसे दिखाया जाने वाला ईमेल आम तौर पर बॉट खातों के साथ होता है।", + "Smarsh_Timezone": "स्मर्श टाइमज़ोन", + "Smileys_and_People": "स्माइलीज़ और लोग", + "SMS": "एसएमएस", + "SMS_Description": "अपने कार्यक्षेत्र पर एसएमएस गेटवे सक्षम और कॉन्फ़िगर करें।", + "SMS_Default_Omnichannel_Department": "ओमनीचैनल विभाग (डिफ़ॉल्ट)", + "SMS_Default_Omnichannel_Department_Description": "यदि सेट किया गया है, तो इस एकीकरण द्वारा शुरू की गई सभी नई आने वाली चैट इस विभाग में भेज दी जाएंगी।\nअनुरोध में विभाग क्वेरी पैरामीटर पास करके इस सेटिंग को ओवरराइट किया जा सकता है।\nजैसे `https://{{SERVER_URL}}/api/v1/livechat/sms-incoming/twilio?department={{Department Id or Name}}`।\nनोट: यदि आप विभाग नाम का उपयोग कर रहे हैं, तो यह यूआरएल सुरक्षित होना चाहिए।", + "SMS_Enabled": "एसएमएस सक्षम", + "SMS_Twilio_NotConfigured": "ट्विलियो एसएमएस अभी तक कॉन्फ़िगर नहीं किया गया है। इसे कॉन्फ़िगर करने के लिए सेटिंग्स -> एसएमएस पर जाएं", + "SMS_Twilio_InvalidCredentials": "ट्विलियो एसएमएस क्रेडेंशियल अमान्य हैं, संदेश नहीं भेज सकते", + "SMTP": "एसएमटीपी", + "SMTP_Host": "एसएमटीपी होस्ट", + "SMTP_Password": "एसएमटीपी पासवर्ड", + "SMTP_Port": "एसएमटीपी पोर्ट", + "SMTP_Server_Not_Setup_Title": "SMTP सर्वर अभी तक सेटअप नहीं हुआ है", + "SMTP_Server_Not_Setup_Description": "आमंत्रण भेजना शुरू करने या उपयोगकर्ताओं को मैन्युअल रूप से जोड़ने के लिए अपना एसएमटीपी ईमेलिंग सर्वर सेट करें", + "SMTP_Test_Button": "एसएमटीपी सेटिंग्स का परीक्षण करें", + "SMTP_Username": "एसएमटीपी उपयोगकर्ता नाम", + "Snippet_Added": "%s पर बनाया गया", + "Snippet_name": "स्निपेट नाम", + "Snippeted_a_message": "एक स्निपेट {{snippetLink}} बनाया गया", + "Social_Network": "सामाजिक नेटवर्क", + "Some_ideas_to_get_you_started": "आपको आरंभ करने के लिए कुछ विचार", + "Something_went_wrong": "कुछ गलत हो गया", + "Something_went_wrong_try_again_later": "कुछ गलत हो गया, बाद में पुनः प्रयास करें।", + "Something_went_wrong_while_executing_command": "कमांड निष्पादित करते समय कुछ गलत हो गया: `/{{command}}`", + "Sorry_page_you_requested_does_not_exist_or_was_deleted": "क्षमा करें, आपके द्वारा अनुरोधित पृष्ठ मौजूद नहीं है या हटा दिया गया है!", + "Sort": "क्रम से लगाना", + "Sort_By": "इसके अनुसार क्रमबद्ध करें", + "Sorting_mechanism": "छँटाई तंत्र", + "Service_level_agreements": "सेवा स्तर अनुबंध", + "Sort_by_activity": "गतिविधि के आधार पर क्रमबद्ध करें", + "Sound": "आवाज़", + "Sounds": "ध्वनि", + "Sound_File_mp3": "ध्वनि फ़ाइल (एमपी3)", + "Sound File": "ध्वनि फ़ाइल", + "Source": "स्रोत", + "Speakers": "वक्ताओं", + "spy-voip-calls": "जासूस वीओआईपी कॉल", + "spy-voip-calls_description": "वीओआईपी कॉल की जासूसी करने की अनुमति", + "SSL": "एसएसएल", + "Star": "तारा", + "Star_Message": "सितारा संदेश", + "Starred_Messages": "तारांकित संदेश", + "Start": "शुरू", + "Start_a_call": "कॉल प्रारंभ करें", + "Start_a_free_trial": "निःशुल्क परीक्षण प्रारंभ करें", + "Start_audio_call": "ऑडियो कॉल प्रारंभ करें", + "Start_call": "कॉल प्रारंभ करें", "Start_Chat": "बातचीत शुरू ", + "Start_conference_call": "कॉन्फ़्रेंस कॉल प्रारंभ करें", + "Start_free_trial": "निशुल्क आजमाइश शुरु करें", + "Start_of_conversation": "बातचीत की शुरुआत", + "Start_OTR": "ओटीआर प्रारंभ करें", + "Start_video_call": "वीडियो कॉल प्रारंभ करें", + "Start_video_conference": "कॉन्फ़्रेंस कॉल प्रारंभ करें?", + "Start_with_s_for_user_or_s_for_channel_Eg_s_or_s": "उपयोगकर्ता के लिए %s या चैनल के लिए %s से प्रारंभ करें। जैसे: %s या %s", + "start-discussion": "चर्चा चलाना", + "start-discussion_description": "चर्चा शुरू करने की अनुमति", + "start-discussion-other-user": "चर्चा प्रारंभ करें (अन्य-उपयोगकर्ता)", + "start-discussion-other-user_description": "चर्चा शुरू करने की अनुमति, जो उपयोगकर्ता को किसी अन्य उपयोगकर्ता द्वारा भेजे गए संदेश से भी चर्चा बनाने की अनुमति देती है", + "Started": "शुरू कर दिया", + "Started_a_video_call": "एक वीडियो कॉल शुरू की", + "Started_At": "इस समय पर शुरू किया", + "Statistics": "आंकड़े", + "Statistics_reporting": "Rocket.Chat पर आँकड़े भेजें", + "Statistics_reporting_Description": "अपने आँकड़े भेजकर, आप हमें यह पहचानने में मदद करेंगे कि Rocket.Chat के कितने उदाहरण तैनात हैं, साथ ही सिस्टम कितना अच्छा व्यवहार कर रहा है, ताकि हम इसे और बेहतर बना सकें। चिंता न करें, क्योंकि कोई भी उपयोगकर्ता जानकारी नहीं भेजी जाती है और हमें प्राप्त होने वाली सभी जानकारी गोपनीय रखी जाती है।", + "Stats_Active_Guests": "सक्रिय अतिथि", + "Stats_Active_Users": "सक्रिय उपयोगकर्ता", + "Stats_App_Users": "Rocket.Chat ऐप उपयोगकर्ता", + "Stats_Avg_Channel_Users": "औसत चैनल उपयोगकर्ता", + "Stats_Avg_Private_Group_Users": "औसत निजी समूह उपयोगकर्ता", + "Stats_Away_Users": "दूर उपयोगकर्ता", + "Stats_Max_Room_Users": "अधिकतम कमरे उपयोगकर्ता", + "Stats_Non_Active_Users": "निष्क्रिय उपयोगकर्ता", + "Stats_Offline_Users": "ऑफ़लाइन उपयोगकर्ता", + "Stats_Online_Users": "ऑनलाइन उपयोगकर्ता", + "Stats_Total_Active_Apps": "कुल सक्रिय ऐप्स", + "Stats_Total_Active_Incoming_Integrations": "कुल सक्रिय आवक एकीकरण", + "Stats_Total_Active_Outgoing_Integrations": "कुल सक्रिय आउटगोइंग एकीकरण", + "Stats_Total_Channels": "चैनल", + "Stats_Total_Connected_Users": "कुल जुड़े हुए उपयोगकर्ता", + "Stats_Total_Direct_Messages": "सीधे संदेश", + "Stats_Total_Incoming_Integrations": "कुल आवक एकीकरण", + "Stats_Total_Installed_Apps": "कुल इंस्टॉल किए गए ऐप्स", + "Stats_Total_Integrations": "कुल एकीकरण", + "Stats_Total_Integrations_With_Script_Enabled": "स्क्रिप्ट सक्षम के साथ पूर्ण एकीकरण", + "Stats_Total_Livechat_Rooms": "ओमनीचैनल कमरे", + "Stats_Total_Messages": "संदेशों", + "Stats_Total_Messages_Channel": "चैनलों में", + "Stats_Total_Messages_Direct": "सीधे संदेशों में", + "Stats_Total_Messages_Livechat": "सर्वचैनल में", + "Stats_Total_Messages_PrivateGroup": "निजी समूहों में", + "Stats_Total_Messages_Discussions": "चर्चाओं में", + "Stats_Total_Outgoing_Integrations": "कुल आउटगोइंग एकीकरण", + "Stats_Total_Private_Groups": "निजी समूह", + "Stats_Total_Rooms": "कमरा", + "Stats_Total_Uploads": "कुल अपलोड", + "Stats_Total_Uploads_Size": "कुल अपलोड आकार", + "Stats_Total_Users": "कुल उपयोगकर्ता", + "Status": "स्थिति", + "StatusMessage": "स्थिति संदेश", + "StatusMessage_Change_Disabled": "आपके Rocket.Chat व्यवस्थापक ने स्थिति संदेशों को बदलना अक्षम कर दिया है", + "StatusMessage_Changed_Successfully": "स्थिति संदेश सफलतापूर्वक बदला गया.", + "StatusMessage_Placeholder": "आप अभी क्या कर रहे हैं?", + "StatusMessage_Too_Long": "स्थिति संदेश 120 अक्षरों से छोटा होना चाहिए.", + "Step": "कदम", + "Stop_call": "कॉल बंद करो", + "Stop_Recording": "रिकॉर्डिंग बंद करें", + "Store_Last_Message": "अंतिम संदेश संग्रहीत करें", + "Store_Last_Message_Sent_per_Room": "प्रत्येक कमरे पर भेजा गया अंतिम संदेश संग्रहीत करें।", + "Stream_Cast": "स्ट्रीम कास्ट", + "Stream_Cast_Address": "स्ट्रीम कास्ट पता", + "Stream_Cast_Address_Description": "आपके रॉकेट.चैट सेंट्रल स्ट्रीम कास्ट का आईपी या होस्ट। जैसे `192.168.1.1:3000` या `लोकलहोस्ट:4000`", + "Strike": "हड़ताल", + "Style": "शैली", + "Subject": "विषय", + "Submit": "जमा करना", + "Subscribe": "सदस्यता लें", + "Success": "सफलता", + "Success_message": "सफलता संदेश", + "Successfully_downloaded_file_from_external_URL_should_start_preparing_soon": "बाहरी यूआरएल से फ़ाइल सफलतापूर्वक डाउनलोड हो गई है, जल्द ही तैयारी शुरू कर देनी चाहिए", + "Suggestion_from_recent_messages": "हाल के संदेशों से सुझाव", + "Sunday": "रविवार", + "Support": "सहायता", "Survey": "सर्वेक्षण", "Survey_instructions": "प्रत्येक प्रश्न को अपनी संतुष्टि के अनुसार रेट करें, 1 मतलब कि आप पूरी तरह से असंतुष्ट हैं और 5 का अर्थ है कि आप पूरी तरह से संतुष्ट हैं।", + "Symbols": "प्रतीक", + "Sync": "साथ-साथ करना", + "Sync / Import": "सिंक/आयात करें", + "Sync_in_progress": "तुल्यकालन प्रगति पर है", + "Sync_Interval": "अंतराल सिंक करना", + "Sync_success": "समन्वयन सफल", + "Sync_Users": "उपयोगकर्ताओं को सिंक करें", + "sync-auth-services-users": "प्रमाणीकरण सेवाओं के उपयोगकर्ताओं को सिंक करें", + "sync-auth-services-users_description": "प्रमाणीकरण सेवाओं के उपयोगकर्ताओं को सिंक करने की अनुमति", + "System_messages": "सिस्टम संदेश", + "Tag": "टैग", + "Tags": "टैग", + "Tag_removed": "टैग हटा दिया गया", + "Tag_already_exists": "टैग पहले से मौजूद है", + "Take_it": "इसे लें!", + "Take_rocket_chat_with_you_with_mobile_applications": "मोबाइल एप्लिकेशन के साथ Rocket.Chat को अपने साथ ले जाएं।", + "Taken_at": "पर लिया गया", + "Talk_Time": "बात करने का समय", + "Talk_to_an_expert": "किसी विशेषज्ञ से बात करें", + "Talk_to_sales": "बिक्री से बात करें", + "Talk_to_your_workspace_administrator_about_enabling_video_conferencing": "वीडियो कॉन्फ्रेंसिंग सक्षम करने के बारे में अपने कार्यक्षेत्र व्यवस्थापक से बात करें", + "Talk_to_your_workspace_admin_to_address_this_issue": "इस समस्या के समाधान के लिए अपने कार्यक्षेत्र व्यवस्थापक से बात करें।", + "Target user not allowed to receive messages": "लक्षित उपयोगकर्ता को संदेश प्राप्त करने की अनुमति नहीं है", + "TargetRoom": "लक्ष्य कक्ष", + "TargetRoom_Description": "वह कमरा जहां संदेश भेजे जाएंगे जो इस घटना के परिणामस्वरूप निकाल दिए गए हैं। केवल एक लक्ष्य कक्ष की अनुमति है और वह मौजूद रहना चाहिए।", + "Team": "टीम", + "Team_Add_existing_channels": "मौजूदा चैनल जोड़ें", + "Team_Add_existing": "मौजूदा जोड़ें", + "Team_Auto-join": "ऑटो में शामिल हों", + "Team_Channels": "टीम चैनल", + "Team_Delete_Channel_modal_content_danger": "इसे पूर्ववत नहीं किया जा सकता.", + "Team_Delete_Channel_modal_content": "क्या आप इस चैनल को हटाना चाहेंगे?", + "Team_has_been_created": "टीम बनाई गई है", + "Team_has_been_deleted": "टीम हटा दी गई है", + "Team_Info": "टीम की जानकारी", + "Team_Mapping": "टीम मैपिंग", + "Team_Name": "टीम का नाम", + "Team_Remove_from_team_modal_content": "क्या आप इस चैनल को {{teamName}} से हटाना चाहेंगे? चैनल को वापस कार्यक्षेत्र में ले जाया जाएगा.", + "Team_Remove_from_team": "टीम से हटाओ", + "Team_what_is_this_team_about": "यह टीम किस बारे में है", + "Teams": "टीमें", + "Teams_about_the_channels": "और चैनलों के बारे में?", + "Teams_channels_didnt_leave": "आपने निम्नलिखित चैनलों का चयन नहीं किया है इसलिए आप उन्हें नहीं छोड़ रहे हैं:", + "Teams_channels_last_owner_delete_channel_warning": "आप इस चैनल के अंतिम मालिक हैं. एक बार जब आप टीम को एक चैनल में बदल देते हैं, तो चैनल को कार्यक्षेत्र में ले जाया जाएगा।", + "Teams_channels_last_owner_leave_channel_warning": "आप इस चैनल के अंतिम मालिक हैं. एक बार जब आप टीम छोड़ देते हैं, तो चैनल टीम के अंदर रखा जाएगा लेकिन आप इसे बाहर से प्रबंधित करेंगे।", + "Teams_leaving_team": "आप इस टीम को छोड़ रहे हैं.", + "Teams_channels": "टीम के चैनल", + "Teams_convert_channel_to_team": "टीम में कनवर्ट करें", + "Teams_delete_team_choose_channels": "वे चैनल चुनें जिन्हें आप हटाना चाहते हैं। जिन्हें आप रखने का निर्णय लेंगे, वे आपके कार्यक्षेत्र पर उपलब्ध रहेंगे।", + "Teams_delete_team_public_notice": "ध्यान दें कि सार्वजनिक चैनल अभी भी सार्वजनिक रहेंगे और सभी को दिखाई देंगे।", + "Teams_delete_team_Warning": "एक बार जब आप किसी टीम को हटा देते हैं, तो सभी चैट सामग्री और कॉन्फ़िगरेशन हटा दिए जाएंगे।", + "Teams_delete_team": "आप इस टीम को हटाने वाले हैं.", + "Teams_deleted_channels": "निम्नलिखित चैनल हटाए जा रहे हैं:", + "Teams_Errors_Already_exists": "टीम `{{name}}` पहले से मौजूद है।", + "Teams_Errors_team_name": "आप टीम के नाम के रूप में \"{{name}}\" का उपयोग नहीं कर सकते।", + "Teams_move_channel_to_team": "टीम में जाएँ", + "Teams_move_channel_to_team_description_first": "किसी चैनल को टीम के अंदर ले जाने का मतलब है कि इस चैनल को टीम के संदर्भ में जोड़ा जाएगा, हालांकि, चैनल के सभी सदस्य, जो संबंधित टीम के सदस्य नहीं हैं, उनके पास अभी भी इस चैनल तक पहुंच होगी, लेकिन उन्हें टीम के सदस्यों के रूप में नहीं जोड़ा जाएगा।", + "Teams_move_channel_to_team_description_second": "चैनल का सारा प्रबंधन अभी भी इस चैनल के मालिकों द्वारा किया जाएगा।", + "Teams_move_channel_to_team_description_third": "टीम के सदस्य और यहां तक कि टीम के मालिक, यदि इस चैनल के सदस्य नहीं हैं, तो चैनल की सामग्री तक पहुंच नहीं पा सकते हैं।", + "Teams_move_channel_to_team_description_fourth": "कृपया ध्यान दें कि टीम का मालिक सदस्यों को चैनल से हटा सकेगा।", + "Teams_move_channel_to_team_confirm_description": "इस व्यवहार के बारे में पिछले निर्देशों को पढ़ने के बाद, क्या आप इस कार्रवाई के साथ आगे बढ़ना चाहते हैं?", + "Teams_New_Title": "टीम बनाएं", + "Teams_New_Name_Label": "नाम", + "Teams_Info": "टीम सूचना", + "Teams_kept_channels": "आपने निम्नलिखित चैनलों का चयन नहीं किया है इसलिए उन्हें कार्यक्षेत्र में ले जाया जाएगा:", + "Teams_kept__username__channels": "आपने निम्नलिखित चैनलों का चयन नहीं किया है इसलिए उन पर {{username}} रखा जाएगा:", + "Teams_leave_channels": "उस टीम के चैनल का चयन करें जिसे आप छोड़ना चाहते हैं।", + "Teams_leave": "टीम छोड़ें", + "Teams_left_team_successfully": "टीम को सफलतापूर्वक छोड़ दिया", + "Teams_members": "टीमों के सदस्य", + "Teams_New_Add_members_Label": "सदस्य जोड़ें", + "Teams_New_Broadcast_Description": "केवल अधिकृत उपयोगकर्ता ही नए संदेश लिख सकते हैं, लेकिन अन्य उपयोगकर्ता उत्तर दे सकेंगे", + "Teams_New_Broadcast_Label": "प्रसारण", + "Teams_New_Description_Label": "विषय", + "Teams_New_Description_Placeholder": "यह टीम किस बारे में है", + "Teams_New_Encrypted_Description_Disabled": "केवल निजी टीम के लिए उपलब्ध है", + "Teams_New_Encrypted_Description_Enabled": "एंड-टू-एंड एन्क्रिप्टेड टीम। खोज एन्क्रिप्टेड टीमों के साथ काम नहीं करेगी और सूचनाएं संदेश सामग्री नहीं दिखा सकती हैं।", + "Teams_New_Encrypted_Label": "कूट रूप दिया गया", + "Teams_New_Private_Description_Disabled": "अक्षम होने पर, कोई भी टीम में शामिल हो सकता है", + "Teams_New_Private_Description_Enabled": "केवल आमंत्रित लोग ही शामिल हो सकते हैं", + "Teams_New_Private_Label": "निजी", + "Teams_New_Read_only_Description": "इस टीम के सभी उपयोगकर्ता संदेश लिख सकते हैं", + "Teams_Public_Team": "सार्वजनिक टीम", + "Teams_Private_Team": "निजी टीम", + "Teams_removing_member": "सदस्य को हटाया जा रहा है", + "Teams_removing__username__from_team": "आप इस टीम से {{username}} हटा रहे हैं", + "Teams_removing__username__from_team_and_channels": "आप इस टीम और इसके सभी चैनलों से {{username}} हटा रहे हैं।", + "Teams_Select_a_team": "एक टीम चुनें", + "Teams_Search_teams": "खोज दल", + "Teams_New_Read_only_Label": "केवल पढ़ने के लिए", + "Technology_Services": "प्रौद्योगिकी सेवाएँ", + "Terms": "शर्तें", + "Terms_of_use": "उपयोग की शर्तें", + "Test_Connection": "परीक्षण कनेक्शन", + "Test_Desktop_Notifications": "डेस्कटॉप सूचनाओं का परीक्षण करें", + "Test_LDAP_Search": "एलडीएपी खोज का परीक्षण करें", + "test-admin-options": "व्यवस्थापक पैनल पर परीक्षण विकल्प", + "test-admin-options_description": "एलडीएपी लॉगिन जैसे व्यवस्थापक पैनल पर विकल्पों का परीक्षण करने की अनुमति।", + "test-push-notifications": "पुश सूचनाओं का परीक्षण करें", + "test-push-notifications_description": "पुश सूचनाओं का परीक्षण करने की अनुमति", + "Texts": "ग्रंथों", "Thank_you_for_your_feedback": "आपकी प्रतिक्रिया के लिए आपका धन्यवाद", + "The_application_name_is_required": "एप्लिकेशन का नाम आवश्यक है", + "The_application_will_be_able_to": "<1>{{appName}} यह करने में सक्षम होगा:", + "The_channel_name_is_required": "चैनल का नाम आवश्यक है", + "The_emails_are_being_sent": "ईमेल भेजे जा रहे हैं.", + "The_empty_room__roomName__will_be_removed_automatically": "खाली कमरा {{roomName}} स्वचालित रूप से हटा दिया जाएगा।", + "The_field_is_required": "फ़ील्ड %s आवश्यक है.", + "The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server": "छवि का आकार बदलना काम नहीं करेगा क्योंकि हम आपके सर्वर पर स्थापित ImageMagick या ग्राफ़िक्सMagick का पता नहीं लगा सकते हैं।", + "The_message_is_a_discussion_you_will_not_be_able_to_recover": "संदेश एक चर्चा है आप संदेशों को पुनर्प्राप्त नहीं कर पाएंगे!", + "The_mobile_notifications_were_disabled_to_all_users_go_to_Admin_Push_to_enable_the_Push_Gateway_again": "मोबाइल सूचनाएं सभी उपयोगकर्ताओं के लिए अक्षम कर दी गई थीं, पुश गेटवे को फिर से सक्षम करने के लिए \"एडमिन > पुश\" पर जाएं", + "The_necessary_browser_permissions_for_location_sharing_are_not_granted": "स्थान साझाकरण के लिए आवश्यक ब्राउज़र अनुमतियाँ प्रदान नहीं की गई हैं", + "The_peer__peer__does_not_exist": "सहकर्मी {{peer}} मौजूद नहीं है।", + "The_redirectUri_is_required": "रीडायरेक्टयूरी आवश्यक है", + "The_selected_user_is_not_a_monitor": "चयनित उपयोगकर्ता मॉनिटर नहीं है", + "The_selected_user_is_not_an_agent": "चयनित उपयोगकर्ता कोई एजेंट नहीं है", + "The_server_will_restart_in_s_seconds": "सर्वर %s सेकंड में पुनरारंभ हो जाएगा", + "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s": "सेटिंग %s को %s पर कॉन्फ़िगर किया गया है और आप %s से एक्सेस कर रहे हैं!", + "The_user_s_will_be_removed_from_role_s": "उपयोगकर्ता %s को भूमिका %s से हटा दिया जाएगा", + "The_user_will_be_removed_from_s": "उपयोगकर्ता को %s से हटा दिया जाएगा", + "The_user_wont_be_able_to_type_in_s": "उपयोगकर्ता %s टाइप नहीं कर पाएगा", + "The_workspace_has_exceeded_the_monthly_limit_of_active_contacts": "कार्यक्षेत्र सक्रिय संपर्कों की मासिक सीमा को पार कर गया है.", + "Theme": "विषय", + "Themes": "विषय-वस्तु", + "Choose_theme_description": "वह इंटरफ़ेस स्वरूप चुनें जो आपकी आवश्यकताओं के लिए सबसे उपयुक्त हो।", + "theme-color-attention-color": "ध्यान दें रंग", + "theme-color-component-color": "घटक रंग", + "theme-color-content-background-color": "सामग्री पृष्ठभूमि रंग", + "theme-color-custom-scrollbar-color": "कस्टम स्क्रॉलबार रंग", + "theme-color-error-color": "त्रुटि रंग", + "theme-color-info-font-color": "जानकारी फ़ॉन्ट रंग", + "theme-color-link-font-color": "लिंक फ़ॉन्ट रंग", + "theme-color-pending-color": "लंबित रंग", + "theme-color-primary-action-color": "प्राथमिक क्रिया रंग", + "theme-color-primary-background-color": "प्राथमिक पृष्ठभूमि रंग", + "theme-color-primary-font-color": "प्राथमिक फ़ॉन्ट रंग", + "theme-color-rc-color-alert": "चेतावनी", + "theme-color-rc-color-alert-light": "चेतावनी प्रकाश", + "theme-color-rc-color-alert-message-primary": "चेतावनी संदेश प्राथमिक", + "theme-color-rc-color-alert-message-primary-background": "चेतावनी संदेश प्राथमिक पृष्ठभूमि", + "theme-color-rc-color-alert-message-secondary": "चेतावनी संदेश माध्यमिक", + "theme-color-rc-color-alert-message-secondary-background": "चेतावनी संदेश द्वितीयक पृष्ठभूमि", + "theme-color-rc-color-alert-message-warning": "चेतावनी संदेश चेतावनी", + "theme-color-rc-color-alert-message-warning-background": "चेतावनी संदेश चेतावनी पृष्ठभूमि", + "theme-color-rc-color-announcement-text": "घोषणा पाठ का रंग", + "theme-color-rc-color-announcement-background": "घोषणा पृष्ठभूमि रंग", + "theme-color-rc-color-announcement-text-hover": "घोषणा पाठ रंग होवर", + "theme-color-rc-color-announcement-background-hover": "घोषणा पृष्ठभूमि रंग होवर", + "theme-color-rc-color-button-primary": "बटन प्राथमिक", + "theme-color-rc-color-button-primary-light": "बटन प्राइमरी लाइट", + "theme-color-rc-color-content": "सामग्री", + "theme-color-rc-color-error": "गलती", + "theme-color-rc-color-error-light": "त्रुटि प्रकाश", + "theme-color-rc-color-link-active": "लिंक सक्रिय", + "theme-color-rc-color-primary": "प्राथमिक", + "theme-color-rc-color-primary-background": "प्राथमिक पृष्ठभूमि", + "theme-color-rc-color-primary-dark": "प्राथमिक अंधेरा", + "theme-color-rc-color-primary-darkest": "प्राथमिक अंधकारमय", + "theme-color-rc-color-primary-light": "प्राथमिक प्रकाश", + "theme-color-rc-color-primary-light-medium": "प्राथमिक प्रकाश माध्यम", + "theme-color-rc-color-primary-lightest": "प्राथमिक सबसे हल्का", + "theme-color-rc-color-success": "सफलता", + "theme-color-rc-color-success-light": "सफलता प्रकाश", + "theme-color-secondary-action-color": "द्वितीयक क्रिया रंग", + "theme-color-secondary-background-color": "द्वितीयक पृष्ठभूमि रंग", + "theme-color-secondary-font-color": "द्वितीयक फ़ॉन्ट रंग", + "theme-color-selection-color": "चयन रंग", + "theme-color-status-away": "दूर स्थिति रंग", + "theme-color-status-busy": "व्यस्त स्थिति रंग", + "theme-color-status-offline": "ऑफ़लाइन स्थिति रंग", + "theme-color-status-online": "ऑनलाइन स्थिति का रंग", + "theme-color-success-color": "सफलता का रंग", + "theme-color-transparent-dark": "पारदर्शी अंधेरा", + "theme-color-transparent-darker": "पारदर्शी गहरा", + "theme-color-transparent-lightest": "पारदर्शी सबसे हल्का", + "theme-color-unread-notification-color": "अपठित सूचनाएं रंग", + "theme-custom-css": "कस्टम सीएसएस", + "theme-font-body-font-family": "बॉडी फ़ॉन्ट परिवार", + "There_are_no_agents_added_to_this_department_yet": "इस विभाग में अभी तक कोई एजेंट नहीं जोड़ा गया है.", + "There_are_no_applications": "अभी तक कोई OAuth एप्लिकेशन नहीं जोड़ा गया है.", + "There_are_no_applications_installed": "वर्तमान में कोई Rocket.Chat एप्लिकेशन इंस्टॉल नहीं हैं।", + "There_are_no_available_monitors": "कोई मॉनिटर उपलब्ध नहीं हैं", + "There_are_no_departments_added_to_this_tag_yet": "इस टैग में अभी तक कोई विभाग नहीं जोड़ा गया है", + "There_are_no_departments_added_to_this_unit_yet": "इस इकाई में अभी तक कोई विभाग नहीं जोड़ा गया है", + "There_are_no_departments_available": "कोई विभाग उपलब्ध नहीं है", + "There_are_no_integrations": "कोई एकीकरण नहीं हैं", + "There_are_no_monitors_added_to_this_unit_yet": "इस इकाई में अभी तक कोई मॉनिटर नहीं जोड़ा गया है", + "There_are_no_personal_access_tokens_created_yet": "अभी तक कोई व्यक्तिगत एक्सेस टोकन नहीं बनाया गया है।", + "There_are_no_rooms_for_the_given_search_criteria": "दिए गए खोज मानदंड के लिए कोई जगह नहीं है", + "There_are_no_users_in_this_role": "इस भूमिका में कोई उपयोगकर्ता नहीं है.", + "There_is_no_video_conference_history_in_this_room": "इस कमरे में कोई कॉन्फ़्रेंस कॉल इतिहास नहीं है", + "There_is_one_or_more_apps_in_an_invalid_state_Click_here_to_review": "एक या अधिक ऐप्स अमान्य स्थिति में हैं. समीक्षा के लिए यहां क्लिक करें.", + "There_has_been_an_error_installing_the_app": "ऐप इंस्टॉल करने में त्रुटि हुई है", + "These_notes_will_be_available_in_the_call_summary": "ये नोट्स कॉल सारांश में उपलब्ध होंगे", + "This_agent_was_already_selected": "यह एजेंट पहले ही चयनित हो चुका था", + "this_app_is_included_with_subscription": "यह ऐप {{bundleName}} योजनाओं के साथ शामिल है", + "This_cant_be_undone": "इसे पूर्ववत नहीं किया जा सकता.", + "This_conversation_is_already_closed": "यह बातचीत पहले ही बंद हो चुकी है.", + "This_email_has_already_been_used_and_has_not_been_verified__Please_change_your_password": "यह ईमेल पहले ही उपयोग किया जा चुका है और सत्यापित नहीं किया गया है. कृपया अपना पासवर्ड बदलें.", + "This_feature_is_currently_in_alpha": "यह सुविधा फिलहाल अल्फ़ा में है!", + "This_is_a_desktop_notification": "यह एक डेस्कटॉप अधिसूचना है", + "This_is_a_deprecated_feature_alert": "यह एक बहिष्कृत सुविधा है. यह उम्मीद के मुताबिक काम नहीं कर पाएगा और नए अपडेट नहीं मिलेंगे।", + "Zapier_integration_has_been_deprecated": "जैपियर एकीकरण को अप्रचलित कर दिया गया है, हो सकता है कि यह अपेक्षा के अनुरूप काम न करे और अपडेट प्राप्त न हो", + "Install_Zapier_from_marketplace": "व्यवधानों से बचने के लिए मार्केटप्लेस से जैपियर ऐप इंस्टॉल करें", + "This_is_a_push_test_messsage": "यह एक पुश परीक्षण संदेश है", + "This_message_was_rejected_by__peer__peer": "इस संदेश को {{peer}} सहकर्मी द्वारा अस्वीकार कर दिया गया था।", + "This_monitor_was_already_selected": "यह मॉनीटर पहले ही चयनित था", + "This_month": "इस महीने", + "This_room_has_been_archived_by__username_": "यह कमरा {{username}} द्वारा संग्रहीत किया गया है", + "This_room_has_been_unarchived_by__username_": "इस कमरे को {{username}} द्वारा असंग्रहीत कर दिया गया है", + "This_room_has_been_archived": "संग्रहीत कक्ष", + "This_room_has_been_unarchived": "अनारक्षित कमरा", + "This_server_will_be_available_while_your_session_is_active": "यह सर्वर आपके सत्र के सक्रिय रहने के दौरान उपलब्ध रहेगा", + "This_week": "इस सप्ताह", + "thread": "धागा", + "Thread_message": "*{{username}} के* संदेश पर टिप्पणी की गई: _ {{msg}} _", + "Threads": "धागे", + "Threads_Description": "थ्रेड्स किसी विशिष्ट संदेश के इर्द-गिर्द संगठित चर्चा की अनुमति देते हैं।", + "Threads_unavailable_for_federation": "फेडरेटेड रूम के लिए थ्रेड्स उपलब्ध नहीं हैं", + "Thursday": "गुरुवार", + "Time_in_minutes": "समय मिनटों में", + "Time_in_seconds": "समय सेकंड में", + "Timeout": "समय समाप्त", + "Timeouts": "समय समाप्ति", + "Timezone": "समय क्षेत्र", + "Title": "शीर्षक", + "Title_bar_color": "टाइटल बार का रंग", + "Title_bar_color_offline": "टाइटल बार का रंग ऑफ़लाइन", + "Title_offline": "शीर्षक ऑफ़लाइन", + "To": "को", + "To_additional_emails": "अतिरिक्त ईमेल के लिए", + "To_install_RocketChat_Livechat_in_your_website_copy_paste_this_code_above_the_last_body_tag_on_your_site": "अपनी वेबसाइट में Rocket.Chat लाइवचैट स्थापित करने के लिए, इस कोड को अपनी साइट पर अंतिम </body> टैग के ऊपर कॉपी और पेस्ट करें।", + "To_prevent_seeing_this_message_again_allow_popups_from_workspace_URL": "इस संदेश को दोबारा देखने से रोकने के लिए, सुनिश्चित करें कि आपकी ब्राउज़र सेटिंग्स कार्यस्थान URL से पॉप-अप खोलने की अनुमति देती हैं:", + "to_see_more_details_on_how_to_integrate": "एकीकृत करने के तरीके के बारे में अधिक विवरण देखने के लिए।", + "To_users": "उपयोगकर्ताओं के लिए", + "Today": "आज", + "Toggle_original_translated": "मूल/अनुवादित टॉगल करें", + "toggle-room-e2e-encryption": "कक्ष E2E एन्क्रिप्शन टॉगल करें", + "toggle-room-e2e-encryption_description": "e2e एन्क्रिप्शन कक्ष को टॉगल करने की अनुमति", + "Token": "टोकन", + "Token_Access": "टोकन एक्सेस", + "Token_Controlled_Access": "टोकन नियंत्रित पहुंच", + "Token_has_been_removed": "टोकन हटा दिया गया है", + "Token_required": "टोकन आवश्यक है", + "Tokens_Minimum_Needed_Balance": "न्यूनतम आवश्यक टोकन बैलेंस", + "Tokens_Minimum_Needed_Balance_Description": "प्रत्येक टोकन पर न्यूनतम आवश्यक शेष राशि निर्धारित करें। सीमा नहीं के लिए रिक्त या \"0\"।", + "Tokens_Minimum_Needed_Balance_Placeholder": "संतुलन मूल्य", + "Tokens_Required": "टोकन आवश्यक है", + "Tokens_Required_Input_Description": "अल्पविराम से अलग किए गए एक या अधिक टोकन परिसंपत्ति नाम टाइप करें।", + "Tokens_Required_Input_Error": "अमान्य टाइप किए गए टोकन.", + "Tokens_Required_Input_Placeholder": "टोकन संपत्ति के नाम", + "Topic": "विषय", + "Top_5_agents_with_the_most_conversations": "सर्वाधिक बातचीत वाले शीर्ष 5 एजेंट", + "Total": "कुल", + "Total_abandoned_chats": "कुल छोड़ी गई चैट", + "Total_conversations": "कुल बातचीत", + "Total_Discussions": "चर्चाएँ", + "Total_messages": "कुल संदेश", + "Total_rooms": "कुल कमरे", + "Total_Threads": "धागे", + "Total_visitors": "कुल आगंतुक", + "TOTP Invalid [totp-invalid]": "कोड या पासवर्ड अमान्य", + "TOTP_reset_email": "दो कारक TOTP रीसेट अधिसूचना", + "TOTP_Reset_Other_Key_Warning": "वर्तमान टू फैक्टर TOTP को रीसेट करने से उपयोगकर्ता लॉग आउट हो जाएगा। यूजर बाद में टू फैक्टर को दोबारा सेट कर सकेगा।", + "totp-disabled": "आपके पास अपने उपयोगकर्ता के लिए 2FA लॉगिन सक्षम नहीं है", + "totp-invalid": "कोड या पासवर्ड अमान्य", + "totp-required": "टीओटीपी आवश्यक", + "Transcript": "प्रतिलिपि", + "Transcript_Enabled": "विज़िटर से पूछें कि क्या वे चैट बंद होने के बाद एक प्रतिलेख चाहेंगे", + "Transcript_message": "प्रतिलेख के बारे में पूछने पर दिखाने योग्य संदेश", + "Transcript_of_your_livechat_conversation": "आपकी सर्वचैनल बातचीत का प्रतिलेख।", + "Transcript_Request": "प्रतिलेख अनुरोध", + "onboarding.form.registeredServerForm.continueStandalone": "स्टैंडअलोन के रूप में जारी रखें", + "transfer-livechat-guest": "लाइवचैट मेहमानों को स्थानांतरित करें", + "transfer-livechat-guest_description": "लाइवचैट मेहमानों को स्थानांतरित करने की अनुमति", + "Transferred": "तबादला", + "Translate": "अनुवाद", + "Translated": "अनुवाद", + "Translate_to": "अनुवाद करने के लिए", + "Translations": "अनुवाद", + "Travel_and_Places": "यात्रा एवं स्थान", + "Trigger_removed": "ट्रिगर हटा दिया गया", + "Trigger_Words": "ट्रिगर शब्द", + "Trigger": "चालू कर देना", + "Triggers": "चलाता है", + "Troubleshoot": "समस्याओं का निवारण", + "Troubleshoot_Description": "कॉन्फ़िगर करें कि आपके कार्यक्षेत्र पर समस्या निवारण कैसे प्रबंधित किया जाता है।", + "Troubleshoot_Disable_Data_Exporter_Processor": "डेटा निर्यातक प्रोसेसर को अक्षम करें", + "Troubleshoot_Disable_Data_Exporter_Processor_Alert": "यह सेटिंग उपयोगकर्ताओं से सभी निर्यात अनुरोधों की प्रोसेसिंग रोक देती है, इसलिए उन्हें अपना डेटा डाउनलोड करने के लिए लिंक प्राप्त नहीं होगा!", + "Troubleshoot_Disable_Instance_Broadcast": "इंस्टेंस प्रसारण अक्षम करें", + "Troubleshoot_Disable_Instance_Broadcast_Alert": "यह सेटिंग Rocket.Chat इंस्टेंस को अन्य इंस्टेंस पर इवेंट भेजने से रोकती है, इससे सिंकिंग समस्याएं और दुर्व्यवहार हो सकता है!", + "Troubleshoot_Disable_Livechat_Activity_Monitor": "लाइवचैट गतिविधि मॉनिटर अक्षम करें", + "Troubleshoot_Disable_Livechat_Activity_Monitor_Alert": "यह सेटिंग लाइवचैट विज़िटर सत्रों की प्रोसेसिंग को रोक देती है जिससे आँकड़े सही ढंग से काम करना बंद कर देते हैं!", + "Troubleshoot_Disable_Notifications": "नोटीफिकेशन निष्क्रिय किया गया", + "Troubleshoot_Disable_Notifications_Alert": "यह सेटिंग अधिसूचना प्रणाली को पूरी तरह से अक्षम कर देती है; ध्वनियाँ, डेस्कटॉप सूचनाएं, मोबाइल सूचनाएं और ईमेल बंद हो जाएंगे!", + "Troubleshoot_Disable_Presence_Broadcast": "उपस्थिति प्रसारण अक्षम करें", + "Troubleshoot_Disable_Presence_Broadcast_Alert": "यह सेटिंग पहले लोड से सभी उपयोगकर्ताओं को उनकी उपस्थिति स्थिति के साथ रखते हुए, उनके क्लाइंट को उपयोगकर्ताओं की स्थिति में बदलाव भेजने वाले सभी उदाहरणों को रोकती है!", + "Troubleshoot_Disable_Sessions_Monitor": "सत्र मॉनिटर अक्षम करें", + "Troubleshoot_Disable_Sessions_Monitor_Alert": "यह सेटिंग उपयोगकर्ता सत्रों के प्रसंस्करण को रोक देती है जिससे आँकड़े सही ढंग से काम करना बंद कर देते हैं!", + "Troubleshoot_Disable_Teams_Mention": "अक्षम टीमों का उल्लेख", + "Troubleshoot_Disable_Teams_Mention_Alert": "यह सेटिंग टीम उल्लेख सुविधा को अक्षम कर देती है. उपयोगकर्ता किसी संदेश में नाम से किसी टीम का उल्लेख नहीं कर पाएंगे और उसके सदस्यों को सूचित नहीं कर पाएंगे।", + "Troubleshoot_Force_Caching_Version": "संस्करण परिवर्तन के आधार पर ब्राउज़रों को नेटवर्किंग कैश साफ़ करने के लिए बाध्य करें", + "Troubleshoot_Force_Caching_Version_Alert": "यदि प्रदान किया गया मान खाली नहीं है और पिछले वाले से भिन्न है तो ब्राउज़र कैश साफ़ करने का प्रयास करेंगे। यह सेटिंग लंबे समय तक सेट नहीं की जानी चाहिए क्योंकि यह ब्राउज़र के प्रदर्शन को प्रभावित करती है, कृपया इसे जल्द से जल्द साफ़ करें।", + "True": "सत्य", + "Try_now": "अब कोशिश करो", + "Try_searching_in_the_marketplace_instead": "इसके बजाय मार्केटप्लेस में खोजने का प्रयास करें", + "Tuesday": "मंगलवार", + "Turn_OFF": "बंद करें", + "Turn_ON": "चालू करो", + "Turn_on_video": "वीडियो चालू करें", + "Turn_on_answer_chats": "उत्तर चैट चालू करें", + "Turn_on_answer_calls": "कॉल का उत्तर देना चालू करें", + "Turn_on_microphone": "माइक्रोफ़ोन चालू करें", + "Turn_off_microphone": "माइक्रोफ़ोन बंद करें", + "Turn_off_answer_chats": "उत्तर चैट बंद करें", + "Turn_off_answer_calls": "उत्तर कॉल बंद करें", + "Turn_off_video": "वीडियो बंद करें", + "Two Factor Authentication": "दो तरीकों से प्रमाणीकरण", + "Two-factor_authentication": "टीओटीपी के माध्यम से दो-कारक प्रमाणीकरण", + "Two-factor_authentication_disabled": "दो-कारक प्रमाणीकरण अक्षम किया गया", + "Two-factor_authentication_email": "ईमेल के माध्यम से दो-कारक प्रमाणीकरण", + "Two-factor_authentication_email_is_currently_disabled": "ईमेल के माध्यम से दो-कारक प्रमाणीकरण वर्तमान में अक्षम है", + "Two-factor_authentication_enabled": "दो-कारक प्रमाणीकरण सक्षम किया गया", + "Two-factor_authentication_is_currently_disabled": "टीओटीपी के माध्यम से दो-कारक प्रमाणीकरण वर्तमान में अक्षम है", + "Two-factor_authentication_native_mobile_app_warning": "चेतावनी: एक बार जब आप इसे सक्षम कर लेते हैं, तो आप अपने पासवर्ड का उपयोग करके मूल मोबाइल ऐप्स (रॉकेट.चैट+) पर तब तक लॉगिन नहीं कर पाएंगे जब तक वे 2FA लागू नहीं कर देते।", + "Type": "प्रकार", + "typing": "टाइपिंग", + "Types": "प्रकार", + "Types_and_Distribution": "प्रकार और वितरण", "Type_your_email": "अपना ईमेल टाइप करें", + "Type_your_job_title": "अपनी नौकरी का शीर्षक टाइप करें", "Type_your_message": "अपना संदेश टाइप करें", "Type_your_name": "अपना नाम लिखें", + "Type_your_password": "अपना पासवर्ड टाइप करें", + "Type_your_username": "अपना उपयोगकर्ता नाम टाइप करें", + "UI_Allow_room_names_with_special_chars": "कमरे के नाम में विशेष वर्णों की अनुमति दें", + "UI_Click_Direct_Message": "सीधा संदेश बनाने के लिए क्लिक करें", + "UI_Click_Direct_Message_Description": "प्रोफ़ाइल टैब खोलना छोड़ें, इसके बजाय सीधे बातचीत पर जाएँ", + "UI_DisplayRoles": "भूमिकाएँ प्रदर्शित करें", + "UI_Group_Channels_By_Type": "चैनलों को प्रकार के अनुसार समूहित करें", + "UI_Merge_Channels_Groups": "निजी समूहों को चैनलों के साथ मिलाएं", + "UI_Show_top_navbar_embedded_layout": "एम्बेडेड लेआउट में शीर्ष नेवबार दिखाएं", + "UI_Unread_Counter_Style": "अपठित काउंटर शैली", + "UI_Use_Name_Avatar": "डिफ़ॉल्ट अवतार उत्पन्न करने के लिए पूरे नाम के पहले अक्षर का उपयोग करें", + "UI_Use_Real_Name": "वास्तविक नाम का प्रयोग करें", + "unable-to-get-file": "फ़ाइल प्राप्त करने में असमर्थ", + "Unable_to_load_active_connections": "सक्रिय कनेक्शन लोड करने में असमर्थ", + "Unarchive": "संग्रह से निकालें", + "unarchive-room": "कक्ष को असंग्रहीत करें", + "unarchive-room_description": "चैनलों को असंग्रहीत करने की अनुमति", + "Unassigned": "सौंपे नहीं गए", + "unauthorized": "अधिकृत नहीं हैं", + "Unavailable": "अनुपलब्ध", + "Unblock": "अनब्लॉक", + "Unblock_User": "उपयोगकर्ता को अनब्लॉक करें", + "Uncheck_All": "सब को अचयनित करें", + "Uncollapse": "खोलना", + "Undefined": "अपरिभाषित", + "Unfavorite": "नापसंद करें", + "Unfollow_message": "संदेश को अनफ़ॉलो करें", + "Unignore": "अनदेखा न करें", + "Uninstall": "स्थापना रद्द करें", + "Units": "इकाइयों", + "Unit_removed": "इकाई हटा दी गई", + "Unique_ID_change_detected_description": "इस कार्यक्षेत्र की पहचान करने वाली जानकारी बदल गई है. ऐसा तब हो सकता है जब साइट यूआरएल या डेटाबेस कनेक्शन स्ट्रिंग बदल दी जाती है या जब मौजूदा डेटाबेस की एक प्रति से एक नया कार्यक्षेत्र बनाया जाता है।

    क्या आप मौजूदा कार्यक्षेत्र में कॉन्फ़िगरेशन अपडेट के साथ आगे बढ़ना चाहेंगे या एक नया कार्यक्षेत्र और अद्वितीय आईडी बनाना चाहेंगे?", + "Unique_ID_change_detected_learn_more_link": "और अधिक जानें", + "Unique_ID_change_detected": "अद्वितीय आईडी परिवर्तन का पता चला", + "Unknown_Import_State": "अज्ञात आयात राज्य", + "Unknown_User": "अज्ञात उपयोगकर्ता", + "Unlimited": "असीमित", + "Unmute": "अनम्यूट", + "Unmute_someone_in_room": "कमरे में किसी को अनम्यूट करें", + "Unmute_user": "उपयोगकर्ता को अनम्यूट करें", + "Unnamed": "अज्ञात", + "Unpin": "अनपिन", + "Unpin_Message": "संदेश अनपिन करें", + "unpinning-not-allowed": "अनपिन करने की अनुमति नहीं है", + "Unprioritized": "प्राथमिकता रहित", + "Unread": "अपठित ग", + "Unread_Count": "अपठित count", + "Unread_Count_DM": "सीधे संदेशों के लिए अपठित गणना", + "Unread_Count_Omni": "ओमनीचैनल चैट के लिए अपठित गणना", + "Unread_Messages": "अपठित संदेश", + "Unread_on_top": "शीर्ष पर अपठित", + "Unread_Rooms": "अपठित कमरे", + "Unread_Rooms_Mode": "अपठित कमरे मोड", + "Unread_Requested_First": "पहले अपठित का अनुरोध किया गया", + "Unread_Requested_Last": "अंतिम बार अपठित का अनुरोध किया गया", + "Unread_Tray_Icon_Alert": "अपठित ट्रे चिह्न चेतावनी", + "Unstar_Message": "तारा हटाएँ", + "Unmute_microphone": "माइक्रोफ़ोन अनम्यूट करें", + "Update": "अद्यतन", + "Update_EnableChecker": "अपडेट चेकर सक्षम करें", + "Update_EnableChecker_Description": "Rocket.Chat डेवलपर्स से नए अपडेट/महत्वपूर्ण संदेशों के लिए स्वचालित रूप से जाँच करता है और उपलब्ध होने पर सूचनाएं प्राप्त करता है। अधिसूचना प्रति नए संस्करण में एक बार क्लिक करने योग्य बैनर के रूप में और रॉकेट.कैट बॉट से एक संदेश के रूप में दिखाई देती है, दोनों ही केवल प्रशासकों के लिए दृश्यमान होते हैं।", + "Update_every": "प्रत्येक को अद्यतन करें", + "Update_LatestAvailableVersion": "नवीनतम उपलब्ध संस्करण अपडेट करें", + "Update_to_version": "{{version}} पर अपडेट करें", + "Update_your_RocketChat": "अपने रॉकेट.चैट को अपडेट करें", + "Updated_at": "पर अद्यतन किया गया", + "Upgrade_tab_upgrade_your_plan": "अपनी योजना को अपग्रेड करें", + "Upload": "डालना", + "Uploads": "अपलोड", + "Upload_private_app": "निजी ऐप अपलोड करें", + "Upload_file_description": "फाइल विवरण", + "Upload_file_name": "फ़ाइल का नाम", "Upload_file_question": "दस्तावेज अपलोड करें?", + "Upload_Folder_Path": "फ़ोल्डर पथ अपलोड करें", + "Upload_From": "{{name}} से अपलोड करें", + "Upload_user_avatar": "अवतार अपलोड करें", + "Uploading_file": "फ़ाइल अपलोड हो रही है...", + "Uptime": "अपटाइम", + "URL": "यूआरएल", + "URLs": "यूआरएल", + "Usage": "प्रयोग", + "Use": "उपयोग", + "Use_account_preference": "खाता प्राथमिकता का उपयोग करें", + "Use_Emojis": "इमोजी का प्रयोग करें", + "Use_Global_Settings": "वैश्विक सेटिंग्स का प्रयोग करें", + "Use_initials_avatar": "अपने उपयोक्तानाम के आरंभिक अक्षरों का प्रयोग करें", + "Use_minor_colors": "छोटे रंग पैलेट का उपयोग करें (डिफ़ॉल्ट रूप से प्रमुख रंग प्राप्त होते हैं)", + "Use_Room_configuration": "सर्वर कॉन्फ़िगरेशन को अधिलेखित करता है और रूम कॉन्फ़िगरेशन का उपयोग करता है", + "Use_Server_configuration": "सर्वर कॉन्फ़िगरेशन का उपयोग करें", + "Use_service_avatar": "%s अवतार का प्रयोग करें", + "Use_this_response": "इस प्रतिक्रिया का प्रयोग करें", + "Use_response": "प्रतिक्रिया का प्रयोग करें", + "Use_this_username": "इस उपयोक्तानाम का प्रयोग करें", + "Use_uploaded_avatar": "अपलोड किए गए अवतार का उपयोग करें", + "Use_url_for_avatar": "अवतार के लिए यूआरएल का प्रयोग करें", + "Use_User_Preferences_or_Global_Settings": "उपयोगकर्ता प्राथमिकताएँ या वैश्विक सेटिंग्स का उपयोग करें", + "User": "उपयोगकर्ता", + "User_menu": "उपयोगकर्ता विकल्प सूची", + "User Search": "उपयोगकर्ता खोज", + "User Search (Group Validation)": "उपयोगकर्ता खोज (समूह सत्यापन)", + "User__username__is_now_a_leader_of__room_name_": "उपयोगकर्ता {{username}} अब {{room_name}} का लीडर है", + "User__username__is_now_a_moderator_of__room_name_": "उपयोगकर्ता {{username}} अब {{room_name}} का मॉडरेटर है", + "User__username__is_now_an_owner_of__room_name_": "उपयोगकर्ता {{username}} अब {{room_name}} का स्वामी है", + "User__username__muted_in_room__roomName__": "उपयोगकर्ता {{username}} को कक्ष {{roomName}} में म्यूट कर दिया गया है", + "User__username__removed_from__room_name__leaders": "उपयोगकर्ता {{username}} को {{room_name}} लीडरों से हटा दिया गया", + "User__username__removed_from__room_name__moderators": "उपयोगकर्ता {{username}} को {{room_name}} मॉडरेटर से हटा दिया गया", + "User__username__removed_from__room_name__owners": "उपयोगकर्ता {{username}} को {{room_name}} स्वामियों से हटा दिया गया", + "User__username__unmuted_in_room__roomName__": "उपयोगकर्ता {{username}} को कमरे में अनम्यूट किया गया है {{roomName}}", + "User_added": "उपयोगकर्ता जोड़ा गया", + "User_added_by": "उपयोगकर्ता {{user_added}} को {{user_by}} द्वारा जोड़ा गया।", + "User_added_to": "जोड़ा गया {{user_added}}", + "User_added_successfully": "उपयोगकर्ता सफलतापूर्वक जोड़ा गया", + "User_and_group_mentions_only": "केवल उपयोगकर्ता और समूह का उल्लेख है", + "User_cant_be_empty": "उपयोगकर्ता खाली नहीं हो सकता", + "User_created_successfully!": "उपयोगकर्ता सफलतापूर्वक बना!", + "User_default": "उपयोगकर्ता डिफ़ॉल्ट", + "User_doesnt_exist": "`@%s` नाम से कोई उपयोगकर्ता मौजूद नहीं है।", + "User_e2e_key_was_reset": "उपयोगकर्ता E2E कुंजी सफलतापूर्वक रीसेट कर दी गई थी।", + "User_has_been_activated": "उपयोगकर्ता सक्रिय कर दिया गया है", + "User_has_been_deactivated": "उपयोगकर्ता को निष्क्रिय कर दिया गया है", + "User_has_been_deleted": "उपयोगकर्ता हटा दिया गया है", + "User_has_been_ignored": "उपयोगकर्ता को नजरअंदाज कर दिया गया है", + "User_has_been_muted_in_s": "उपयोगकर्ता को %s में म्यूट कर दिया गया है", + "User_has_been_removed_from_s": "उपयोगकर्ता को %s से हटा दिया गया है", + "User_has_been_removed_from_team": "उपयोगकर्ता को टीम से हटा दिया गया है", + "User_has_been_unignored": "उपयोगकर्ता को अब अनदेखा नहीं किया जाएगा", + "User_Info": "उपयोगकर्ता जानकारी", + "User_Interface": "प्रयोक्ता इंटरफ़ेस", + "User_is_blocked": "उपयोगकर्ता अवरुद्ध है", + "User_is_no_longer_an_admin": "उपयोगकर्ता अब व्यवस्थापक नहीं है", + "User_is_now_an_admin": "उपयोगकर्ता अब एक व्यवस्थापक है", + "User_is_unblocked": "उपयोगकर्ता को अनब्लॉक कर दिया गया है", + "User_joined_channel": "चैनल से जुड़ गया है.", + "User_joined_conversation": "बातचीत में शामिल हो गए हैं", + "User_joined_team": "इस टीम में शामिल हुए", + "User_joined_the_channel": "चैनल से जुड़े", + "User_joined_the_conversation": "बातचीत में शामिल हुए", + "User_joined_the_team": "इस टीम में शामिल हुए", + "user_joined_otr": "ओटीआर चैट में शामिल हो गया है।", + "user_key_refreshed_successfully": "कुंजी सफलतापूर्वक ताज़ा हो गई", + "user_requested_otr_key_refresh": "कुंजी ताज़ा करने का अनुरोध किया है.", "User_left": "उपयोगकर्ता छोड़ दिया", + "User_left_team": "इस टीम को छोड़ दिया", + "User_left_this_channel": "चैनल छोड़ दिया", + "User_left_this_team": "इस टीम को छोड़ दिया", + "User_logged_out": "उपयोगकर्ता लॉग आउट हो गया है", + "User_management": "प्रयोक्ता प्रबंधन", + "User_mentions_only": "उपयोगकर्ता केवल उल्लेख करता है", + "User_muted": "उपयोगकर्ता म्यूट किया गया", + "User_muted_by": "उपयोगकर्ता {{user_muted}} को {{user_by}} द्वारा म्यूट कर दिया गया है।", + "User_has_been_muted": "म्यूट किया गया {{user_muted}}", + "User_not_found": "उपयोगकर्ता नहीं मिला", + "User_not_found_or_incorrect_password": "उपयोगकर्ता नहीं मिला या पासवर्ड ग़लत है", + "User_or_channel_name": "उपयोगकर्ता या चैनल का नाम", + "User_Presence": "उपयोगकर्ता की उपस्थिति", + "User_removed": "उपयोगकर्ता हटा दिया गया", + "User_removed_by": "उपयोगकर्ता {{user_removed}} को {{user_by}} द्वारा हटा दिया गया।", + "User_has_been_removed": "हटा दिया गया {{user_removed}}", + "User_sent_a_message_on_channel": "{{username}} ने {{channel}} पर एक संदेश भेजा", + "User_sent_a_message_to_you": "{{username}} ने आपको एक संदेश भेजा है", + "user_sent_an_attachment": "{{user}} ने एक अनुलग्नक भेजा", + "User_Settings": "उपयोगकर्ता सेटिंग", + "User_started_a_new_conversation": "{{username}} ने एक नई बातचीत शुरू की", + "User_unmuted_by": "उपयोगकर्ता {{user_unmuted}} को {{user_by}} द्वारा अनम्यूट किया गया।", + "User_has_been_unmuted": "अनम्यूट किया गया {{user_unmuted}}", + "User_unmuted_in_room": "उपयोगकर्ता को कमरे में अनम्यूट कर दिया गया", + "User_updated_successfully": "उपयोगकर्ता सफलतापूर्वक अपडेट किया गया", + "User_uploaded_a_file_on_channel": "{{username}} ने {{channel}} पर एक फ़ाइल अपलोड की", + "User_uploaded_a_file_to_you": "{{username}} ने आपको एक फ़ाइल भेजी है", + "User_uploaded_file": "एक फ़ाइल अपलोड की गई", + "User_uploaded_image": "एक छवि अपलोड की गई", + "user-generate-access-token": "उपयोगकर्ता एक्सेस टोकन जनरेट करें", + "user-generate-access-token_description": "उपयोगकर्ताओं को एक्सेस टोकन जनरेट करने की अनुमति", + "UserData_EnableDownload": "उपयोगकर्ता डेटा डाउनलोड सक्षम करें", + "UserData_FileSystemPath": "सिस्टम पथ (निर्यात फ़ाइलें)", + "view-livechat-facebook": "ओमनीचैनल फेसबुक देखें", + "UserData_FileSystemZipPath": "सिस्टम पथ (संपीड़ित फ़ाइल)", + "view-livechat-facebook_description": "ओमनीचैनल फेसबुक देखने की अनुमति", + "UserData_MessageLimitPerRequest": "प्रति अनुरोध संदेश सीमा", + "UserData_ProcessingFrequency": "प्रसंस्करण आवृत्ति (मिनट)", + "UserDataDownload": "उपयोगकर्ता डेटा डाउनलोड", + "UserDataDownload_Description": "कार्यस्थान सदस्यों को कार्यस्थान डेटा डाउनलोड करने की अनुमति देने या अस्वीकृत करने के लिए कॉन्फ़िगरेशन।", + "UserDataDownload_CompletedRequestExisted_Text": "आपकी डेटा फ़ाइल पहले ही जनरेट हो चुकी थी. डाउनलोड लिंक के लिए अपना ईमेल खाता जांचें।", + "UserDataDownload_CompletedRequestExistedWithLink_Text": "आपकी डेटा फ़ाइल पहले ही जनरेट हो चुकी थी. इसे डाउनलोड करने के लिए यहां क्लिक करें।", + "UserDataDownload_EmailBody": "आपकी डेटा फ़ाइल अब डाउनलोड करने के लिए तैयार है। इसे डाउनलोड करने के लिए यहां क्लिक करें।", + "UserDataDownload_EmailSubject": "आपकी डेटा फ़ाइल डाउनलोड करने के लिए तैयार है", + "UserDataDownload_Requested": "अनुरोधित फ़ाइल डाउनलोड करें", + "UserDataDownload_Requested_Text": "आपकी डेटा फ़ाइल तैयार हो जाएगी. तैयार होने पर इसे डाउनलोड करने का एक लिंक आपके ईमेल पते पर भेजा जाएगा। आपके सामने चलने के लिए कतारबद्ध {{pending_operations}} हैं।", + "UserDataDownload_RequestExisted_Text": "आपकी डेटा फ़ाइल पहले से ही जेनरेट की जा रही है. तैयार होने पर इसे डाउनलोड करने का एक लिंक आपके ईमेल पते पर भेजा जाएगा। आपके सामने चलने के लिए कतारबद्ध {{pending_operations}} हैं।", + "Username": "उपयोगकर्ता नाम", + "Username_already_exist": "उपयोगकर्ता का नाम पहले से मौजूद है। कृपया कोई अन्य उपयोक्तानाम आज़माएँ.", + "Username_and_message_must_not_be_empty": "उपयोगकर्ता नाम और संदेश खाली नहीं होना चाहिए.", + "Username_cant_be_empty": "उपयोक्तानाम खाली नहीं हो सकता", + "Username_Change_Disabled": "आपके Rocket.Chat व्यवस्थापक ने उपयोगकर्ता नाम बदलना अक्षम कर दिया है", + "Username_denied_the_OTR_session": "{{username}} ने ओटीआर सत्र अस्वीकृत कर दिया", + "Username_description": "उपयोगकर्ता नाम का उपयोग दूसरों को संदेशों में आपका उल्लेख करने की अनुमति देने के लिए किया जाता है।", + "Username_doesnt_exist": "उपयोक्तानाम `%s` मौजूद नहीं है.", + "Username_ended_the_OTR_session": "{{username}} ने ओटीआर सत्र समाप्त कर दिया", + "Username_invalid": "%s वैध उपयोक्तानाम नहीं है,
    केवल अक्षरों, संख्याओं, बिंदुओं, हाइफ़न और अंडरस्कोर का उपयोग करें", + "Username_is_already_in_here": "`@%s` पहले से ही यहां मौजूद है।", + "Username_Placeholder": "कृपया उपयोक्तानाम दर्ज करें...", + "Username_title": "उपयोक्तानाम पंजीकृत करें", + "Username_has_been_updated": "उपयोगकर्ता नाम अपडेट कर दिया गया है", + "Username_wants_to_start_otr_Do_you_want_to_accept": "{{username}} ओटीआर प्रारंभ करना चाहता है। क्या आप स्वीकार करना चाहते हैं?", + "Username_name_email": "उपयोगकर्ता नाम, नाम या ई-मेल", + "Users": "उपयोगकर्ताओं", + "Users must use Two Factor Authentication": "यूजर्स को टू फैक्टर ऑथेंटिकेशन का इस्तेमाल करना होगा", + "Users_added": "उपयोगकर्ताओं को जोड़ दिया गया है", + "Users_and_rooms": "उपयोगकर्ता और कमरे", + "Users_by_time_of_day": "दिन के समय के अनुसार उपयोगकर्ता", + "Users_in_role": "भूमिका में उपयोगकर्ता", + "Users_key_has_been_reset": "उपयोगकर्ता की कुंजी रीसेट कर दी गई है", + "Users_reacted": "जिन उपयोगकर्ताओं ने प्रतिक्रिया दी", + "Users_TOTP_has_been_reset": "उपयोगकर्ता का TOTP रीसेट कर दिया गया है", + "Uses": "उपयोग", + "Uses_left": "बाएँ उपयोग", + "UTC_Timezone": "यूटीसी समय क्षेत्र", + "Utilities": "उपयोगिताओं", + "UTF8_Names_Slugify": "UTF8 नाम Slugify", + "UTF8_User_Names_Validation": "UTF8 उपयोगकर्ता नाम सत्यापन", + "UTF8_User_Names_Validation_Description": "रेगएक्सपी जिसका उपयोग उपयोगकर्ता नाम सत्यापित करने के लिए किया जाएगा", + "UTF8_Channel_Names_Validation": "UTF8 चैनल नाम सत्यापन", + "UTF8_Channel_Names_Validation_Description": "रेगएक्सपी जिसका उपयोग चैनल नामों को मान्य करने के लिए किया जाएगा", + "Videocall_enabled": "वीडियो कॉल सक्षम", + "Validate_email_address": "ई - मेल पता की पुष्टि करें", + "Validation": "मान्यकरण", + "Value_messages": "{{price}} संदेश", + "Value_users": "{{price}} उपयोगकर्ता", + "Verification": "सत्यापन", + "Verification_Description": "आप निम्नलिखित प्लेसहोल्डर्स का उपयोग कर सकते हैं:\n - सत्यापन URL के लिए `[Verification_Url]`।\n - `[नाम]`, `[fname]`, `[lname]` क्रमशः उपयोगकर्ता के पूर्ण नाम, प्रथम नाम या अंतिम नाम के लिए।\n - `[ईमेल]` उपयोगकर्ता के ईमेल के लिए।\n - एप्लिकेशन नाम और यूआरएल के लिए क्रमशः `[Site_Name]` और `[Site_URL]`।", + "Verification_Email": "अपना ईमेल पता सत्यापित करने के लिए यहां क्लिक करें।", + "Verification_email_body": "कृपया, अपने ईमेल पते की पुष्टि करने के लिए नीचे दिए गए बटन पर क्लिक करें।", + "Verification_email_sent": "सत्यापन विद्युतडाक भेज दिया गया है", + "Verification_Email_Subject": "[साइट_नाम] - ईमेल पता सत्यापन", + "Verified": "सत्यापित", + "Verify": "सत्यापित करें", + "Verify_your_email": "अपना ईमेल सत्यापित करें", + "Version": "संस्करण", + "Version_version": "संस्करण {{version}}", + "App_Request_Admin_Message": "नमस्ते {{admin_name}}, {{user_name}} ने इस कार्यक्षेत्र पर {{app_name}} ऐप इंस्टॉल करने का अनुरोध सबमिट किया है।\n \n यह वह संदेश है जिसमें उन्होंने शामिल किया:\n>{{message}}\n \n अधिक जानने और {{app_name}} ऐप इंस्टॉल करने के लिए, [यहां क्लिक करें]({{learn_more}})।", + "App_version_incompatible_tooltip": "ऐप Rocket.Chat संस्करण के साथ असंगत है", + "App_request_enduser_message": "आपके द्वारा अनुरोधित ऐप, {{appName}}, अभी इस कार्यक्षेत्र पर इंस्टॉल किया गया है।\n [यहां क्लिक करें]({{learnmore}}) ऐप के बारे में जानने के लिए।", + "App_requests_by_workspace": "कार्यक्षेत्र के सदस्यों द्वारा किए गए ऐप अनुरोध यहां दिखाई देते हैं", + "Video_Conference_Description": "अपने कार्यक्षेत्र के लिए कॉन्फ्रेंसिंग कॉल कॉन्फ़िगर करें।", + "Video_Chat_Window": "वीडियो चैट", + "Video_Conference": "कांफ्रेंस कॉल", + "Video_Call_unavailable_for_this_type_of_room": "इस प्रकार के कमरे के लिए वीडियो कॉल उपलब्ध नहीं है", + "Video_Conferences": "सम्मेलन में बुलावा", + "Video_Conference_Info": "बैठक की जानकारी", + "Video_Conference_Url": "मीटिंग यूआरएल", + "video-conf-provider-not-configured": "**कॉन्फ़्रेंस कॉल सक्षम नहीं है**: कार्यस्थान व्यवस्थापक को पहले कॉन्फ़्रेंस कॉल सुविधा सक्षम करने की आवश्यकता है।", + "Video_message": "वीडियो संदेश", + "Videocall_declined": "वीडियो कॉल अस्वीकृत.", + "Video_and_Audio_Call": "वीडियो और ऑडियो कॉल", + "video_conference_started": "_कॉल प्रारंभ किया._", + "video_conference_started_by": "**{{username}}** _कॉल शुरू हुई।_", + "video_conference_ended": "_कॉल समाप्त हो गया है._", + "video_conference_ended_by": "**{{username}}** _कॉल समाप्त हुई।_", + "video_livechat_started": "_वीडियो कॉल शुरू की._", + "video_livechat_missed": "_एक वीडियो कॉल शुरू की जिसका उत्तर नहीं दिया गया।_", + "video_direct_calling": "_कॉल कर रहा है।_", + "video_direct_ended": "_कॉल समाप्त हो गया है._", + "video_direct_ended_by": "**{{username}}** _कॉल समाप्त हुई।_", + "video_direct_missed": "_एक कॉल शुरू हुई जिसका उत्तर नहीं दिया गया।_", + "video_direct_started": "_कॉल प्रारंभ किया._", + "VideoConf_Default_Provider": "डिफ़ॉल्ट प्रदाता", + "VideoConf_Default_Provider_Description": "यदि आपके पास एकाधिक प्रदाता ऐप्स इंस्टॉल हैं, तो चुनें कि नए कॉन्फ़्रेंस कॉल के लिए किसका उपयोग किया जाना चाहिए।", + "VideoConf_Enable_Channels": "सार्वजनिक चैनलों में सक्षम करें", + "VideoConf_Enable_Groups": "निजी चैनलों में सक्षम करें", + "VideoConf_Enable_DMs": "सीधे संदेशों में सक्षम करें", + "VideoConf_Enable_Teams": "टीमों में सक्षम करें", + "VideoConf_Mobile_Ringing": "मोबाइल रिंगिंग सक्षम करें", + "VideoConf_Mobile_Ringing_Description": "सक्षम होने पर, मोबाइल उपयोगकर्ताओं को सीधे कॉल उनके डिवाइस पर फ़ोन कॉल के रूप में सुनाई देगी।", + "VideoConf_Mobile_Ringing_Alert": "यह सुविधा अभी प्रायोगिक चरण में है और हो सकता है कि यह अभी तक मोबाइल ऐप द्वारा पूरी तरह से समर्थित न हो। सक्षम होने पर यह उपयोगकर्ताओं को अतिरिक्त पुश सूचनाएं भेजेगा।", + "videoconf-ring-users": "कॉल करते समय अन्य उपयोगकर्ताओं को रिंग करें", + "videoconf-ring-users_description": "कॉल करते समय अन्य उपयोगकर्ताओं को रिंग करने की अनुमति", + "Video_record": "चलचित्र आलेख", + "Videos": "वीडियो", + "View_mode": "दृश्य मोड", + "View_All": "सभी सदस्यों को देखें", + "View_channels": "चैनल देखें", + "view-agent-canned-responses": "एजेंट की डिब्बाबंद प्रतिक्रियाएँ देखें", + "view-agent-canned-responses_description": "एजेंट की डिब्बाबंद प्रतिक्रियाएँ देखने की अनुमति", + "view-agent-extension-association": "एजेंट एक्सटेंशन एसोसिएशन देखें", + "view-agent-extension-association_description": "एजेंट एक्सटेंशन एसोसिएशन देखने की अनुमति", + "view-all-canned-responses": "सभी डिब्बाबंद प्रतिक्रियाएँ देखें", + "view-all-canned-responses_description": "सभी डिब्बाबंद प्रतिक्रियाओं को देखने की अनुमति", + "view-import-operations": "आयात परिचालन देखें", + "view-import-operations_description": "आयात परिचालन देखने की अनुमति", + "view-omnichannel-contact-center": "ओमनीचैनल संपर्क केंद्र देखें", + "view-omnichannel-contact-center_description": "ओमनीचैनल संपर्क केंद्र को देखने और उसके साथ बातचीत करने की अनुमति", + "View_Logs": "लॉग्स को देखें", + "View_original": "मूल देखें", + "View_the_Logs_for": "इसके लिए लॉग देखें: \"{{name}}\"", + "view-all-teams": "सभी टीमें देखें", + "view-all-teams_description": "सभी टीमों को देखने की अनुमति", + "view-all-team-channels": "सभी टीम चैनल देखें", + "view-all-team-channels_description": "सभी टीम के चैनल देखने की अनुमति", + "view-broadcast-member-list": "प्रसारण कक्ष में सदस्यों की सूची देखें", + "view-broadcast-member-list_description": "प्रसारण चैनल में उपयोगकर्ताओं की सूची देखने की अनुमति", + "view-c-room": "सार्वजनिक चैनल देखें", + "view-c-room_description": "सार्वजनिक चैनल देखने की अनुमति", + "view-canned-responses": "डिब्बाबंद प्रतिक्रियाएँ देखें", + "view-canned-responses_description": "डिब्बाबंद प्रतिक्रियाएँ देखने की अनुमति", + "view-d-room": "सीधे संदेश देखें", + "view-d-room_description": "सीधे संदेश देखने की अनुमति", + "view-device-management": "डिवाइस प्रबंधन देखें", + "view-device-management_description": "डिवाइस प्रबंधन डैशबोर्ड देखने की अनुमति", + "view-engagement-dashboard": "सहभागिता डैशबोर्ड देखें", + "view-engagement-dashboard_description": "सहभागिता डैशबोर्ड देखने की अनुमति", + "view-federation-data": "फ़ेडरेशन डेटा देखें", + "view-federation-data_description": "फ़ेडरेशन डेटा देखने की अनुमति", + "View_full_conversation": "पूरी बातचीत देखें", + "view-full-other-user-info": "अन्य उपयोगकर्ता की पूरी जानकारी देखें", + "view-full-other-user-info_description": "खाता निर्माण तिथि, अंतिम लॉगिन आदि सहित अन्य उपयोगकर्ताओं की पूरी प्रोफ़ाइल देखने की अनुमति।", + "view-history": "इतिहास देखें", + "view-history_description": "चैनल इतिहास देखने की अनुमति", + "view-join-code": "जॉइन कोड देखें", + "view-join-code_description": "चैनल जॉइन कोड देखने की अनुमति", + "view-joined-room": "सम्मिलित कक्ष देखें", + "view-joined-room_description": "वर्तमान में शामिल चैनलों को देखने की अनुमति", + "view-l-room": "ओमनीचैनल कमरे देखें", + "view-l-room_description": "ओमनीचैनल कमरे देखने की अनुमति", + "view-livechat-analytics": "ओमनीचैनल एनालिटिक्स देखें", + "view-livechat-analytics_description": "लाइव चैट विश्लेषण देखने की अनुमति", + "view-livechat-appearance": "ओमनीचैनल उपस्थिति देखें", + "view-livechat-appearance_description": "लाइव चैट उपस्थिति देखने की अनुमति", + "view-livechat-business-hours": "ओमनीचैनल व्यावसायिक घंटे देखें", + "view-livechat-business-hours_description": "लाइव चैट व्यावसायिक घंटे देखने की अनुमति", + "view-livechat-current-chats": "ओमनीचैनल वर्तमान चैट देखें", + "view-livechat-current-chats_description": "लाइव चैट वर्तमान चैट देखने की अनुमति", + "view-livechat-customfields": "ओमनीचैनल कस्टम फ़ील्ड देखें", + "view-livechat-customfields_description": "ओमनीचैनल कस्टम फ़ील्ड देखने की अनुमति", + "view-livechat-departments": "ओमनीचैनल विभाग देखें", + "view-livechat-departments_description": "ओमनीचैनल विभागों को देखने की अनुमति", + "view-livechat-installation": "ओमनीचैनल इंस्टालेशन देखें", + "view-livechat-installation_description": "ओमनीचैनल स्थापना देखने की अनुमति", + "view-livechat-manager": "ओमनीचैनल प्रबंधक देखें", + "view-livechat-manager_description": "अन्य ओमनीचैनल प्रबंधकों को देखने की अनुमति", + "view-livechat-monitor": "लाइवचैट मॉनिटर्स देखें", + "view-livechat-queue": "ओमनीचैनल कतार देखें", + "view-livechat-queue_description": "ओमनीचैनल कतार देखने की अनुमति", + "view-livechat-real-time-monitoring": "ओमनीचैनल रीयल-टाइम मॉनिटरिंग देखें", + "view-livechat-room-closed-by-another-agent": "किसी अन्य एजेंट द्वारा बंद किए गए ओमनीचैनल रूम देखें", + "view-livechat-room-closed-by-another-agent_description": "किसी अन्य एजेंट द्वारा बंद किए गए लाइव चैट रूम देखने की अनुमति", + "view-livechat-room-closed-same-department": "उसी विभाग में किसी अन्य एजेंट द्वारा बंद किए गए ओमनीचैनल रूम देखें", + "view-livechat-room-closed-same-department_description": "उसी विभाग में किसी अन्य एजेंट द्वारा बंद किए गए लाइव चैट रूम देखने की अनुमति", + "view-livechat-room-customfields": "ओमनीचैनल कक्ष कस्टम फ़ील्ड देखें", + "view-livechat-room-customfields_description": "लाइव चैट रूम कस्टम फ़ील्ड देखने की अनुमति", + "view-livechat-rooms": "ओमनीचैनल कमरे देखें", + "view-livechat-rooms_description": "अन्य ओमनीचैनल कमरे देखने की अनुमति", + "view-livechat-triggers": "ओमनीचैनल ट्रिगर देखें", + "view-livechat-triggers_description": "लाइव चैट ट्रिगर देखने की अनुमति", + "view-livechat-webhooks": "ओमनीचैनल वेबहुक देखें", + "view-livechat-webhooks_description": "लाइव चैट वेबहुक देखने की अनुमति", + "view-livechat-unit": "लाइवचैट इकाइयाँ देखें", + "view-logs": "लॉग्स को देखें", + "view-logs_description": "सर्वर लॉग देखने की अनुमति", + "view-other-user-channels": "अन्य उपयोगकर्ता चैनल देखें", + "view-other-user-channels_description": "अन्य उपयोगकर्ताओं के स्वामित्व वाले चैनल देखने की अनुमति", + "view-outside-room": "बाहरी कक्ष का दृश्य", + "view-outside-room_description": "मौजूदा कमरे के बाहर के उपयोगकर्ताओं को देखने की अनुमति", + "view-p-room": "निजी कक्ष देखें", + "view-p-room_description": "निजी चैनल देखने की अनुमति", + "view-privileged-setting": "विशेषाधिकार प्राप्त सेटिंग देखें", + "view-privileged-setting_description": "सेटिंग्स देखने की अनुमति", + "view-moderation-console": "मॉडरेशन कंसोल देखें", + "view-moderation-console_description": "सर्वर का मॉडरेशन कंसोल देखने की अनुमति", + "manage-moderation-actions": "मॉडरेशन क्रियाएँ प्रबंधित करें", + "manage-moderation-actions_description": "मॉडरेशन कार्रवाइयों को प्रबंधित करने, रिपोर्ट किए गए उपयोगकर्ताओं पर कार्रवाई करने की अनुमति", + "view-room-administration": "कक्ष प्रशासन देखें", + "view-room-administration_description": "सार्वजनिक, निजी और प्रत्यक्ष संदेश आँकड़े देखने की अनुमति। इसमें वार्तालाप या संग्रह देखने की क्षमता शामिल नहीं है", + "view-statistics": "सांख्यिकी देखें", + "view-statistics_description": "सिस्टम आँकड़े देखने की अनुमति जैसे लॉग इन किए गए उपयोगकर्ताओं की संख्या, कमरों की संख्या, ऑपरेटिंग सिस्टम की जानकारी", + "view-user-administration": "उपयोगकर्ता प्रशासन देखें", + "view-user-administration_description": "वर्तमान में सिस्टम में लॉग इन अन्य उपयोगकर्ता खातों के आंशिक, केवल पढ़ने योग्य सूची दृश्य की अनुमति। इस अनुमति के साथ कोई भी उपयोगकर्ता खाता जानकारी पहुंच योग्य नहीं है", + "Viewing_room_administration": "देखने का कमरा प्रशासन", + "Visibility": "दृश्यता", + "Visible": "दृश्यमान", + "Visible_To_Workspace": "कार्यस्थल पर दृश्यमान", + "Visit_Site_Url_and_try_the_best_open_source_chat_solution_available_today": "[Site_URL] पर जाएँ और आज ही उपलब्ध सर्वोत्तम ओपन सोर्स चैट समाधान आज़माएँ!", + "Visitor": "आगंतुक", + "Visitor_Email": "आगंतुक ई-मेल", + "Visitor_Info": "आगंतुक जानकारी", + "Visitor_message": "आगंतुक संदेश", + "Visitor_Name": "आगंतुक का नाम", + "Visitor_Name_Placeholder": "कृपया विज़िटर का नाम दर्ज करें...", + "Visitor_not_found": "विज़िटर नहीं मिला", + "Visitor_does_not_exist": "विज़िटर मौजूद नहीं है!", + "Visitor_Navigation": "विज़िटर नेविगेशन", + "Visitor_page_URL": "विज़िटर पृष्ठ URL", + "Visitor_time_on_site": "साइट पर आगंतुक का समय", + "Voice_Call": "आवाज कॉल", + "VoIP_Enable_Keep_Alive_For_Unstable_Networks": "एसआईपी विकल्प सक्रिय रखें सक्षम करें", + "VoIP_Enable_Keep_Alive_For_Unstable_Networks_Description": "समय-समय पर एसआईपी विकल्प संदेश भेजकर कई बाहरी एसआईपी गेटवे की स्थिति की निगरानी करें। अस्थिर नेटवर्क के लिए उपयोग किया जाता है.", + "VoIP_Enabled": "ध्वनि चैनल सक्षम करें", + "VoIP_Enabled_Description": "आउटबाउंड और इनकमिंग कॉल के माध्यम से एजेंटों को ग्राहकों से जोड़ें", + "VoIP_Extension": "वीओआइपी एक्सटेंशन", + "Voip_Server_Configuration": "तारांकन वेबसॉकेट सर्वर", + "VoIP_Server_Websocket_Port": "वेबसॉकेट पोर्ट", + "VoIP_Server_Name": "सर्वर का नाम", + "VoIP_Server_Websocket_Path": "वेबसोकेट यूआरएल", + "VoIP_Retry_Count": "count पुनः प्रयास करें", + "VoIP_Retry_Count_Description": "यह परिभाषित करता है कि कनेक्शन खो जाने पर क्लाइंट कितनी बार वीओआईपी सर्वर से दोबारा कनेक्ट करने का प्रयास करेगा।", + "VoIP_Management_Server": "वीओआईपी प्रबंधन सर्वर", + "VoIP_Management_Server_Host": "सर्वर होस्ट", + "VoIP_Management_Server_Port": "सर्वर पोर्ट", + "VoIP_Management_Server_Name": "सर्वर का नाम", + "VoIP_Management_Server_Username": "उपयोगकर्ता नाम", + "VoIP_Management_Server_Password": "पासवर्ड", + "Voip_call_started": "पर कॉल शुरू हुई", + "Voip_call_duration": "कॉल {{period}} तक चली", + "Voip_call_declined": "एजेंट द्वारा फोन काट दिया गया", + "Voip_call_on_hold": "कॉल को होल्ड पर रखा गया", + "Voip_call_unhold": "पर कॉल फिर से शुरू हुई", + "Voip_call_ended": "कॉल समाप्त हो गई", + "Voip_call_ended_unexpectedly": "कॉल अप्रत्याशित रूप से समाप्त हुई: {{reason}}", + "Voip_call_wrapup": "कॉल रैपअप नोट्स जोड़े गए: {{comment}}", + "VoIP_JWT_Secret": "गुप्त कुंजी (JWT)", + "VoIP_JWT_Secret_description": "सादे पाठ के बजाय JWT के रूप में सर्वर से क्लाइंट तक एक्सटेंशन विवरण साझा करने के लिए एक गुप्त कुंजी सेट करें। यदि कोई गुप्त कुंजी सेट नहीं की गई है तो एक्सटेंशन पंजीकरण विवरण सादे पाठ के रूप में भेजा जाएगा।", + "Voip_is_disabled": "वीओआईपी अक्षम है", + "Voip_is_disabled_description": "एक्सटेंशन की सूची देखने के लिए वीओआईपी को सक्रिय करना आवश्यक है, सेटिंग्स टैब में ऐसा करें।", + "VoIP_Toggle": "वीओआईपी सक्षम/अक्षम करें", + "Chat_opened_by_visitor": "विज़िटर द्वारा चैट खोली गई", + "Wait_activation_warning": "इससे पहले कि आप लॉग इन कर सकें, आपका खाता किसी व्यवस्थापक द्वारा मैन्युअल रूप से सक्रिय होना चाहिए।", + "Waiting_for_answer": "जवाब का इंतज़ार रहा हूँ", + "Waiting_queue": "प्रतीक्षा कतार", + "Waiting_queue_message": "प्रतीक्षा कतार संदेश", + "Waiting_queue_message_description": "संदेश जो आगंतुकों को कतार में लगने पर प्रदर्शित किया जाएगा", + "Waiting_Time": "इंतज़ार का समय", + "Waiting_for_server_connection": "सर्वर कनेक्शन की प्रतीक्षा की जा रही है", + "Warning": "चेतावनी", + "Warnings": "चेतावनियाँ", + "WAU_value": "मैं कद्र करता हूं {{value}}", + "We_appreciate_your_feedback": "हम आपके फ़ीडबैक की सराहना करते हैं", "We_are_offline_Sorry_for_the_inconvenience": "हम ऑफ़लाइन हैं। असुविधा के लिए खेद है।", + "We_Could_not_retrive_any_data": "हम कोई डेटा पुनः प्राप्त नहीं कर सके", + "We_have_sent_password_email": "हमने आपको पासवर्ड रीसेट निर्देशों के साथ एक ईमेल भेजा है। यदि आपको शीघ्र ही कोई ईमेल प्राप्त नहीं होता है, तो कृपया वापस आएं और पुनः प्रयास करें।", + "We_have_sent_registration_email": "हमने आपके पंजीकरण की पुष्टि के लिए आपको एक ईमेल भेजा है। यदि आपको शीघ्र ही कोई ईमेल प्राप्त नहीं होता है, तो कृपया वापस आएं और पुनः प्रयास करें।", + "Webdav Integration": "वेबडाव एकीकरण", + "Webdav Integration_Description": "उपयोगकर्ताओं के लिए सर्वर पर दस्तावेज़ बनाने, बदलने और स्थानांतरित करने के लिए एक रूपरेखा। Nextcloud जैसे WebDAV सर्वर को लिंक करने के लिए उपयोग किया जाता है।", + "WebDAV_Accounts": "वेबडीएवी खाते", + "Webdav_add_new_account": "नया WebDAV खाता जोड़ें", + "Webdav_Integration_Enabled": "वेबडाव एकीकरण सक्षम", + "WebDAV_Integration_Not_Allowed": "WebDAV एकीकरण की अनुमति नहीं है", + "Webdav_Password": "वेबडीएवी पासवर्ड", + "Webdav_Server_URL": "WebDAV सर्वर एक्सेस यूआरएल", + "Webdav_Username": "वेबडीएवी उपयोगकर्ता नाम", + "Webdav_account_removed": "WebDAV खाता हटा दिया गया", + "webdav-account-saved": "WebDAV खाता सहेजा गया", + "webdav-account-updated": "WebDAV खाता अपडेट किया गया", + "webdav-server-not-found": "WebDAV सर्वर नहीं मिला", + "Webhook_Details": "वेबहुक विवरण", + "Webhook_URL": "वेबहुक यूआरएल", + "Webhook_URL_not_set": "वेबहुक यूआरएल सेट नहीं है", + "Webhooks": "वेबहुक", + "WebRTC": "वेबआरटीसी", + "WebRTC_Description": "ऑडियो और/या वीडियो सामग्री प्रसारित करें, साथ ही किसी बिचौलिए की आवश्यकता के बिना ब्राउज़रों के बीच मनमाना डेटा प्रसारित करें।", + "WebRTC_Call": "वेबआरटीसी कॉल", + "WebRTC_Call_unavailable_for_federation": "फ़ेडरेटेड रूम के लिए WebRTC कॉल उपलब्ध नहीं है", + "WebRTC_direct_audio_call_from_%s": "%s से सीधा ऑडियो कॉल", + "WebRTC_direct_video_call_from_%s": "%s से सीधा वीडियो कॉल", + "WebRTC_Enable_Channel": "सार्वजनिक चैनलों के लिए सक्षम करें", + "WebRTC_Enable_Direct": "सीधे संदेशों के लिए सक्षम करें", + "WebRTC_Enable_Private": "निजी चैनलों के लिए सक्षम करें", + "WebRTC_group_audio_call_from_%s": "%s से समूह ऑडियो कॉल", + "WebRTC_group_video_call_from_%s": "%s से समूह वीडियो कॉल", + "WebRTC_monitor_call_from_%s": "%s से कॉल की निगरानी करें", + "WebRTC_Servers": "स्टन/टर्न सर्वर", + "WebRTC_Servers_Description": "अल्पविराम द्वारा अलग किए गए STUN और TURN सर्वरों की एक सूची।\n उपयोगकर्ता नाम, पासवर्ड और पोर्ट को `username:password@stun:host:port` या `username:password@turn:host:port` प्रारूप में अनुमति दी जाती है।", + "WebRTC_call_ended_message": "कॉल {{endTime}} पर समाप्त हुई - {{callDuration}} तक चली", + "WebRTC_call_declined_message": "संपर्क द्वारा कॉल अस्वीकृत.", + "Website": "वेबसाइट", + "Wednesday": "बुधवार", + "Weekly_Active_Users": "साप्ताहिक सक्रिय उपयोगकर्ता", + "Welcome": "स्वागत है %s .", + "Welcome_to": "[साइट_नाम] में आपका स्वागत है", + "Welcome_to_workspace": "{{Site_Name}} में आपका स्वागत है", + "Welcome_to_the": "आपका स्वागत है", + "When": "कब", + "When_a_line_starts_with_one_of_there_words_post_to_the_URLs_below": "जब कोई पंक्ति इनमें से किसी एक शब्द से शुरू होती है, तो नीचे दिए गए यूआरएल पर पोस्ट करें", + "When_is_the_chat_busier?": "चैट कब व्यस्त है?", + "Where_are_the_messages_being_sent?": "संदेश कहां भेजे जा रहे हैं?", + "Why_did_you_chose__score__": "आपने {{score}} क्यों चुना?", + "Why_do_you_want_to_report_question_mark": "आप रिपोर्ट क्यों करना चाहते हैं?", + "Will_Appear_In_From": "आपके द्वारा भेजे गए ईमेल के प्रेषक: शीर्षक में दिखाई देगा।", + "will_be_able_to": "के लिए योग्य होगा", + "Will_be_available_here_after_saving": "सेव करने के बाद यहां उपलब्ध होगा.", + "Without_priority": "बिना प्राथमिकता के", + "Without_SLA": "एसएलए के बिना", + "Workspace_now_using_device_management": "कार्यक्षेत्र अब डिवाइस प्रबंधन का उपयोग कर रहा है", + "Worldwide": "दुनिया भर", + "Would_you_like_to_return_the_inquiry": "क्या आप पूछताछ वापस करना चाहेंगे?", + "Would_you_like_to_return_the_queue": "क्या आप इस कमरे को वापस कतार में ले जाना चाहेंगे? सारी बातचीत का इतिहास कमरे में रखा जाएगा.", + "Would_you_like_to_place_chat_on_hold": "क्या आप इस चैट को ऑन-होल्ड रखना चाहेंगे?", + "Wrap_up_the_call": "कॉल समाप्त करें", + "Wrap_Up_Notes": "समापन नोट्स", + "Workspace": "कार्यस्थान", "Yes": "हाँ", - "You": "आप" + "Yes_archive_it": "हाँ, इसे संग्रहित करें!", + "Yes_clear_all": "हाँ, सब साफ़ करें!", + "Yes_continue": "हाँ, जारी रखें!", + "Yes_deactivate_it": "हाँ, इसे निष्क्रिय करें!", + "Yes_delete_it": "हाँ, इसे हटा दें!", + "Yes_hide_it": "हाँ, छुपाओ!", + "Yes_leave_it": "हाँ, छोड़ो!", + "Yes_mute_user": "हाँ, उपयोगकर्ता को म्यूट करें!", + "Yes_prune_them": "हाँ, उनकी काट-छाँट करें!", + "Yes_remove_user": "हाँ, उपयोगकर्ता को हटा दें!", + "Yes_unarchive_it": "हाँ, इसे असंग्रहीत करें!", + "yesterday": "कल", + "Yesterday": "कल", + "You": "आप", + "You_reacted_with": "आपने {{emoji}} के साथ प्रतिक्रिया व्यक्त की", + "Users_reacted_with": "{{users}} ने {{emoji}} के साथ प्रतिक्रिया व्यक्त की", + "Users_and_more_reacted_with": "{{user}} और {{counter}} और अधिक लोगों ने {{emoji}} के साथ प्रतिक्रिया व्यक्त की", + "You_and_users_Reacted_with": "आपने और {{users}} ने {{emoji}} के साथ प्रतिक्रिया व्यक्त की", + "You_users_and_more_Reacted_with": "आपने, {{user}} और {{counter}} ने {{emoji}} के साथ प्रतिक्रिया व्यक्त की", + "You_are_converting_team_to_channel": "आप इस टीम को एक चैनल में परिवर्तित कर रहे हैं।", + "you_are_in_preview_mode_of": "आप चैनल # {{room_name}} के पूर्वावलोकन मोड में हैं", + "you_are_in_preview": "आप पूर्वावलोकन मोड में हैं", + "you_are_in_preview_please_insert_the_password": "कृपया पासवर्ड डालें", + "you_are_in_preview_mode_of_incoming_livechat": "आप इस चैट के पूर्वावलोकन मोड में हैं", + "You_are_logged_in_as": "आपने इसके रूप में लॉगिन किया है", + "You_are_not_authorized_to_view_this_page": "आप इस पृष्ठ को देखने के लिए अधिकृत नहीं हैं।", + "You_can_change_a_different_avatar_too": "आप इस एकीकरण से पोस्ट करने के लिए उपयोग किए गए अवतार को ओवरराइड कर सकते हैं।", + "You_can_close_this_window_now": "अब आप इस विंडो को बंद कर सकते हैं.", + "You_can_search_using_RegExp_eg": "आप रेगुलर एक्सप्रेशन का उपयोग करके खोज सकते हैं। उदाहरण के लिए /^text$/i", + "You_can_try_to": "आप कोशिश कर सकते हैं", + "You_can_use_an_emoji_as_avatar": "आप इमोजी को अवतार के तौर पर भी इस्तेमाल कर सकते हैं.", + "You_can_use_webhooks_to_easily_integrate_livechat_with_your_CRM": "आप अपने सीआरएम के साथ ओमनीचैनल को आसानी से एकीकृत करने के लिए वेबहुक का उपयोग कर सकते हैं।", + "You_cant_leave_a_livechat_room_Please_use_the_close_button": "आप एक सर्वचैनल कमरा नहीं छोड़ सकते। कृपया, बंद करें बटन का उपयोग करें।", + "You_followed_this_message": "आपने इस संदेश का अनुसरण किया.", + "You_have_a_new_message": "आपको एक नया संदेश आया है", + "You_have_been_muted": "आपको मौन कर दिया गया है और आप इस कमरे में बोल नहीं सकते", + "You_have_been_removed_from__roomName_": "आपको कमरे {{roomName}} से निकाल दिया गया है", + "You_have_joined_a_new_call_with": "आप एक नई कॉल में शामिल हुए हैं", + "You_have_n_codes_remaining": "आपके पास {{number}} कोड शेष हैं।", + "You_have_not_verified_your_email": "आपने अपना ईमेल सत्यापित नहीं किया है.", + "You_have_successfully_unsubscribed": "आपने हमारी मेलिंग सूची से सफलतापूर्वक सदस्यता समाप्त कर दी है।", + "You_must_join_to_view_messages_in_this_channel": "इस चैनल में संदेश देखने के लिए आपको अवश्य शामिल होना चाहिए", + "You_need_confirm_email": "लॉगिन करने के लिए आपको अपने ईमेल की पुष्टि करनी होगी!", + "You_need_install_an_extension_to_allow_screen_sharing": "स्क्रीन शेयरिंग की अनुमति देने के लिए आपको एक एक्सटेंशन इंस्टॉल करना होगा", + "You_need_to_change_your_password": "आपको अपना पासवर्ड बदलना होगा", + "You_need_to_type_in_your_password_in_order_to_do_this": "ऐसा करने के लिए आपको अपना पासवर्ड टाइप करना होगा!", + "You_need_to_type_in_your_username_in_order_to_do_this": "ऐसा करने के लिए आपको अपना उपयोगकर्ता नाम टाइप करना होगा!", + "You_need_to_verifiy_your_email_address_to_get_notications": "सूचनाएं प्राप्त करने के लिए आपको अपना ईमेल पता सत्यापित करना होगा", + "You_need_to_write_something": "तुम्हें कुछ लिखना होगा!", + "You_reached_the_maximum_number_of_guest_users_allowed_by_your_license": "आप अपने लाइसेंस द्वारा अनुमत अतिथि उपयोगकर्ताओं की अधिकतम संख्या तक पहुँच गए हैं।", + "You_should_inform_one_url_at_least": "आपको कम से कम एक यूआरएल परिभाषित करना चाहिए.", + "You_should_name_it_to_easily_manage_your_integrations": "अपने एकीकरणों को आसानी से प्रबंधित करने के लिए आपको इसे नाम देना चाहिए।", + "You_unfollowed_this_message": "आपने इस संदेश को अनफ़ॉलो कर दिया है.", + "You_will_be_asked_for_permissions": "आपसे अनुमतियां मांगी जाएंगी", + "You_will_not_be_able_to_recover": "आप इस संदेश को पुनर्प्राप्त नहीं कर पाएंगे!", + "You_will_not_be_able_to_recover_email_inbox": "आप इस ईमेल इनबॉक्स को पुनर्प्राप्त नहीं कर पाएंगे", + "You_will_not_be_able_to_recover_file": "आप इस फ़ाइल को पुनर्प्राप्त नहीं कर पाएंगे!", + "You_wont_receive_email_notifications_because_you_have_not_verified_your_email": "आपको ईमेल सूचनाएं प्राप्त नहीं होंगी क्योंकि आपने अपना ईमेल सत्यापित नहीं किया है।", + "Your_e2e_key_has_been_reset": "आपकी e2e कुंजी रीसेट कर दी गई है.", + "Your_email_address_has_changed": "आपका ईमेल पता बदल दिया गया है.", + "Your_email_has_been_queued_for_sending": "आपका ईमेल भेजने के लिए कतारबद्ध है", + "Your_entry_has_been_deleted": "आपकी प्रविष्टि हटा दी गई है.", + "Your_file_has_been_deleted": "आपकी फ़ाइल हटा दी गई है.", + "Your_invite_link_will_expire_after__usesLeft__uses": "आपका आमंत्रण लिंक {{usesLeft}} के उपयोग के बाद समाप्त हो जाएगा।", + "Your_invite_link_will_expire_on__date__": "आपका आमंत्रण लिंक {{date}} को समाप्त हो जाएगा।", + "Your_invite_link_will_expire_on__date__or_after__usesLeft__uses": "आपका आमंत्रण लिंक {{date}} को या {{usesLeft}} उपयोग के बाद समाप्त हो जाएगा।", + "Your_invite_link_will_never_expire": "आपका आमंत्रण लिंक कभी समाप्त नहीं होगा.", + "your_message": "आपका संदेश", + "your_message_optional": "आपका संदेश (वैकल्पिक)", + "Your_new_email_is_email": "आपका नया ईमेल पता [ईमेल] है।", + "Your_password_is_wrong": "आपका पासवर्ड ग़लत है!", + "Your_password_was_changed_by_an_admin": "आपका पासवर्ड किसी व्यवस्थापक द्वारा बदल दिया गया था.", + "Your_push_was_sent_to_s_devices": "आपका पुश %s डिवाइस पर भेजा गया था", + "Your_request_to_join__roomName__has_been_made_it_could_take_up_to_15_minutes_to_be_processed": "{{roomName}} में शामिल होने के लिए आपका अनुरोध कर दिया गया है, इसे संसाधित होने में 15 मिनट तक का समय लग सकता है। जब यह जाने के लिए तैयार होगा तो आपको सूचित कर दिया जाएगा।", + "Your_question": "आपका प्रश्न", + "Your_server_link": "आपका सर्वर लिंक", + "Your_temporary_password_is_password": "आपका अस्थायी पासवर्ड [पासवर्ड] है।", + "Your_TOTP_has_been_reset": "आपका टू फैक्टर टीओटीपी रीसेट कर दिया गया है।", + "Your_web_browser_blocked_Rocket_Chat_from_opening_tab": "आपके वेब ब्राउज़र ने Rocket.Chat को नया टैब खोलने से रोक दिया है।", + "Your_workspace_is_ready": "आपका कार्यक्षेत्र उपयोग के लिए तैयार है 🎉", + "Zapier": "Zapier", + "registration.page.login.errors.wrongCredentials": "उपयोगकर्ता नहीं मिला या पासवर्ड ग़लत है", + "registration.page.login.errors.invalidEmail": "अमान्य ईमेल", + "registration.page.login.errors.loginBlockedForIp": "इस आईपी के लिए लॉगिन अस्थायी रूप से अवरुद्ध कर दिया गया है", + "registration.page.login.errors.loginBlockedForUser": "इस उपयोगकर्ता के लिए लॉगिन अस्थायी रूप से अवरुद्ध कर दिया गया है", + "registration.page.login.errors.licenseUserLimitReached": "उपयोगकर्ताओं की अधिकतम संख्या तक पहुँच गया है.", + "registration.page.login.errors.AppUserNotAllowedToLogin": "ऐप उपयोगकर्ताओं को सीधे लॉग इन करने की अनुमति नहीं है।", + "registration.page.registration.waitActivationWarning": "इससे पहले कि आप लॉग इन कर सकें, आपका खाता किसी व्यवस्थापक द्वारा मैन्युअल रूप से सक्रिय होना चाहिए।", + "registration.page.login.register": "अब यहां? <1>एक खाता बनाएं", + "registration.page.login.forgot": "अपना कूट शब्द भूल गए?", + "registration.page.register.back": "लॉगिन पर वापस जाएं", + "registration.page.emailVerification.subTitle": "इस सर्वर को सत्यापित ईमेल पते की आवश्यकता है। सत्यापन लिंक के लिए कृपया अपना ईमेल इनबॉक्स जांचें।", + "registration.page.emailVerification.sent": "सत्यापन ईमेल भेजा गया, कृपया अपना इनबॉक्स जांचें।", + "registration.page.resetPassword.sent": "यदि यह ईमेल पंजीकृत है, तो हम आपका पासवर्ड रीसेट करने के तरीके पर निर्देश भेजेंगे। यदि आपको शीघ्र ही कोई ईमेल प्राप्त नहीं होता है, तो कृपया वापस आएं और पुनः प्रयास करें।", + "registration.page.resetPassword.sendInstructions": "निर्देश भेजें", + "registration.page.resetPassword.errors.invalidEmail": "अमान्य ईमेल", + "registration.page.poweredBy": "<1>Rocket.Chat द्वारा संचालित", + "registration.page.guest.chooseHowToJoin": "चुनें कि आप कैसे शामिल होना चाहते हैं", + "registration.page.guest.loginWithRocketChat": "Rocket.Chat के साथ लॉगिन करें", + "registration.page.guest.continueAsGuest": "अतिथि के रूप में जारी रखें", + "registration.component.welcome": "<1>Rocket.Chat कार्यक्षेत्र में आपका स्वागत है", + "registration.component.login": "लॉग इन करें", + "registration.component.login.userNotFound": "उपयोगकर्ता नहीं मिला", + "registration.component.login.incorrectPassword": "गलत पासवर्ड", + "registration.component.switchLanguage": "<1>{{name}} में बदलें", + "registration.component.resetPassword": "पासवर्ड रीसेट", + "registration.component.form.emailOrUsername": "ईमेल या उपयोगकर्ता का नाम", + "registration.component.form.username": "उपयोगकर्ता नाम", + "registration.component.form.name": "नाम", + "registration.component.form.nameOptional": "नाम: (वैकल्पिक", + "registration.component.form.createAnAccount": "खाता बनाएं", + "registration.component.form.userAlreadyExist": "उपयोगकर्ता का नाम पहले से मौजूद है। कृपया कोई अन्य उपयोक्तानाम आज़माएँ.", + "registration.component.form.emailAlreadyExists": "ईमेल पहले से ही मौजूद है", + "registration.component.form.usernameAlreadyExists": "उपयोगकर्ता का नाम पहले से मौजूद है। कृपया कोई अन्य उपयोक्तानाम आज़माएँ.", + "registration.component.form.invalidEmail": "दर्ज किया गया ईमेल अमान्य है", + "registration.component.form.email": "ईमेल", + "registration.component.form.emailPlaceholder": "example@example.com", + "registration.component.form.password": "पासवर्ड", + "registration.component.form.divider": "या", + "registration.component.form.submit": "जमा करना", + "registration.component.form.requiredField": "यह फ़ील्ड आवश्यक है", + "registration.component.form.joinYourTeam": "अपनी टीम में शामिल हों", + "registration.component.form.reasonToJoin": "शामिल होने का कारण", + "registration.component.form.invalidConfirmPass": "पासवर्ड पुष्टिकरण पासवर्ड से मेल नहीं खाता", + "registration.component.form.confirmPassword": "अपने पासवर्ड की पुष्टि करें", + "registration.component.form.confirmation": "पुष्टीकरण", + "registration.component.form.sendConfirmationEmail": "पुष्टिकरण ईमेल भेजें", + "registration.component.form.register": "पंजीकरण करवाना", + "onboarding.component.form.requiredField": "यह फ़ील्ड आवश्यक है", + "onboarding.component.form.steps": "{{stepCount}} का चरण {{currentStep}}", + "onboarding.component.form.action.back": "पीछे", + "onboarding.component.form.action.next": "अगला", + "onboarding.component.form.action.skip": "इस स्टेप को छोड़ दें", + "onboarding.component.form.action.register": "पंजीकरण करवाना", + "onboarding.component.form.action.registerWorkspace": "कार्यक्षेत्र पंजीकृत करें", + "onboarding.component.form.action.registerOffline": "ऑफ़लाइन पंजीकरण करें", + "onboarding.component.form.action.confirm": "पुष्टि करना", + "onboarding.component.form.action.pasteHere": "यहां चिपकाएं...", + "onboarding.component.form.action.completeRegistration": "पूरा पंजीकरण", + "onboarding.component.form.termsAndConditions": "मैं <1>नियम एवं शर्तें और <3>गोपनीयता नीति से सहमत हूं", + "onboarding.component.emailCodeFallback": "ईमेल प्राप्त नहीं हुआ? <1>पुनः भेजें या <3>ईमेल बदलें।", + "onboarding.page.form.title": "आइए आपका कार्यक्षेत्र लॉन्च करें", + "onboarding.page.emailConfirmed.title": "ईमेल की पुष्टि!", + "onboarding.page.emailConfirmed.subtitle": "आप अपने Rocket.Chat एप्लिकेशन पर वापस लौट सकते हैं - हमने आपका कार्यक्षेत्र पहले ही लॉन्च कर दिया है।", + "onboarding.page.checkYourEmail.title": "अपने ईमेल की जाँच करें", + "onboarding.page.checkYourEmail.subtitle": "आपका अनुरोध सफलतापूर्वक भेज दिया गया है।<1>अपना प्रीमियम योजना परीक्षण शुरू करने के लिए अपना ईमेल इनबॉक्स जांचें।<1>लिंक 30 मिनट में समाप्त हो जाएगा।", + "onboarding.page.confirmationProcess.title": "पुष्टि प्रक्रिया में है", + "onboarding.page.cloudDescription.title": "आइए आपका कार्यक्षेत्र और <1>14-दिवसीय परीक्षण लॉन्च करें", + "onboarding.page.cloudDescription.tryGold": "14 दिनों के लिए हमारा सर्वोत्तम गोल्ड प्लान निःशुल्क आज़माएँ", + "onboarding.page.cloudDescription.numberOfIntegrations": "1,000 एकीकरण", + "onboarding.page.cloudDescription.availability": "उच्च उपलब्धता", + "onboarding.page.cloudDescription.auditing": "संदेश ऑडिट पैनल/ऑडिट लॉग", + "onboarding.page.cloudDescription.engagement": "सगाई डैशबोर्ड", + "onboarding.page.cloudDescription.ldap": "एलडीएपी उन्नत सिंक", + "onboarding.page.cloudDescription.omnichannel": "ओमनीचैनल प्रीमियम", + "onboarding.page.cloudDescription.sla": "एसएलए: प्रीमियम", + "onboarding.page.cloudDescription.push": "सुरक्षित पुश सूचनाएं", + "onboarding.page.cloudDescription.goldIncludes": "* गोल्डन प्लान में अन्य प्लान की सभी सुविधाएँ शामिल हैं", + "onboarding.page.alreadyHaveAccount": "क्या आपके पास पहले से एक खाता मौजूद है? <1>अपने कार्यस्थान प्रबंधित करें।", + "onboarding.page.invalidLink.title": "आपका लिंक अब मान्य नहीं है", + "onboarding.page.invalidLink.content": "ऐसा लगता है कि आप पहले ही आमंत्रण लिंक का उपयोग कर चुके हैं. यह एकल साइन इन के लिए तैयार किया गया है। अपने कार्यक्षेत्र में शामिल होने के लिए एक नए साइन इन का अनुरोध करें।", + "onboarding.page.invalidLink.button.text": "नए लिंक का अनुरोध करें", + "onboarding.page.requestTrial.title": "<1>30-दिवसीय परीक्षण का अनुरोध करें", + "onboarding.page.requestTrial.subtitle": "30 दिनों के लिए हमारी सर्वोत्तम प्रीमियम योजना निःशुल्क आज़माएँ", + "onboarding.page.magicLinkEmail.title": "हमने आपको एक लॉगिन लिंक ईमेल किया है", + "onboarding.page.magicLinkEmail.subtitle": "आपके कार्यक्षेत्र में साइन इन करने के लिए हमने आपको अभी जो ईमेल भेजा है उसमें दिए गए लिंक पर क्लिक करें। <1>लिंक 30 मिनट में समाप्त हो जाएगा।", + "onboarding.form.adminInfoForm.title": "व्यवस्थापक जानकारी", + "onboarding.form.adminInfoForm.subtitle": "आपके कार्यक्षेत्र के लिए एक व्यवस्थापक प्रोफ़ाइल बनाने के लिए हमें इस जानकारी की आवश्यकता है।", + "onboarding.form.adminInfoForm.fields.fullName.label": "पूरा नाम", + "onboarding.form.adminInfoForm.fields.fullName.placeholder": "पहला और आखिरी नाम", + "onboarding.form.adminInfoForm.fields.username.label": "उपयोगकर्ता नाम", + "onboarding.form.adminInfoForm.fields.username.placeholder": "@उपयोगकर्ता नाम", + "onboarding.form.adminInfoForm.fields.email.label": "ईमेल", + "onboarding.form.adminInfoForm.fields.email.placeholder": "ईमेल", + "onboarding.form.adminInfoForm.fields.password.label": "पासवर्ड", + "onboarding.form.adminInfoForm.fields.password.placeholder": "पासवर्ड बनाएं", + "onboarding.form.adminInfoForm.fields.keepPosted.label": "मुझे Rocket.Chat अपडेट के बारे में बताते रहें", + "onboarding.form.awaitConfirmationForm.title": "पुष्टिकरण की प्रतीक्षा", + "onboarding.form.awaitConfirmationForm.content.securityCode": "सुरक्षा कोड", + "onboarding.form.awaitConfirmationForm.content.sentEmail": "ईमेल एक पुष्टिकरण लिंक के साथ <1>{{emailAddress}} पर भेजा गया है। कृपया सत्यापित करें कि नीचे दिया गया सुरक्षा कोड ईमेल में दिए गए सुरक्षा कोड से मेल खाता है।", + "onboarding.form.organizationInfoForm.title": "संगठन की जानकारी", + "onboarding.form.organizationInfoForm.subtitle": "हमें यह जानना होगा कि आप कौन हैं.", + "onboarding.form.organizationInfoForm.fields.organizationName.label": "संगठन का नाम", + "onboarding.form.organizationInfoForm.fields.organizationName.placeholder": "संगठन का नाम", + "onboarding.form.organizationInfoForm.fields.organizationType.label": "संगठन का प्रकार", + "onboarding.form.organizationInfoForm.fields.organizationType.placeholder": "चुनना", + "onboarding.form.organizationInfoForm.fields.organizationIndustry.label": "संगठन उद्योग", + "onboarding.form.organizationInfoForm.fields.organizationIndustry.placeholder": "चुनना", + "onboarding.form.organizationInfoForm.fields.organizationSize.label": "संगठन का आकार", + "onboarding.form.organizationInfoForm.fields.organizationSize.placeholder": "चुनना", + "onboarding.form.organizationInfoForm.fields.country.label": "देश", + "onboarding.form.organizationInfoForm.fields.country.placeholder": "चुनना", + "onboarding.form.registerOfflineForm.title": "ऑफ़लाइन पंजीकरण करें", + "onboarding.form.registerOfflineForm.copyStep.description": "यदि किसी कारण से आपका कार्यक्षेत्र इंटरनेट से कनेक्ट नहीं हो पाता है, तो इन चरणों का पालन करें:<1>1. यहां जाएं: <2>cloud.rocket.chat > कार्यस्थान और \"<3>स्वयं-प्रबंधित पंजीकरण करें\"<4>2 पर क्लिक करें। “<5>ऑफ़लाइन जारी रखें”<6>3 पर क्लिक करें। Cloud.rocket.chat में <7>ऑफ़लाइन कार्यस्थान पंजीकृत करें संवाद में, नीचे दिए गए बॉक्स में टोकन पेस्ट करें", + "onboarding.form.registerOfflineForm.pasteStep.description": "1. <1>cloud.rocket.chat में जेनरेटेड टेक्स्ट प्राप्त करें और अपनी पंजीकरण प्रक्रिया पूरी करने के लिए नीचे पेस्ट करें", + "onboarding.form.registerOfflineForm.fields.registrationToken.inputLabel": "पंजीकरण टोकन", + "onboarding.form.registeredServerForm.title": "अपना कार्यक्षेत्र पंजीकृत करें", + "onboarding.form.registeredServerForm.included.push": "मोबाइल पुश सूचनाएँ", + "onboarding.form.registeredServerForm.included.externalProviders": "बाहरी प्रदाताओं के साथ एकीकरण (व्हाट्सएप, फेसबुक, टेलीग्राम, ट्विटर)", + "onboarding.form.registeredServerForm.included.apps": "बाज़ार ऐप्स तक पहुंच", + "onboarding.form.registeredServerForm.fields.accountEmail.inputLabel": "व्यवस्थापक ईमेल", + "onboarding.form.registeredServerForm.fields.accountEmail.inputPlaceholder": "जारी रखने के लिए अपना ईमेल डालें", + "onboarding.form.registeredServerForm.keepInformed": "मुझे समाचारों और घटनाओं के बारे में सूचित रखें", + "onboarding.form.registeredServerForm.registerLater": "बाद में दर्ज करें", + "onboarding.form.registeredServerForm.notConnectedToInternet": "सर्वर इंटरनेट से कनेक्ट नहीं है, इसलिए आपको इस कार्यक्षेत्र के लिए ऑफ़लाइन पंजीकरण करना होगा।", + "onboarding.form.registeredServerForm.registrationEngagement": "पंजीकरण स्वचालित लाइसेंस अपडेट, महत्वपूर्ण कमजोरियों की अधिसूचना और रॉकेट.चैट क्लाउड सेवाओं तक पहुंच की अनुमति देता है। कोई संवेदनशील कार्यक्षेत्र डेटा साझा नहीं किया जाता है; Rocket.Chat पर भेजे गए आँकड़े आपको प्रशासन क्षेत्र के भीतर दिखाई देंगे।", + "onboarding.form.registeredServerForm.registrationKeepInformed": "इस फॉर्म को सबमिट करके आप हमारी <1>गोपनीयता नीति के अनुसार, Rocket.Chat उत्पादों, घटनाओं और अपडेट के बारे में अधिक जानकारी प्राप्त करने के लिए सहमति देते हैं। आप किसी भी समय सदस्यता वापस ले सकते हैं।", + "onboarding.form.standaloneServerForm.title": "स्टैंडअलोन सर्वर पुष्टिकरण", + "onboarding.form.standaloneServerForm.servicesUnavailable": "कुछ सेवाएँ अनुपलब्ध होंगी या मैन्युअल सेटअप की आवश्यकता होगी", + "onboarding.form.standaloneServerForm.publishOwnApp": "पुश सूचनाएं भेजने के लिए आपको अपना स्वयं का ऐप Google Play और App Store पर संकलित और प्रकाशित करना होगा", + "onboarding.form.standaloneServerForm.manuallyIntegrate": "बाहरी सेवाओं के साथ मैन्युअल रूप से एकीकृत करने की आवश्यकता है", + "Something_Went_Wrong": "कुछ गलत हो गया", + "Toolbox_room_actions": "प्राथमिक कक्ष क्रियाएँ", + "Theme_light": "रोशनी", + "Theme_light_description": "दृष्टिबाधित व्यक्तियों के लिए अधिक सुलभ और अच्छी रोशनी वाले वातावरण के लिए एक अच्छा विकल्प।", + "Theme_dark": "अँधेरा", + "Theme_dark_description": "स्क्रीन द्वारा उत्सर्जित प्रकाश की मात्रा को कम करके कम रोशनी की स्थिति में आंखों का तनाव और थकान कम करें।", + "Enable_of_limit_apps_currently_enabled": "** वर्तमान में {{limit}} {{context}} ऐप्स में से {{limit}} सक्षम हैं।**\n \nसमुदाय पर कार्यस्थानों में अधिकतम {{limit}} {{context}} ऐप्स सक्षम हो सकते हैं।\n \n**{{appName}} डिफ़ॉल्ट रूप से अक्षम कर दिया जाएगा।** इस ऐप को सक्षम करने के लिए किसी अन्य {{context}} ऐप को अक्षम करें या प्रीमियम में अपग्रेड करें।", + "Enable_of_limit_apps_currently_enabled_exceeded": "** वर्तमान में {{limit}} {{context}} ऐप्स में से {{limit}} सक्षम हैं।**\n \nसामुदायिक ऐप की सीमा पार हो गई है.\n \nसमुदाय पर कार्यस्थानों में अधिकतम {{limit}} {{context}} ऐप्स सक्षम हो सकते हैं।\n \n**{{appName}} डिफ़ॉल्ट रूप से अक्षम कर दिया जाएगा।** इस ऐप को सक्षम करने के लिए आपको कम से कम {{exceed}} अन्य {{context}} ऐप्स को अक्षम करना होगा या प्रीमियम प्लान में अपग्रेड करना होगा।", + "Workspaces_on_Community_edition_install_app": "सामुदायिक कार्यस्थानों में अधिकतम {{limit}} {{context}} ऐप्स सक्षम हो सकते हैं। असीमित ऐप्स सक्षम करने के लिए प्रीमियम प्लान में अपग्रेड करें।", + "Apps_Currently_Enabled": "{{limit}} {{context}} में से {{limit}} ऐप्स वर्तमान में सक्षम हैं", + "Disable_another_app": "इस ऐप को सक्षम करने के लिए किसी अन्य ऐप को अक्षम करें या प्रीमियम प्लान में अपग्रेड करें।", + "Upload_anyway": "फिर भी अपलोड करें", + "App_limit_reached": "ऐप की सीमा पूरी हो गई", + "App_limit_exceeded": "ऐप की सीमा पार हो गई", + "Private_apps_limit_reached": "निजी ऐप्स की सीमा पूरी हो गई", + "Private_apps_limit_exceeded": "निजी ऐप्स की सीमा पार हो गई", + "Disable_at_least_more_apps": "इस ऐप को सक्षम करने के लिए आपको कम से कम {{numberOfExceededApps}} अन्य ऐप्स को अक्षम करना होगा या प्रीमियम प्लान में अपग्रेड करना होगा।", + "Community_Private_apps_limit_exceeded": "सामुदायिक ऐप की सीमा पार हो गई है.", + "Theme_match_system": "मिलान प्रणाली", + "Theme_match_system_description": "स्वचालित रूप से आपके सिस्टम के स्वरूप का मिलान करें।", + "Theme_high_contrast": "हाई कॉन्ट्रास्ट", + "Theme_high_contrast_description": "बोल्ड रंगों और तीव्र विरोधाभासों के साथ अधिकतम तानवाला विभेदन बेहतर पहुंच प्रदान करता है।", + "Highlighted_chosen_word": "चयनित शब्द पर प्रकाश डाला गया", + "Join_your_team": "अपनी टीम में शामिल हों", + "Create_a_password": "एक पासवर्ड बनाएं", + "Create_an_account": "खाता बनाएं", + "Get_all_apps": "वे सभी ऐप्स प्राप्त करें जिनकी आपकी टीम को आवश्यकता है", + "Workspaces_on_community_edition_trial_on": "समुदाय पर कार्यस्थानों में अधिकतम 5 मार्केटप्लेस ऐप्स और 3 निजी ऐप्स सक्षम हो सकते हैं। इन सीमाओं को हटाने के लिए आज ही निःशुल्क प्रीमियम परीक्षण शुरू करें!", + "Workspaces_on_community_edition_trial_off": "समुदाय पर कार्यस्थानों में अधिकतम 5 मार्केटप्लेस ऐप्स और 3 निजी ऐप्स सक्षम हो सकते हैं। सीमाएं हटाने और अपने कार्यक्षेत्र को सुपरचार्ज करने के लिए प्रीमियम में अपग्रेड करें।", + "No_private_apps_installed": "कोई निजी ऐप्स इंस्टॉल नहीं", + "Private_apps_are_side-loaded": "निजी ऐप्स साइड-लोडेड हैं और मार्केटप्लेस पर उपलब्ध नहीं हैं।", + "Chat_transcript": "चैट प्रतिलेख", + "Conversational_transcript": "संवादी प्रतिलेख", + "Conversations_by_agents": "एजेंटों द्वारा बातचीत", + "Conversations_by_channel": "चैनल द्वारा बातचीत", + "Conversations_by_department": "विभाग द्वारा बातचीत", + "Conversations_by_status": "स्थिति के अनुसार बातचीत", + "Conversations_by_tag": "टैग द्वारा बातचीत", + "Send_conversation_transcript_via_email": "ईमेल के माध्यम से वार्तालाप प्रतिलेख भेजें", + "Always_send_the_transcript_to_contacts_at_the_end_of_the_conversations": "बातचीत के अंत में हमेशा संपर्कों को प्रतिलेख भेजें।", + "Export_conversation_transcript_as_PDF": "वार्तालाप प्रतिलेख को पीडीएफ के रूप में निर्यात करें", + "Omnichannel_transcript_email": "ईमेल के माध्यम से चैट प्रतिलेख भेजें.", + "Accounts_Default_User_Preferences_omnichannelTranscriptEmail_Description": "बातचीत के अंत में हमेशा संपर्कों को प्रतिलेख भेजें।", + "Omnichannel_transcript_pdf": "चैट प्रतिलेख को पीडीएफ के रूप में निर्यात करें।", + "Accounts_Default_User_Preferences_omnichannelTranscriptPDF_Description": "बातचीत के अंत में प्रतिलेख को हमेशा पीडीएफ के रूप में निर्यात करें।", + "Contact_email": "ई - मेल से संपर्क करे", + "Customer": "ग्राहक", + "Time": "समय", + "Omnichannel_Agent": "ओमनीचैनल एजेंट", + "This_attachment_is_not_supported": "अनुलग्नक प्रारूप समर्थित नहीं है", + "Send_transcript": "प्रतिलेख भेजें", + "Undo_request": "अनुरोध पूर्ववत करें", + "No_permission": "अनुमति नहीं", + "Community_cap_description": "सामुदायिक कार्यस्थानों में 200 समवर्ती कनेक्शन की सीमा होती है। यदि यह सीमा पार हो जाती है तो उपयोगकर्ताओं के लिए एक-दूसरे की स्थिति देखना संभव नहीं होगा। इससे संदेश भेजने और प्राप्त करने पर कोई प्रभाव नहीं पड़ता है.", + "Premium_cap_description": "प्रीमियम योजनाओं में उपस्थिति सेवा सीमा नहीं होती है।", + "Service_status": "सेवा की स्थिति", + "More_about_Premium_plans": "प्रीमियम योजनाओं के बारे में अधिक जानकारी", + "Presence_service_cap": "उपस्थिति सेवा कैप", + "User_Status": "उपयोगकर्ता की स्थिति", + "User_status_menu": "उपयोगकर्ता स्थिति मेनू", + "Active_connections": "सक्रिय कनेक्शन", + "Presence_service": "उपस्थिति सेवा", + "Presence_broadcast_disabled": "उपस्थिति प्रसारण आंतरिक रूप से अक्षम है", + "Presence_broadcast_disabled_Description": "इससे पता चलता है कि क्या उपस्थिति प्रसारण स्वचालित रूप से अक्षम कर दिया गया है। ऐसा तब हो सकता है जब आपके पास प्रीमियम लाइसेंस नहीं है और 200 से अधिक समवर्ती कनेक्शन हैं।", + "New_custom_status": "नई कस्टम स्थिति", + "Service_disabled": "सेवा अब अक्षम है", + "Service_disabled_description": "जब तक एक ही समय में 200 से कम सक्रिय कनेक्शन न हों तब तक आप इसे दोबारा सक्षम नहीं कर सकते", + "User_status_disabled": "प्रदर्शन को बनाए रखने के लिए उपयोगकर्ता स्थिति अस्थायी रूप से अक्षम कर दी गई है।", + "User_status_disabled_learn_more": "उपयोगकर्ता स्थिति अक्षम", + "User_status_disabled_learn_more_description": "सक्रिय कनेक्शनों की अधिक मात्रा के कारण, उपयोगकर्ता की स्थिति को संभालने वाली सेवा अस्थायी रूप से अक्षम है। व्यवस्थापक इसे कार्यस्थान सेटिंग्स में मैन्युअल रूप से पुनः सक्षम कर सकते हैं।", + "Go_to_workspace_settings": "कार्यस्थान सेटिंग्स पर जाएँ", + "User_status_temporarily_disabled": "उपयोगकर्ता स्थिति अस्थायी रूप से अक्षम है", + "Use_token": "टोकन का प्रयोग करें", + "Disconnected": "डिस्कनेक्ट किया गया", + "Disconnect_workspace": "कार्यस्थान को डिस्कनेक्ट करें", + "Awaiting_confirmation": "पुष्टिकरण की प्रतीक्षा", + "Security_code": "सुरक्षा कोड", + "Registration_Token": "पंजीकरण टोकन", + "RegisterWorkspace_Button": "कार्यक्षेत्र पंजीकृत करें", + "ConnectWorkspace_Button": "कार्यक्षेत्र कनेक्ट करें", + "Workspace_registered": "कार्यक्षेत्र पंजीकृत", + "Workspace_not_connected": "कार्यस्थल कनेक्ट नहीं है", + "Token_Not_Recognized": "टोकन पहचाना नहीं गया", + "RegisterWorkspace_Registered_Description": "ये सेवाएँ उपलब्ध हैं", + "RegisterWorkspace_Registered_Subtitle": "चूँकि यह कार्यस्थान पंजीकृत है इसलिए निम्नलिखित उपलब्ध है", + "RegisterWorkspace_Registered_Benefits": "पंजीकरण स्वचालित लाइसेंस अपडेट, महत्वपूर्ण कमजोरियों की अधिसूचना और रॉकेट.चैट क्लाउड सेवाओं तक पहुंच की अनुमति देता है। कोई भी संवेदनशील कार्यक्षेत्र डेटा Rocket.Chat के साथ साझा नहीं किया जाता है।", + "RegisterWorkspace_NotRegistered_Title": "कार्यस्थल पंजीकृत नहीं है", + "RegisterWorkspace_NotRegistered_Subtitle": "इस कार्यक्षेत्र को पंजीकृत करें और प्राप्त करें", + "RegisterWorkspace_NotConnected_Title": "कार्यस्थल डिस्कनेक्ट हो गया", + "RegisterWorkspace_NotConnected_Subtitle": "इस कार्यक्षेत्र को कनेक्ट करें और प्राप्त करें", + "RegisterWorkspace_NotRegistered_Description": "कार्यक्षेत्र पंजीकृत करने के लाभ", + "RegisterWorkspace_Disconnect_Subtitle": "आपके कार्यक्षेत्र को डिस्कनेक्ट करने से निम्नलिखित की हानि होगी", + "RegisterWorkspace_Disconnect_Error": "डिस्कनेक्ट करने में त्रुटि उत्पन्न हुई", + "RegisterWorkspace_Features_MobileNotifications_Title": "मोबाइल पुश सूचनाएँ", + "RegisterWorkspace_Features_MobileNotifications_Description": "कार्यक्षेत्र के सदस्यों को उनके मोबाइल उपकरणों पर सूचनाएं प्राप्त करने की अनुमति देता है।", + "RegisterWorkspace_Features_MobileNotifications_Disconnect": "कार्यक्षेत्र के सदस्यों को अब अपने मोबाइल उपकरणों पर सूचनाएं प्राप्त नहीं होंगी।", + "RegisterWorkspace_Features_Marketplace_Title": "बाजार", + "RegisterWorkspace_Features_Marketplace_Description": "इस कार्यक्षेत्र पर Rocket.Chat मार्केटप्लेस ऐप्स इंस्टॉल करें।", + "RegisterWorkspace_Features_Marketplace_Disconnect": "अब ऐप्स इंस्टॉल करना संभव नहीं होगा.", + "RegisterWorkspace_Features_Omnichannel_Title": "सर्वचैनल", + "RegisterWorkspace_Features_Omnichannel_Description": "दुनिया के सबसे लोकप्रिय सामाजिक चैनलों के माध्यम से अपने दर्शकों से, जहां वे हैं, बात करें।", + "RegisterWorkspace_Features_Omnichannel_Disconnect": "ओमनीचैनल क्षमताएं अब उपलब्ध नहीं होंगी.", + "RegisterWorkspace_Features_ThirdPartyLogin_Title": "तृतीय-पक्ष लॉगिन", + "RegisterWorkspace_Features_ThirdPartyLogin_Description": "कार्यस्थान सदस्यों को तृतीय-पक्ष एप्लिकेशन के सेट का उपयोग करके लॉग इन करने दें।", + "RegisterWorkspace_Features_ThirdPartyLogin_Disconnect": "तृतीय-पक्ष लॉगिन विकल्प अब उपलब्ध नहीं होंगे।", + "RegisterWorkspace_Token_Title": "टोकन के साथ कार्यक्षेत्र पंजीकृत करें", + "RegisterWorkspace_Token_Step_Two": "टोकन को कॉपी करें और नीचे पेस्ट करें।", + "RegisterWorkspace_with_email": "कार्यस्थल को ईमेल से पंजीकृत करें", + "RegisterWorkspace_Setup_Subtitle": "इस कार्यक्षेत्र को पंजीकृत करने के लिए इसे Rocket.Chat क्लाउड खाते से संबद्ध करना होगा।", + "RegisterWorkspace_Setup_Steps": "{{numberOfSteps}} का चरण {{step}}", + "RegisterWorkspace_Setup_Label": "क्लाउड खाता ईमेल", + "RegisterWorkspace_Setup_Have_Account_Title": "एक खाता है?", + "RegisterWorkspace_Setup_Have_Account_Subtitle": "इस कार्यक्षेत्र को अपने खाते से संबद्ध करने के लिए अपना क्लाउड खाता ईमेल दर्ज करें।", + "RegisterWorkspace_Setup_No_Account_Title": "कोई खाता नहीं है?", + "RegisterWorkspace_Setup_No_Account_Subtitle": "एक नया क्लाउड खाता बनाने और इस कार्यक्षेत्र को संबद्ध करने के लिए अपना ईमेल दर्ज करें।", + "cloud.RegisterWorkspace_Setup_Email_Confirmation": "पुष्टिकरण लिंक के साथ <1>ईमेल पर ईमेल भेजा गया।", + "RegisterWorkspace_Setup_Email_Verification": "कृपया सत्यापित करें कि नीचे दिया गया सुरक्षा कोड ईमेल में दिए गए सुरक्षा कोड से मेल खाता है।", + "RegisterWorkspace_Syncing_Error": "आपके कार्यस्थान को समन्वयित करते समय एक त्रुटि उत्पन्न हुई", + "RegisterWorkspace_Syncing_Complete": "सिंक पूर्ण", + "RegisterWorkspace_Connection_Error": "कनेक्ट करने में त्रुटि उत्पन्न हुई", + "cloud.RegisterWorkspace_Token_Step_One": "1. यहां जाएं: <1>cloud.rocket.chat > कार्यस्थान और <3>'स्वयं-प्रबंधित पंजीकरण करें' पर क्लिक करें।", + "cloud.RegisterWorkspace_Setup_Terms_Privacy": "मैं <1>नियम एवं शर्तें और <3>गोपनीयता नीति से सहमत हूं", + "Larger_amounts_of_active_connections": "बड़ी मात्रा में सक्रिय कनेक्शन के लिए आप हमारे <1>मल्टीपल इंस्टेंस समाधान पर विचार कर सकते हैं।", + "Uninstall_grandfathered_app": "{{appName}} अनइंस्टॉल करें?", + "App_will_lose_grandfathered_status": "**यह {{context}} ऐप अपना दादा दर्जा खो देगा।**\n \nसमुदाय पर कार्यस्थानों में अधिकतम {{limit}} {{context}} ऐप्स सक्षम हो सकते हैं। दादाजी ऐप्स को सीमा में गिना जाता है लेकिन सीमा उन पर लागू नहीं होती है।", + "All_rooms": "सभी कमरे", + "All_visible": "सब दिख रहा है", + "Filter_by_room": "कमरे के प्रकार के अनुसार फ़िल्टर करें", + "Filter_by_visibility": "दृश्यता के आधार पर फ़िल्टर करें", + "Theme_Appearence": "थीम उपस्थिति", + "mentions_counter": "{{count}} उल्लेख", + "threads_counter": "{{count}} अपठित थ्रेडेड संदेश", + "group_mentions_counter": "{{count}} समूह का उल्लेख", + "unread_messages_counter": "अपठित संदेश को {{count}}", + "Premium": "अधिमूल्य", + "Premium_capability": "प्रीमियम क्षमता", + "Operating_withing_plan_limits": "योजना सीमा के भीतर संचालन", + "Plan_limits_reached": "योजना की सीमा पूरी हो गई", + "Workspace_not_registered": "कार्यस्थल पंजीकृत नहीं है", + "Users_Connected": "उपयोगकर्ता जुड़े", + "Solve_issues": "मुद्दे सुलझाओ", + "Update_version": "नया संस्करण", + "Version_not_supported": "संस्करण <1>समर्थित नहीं", + "Version_supported_until": "संस्करण <1>समर्थित {{date}} तक", + "Check_support_availability": "<1>समर्थन उपलब्धता की जाँच करें", + "Outdated": "रगड़ा हुआ", + "Latest": "नवीनतम", + "New_version_available": "नया संस्करण उपलब्ध है", + "trial": "परीक्षण", + "Subscription": "अंशदान", + "Manage_subscription": "सदस्यता प्रबंधित करें", + "ActiveSessionsPeak": "सक्रिय सत्र चरम पर हैं", + "ActiveSessionsPeak_InfoText": "पिछले 30 दिनों में सक्रिय कनेक्शनों की सर्वाधिक संख्या", + "ActiveSessions": "सक्रिय सत्र", + "ActiveSessions_available": "सत्र उपलब्ध हैं", + "Monthly_active_contacts": "मासिक सक्रिय संपर्क", + "Upgrade": "उन्नत करना", + "Seats": "सीटें", + "Marketplace_apps": "मार्केटप्लेस ऐप्स", + "Private_apps": "निजी ऐप्स", + "Finish_your_purchase_trial": "<1>डाउनग्रेड परिणामों से बचने के लिए अपनी खरीदारी समाप्त करें", + "Contact_sales_trial": "अपनी खरीदारी पूरी करने और <1>डाउनग्रेड परिणामों से बचने के लिए सेल्स से संपर्क करें", + "Why_has_a_trial_been_applied_to_this_workspace": "<0>इस कार्यक्षेत्र पर परीक्षण क्यों लागू किया गया है?", + "Compare_plans": "योजनाओं की तुलना करें", + "n_days_left": "{{n}} दिन बचे हैं", + "Contact_sales": "बिक्री से संपर्क करें", + "Finish_purchase": "खरीदारी समाप्त करें", + "Self_managed_hosting": "स्व-प्रबंधित होस्टिंग", + "Cloud_hosting": "रॉकेट.चैट क्लाउड होस्टिंग", + "free_per_month_user": "$0 प्रति माह/उपयोगकर्ता", + "Trial_active": "परीक्षण सक्रिय", + "Contact_sales_renew_date": "योजना नवीनीकरण तिथि की जांच करने के लिए <0>बिक्री से संपर्क करें", + "Renews_DATE": "नवीनीकरण {{date}}", + "UpgradeToGetMore_Headline": "अधिक पाने के लिए अपग्रेड करें", + "UpgradeToGetMore_Subtitle": "उन्नत क्षमताओं के साथ अपने कार्यक्षेत्र को सुपरचार्ज करें।", + "UpgradeToGetMore_scalability_Title": "उच्च मापनीयता", + "UpgradeToGetMore_scalability_Body": "मोनोलिथिक से माइक्रोसर्विसेज या मल्टी-इंस्टेंस पर स्विच करके दक्षता में सुधार करें, लागत कम करें और समवर्ती उपयोगकर्ताओं का उपयोग बढ़ाएं।", + "UpgradeToGetMore_accessibility-certification_Title": "WCAG 2.1 और BITV 2.0", + "UpgradeToGetMore_accessibility-certification_Body": "Rocket.Chat के एक्सेसिबिलिटी प्रोग्राम के साथ WCAG और BITV मानकों का अनुपालन करें।", + "UpgradeToGetMore_engagement-dashboard_Title": "एनालिटिक्स", + "UpgradeToGetMore_engagement-dashboard_Body": "सहभागिता डैशबोर्ड के माध्यम से उपयोगकर्ता, संदेश और चैनल के उपयोग के बारे में जानकारी प्राप्त करें।", + "UpgradeToGetMore_oauth-enterprise_Title": "उन्नत प्रमाणीकरण", + "UpgradeToGetMore_oauth-enterprise_Body": "समूह भूमिका मैपिंग, चैनल सदस्यता, ऑटो लॉगआउट और बहुत कुछ के साथ एलडीएपी/एसएएमएल/ओथ के माध्यम से उचित पहुंच अनुमतियां सुनिश्चित करें।", + "UpgradeToGetMore_custom-roles_Title": "कस्टम भूमिकाएँ", + "UpgradeToGetMore_custom-roles_Body": "अपने कार्यक्षेत्र में लोगों के लिए विशिष्ट भूमिकाएँ और अनुमतियाँ निर्धारित करके एक सुरक्षित और उत्पादक कार्य वातावरण सुनिश्चित करें।", + "UpgradeToGetMore_auditing_Title": "संदेश ऑडिटिंग", + "UpgradeToGetMore_auditing_Body": "ग्राहकों, आपूर्तिकर्ताओं और आंतरिक टीमों के साथ संचार गुणवत्ता सुनिश्चित करने के लिए बातचीत को एक ही स्थान पर ऑडिट करें।", + "Seats_InfoText": "प्रत्येक अद्वितीय उपयोगकर्ता एक सीट पर रहता है। निष्क्रिय उपयोगकर्ता सीटों पर कब्जा नहीं करते हैं। सीटों की कुल संख्या सक्रिय लाइसेंस प्रकार द्वारा परिभाषित की जाती है।", + "CountSeats_InfoText": "प्रत्येक अद्वितीय उपयोगकर्ता एक सीट पर रहता है। निष्क्रिय उपयोगकर्ता सीटों पर कब्जा नहीं करते हैं।", + "MAC_InfoText": "(मैक) बिलिंग माह के दौरान जुड़े अद्वितीय सर्वचैनल संपर्कों की संख्या।", + "CountMAC_InfoText": "(मैक) कैलेंडर माह के दौरान जुड़े अद्वितीय ओमनीचैनल संपर्कों की संख्या।", + "ActiveSessions_InfoText": "कुल समवर्ती कनेक्शन. एक ही यूजर को कई बार कनेक्ट किया जा सकता है। प्रदर्शन समस्याओं को रोकने के लिए उपयोगकर्ता उपस्थिति सेवा 200 या उससे अधिक पर अक्षम है।", + "Apps_InfoText": "समुदाय 3 निजी ऐप्स और 5 मार्केटप्लेस ऐप्स को सक्षम करने की अनुमति देता है", + "Remove_RocketChat_Watermark_InfoText": "सशुल्क लाइसेंस सक्रिय होने पर वॉटरमार्क स्वचालित रूप से हटा दिया जाता है।", + "Remove_RocketChat_Watermark": "रॉकेट.चैट वॉटरमार्क हटाएँ", + "High_scalabaility": "उच्च मापनीयता", + "Premium_and_unlimited_apps": "प्रीमियम और असीमित ऐप्स", + "Message_audit": "संदेश ऑडिटिंग", + "Premium_omnichannel_capabilities": "प्रीमियम सर्वचैनल क्षमताएँ", + "Video_call_manager": "वीडियो कॉल प्रबंधक", + "Unlimited_push_notifications": "असीमित पुश सूचनाएं", + "Buy_more": "अधिक खरीदें", + "Upgrade_to_Pro": "प्रो में अपग्रेड", + "Sync_license_update": "सिंक लाइसेंस अद्यतन", + "Sync_license_update_Callout_Title": "हम आपका लाइसेंस अपडेट कर रहे हैं", + "Sync_license_update_Callout": "यदि आपको कुछ मिनटों के भीतर अपने कार्यक्षेत्र में कोई बदलाव नज़र नहीं आता है, तो लाइसेंस अपडेट को सिंक करें।", + "Includes": "शामिल", + "Unlock_premium_capabilities": "प्रीमियम क्षमताओं को अनलॉक करें", + "Unlimited_seats": "असीमित सीटें", + "Unlimited_MACs": "असीमित एमएसी", + "Unlimited_seats_MACs": "असीमित सीटें और एमएसी" } \ No newline at end of file From c676b357c8d142fa0e08f209da7376f4c2e38f66 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Thu, 15 Aug 2024 13:55:50 -0300 Subject: [PATCH 49/80] chore(client): Remove Meteor.Error from `slashCommand` (#32915) --- .../client/slackbridge_import.client.js | 2 +- .../slashcommand-asciiarts/client/gimme.ts | 2 +- .../slashcommand-asciiarts/client/lenny.ts | 2 +- .../slashcommand-asciiarts/client/shrug.ts | 2 +- .../client/tableflip.ts | 2 +- .../slashcommand-asciiarts/client/unflip.ts | 2 +- .../slashcommand-asciiarts/server/gimme.ts | 2 +- .../slashcommand-asciiarts/server/lenny.ts | 2 +- .../slashcommand-asciiarts/server/shrug.ts | 2 +- .../server/tableflip.ts | 2 +- .../slashcommand-asciiarts/server/unflip.ts | 2 +- .../client/client.ts | 2 +- .../server/server.ts | 2 +- .../app/slashcommands-create/client/client.ts | 2 +- .../app/slashcommands-create/server/server.ts | 2 +- .../app/slashcommands-help/server/server.ts | 2 +- .../app/slashcommands-hide/client/hide.ts | 2 +- .../app/slashcommands-invite/client/client.ts | 2 +- .../app/slashcommands-invite/server/server.ts | 2 +- .../slashcommands-inviteall/client/client.ts | 2 +- .../slashcommands-inviteall/server/server.ts | 2 +- .../app/slashcommands-join/client/client.ts | 2 +- .../app/slashcommands-join/server/server.ts | 2 +- .../app/slashcommands-kick/client/client.ts | 2 +- .../app/slashcommands-kick/server/server.ts | 2 +- .../app/slashcommands-leave/server/leave.ts | 2 +- apps/meteor/app/slashcommands-me/server/me.ts | 2 +- .../app/slashcommands-msg/server/server.ts | 2 +- .../app/slashcommands-mute/server/mute.ts | 2 +- .../app/slashcommands-mute/server/unmute.ts | 2 +- .../app/slashcommands-open/client/client.ts | 2 +- .../app/slashcommands-status/client/status.ts | 2 +- .../app/slashcommands-status/server/status.ts | 2 +- .../app/slashcommands-topic/client/topic.ts | 2 +- .../app/slashcommands-topic/server/topic.ts | 2 +- .../client/client.ts | 2 +- .../server/server.ts | 2 +- apps/meteor/app/utils/client/index.ts | 2 +- .../app/utils/{lib => client}/slashCommand.ts | 11 +- apps/meteor/app/utils/server/slashCommand.ts | 136 +++++++++++++++++- .../client/hooks/useAppSlashCommands.ts | 2 +- .../client/lib/errors/InvalidCommandUsage.ts | 7 + .../client/lib/errors/InvalidPreview.ts | 7 + apps/meteor/client/lib/errors/index.ts | 2 + .../startup/slashCommands/federation.ts | 2 +- .../hooks/useComposerBoxPopupQueries.ts | 2 +- 46 files changed, 196 insertions(+), 49 deletions(-) rename apps/meteor/app/utils/{lib => client}/slashCommand.ts (85%) create mode 100644 apps/meteor/client/lib/errors/InvalidCommandUsage.ts create mode 100644 apps/meteor/client/lib/errors/InvalidPreview.ts create mode 100644 apps/meteor/client/lib/errors/index.ts diff --git a/apps/meteor/app/slackbridge/client/slackbridge_import.client.js b/apps/meteor/app/slackbridge/client/slackbridge_import.client.js index 6aeffb7bef45..eebc07ddb72d 100644 --- a/apps/meteor/app/slackbridge/client/slackbridge_import.client.js +++ b/apps/meteor/app/slackbridge/client/slackbridge_import.client.js @@ -1,5 +1,5 @@ import { settings } from '../../settings/client'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; settings.onload('SlackBridge_Enabled', (key, value) => { if (value) { diff --git a/apps/meteor/app/slashcommand-asciiarts/client/gimme.ts b/apps/meteor/app/slashcommand-asciiarts/client/gimme.ts index 4c9d6a4e40c8..7cd5edb6bb87 100644 --- a/apps/meteor/app/slashcommand-asciiarts/client/gimme.ts +++ b/apps/meteor/app/slashcommand-asciiarts/client/gimme.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { sdk } from '../../utils/client/lib/SDKClient'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; /* * Gimme is a named function that will replace /gimme commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommand-asciiarts/client/lenny.ts b/apps/meteor/app/slashcommand-asciiarts/client/lenny.ts index 99eaa03b9e59..0e3cc55f6b86 100644 --- a/apps/meteor/app/slashcommand-asciiarts/client/lenny.ts +++ b/apps/meteor/app/slashcommand-asciiarts/client/lenny.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { sdk } from '../../utils/client/lib/SDKClient'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; /* * Lenny is a named function that will replace /lenny commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommand-asciiarts/client/shrug.ts b/apps/meteor/app/slashcommand-asciiarts/client/shrug.ts index bc0fb300789e..c4bdec8f1a8c 100644 --- a/apps/meteor/app/slashcommand-asciiarts/client/shrug.ts +++ b/apps/meteor/app/slashcommand-asciiarts/client/shrug.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { sdk } from '../../utils/client/lib/SDKClient'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; /* * Shrug is a named function that will replace /shrug commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommand-asciiarts/client/tableflip.ts b/apps/meteor/app/slashcommand-asciiarts/client/tableflip.ts index 0d709760fe84..8820b81f7c4a 100644 --- a/apps/meteor/app/slashcommand-asciiarts/client/tableflip.ts +++ b/apps/meteor/app/slashcommand-asciiarts/client/tableflip.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { sdk } from '../../utils/client/lib/SDKClient'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; /* * Tableflip is a named function that will replace /Tableflip commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommand-asciiarts/client/unflip.ts b/apps/meteor/app/slashcommand-asciiarts/client/unflip.ts index a7dc0d257e78..6c02fa196052 100644 --- a/apps/meteor/app/slashcommand-asciiarts/client/unflip.ts +++ b/apps/meteor/app/slashcommand-asciiarts/client/unflip.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { sdk } from '../../utils/client/lib/SDKClient'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; /* * Unflip is a named function that will replace /unflip commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommand-asciiarts/server/gimme.ts b/apps/meteor/app/slashcommand-asciiarts/server/gimme.ts index f426d6cf85c0..f902d75f33d1 100644 --- a/apps/meteor/app/slashcommand-asciiarts/server/gimme.ts +++ b/apps/meteor/app/slashcommand-asciiarts/server/gimme.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { executeSendMessage } from '../../lib/server/methods/sendMessage'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Gimme is a named function that will replace /gimme commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommand-asciiarts/server/lenny.ts b/apps/meteor/app/slashcommand-asciiarts/server/lenny.ts index 878a10e356d4..e760b5a1169e 100644 --- a/apps/meteor/app/slashcommand-asciiarts/server/lenny.ts +++ b/apps/meteor/app/slashcommand-asciiarts/server/lenny.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { executeSendMessage } from '../../lib/server/methods/sendMessage'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Lenny is a named function that will replace /lenny commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommand-asciiarts/server/shrug.ts b/apps/meteor/app/slashcommand-asciiarts/server/shrug.ts index 1240027bb38f..c2e5d166bfd8 100644 --- a/apps/meteor/app/slashcommand-asciiarts/server/shrug.ts +++ b/apps/meteor/app/slashcommand-asciiarts/server/shrug.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { executeSendMessage } from '../../lib/server/methods/sendMessage'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Shrug is a named function that will replace /shrug commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommand-asciiarts/server/tableflip.ts b/apps/meteor/app/slashcommand-asciiarts/server/tableflip.ts index 34acef9805e2..ac3f599dff1d 100644 --- a/apps/meteor/app/slashcommand-asciiarts/server/tableflip.ts +++ b/apps/meteor/app/slashcommand-asciiarts/server/tableflip.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { executeSendMessage } from '../../lib/server/methods/sendMessage'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Tableflip is a named function that will replace /Tableflip commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommand-asciiarts/server/unflip.ts b/apps/meteor/app/slashcommand-asciiarts/server/unflip.ts index 689e7262eac0..b905ed567447 100644 --- a/apps/meteor/app/slashcommand-asciiarts/server/unflip.ts +++ b/apps/meteor/app/slashcommand-asciiarts/server/unflip.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { executeSendMessage } from '../../lib/server/methods/sendMessage'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Unflip is a named function that will replace /unflip commands * @param {Object} message - The message object diff --git a/apps/meteor/app/slashcommands-archiveroom/client/client.ts b/apps/meteor/app/slashcommands-archiveroom/client/client.ts index c24763106684..f5154fb32a5b 100644 --- a/apps/meteor/app/slashcommands-archiveroom/client/client.ts +++ b/apps/meteor/app/slashcommands-archiveroom/client/client.ts @@ -1,4 +1,4 @@ -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'archive', diff --git a/apps/meteor/app/slashcommands-archiveroom/server/server.ts b/apps/meteor/app/slashcommands-archiveroom/server/server.ts index 99bcec2cd7b3..f1b33c1022bb 100644 --- a/apps/meteor/app/slashcommands-archiveroom/server/server.ts +++ b/apps/meteor/app/slashcommands-archiveroom/server/server.ts @@ -10,7 +10,7 @@ import { roomCoordinator } from '../../../server/lib/rooms/roomCoordinator'; import { hasPermissionAsync } from '../../authorization/server/functions/hasPermission'; import { archiveRoom } from '../../lib/server/functions/archiveRoom'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; slashCommands.add({ command: 'archive', diff --git a/apps/meteor/app/slashcommands-create/client/client.ts b/apps/meteor/app/slashcommands-create/client/client.ts index 299db606db9c..7e8ba831dbd8 100644 --- a/apps/meteor/app/slashcommands-create/client/client.ts +++ b/apps/meteor/app/slashcommands-create/client/client.ts @@ -1,4 +1,4 @@ -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'create', diff --git a/apps/meteor/app/slashcommands-create/server/server.ts b/apps/meteor/app/slashcommands-create/server/server.ts index 104d50c56926..6abee71c56fd 100644 --- a/apps/meteor/app/slashcommands-create/server/server.ts +++ b/apps/meteor/app/slashcommands-create/server/server.ts @@ -6,7 +6,7 @@ import { i18n } from '../../../server/lib/i18n'; import { createChannelMethod } from '../../lib/server/methods/createChannel'; import { createPrivateGroupMethod } from '../../lib/server/methods/createPrivateGroup'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; slashCommands.add({ command: 'create', diff --git a/apps/meteor/app/slashcommands-help/server/server.ts b/apps/meteor/app/slashcommands-help/server/server.ts index c24bfb22c6fe..80efaffeb852 100644 --- a/apps/meteor/app/slashcommands-help/server/server.ts +++ b/apps/meteor/app/slashcommands-help/server/server.ts @@ -4,7 +4,7 @@ import { Users } from '@rocket.chat/models'; import { i18n } from '../../../server/lib/i18n'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Help is a named function that will replace /help commands diff --git a/apps/meteor/app/slashcommands-hide/client/hide.ts b/apps/meteor/app/slashcommands-hide/client/hide.ts index 99c1eaea7049..c6486053ecc2 100644 --- a/apps/meteor/app/slashcommands-hide/client/hide.ts +++ b/apps/meteor/app/slashcommands-hide/client/hide.ts @@ -1,4 +1,4 @@ -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'hide', diff --git a/apps/meteor/app/slashcommands-invite/client/client.ts b/apps/meteor/app/slashcommands-invite/client/client.ts index 729073b785d8..7c8af755d64d 100644 --- a/apps/meteor/app/slashcommands-invite/client/client.ts +++ b/apps/meteor/app/slashcommands-invite/client/client.ts @@ -1,4 +1,4 @@ -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'invite', diff --git a/apps/meteor/app/slashcommands-invite/server/server.ts b/apps/meteor/app/slashcommands-invite/server/server.ts index de525d8c6fc6..06a85301540c 100644 --- a/apps/meteor/app/slashcommands-invite/server/server.ts +++ b/apps/meteor/app/slashcommands-invite/server/server.ts @@ -6,7 +6,7 @@ import { Meteor } from 'meteor/meteor'; import { i18n } from '../../../server/lib/i18n'; import { addUsersToRoomMethod } from '../../lib/server/methods/addUsersToRoom'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Invite is a named function that will replace /invite commands diff --git a/apps/meteor/app/slashcommands-inviteall/client/client.ts b/apps/meteor/app/slashcommands-inviteall/client/client.ts index f8ab40953d27..5083cd4a83ab 100644 --- a/apps/meteor/app/slashcommands-inviteall/client/client.ts +++ b/apps/meteor/app/slashcommands-inviteall/client/client.ts @@ -1,4 +1,4 @@ -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'invite-all-to', diff --git a/apps/meteor/app/slashcommands-inviteall/server/server.ts b/apps/meteor/app/slashcommands-inviteall/server/server.ts index bac4349ec72c..e74bb89899c2 100644 --- a/apps/meteor/app/slashcommands-inviteall/server/server.ts +++ b/apps/meteor/app/slashcommands-inviteall/server/server.ts @@ -15,7 +15,7 @@ import { addUsersToRoomMethod } from '../../lib/server/methods/addUsersToRoom'; import { createChannelMethod } from '../../lib/server/methods/createChannel'; import { createPrivateGroupMethod } from '../../lib/server/methods/createPrivateGroup'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; function inviteAll(type: T): SlashCommand['callback'] { return async function inviteAll({ command, params, message, userId }: SlashCommandCallbackParams): Promise { diff --git a/apps/meteor/app/slashcommands-join/client/client.ts b/apps/meteor/app/slashcommands-join/client/client.ts index 417fe1e5cd47..bc8d589f51ac 100644 --- a/apps/meteor/app/slashcommands-join/client/client.ts +++ b/apps/meteor/app/slashcommands-join/client/client.ts @@ -1,6 +1,6 @@ import type { Meteor } from 'meteor/meteor'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'join', diff --git a/apps/meteor/app/slashcommands-join/server/server.ts b/apps/meteor/app/slashcommands-join/server/server.ts index 33d0278f81a3..6497324ae9e0 100644 --- a/apps/meteor/app/slashcommands-join/server/server.ts +++ b/apps/meteor/app/slashcommands-join/server/server.ts @@ -5,7 +5,7 @@ import { Meteor } from 'meteor/meteor'; import { i18n } from '../../../server/lib/i18n'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; slashCommands.add({ command: 'join', diff --git a/apps/meteor/app/slashcommands-kick/client/client.ts b/apps/meteor/app/slashcommands-kick/client/client.ts index 475346216f1e..7fc167e17c88 100644 --- a/apps/meteor/app/slashcommands-kick/client/client.ts +++ b/apps/meteor/app/slashcommands-kick/client/client.ts @@ -1,6 +1,6 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'kick', diff --git a/apps/meteor/app/slashcommands-kick/server/server.ts b/apps/meteor/app/slashcommands-kick/server/server.ts index 5ca6b45ec835..fdde07b897bf 100644 --- a/apps/meteor/app/slashcommands-kick/server/server.ts +++ b/apps/meteor/app/slashcommands-kick/server/server.ts @@ -6,7 +6,7 @@ import { Users } from '@rocket.chat/models'; import { i18n } from '../../../server/lib/i18n'; import { removeUserFromRoomMethod } from '../../../server/methods/removeUserFromRoom'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; slashCommands.add({ command: 'kick', diff --git a/apps/meteor/app/slashcommands-leave/server/leave.ts b/apps/meteor/app/slashcommands-leave/server/leave.ts index 42dad0807246..fa108fe18c72 100644 --- a/apps/meteor/app/slashcommands-leave/server/leave.ts +++ b/apps/meteor/app/slashcommands-leave/server/leave.ts @@ -5,7 +5,7 @@ import { Users } from '@rocket.chat/models'; import { i18n } from '../../../server/lib/i18n'; import { leaveRoomMethod } from '../../lib/server/methods/leaveRoom'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Leave is a named function that will replace /leave commands diff --git a/apps/meteor/app/slashcommands-me/server/me.ts b/apps/meteor/app/slashcommands-me/server/me.ts index ba6a9f8c82cc..b8b4a593cb73 100644 --- a/apps/meteor/app/slashcommands-me/server/me.ts +++ b/apps/meteor/app/slashcommands-me/server/me.ts @@ -1,7 +1,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { executeSendMessage } from '../../lib/server/methods/sendMessage'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Me is a named function that will replace /me commands diff --git a/apps/meteor/app/slashcommands-msg/server/server.ts b/apps/meteor/app/slashcommands-msg/server/server.ts index c6a244b80207..e757938106eb 100644 --- a/apps/meteor/app/slashcommands-msg/server/server.ts +++ b/apps/meteor/app/slashcommands-msg/server/server.ts @@ -7,7 +7,7 @@ import { i18n } from '../../../server/lib/i18n'; import { createDirectMessage } from '../../../server/methods/createDirectMessage'; import { executeSendMessage } from '../../lib/server/methods/sendMessage'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Msg is a named function that will replace /msg commands diff --git a/apps/meteor/app/slashcommands-mute/server/mute.ts b/apps/meteor/app/slashcommands-mute/server/mute.ts index 03ce960496da..da20ff4fed47 100644 --- a/apps/meteor/app/slashcommands-mute/server/mute.ts +++ b/apps/meteor/app/slashcommands-mute/server/mute.ts @@ -5,7 +5,7 @@ import { Users } from '@rocket.chat/models'; import { i18n } from '../../../server/lib/i18n'; import { muteUserInRoom } from '../../../server/methods/muteUserInRoom'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Mute is a named function that will replace /mute commands diff --git a/apps/meteor/app/slashcommands-mute/server/unmute.ts b/apps/meteor/app/slashcommands-mute/server/unmute.ts index 25c0956d49e3..4dc683f4ca93 100644 --- a/apps/meteor/app/slashcommands-mute/server/unmute.ts +++ b/apps/meteor/app/slashcommands-mute/server/unmute.ts @@ -5,7 +5,7 @@ import { Users } from '@rocket.chat/models'; import { i18n } from '../../../server/lib/i18n'; import { unmuteUserInRoom } from '../../../server/methods/unmuteUserInRoom'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; /* * Unmute is a named function that will replace /unmute commands diff --git a/apps/meteor/app/slashcommands-open/client/client.ts b/apps/meteor/app/slashcommands-open/client/client.ts index 987df9599761..99438a24eeb0 100644 --- a/apps/meteor/app/slashcommands-open/client/client.ts +++ b/apps/meteor/app/slashcommands-open/client/client.ts @@ -5,7 +5,7 @@ import { roomCoordinator } from '../../../client/lib/rooms/roomCoordinator'; import { router } from '../../../client/providers/RouterProvider'; import { Subscriptions, ChatSubscription } from '../../models/client'; import { sdk } from '../../utils/client/lib/SDKClient'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'open', diff --git a/apps/meteor/app/slashcommands-status/client/status.ts b/apps/meteor/app/slashcommands-status/client/status.ts index 9136ef8f586f..3698b5fda4cb 100644 --- a/apps/meteor/app/slashcommands-status/client/status.ts +++ b/apps/meteor/app/slashcommands-status/client/status.ts @@ -2,7 +2,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { dispatchToastMessage } from '../../../client/lib/toast'; import { sdk } from '../../utils/client/lib/SDKClient'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'status', diff --git a/apps/meteor/app/slashcommands-status/server/status.ts b/apps/meteor/app/slashcommands-status/server/status.ts index 72d92afaf3f2..a2ff6483d398 100644 --- a/apps/meteor/app/slashcommands-status/server/status.ts +++ b/apps/meteor/app/slashcommands-status/server/status.ts @@ -5,7 +5,7 @@ import { Users } from '@rocket.chat/models'; import { i18n } from '../../../server/lib/i18n'; import { settings } from '../../settings/server'; import { setUserStatusMethod } from '../../user-status/server/methods/setUserStatus'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; slashCommands.add({ command: 'status', diff --git a/apps/meteor/app/slashcommands-topic/client/topic.ts b/apps/meteor/app/slashcommands-topic/client/topic.ts index f5f5ed58bb0f..f7e47c334b5a 100644 --- a/apps/meteor/app/slashcommands-topic/client/topic.ts +++ b/apps/meteor/app/slashcommands-topic/client/topic.ts @@ -5,7 +5,7 @@ import { callbacks } from '../../../lib/callbacks'; import { hasPermission } from '../../authorization/client'; import { ChatRoom } from '../../models/client/models/ChatRoom'; import { sdk } from '../../utils/client/lib/SDKClient'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'topic', diff --git a/apps/meteor/app/slashcommands-topic/server/topic.ts b/apps/meteor/app/slashcommands-topic/server/topic.ts index 24fd51d5f509..c1fa6ea283b7 100644 --- a/apps/meteor/app/slashcommands-topic/server/topic.ts +++ b/apps/meteor/app/slashcommands-topic/server/topic.ts @@ -2,7 +2,7 @@ import type { SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { hasPermissionAsync } from '../../authorization/server/functions/hasPermission'; import { saveRoomSettings } from '../../channel-settings/server/methods/saveRoomSettings'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; slashCommands.add({ command: 'topic', diff --git a/apps/meteor/app/slashcommands-unarchiveroom/client/client.ts b/apps/meteor/app/slashcommands-unarchiveroom/client/client.ts index 2fed1e1c7802..7b65fc067031 100644 --- a/apps/meteor/app/slashcommands-unarchiveroom/client/client.ts +++ b/apps/meteor/app/slashcommands-unarchiveroom/client/client.ts @@ -1,4 +1,4 @@ -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/client/slashCommand'; slashCommands.add({ command: 'unarchive', diff --git a/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts b/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts index d87981bd65a2..4c0c44269d2f 100644 --- a/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts +++ b/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts @@ -10,7 +10,7 @@ import { roomCoordinator } from '../../../server/lib/rooms/roomCoordinator'; import { hasPermissionAsync } from '../../authorization/server/functions/hasPermission'; import { unarchiveRoom } from '../../lib/server/functions/unarchiveRoom'; import { settings } from '../../settings/server'; -import { slashCommands } from '../../utils/lib/slashCommand'; +import { slashCommands } from '../../utils/server/slashCommand'; slashCommands.add({ command: 'unarchive', diff --git a/apps/meteor/app/utils/client/index.ts b/apps/meteor/app/utils/client/index.ts index fd03ffc3d720..561a1116141b 100644 --- a/apps/meteor/app/utils/client/index.ts +++ b/apps/meteor/app/utils/client/index.ts @@ -2,6 +2,6 @@ export { Info } from '../rocketchat.info'; export { getUserPreference } from './lib/getUserPreference'; export { fileUploadIsValidContentType } from './restrictions'; export { getUserAvatarURL } from './getUserAvatarURL'; -export { slashCommands } from '../lib/slashCommand'; +export { slashCommands } from './slashCommand'; export { getURL } from './getURL'; export { APIClient } from './lib/RestApiClient'; diff --git a/apps/meteor/app/utils/lib/slashCommand.ts b/apps/meteor/app/utils/client/slashCommand.ts similarity index 85% rename from apps/meteor/app/utils/lib/slashCommand.ts rename to apps/meteor/app/utils/client/slashCommand.ts index 47149807bbd8..66e793012fac 100644 --- a/apps/meteor/app/utils/lib/slashCommand.ts +++ b/apps/meteor/app/utils/client/slashCommand.ts @@ -6,7 +6,8 @@ import type { SlashCommandPreviewItem, SlashCommandPreviews, } from '@rocket.chat/core-typings'; -import { Meteor } from 'meteor/meteor'; + +import { InvalidCommandUsage, InvalidPreview } from '../../../client/lib/errors'; interface ISlashCommandAddParams { command: string; @@ -69,7 +70,7 @@ export const slashCommands = { } if (!message?.rid) { - throw new Meteor.Error('invalid-command-usage', 'Executing a command requires at least a message with a room id.'); + throw new InvalidCommandUsage(); } return cmd.callback({ command, params, message, triggerId, userId }); @@ -85,7 +86,7 @@ export const slashCommands = { } if (!message?.rid) { - throw new Meteor.Error('invalid-command-usage', 'Executing a command requires at least a message with a room id.'); + throw new InvalidCommandUsage(); } const previewInfo = await cmd.previewer(command, params, message); @@ -114,12 +115,12 @@ export const slashCommands = { } if (!message?.rid) { - throw new Meteor.Error('invalid-command-usage', 'Executing a command requires at least a message with a room id.'); + throw new InvalidCommandUsage(); } // { id, type, value } if (!preview.id || !preview.type || !preview.value) { - throw new Meteor.Error('error-invalid-preview', 'Preview Item must have an id, type, and value.'); + throw new InvalidPreview(); } return cmd.previewCallback(command, params, message, preview, triggerId); diff --git a/apps/meteor/app/utils/server/slashCommand.ts b/apps/meteor/app/utils/server/slashCommand.ts index dc85fee9b671..27b3c81735f9 100644 --- a/apps/meteor/app/utils/server/slashCommand.ts +++ b/apps/meteor/app/utils/server/slashCommand.ts @@ -1,7 +1,139 @@ +import { MeteorError } from '@rocket.chat/core-services'; +import type { + IMessage, + SlashCommand, + SlashCommandOptions, + RequiredField, + SlashCommandPreviewItem, + SlashCommandPreviews, +} from '@rocket.chat/core-typings'; import type { ServerMethods } from '@rocket.chat/ddp-client'; import { Meteor } from 'meteor/meteor'; -import { slashCommands } from '../lib/slashCommand'; +interface ISlashCommandAddParams { + command: string; + callback?: SlashCommand['callback']; + options?: SlashCommandOptions; + result?: SlashCommand['result']; + providesPreview?: boolean; + previewer?: SlashCommand['previewer']; + previewCallback?: SlashCommand['previewCallback']; + appId?: string; + description?: string; +} + +export const slashCommands = { + commands: {} as Record, + add({ + command, + callback, + options = {}, + result, + providesPreview = false, + previewer, + previewCallback, + appId, + description = '', + }: ISlashCommandAddParams): void { + if (this.commands[command]) { + return; + } + this.commands[command] = { + command, + callback, + params: options.params, + description: options.description || description, + permission: options.permission, + clientOnly: options.clientOnly || false, + result, + providesPreview: Boolean(providesPreview), + previewer, + previewCallback, + appId, + } as SlashCommand; + }, + async run({ + command, + message, + params, + triggerId, + userId, + }: { + command: string; + params: string; + message: RequiredField, 'rid' | '_id'>; + userId: string; + triggerId?: string | undefined; + }): Promise { + const cmd = this.commands[command]; + if (typeof cmd?.callback !== 'function') { + return; + } + + if (!message?.rid) { + throw new MeteorError('invalid-command-usage', 'Executing a command requires at least a message with a room id.'); + } + + return cmd.callback({ command, params, message, triggerId, userId }); + }, + async getPreviews( + command: string, + params: string, + message: RequiredField, 'rid'>, + ): Promise { + const cmd = this.commands[command]; + if (typeof cmd?.previewer !== 'function') { + return; + } + + if (!message?.rid) { + throw new MeteorError('invalid-command-usage', 'Executing a command requires at least a message with a room id.'); + } + + const previewInfo = await cmd.previewer(command, params, message); + + if (!previewInfo?.items?.length) { + return; + } + + // A limit of ten results, to save time and bandwidth + if (previewInfo.items.length >= 10) { + previewInfo.items = previewInfo.items.slice(0, 10); + } + + return previewInfo; + }, + async executePreview( + command: string, + params: string, + message: Pick & Partial>, + preview: SlashCommandPreviewItem, + triggerId?: string, + ) { + const cmd = this.commands[command]; + if (typeof cmd?.previewCallback !== 'function') { + return; + } + + if (!message?.rid) { + throw new MeteorError('invalid-command-usage', 'Executing a command requires at least a message with a room id.'); + } + + // { id, type, value } + if (!preview.id || !preview.type || !preview.value) { + throw new MeteorError('error-invalid-preview', 'Preview Item must have an id, type, and value.'); + } + + return cmd.previewCallback(command, params, message, preview, triggerId); + }, +}; + +declare module '@rocket.chat/ddp-client' { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface ServerMethods { + slashCommand(params: { cmd: string; params: string; msg: IMessage; triggerId: string }): unknown; + } +} Meteor.methods({ async slashCommand(command) { @@ -27,5 +159,3 @@ Meteor.methods({ }); }, }); - -export { slashCommands }; diff --git a/apps/meteor/client/hooks/useAppSlashCommands.ts b/apps/meteor/client/hooks/useAppSlashCommands.ts index c49c629a2a06..3a925cb24690 100644 --- a/apps/meteor/client/hooks/useAppSlashCommands.ts +++ b/apps/meteor/client/hooks/useAppSlashCommands.ts @@ -3,7 +3,7 @@ import { useEndpoint, useStream, useUserId } from '@rocket.chat/ui-contexts'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useEffect } from 'react'; -import { slashCommands } from '../../app/utils/lib/slashCommand'; +import { slashCommands } from '../../app/utils/client/slashCommand'; export const useAppSlashCommands = () => { const queryClient = useQueryClient(); diff --git a/apps/meteor/client/lib/errors/InvalidCommandUsage.ts b/apps/meteor/client/lib/errors/InvalidCommandUsage.ts new file mode 100644 index 000000000000..66e240cf2804 --- /dev/null +++ b/apps/meteor/client/lib/errors/InvalidCommandUsage.ts @@ -0,0 +1,7 @@ +import { RocketChatError } from './RocketChatError'; + +export class InvalidCommandUsage extends RocketChatError<'invalid-command-usage'> { + constructor(message = 'Executing a command requires at least a message with a room id.', details?: string) { + super('invalid-command-usage', message, details); + } +} diff --git a/apps/meteor/client/lib/errors/InvalidPreview.ts b/apps/meteor/client/lib/errors/InvalidPreview.ts new file mode 100644 index 000000000000..2c56a74a88e4 --- /dev/null +++ b/apps/meteor/client/lib/errors/InvalidPreview.ts @@ -0,0 +1,7 @@ +import { RocketChatError } from './RocketChatError'; + +export class InvalidPreview extends RocketChatError<'error-invalid-preview'> { + constructor(message = 'Preview Item must have an id, type, and value.', details?: string) { + super('error-invalid-preview', message, details); + } +} diff --git a/apps/meteor/client/lib/errors/index.ts b/apps/meteor/client/lib/errors/index.ts new file mode 100644 index 000000000000..6c57c5f25da6 --- /dev/null +++ b/apps/meteor/client/lib/errors/index.ts @@ -0,0 +1,2 @@ +export * from './InvalidCommandUsage'; +export * from './InvalidPreview'; diff --git a/apps/meteor/client/startup/slashCommands/federation.ts b/apps/meteor/client/startup/slashCommands/federation.ts index 76f083c16468..25728ad4601a 100644 --- a/apps/meteor/client/startup/slashCommands/federation.ts +++ b/apps/meteor/client/startup/slashCommands/federation.ts @@ -1,4 +1,4 @@ -import { slashCommands } from '../../../app/utils/lib/slashCommand'; +import { slashCommands } from '../../../app/utils/client/slashCommand'; const callback = undefined; const result = undefined; diff --git a/apps/meteor/client/views/room/composer/hooks/useComposerBoxPopupQueries.ts b/apps/meteor/client/views/room/composer/hooks/useComposerBoxPopupQueries.ts index f5e0c7ca710c..492579f2738c 100644 --- a/apps/meteor/client/views/room/composer/hooks/useComposerBoxPopupQueries.ts +++ b/apps/meteor/client/views/room/composer/hooks/useComposerBoxPopupQueries.ts @@ -2,7 +2,7 @@ import type { QueriesResults } from '@tanstack/react-query'; import { useQueries } from '@tanstack/react-query'; import { useEffect, useState } from 'react'; -import { slashCommands } from '../../../../../app/utils/lib/slashCommand'; +import { slashCommands } from '../../../../../app/utils/client/slashCommand'; import type { ComposerPopupOption } from '../../contexts/ComposerPopupContext'; import { useEnablePopupPreview } from './useEnablePopupPreview'; From c7bdb14b47f7c3fd5ae30c77d393befc9cd57954 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Thu, 15 Aug 2024 14:41:54 -0300 Subject: [PATCH 50/80] chore: promote roomUpdater to afterSaveMessage hook (#33034) Co-authored-by: Guilherme Gazzo --- .../app/autotranslate/server/autotranslate.ts | 4 +-- .../hooks/propagateDiscussionMetadata.ts | 2 +- .../server/methods/createDiscussion.ts | 5 +-- .../server/hooks/afterSaveMessage.js | 2 +- .../app/lib/server/functions/sendMessage.ts | 9 +++-- .../app/lib/server/functions/updateMessage.ts | 6 ++-- .../app/lib/server/lib/afterSaveMessage.ts | 35 +++++++++++++++++++ .../lib/server/lib/notifyUsersOnMessage.ts | 13 +++---- .../server/lib/sendNotificationsOnMessage.ts | 2 +- .../server/startup/mentionUserNotInChannel.ts | 2 +- .../hooks/afterSaveOmnichannelMessage.ts | 2 +- .../threads/server/hooks/aftersavemessage.ts | 2 +- .../client/hooks/useAnalyticsEventTracking.ts | 2 +- .../server/hooks/afterSaveMessage.ts | 3 +- .../lib/engagementDashboard/messages.ts | 2 +- apps/meteor/lib/callbacks.ts | 2 +- .../EmailInbox/EmailInbox_Outgoing.ts | 6 ++-- .../infrastructure/rocket-chat/hooks/index.ts | 4 +-- .../rocket-chat/hooks/hooks.spec.ts | 4 +-- 19 files changed, 72 insertions(+), 35 deletions(-) create mode 100644 apps/meteor/app/lib/server/lib/afterSaveMessage.ts diff --git a/apps/meteor/app/autotranslate/server/autotranslate.ts b/apps/meteor/app/autotranslate/server/autotranslate.ts index 1e6c224c4115..f3c6d9e55fdb 100644 --- a/apps/meteor/app/autotranslate/server/autotranslate.ts +++ b/apps/meteor/app/autotranslate/server/autotranslate.ts @@ -79,7 +79,7 @@ export class TranslationProviderRegistry { return null; } - return provider.translateMessage(message, room, targetLanguage); + return provider.translateMessage(message, { room, targetLanguage }); } static getProviders(): AutoTranslate[] { @@ -290,7 +290,7 @@ export abstract class AutoTranslate { * @param {object} targetLanguage * @returns {object} unmodified message object. */ - async translateMessage(message: IMessage, room: IRoom, targetLanguage?: string): Promise { + async translateMessage(message: IMessage, { room, targetLanguage }: { room: IRoom; targetLanguage?: string }): Promise { let targetLanguages: string[]; if (targetLanguage) { targetLanguages = [targetLanguage]; diff --git a/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts b/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts index 05cf2326156f..1ff9ed1dc1ba 100644 --- a/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts +++ b/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts @@ -22,7 +22,7 @@ const updateAndNotifyParentRoomWithParentMessage = async (room: IRoom): Promise< */ callbacks.add( 'afterSaveMessage', - async (message, { _id, prid }) => { + async (message, { room: { _id, prid } }) => { if (!prid) { return message; } diff --git a/apps/meteor/app/discussion/server/methods/createDiscussion.ts b/apps/meteor/app/discussion/server/methods/createDiscussion.ts index 6e670d723ec9..7f18e5371a23 100644 --- a/apps/meteor/app/discussion/server/methods/createDiscussion.ts +++ b/apps/meteor/app/discussion/server/methods/createDiscussion.ts @@ -5,7 +5,6 @@ import { Messages, Rooms, Users } from '@rocket.chat/models'; import { Random } from '@rocket.chat/random'; import { Meteor } from 'meteor/meteor'; -import { callbacks } from '../../../../lib/callbacks'; import { i18n } from '../../../../server/lib/i18n'; import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; import { canSendMessageAsync } from '../../../authorization/server/functions/canSendMessage'; @@ -14,6 +13,7 @@ import { addUserToRoom } from '../../../lib/server/functions/addUserToRoom'; import { attachMessage } from '../../../lib/server/functions/attachMessage'; import { createRoom } from '../../../lib/server/functions/createRoom'; import { sendMessage } from '../../../lib/server/functions/sendMessage'; +import { afterSaveMessageAsync } from '../../../lib/server/lib/afterSaveMessage'; import { settings } from '../../../settings/server'; const getParentRoom = async (rid: IRoom['_id']) => { @@ -191,8 +191,9 @@ const create = async ({ } if (discussionMsg) { - callbacks.runAsync('afterSaveMessage', discussionMsg, parentRoom); + afterSaveMessageAsync(discussionMsg, parentRoom); } + return discussion; }; diff --git a/apps/meteor/app/federation/server/hooks/afterSaveMessage.js b/apps/meteor/app/federation/server/hooks/afterSaveMessage.js index 7f67f4770686..20c64f87dda8 100644 --- a/apps/meteor/app/federation/server/hooks/afterSaveMessage.js +++ b/apps/meteor/app/federation/server/hooks/afterSaveMessage.js @@ -6,7 +6,7 @@ import { getFederationDomain } from '../lib/getFederationDomain'; import { clientLogger } from '../lib/logger'; import { normalizers } from '../normalizers'; -async function afterSaveMessage(message, room) { +async function afterSaveMessage(message, { room }) { // If there are not federated users on this room, ignore it if (!hasExternalDomain(room)) { return message; diff --git a/apps/meteor/app/lib/server/functions/sendMessage.ts b/apps/meteor/app/lib/server/functions/sendMessage.ts index 4a5b8313ebcd..aba5ddb7264c 100644 --- a/apps/meteor/app/lib/server/functions/sendMessage.ts +++ b/apps/meteor/app/lib/server/functions/sendMessage.ts @@ -4,12 +4,12 @@ import type { IMessage, IRoom } from '@rocket.chat/core-typings'; import { Messages } from '@rocket.chat/models'; import { Match, check } from 'meteor/check'; -import { callbacks } from '../../../../lib/callbacks'; import { isRelativeURL } from '../../../../lib/utils/isRelativeURL'; import { isURL } from '../../../../lib/utils/isURL'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { FileUpload } from '../../../file-upload/server'; import { settings } from '../../../settings/server'; +import { afterSaveMessage } from '../lib/afterSaveMessage'; import { notifyOnRoomChangedById, notifyOnMessageChange } from '../lib/notifyListener'; import { validateCustomMessageFields } from '../lib/validateCustomMessageFields'; import { parseUrlsInMessage } from './parseUrlsInMessage'; @@ -289,11 +289,10 @@ export const sendMessage = async function (user: any, message: any, room: any, u void Apps.getBridges()?.getListenerBridge().messageEvent('IPostMessageSent', message); } - await callbacks.run('afterSaveMessage', message, room); + // TODO: is there an opportunity to send returned data to notifyOnMessageChange? + await afterSaveMessage(message, room); - void notifyOnMessageChange({ - id: message._id, - }); + void notifyOnMessageChange({ id: message._id }); void notifyOnRoomChangedById(message.rid); diff --git a/apps/meteor/app/lib/server/functions/updateMessage.ts b/apps/meteor/app/lib/server/functions/updateMessage.ts index b0f2acd1f4ee..96683d40348f 100644 --- a/apps/meteor/app/lib/server/functions/updateMessage.ts +++ b/apps/meteor/app/lib/server/functions/updateMessage.ts @@ -4,8 +4,8 @@ import type { IMessage, IUser, AtLeast } from '@rocket.chat/core-typings'; import { Messages, Rooms } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; -import { callbacks } from '../../../../lib/callbacks'; import { settings } from '../../../settings/server'; +import { afterSaveMessage } from '../lib/afterSaveMessage'; import { notifyOnRoomChangedById, notifyOnMessageChange } from '../lib/notifyListener'; import { validateCustomMessageFields } from '../lib/validateCustomMessageFields'; import { parseUrlsInMessage } from './parseUrlsInMessage'; @@ -99,11 +99,11 @@ export const updateMessage = async function ( // although this is an "afterSave" kind callback, we know they can extend message's properties // so we wait for it to run before broadcasting - const data = await callbacks.run('afterSaveMessage', msg, room, user._id); + const data = await afterSaveMessage(msg, room, user._id); void notifyOnMessageChange({ id: msg._id, - data: data as any, // TODO move "afterSaveMessage" type definition to specify a return value + data, }); if (room?.lastMessage?._id === msg._id) { diff --git a/apps/meteor/app/lib/server/lib/afterSaveMessage.ts b/apps/meteor/app/lib/server/lib/afterSaveMessage.ts new file mode 100644 index 000000000000..5b6e12b1e185 --- /dev/null +++ b/apps/meteor/app/lib/server/lib/afterSaveMessage.ts @@ -0,0 +1,35 @@ +import type { IMessage, IUser, IRoom } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/models'; +import { Rooms } from '@rocket.chat/models'; + +import { callbacks } from '../../../../lib/callbacks'; + +export async function afterSaveMessage( + message: IMessage, + room: IRoom, + uid?: IUser['_id'], + roomUpdater?: Updater, +): Promise { + const updater = roomUpdater ?? Rooms.getUpdater(); + const data = await callbacks.run('afterSaveMessage', message, { room, uid, roomUpdater: updater }); + + if (!roomUpdater && updater.hasChanges()) { + await Rooms.updateFromUpdater({ _id: room._id }, updater); + } + + // TODO: Fix type - callback configuration needs to be updated + return data as unknown as IMessage; +} + +export function afterSaveMessageAsync( + message: IMessage, + room: IRoom, + uid?: IUser['_id'], + roomUpdater: Updater = Rooms.getUpdater(), +): void { + callbacks.runAsync('afterSaveMessage', message, { room, uid, roomUpdater }); + + if (roomUpdater.hasChanges()) { + void Rooms.updateFromUpdater({ _id: room._id }, roomUpdater); + } +} diff --git a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts index a05c05b4bb94..990a1f2e4029 100644 --- a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts +++ b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.ts @@ -143,6 +143,8 @@ export async function updateThreadUsersSubscriptions(message: IMessage, replies: } export async function notifyUsersOnMessage(message: IMessage, room: IRoom, roomUpdater: Updater): Promise { + console.log('notifyUsersOnMessage function'); + // Skips this callback if the message was edited and increments it if the edit was way in the past (aka imported) if (isEditedMessage(message)) { if (Math.abs(moment(message.editedAt).diff(Date.now())) > 60000) { @@ -183,14 +185,13 @@ export async function notifyUsersOnMessage(message: IMessage, room: IRoom, roomU callbacks.add( 'afterSaveMessage', - async (message, room) => { - const roomUpdater = Rooms.getUpdater(); - await notifyUsersOnMessage(message, room, roomUpdater); - - if (roomUpdater.hasChanges()) { - await Rooms.updateFromUpdater({ _id: room._id }, roomUpdater); + async (message, { room, roomUpdater }) => { + if (!roomUpdater) { + return message; } + await notifyUsersOnMessage(message, room, roomUpdater); + return message; }, callbacks.priority.MEDIUM, diff --git a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts index 49fcc0ea4725..94c25f476222 100644 --- a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts +++ b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.ts @@ -406,7 +406,7 @@ settings.watch('Troubleshoot_Disable_Notifications', (value) => { callbacks.add( 'afterSaveMessage', - (message, room) => sendAllNotifications(message, room), + (message, { room }) => sendAllNotifications(message, room), callbacks.priority.LOW, 'sendNotificationsOnMessage', ); diff --git a/apps/meteor/app/lib/server/startup/mentionUserNotInChannel.ts b/apps/meteor/app/lib/server/startup/mentionUserNotInChannel.ts index 962691a78bd8..8a17686ba158 100644 --- a/apps/meteor/app/lib/server/startup/mentionUserNotInChannel.ts +++ b/apps/meteor/app/lib/server/startup/mentionUserNotInChannel.ts @@ -54,7 +54,7 @@ const getBlocks = (mentions: IMessage['mentions'], messageId: string, lng: strin callbacks.add( 'afterSaveMessage', - async (message, room) => { + async (message, { room }) => { // TODO: check if I need to test this 60 second rule. // If the message was edited, or is older than 60 seconds (imported) // the notifications will be skipped, so we can also skip this validation diff --git a/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts b/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts index 07ce7fe08573..311343c4ad01 100644 --- a/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts +++ b/apps/meteor/app/livechat/server/hooks/afterSaveOmnichannelMessage.ts @@ -5,7 +5,7 @@ import { callbacks } from '../../../../lib/callbacks'; callbacks.add( 'afterSaveMessage', - async (message, room) => { + async (message, { room }) => { if (!isOmnichannelRoom(room)) { return message; } diff --git a/apps/meteor/app/threads/server/hooks/aftersavemessage.ts b/apps/meteor/app/threads/server/hooks/aftersavemessage.ts index 179cb5ec12b7..a938dadddb27 100644 --- a/apps/meteor/app/threads/server/hooks/aftersavemessage.ts +++ b/apps/meteor/app/threads/server/hooks/aftersavemessage.ts @@ -77,7 +77,7 @@ Meteor.startup(() => { } callbacks.add( 'afterSaveMessage', - async (message, room) => { + async (message, { room }) => { return processThreads(message, room); }, callbacks.priority.LOW, diff --git a/apps/meteor/client/hooks/useAnalyticsEventTracking.ts b/apps/meteor/client/hooks/useAnalyticsEventTracking.ts index 78e078ef0070..9d1acf7b4318 100644 --- a/apps/meteor/client/hooks/useAnalyticsEventTracking.ts +++ b/apps/meteor/client/hooks/useAnalyticsEventTracking.ts @@ -55,7 +55,7 @@ export const useAnalyticsEventTracking = () => { callbacks.add( 'afterSaveMessage', - (_message, room, _uid) => { + (_message, { room }) => { trackEvent('Message', 'Send', `${room.name} (${room._id})`); }, callbacks.priority.LOW, diff --git a/apps/meteor/ee/app/message-read-receipt/server/hooks/afterSaveMessage.ts b/apps/meteor/ee/app/message-read-receipt/server/hooks/afterSaveMessage.ts index 5b7a720ba312..9180632768af 100644 --- a/apps/meteor/ee/app/message-read-receipt/server/hooks/afterSaveMessage.ts +++ b/apps/meteor/ee/app/message-read-receipt/server/hooks/afterSaveMessage.ts @@ -1,4 +1,3 @@ -import type { IRoom, IMessage } from '@rocket.chat/core-typings'; import { isEditedMessage, isOmnichannelRoom } from '@rocket.chat/core-typings'; import { Subscriptions } from '@rocket.chat/models'; @@ -7,7 +6,7 @@ import { ReadReceipt } from '../../../../server/lib/message-read-receipt/ReadRec callbacks.add( 'afterSaveMessage', - async (message: IMessage, room: IRoom) => { + async (message, { room }) => { // skips this callback if the message was edited if (isEditedMessage(message)) { return message; diff --git a/apps/meteor/ee/server/lib/engagementDashboard/messages.ts b/apps/meteor/ee/server/lib/engagementDashboard/messages.ts index 19939ae6e4e1..2a4bf67c12c5 100644 --- a/apps/meteor/ee/server/lib/engagementDashboard/messages.ts +++ b/apps/meteor/ee/server/lib/engagementDashboard/messages.ts @@ -5,7 +5,7 @@ import moment from 'moment'; import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; import { convertDateToInt, diffBetweenDaysInclusive, convertIntToDate, getTotalOfWeekItems } from './date'; -export const handleMessagesSent = async (message: IMessage, room?: IRoom): Promise => { +export const handleMessagesSent = async (message: IMessage, { room }: { room?: IRoom }): Promise => { const roomTypesToShow = roomCoordinator.getTypesToShowOnDashboard(); if (!room || !roomTypesToShow.includes(room.t)) { return message; diff --git a/apps/meteor/lib/callbacks.ts b/apps/meteor/lib/callbacks.ts index eb8e032804f7..7eaa9ed7595d 100644 --- a/apps/meteor/lib/callbacks.ts +++ b/apps/meteor/lib/callbacks.ts @@ -50,7 +50,7 @@ interface EventLikeCallbackSignatures { 'afterDeleteUser': (user: IUser) => void; 'afterFileUpload': (params: { user: IUser; room: IRoom; message: IMessage }) => void; 'afterRoomNameChange': (params: { rid: string; name: string; oldName: string }) => void; - 'afterSaveMessage': (message: IMessage, room: IRoom, uid?: string) => void; + 'afterSaveMessage': (message: IMessage, params: { room: IRoom; uid?: string; roomUpdater?: Updater }) => void; 'afterOmnichannelSaveMessage': (message: IMessage, constant: { room: IOmnichannelRoom; roomUpdater: Updater }) => void; 'livechat.removeAgentDepartment': (params: { departmentId: ILivechatDepartmentRecord['_id']; agentsId: ILivechatAgent['_id'][] }) => void; 'livechat.saveAgentDepartment': (params: { departmentId: ILivechatDepartmentRecord['_id']; agentsId: ILivechatAgent['_id'][] }) => void; diff --git a/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts b/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts index 80be176ada35..51718e4937d8 100644 --- a/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts +++ b/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts @@ -1,5 +1,5 @@ import { isIMessageInbox } from '@rocket.chat/core-typings'; -import type { IEmailInbox, IUser, IMessage, IOmnichannelRoom, SlashCommandCallbackParams } from '@rocket.chat/core-typings'; +import type { IEmailInbox, IUser, IOmnichannelRoom, SlashCommandCallbackParams } from '@rocket.chat/core-typings'; import { Messages, Uploads, LivechatRooms, Rooms, Users } from '@rocket.chat/models'; import { Match } from 'meteor/check'; import type Mail from 'nodemailer/lib/mailer'; @@ -190,7 +190,9 @@ slashCommands.add({ callbacks.add( 'afterSaveMessage', - async (message: IMessage, room: any) => { + async (message, { room: omnichannelRoom }) => { + const room = omnichannelRoom as IOmnichannelRoom; + if (!room?.email?.inbox) { return message; } diff --git a/apps/meteor/server/services/federation/infrastructure/rocket-chat/hooks/index.ts b/apps/meteor/server/services/federation/infrastructure/rocket-chat/hooks/index.ts index 950aac23a39a..f14257512b11 100644 --- a/apps/meteor/server/services/federation/infrastructure/rocket-chat/hooks/index.ts +++ b/apps/meteor/server/services/federation/infrastructure/rocket-chat/hooks/index.ts @@ -150,7 +150,7 @@ export class FederationHooks { public static afterMessageUpdated(callback: (message: IMessage, roomId: IRoom['_id'], userId: string) => Promise): void { callbacks.add( 'afterSaveMessage', - async (message: IMessage, room: IRoom): Promise => { + async (message, { room }): Promise => { if ( !room || !isRoomFederated(room) || @@ -174,7 +174,7 @@ export class FederationHooks { public static afterMessageSent(callback: (message: IMessage, roomId: IRoom['_id'], userId: string) => Promise): void { callbacks.add( 'afterSaveMessage', - async (message: IMessage, room: IRoom): Promise => { + async (message, { room }): Promise => { if (!room || !isRoomFederated(room) || !message || !settings.get('Federation_Matrix_enabled')) { return message; } diff --git a/apps/meteor/tests/unit/server/federation/infrastructure/rocket-chat/hooks/hooks.spec.ts b/apps/meteor/tests/unit/server/federation/infrastructure/rocket-chat/hooks/hooks.spec.ts index 7d3e664022c8..c77f6e4993fa 100644 --- a/apps/meteor/tests/unit/server/federation/infrastructure/rocket-chat/hooks/hooks.spec.ts +++ b/apps/meteor/tests/unit/server/federation/infrastructure/rocket-chat/hooks/hooks.spec.ts @@ -507,7 +507,7 @@ describe('Federation - Infrastructure - RocketChat - Hooks', () => { get.returns(true); const stub = sinon.stub(); FederationHooks.afterMessageUpdated(stub); - hooks['federation-v2-after-room-message-updated'](message, { federated: true, _id: 'roomId' }); + hooks['federation-v2-after-room-message-updated'](message, { room: { federated: true, _id: 'roomId' } }); expect(stub.calledWith(message, 'roomId', 'userId')).to.be.true; }); }); @@ -551,7 +551,7 @@ describe('Federation - Infrastructure - RocketChat - Hooks', () => { get.returns(true); const stub = sinon.stub(); FederationHooks.afterMessageSent(stub); - hooks['federation-v2-after-room-message-sent']({ u: { _id: 'userId' } }, { federated: true, _id: 'roomId' }); + hooks['federation-v2-after-room-message-sent']({ u: { _id: 'userId' } }, { room: { federated: true, _id: 'roomId' } }); expect(stub.calledWith({ u: { _id: 'userId' } }, 'roomId', 'userId')).to.be.true; }); }); From 95178e09171469d2740f7fa076e7b58ad030c927 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Thu, 15 Aug 2024 15:25:54 -0300 Subject: [PATCH 51/80] fix: File uploads should only be allowed for room members (#32940) --- .changeset/gorgeous-hotels-attend.md | 5 ++++ .../body/hooks/useFileUploadDropTarget.ts | 7 ++--- apps/meteor/tests/e2e/file-upload.spec.ts | 26 ++++++++++++++++++- 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 .changeset/gorgeous-hotels-attend.md diff --git a/.changeset/gorgeous-hotels-attend.md b/.changeset/gorgeous-hotels-attend.md new file mode 100644 index 000000000000..fd858d7ace86 --- /dev/null +++ b/.changeset/gorgeous-hotels-attend.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Stopped non channel members from dragging and dropping files in a channel they do not belong diff --git a/apps/meteor/client/views/room/body/hooks/useFileUploadDropTarget.ts b/apps/meteor/client/views/room/body/hooks/useFileUploadDropTarget.ts index 314eb64304b5..b97c0ad0866c 100644 --- a/apps/meteor/client/views/room/body/hooks/useFileUploadDropTarget.ts +++ b/apps/meteor/client/views/room/body/hooks/useFileUploadDropTarget.ts @@ -8,7 +8,7 @@ import { useIsRoomOverMacLimit } from '../../../../hooks/omnichannel/useIsRoomOv import { useReactiveValue } from '../../../../hooks/useReactiveValue'; import { roomCoordinator } from '../../../../lib/rooms/roomCoordinator'; import { useChat } from '../../contexts/ChatContext'; -import { useRoom } from '../../contexts/RoomContext'; +import { useRoom, useRoomSubscription } from '../../contexts/RoomContext'; import { useDropTarget } from './useDropTarget'; export const useFileUploadDropTarget = (): readonly [ @@ -36,6 +36,7 @@ export const useFileUploadDropTarget = (): readonly [ ); const chat = useChat(); + const subscription = useRoomSubscription(); const onFileDrop = useMutableCallback(async (files: File[]) => { const { getMimeType } = await import('../../../../../app/utils/lib/mimeTypes'); @@ -70,7 +71,7 @@ export const useFileUploadDropTarget = (): readonly [ } as const; } - if (!fileUploadAllowedForUser) { + if (!fileUploadAllowedForUser || !subscription) { return { enabled: false, reason: t('error-not-allowed'), @@ -83,7 +84,7 @@ export const useFileUploadDropTarget = (): readonly [ onFileDrop, ...overlayProps, } as const; - }, [fileUploadAllowedForUser, fileUploadEnabled, isRoomOverMacLimit, onFileDrop, overlayProps, t]); + }, [fileUploadAllowedForUser, fileUploadEnabled, isRoomOverMacLimit, onFileDrop, overlayProps, subscription, t]); return [triggerProps, allOverlayProps] as const; }; diff --git a/apps/meteor/tests/e2e/file-upload.spec.ts b/apps/meteor/tests/e2e/file-upload.spec.ts index 0a5d1cfd2512..159b2650ac16 100644 --- a/apps/meteor/tests/e2e/file-upload.spec.ts +++ b/apps/meteor/tests/e2e/file-upload.spec.ts @@ -12,7 +12,7 @@ test.describe.serial('file-upload', () => { test.beforeAll(async ({ api }) => { await setSettingValueById(api, 'FileUpload_MediaTypeBlackList', 'image/svg+xml'); - targetChannel = await createTargetChannel(api); + targetChannel = await createTargetChannel(api, { members: ['user1'] }); }); test.beforeEach(async ({ page }) => { @@ -76,3 +76,27 @@ test.describe.serial('file-upload', () => { await expect(poHomeChannel.content.btnModalConfirm).not.toBeVisible(); }); }); +test.describe('file-upload-not-member', () => { + let poHomeChannel: HomeChannel; + let targetChannel: string; + + test.beforeAll(async ({ api }) => { + targetChannel = await createTargetChannel(api); + }); + + test.beforeEach(async ({ page }) => { + poHomeChannel = new HomeChannel(page); + + await page.goto('/home'); + await poHomeChannel.sidenav.openChat(targetChannel); + }); + + test.afterAll(async ({ api }) => { + expect((await api.post('/channels.delete', { roomName: targetChannel })).status()).toBe(200); + }); + + test('expect not be able to upload if not a member', async () => { + await poHomeChannel.content.dragAndDropTxtFile(); + await expect(poHomeChannel.content.modalFilePreview).not.toBeVisible(); + }); +}); From 320485db2d461ad8aedd703d3c045463ac094908 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:11:00 -0400 Subject: [PATCH 52/80] chore(deps): bump actions/setup-node from 3.7.0 to 4.0.3 (#32965) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/update-version-durability.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-version-durability.yml b/.github/workflows/update-version-durability.yml index e52b4870b369..90c835577dc1 100644 --- a/.github/workflows/update-version-durability.yml +++ b/.github/workflows/update-version-durability.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v3.7.0 + uses: actions/setup-node@v4.0.3 with: node-version: '20.15.1' From 0b2af2bccec0f1290d25c272f185c02eff07620d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:12:33 -0400 Subject: [PATCH 53/80] chore(deps): bump thehanimo/pr-title-checker from 1.3.7 to 1.4.2 (#31704) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Guilherme Gazzo --- .github/workflows/pr-title-checker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-title-checker.yml b/.github/workflows/pr-title-checker.yml index bc9d1f042d58..d8f6db97c455 100644 --- a/.github/workflows/pr-title-checker.yml +++ b/.github/workflows/pr-title-checker.yml @@ -12,6 +12,6 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: thehanimo/pr-title-checker@v1.4.1 + - uses: thehanimo/pr-title-checker@v1.4.2 with: GITHUB_TOKEN: ${{ secrets.RC_TITLE_CHECKER }} From 760b5aaa589ef8661f7c2fc445f5209ac230cb6e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:13:44 -0400 Subject: [PATCH 54/80] chore(deps): bump github/codeql-action from 2 to 3 (#32964) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Guilherme Gazzo --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 483b404a6dc8..202a02dd7785 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -26,7 +26,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 # Override language selection by uncommenting this and choosing your languages with: languages: javascript @@ -34,7 +34,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -48,4 +48,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From 443eda1e453f49299f801242a671c62cb4df334b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:15:41 -0400 Subject: [PATCH 55/80] chore(deps): bump docker/login-action from 2 to 3 (#30378) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66cf1afcccfb..246c34423bb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -576,13 +576,13 @@ jobs: steps: - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASS }} - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ secrets.CR_USER }} @@ -683,13 +683,13 @@ jobs: steps: - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASS }} - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ secrets.CR_USER }} From 17f3d5e96ae53a45307176cc5f20a6e2870c0f08 Mon Sep 17 00:00:00 2001 From: csuadev <72958726+csuadev@users.noreply.github.com> Date: Thu, 15 Aug 2024 22:01:43 +0200 Subject: [PATCH 56/80] fix: Missing department names on OC edit agent view (#33033) --- .changeset/fast-lobsters-turn.md | 5 ++++ .../views/omnichannel/agents/AgentEdit.tsx | 17 +++++++++++--- .../omnichannel/omnichannel-agents.spec.ts | 23 +++++++++++++++++++ .../e2e/page-objects/omnichannel-agents.ts | 4 ++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 .changeset/fast-lobsters-turn.md diff --git a/.changeset/fast-lobsters-turn.md b/.changeset/fast-lobsters-turn.md new file mode 100644 index 000000000000..ff1d97ea7289 --- /dev/null +++ b/.changeset/fast-lobsters-turn.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed an issue due to an endpoint pagination that was causing that when an agent have assigned more than 50 departments, the departments have a blank space instead of the name. diff --git a/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx b/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx index 7b854b0f36c3..9e114b7a0c64 100644 --- a/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx +++ b/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx @@ -34,7 +34,7 @@ import { MaxChatsPerAgent } from '../additionalForms'; type AgentEditProps = { agentData: Pick; - userDepartments: Pick[]; + userDepartments: (Pick & { departmentName: string })[]; availableDepartments: Pick[]; }; @@ -50,15 +50,26 @@ const AgentEdit = ({ agentData, userDepartments, availableDepartments }: AgentEd const email = getUserEmailAddress(agentData); + const departments: Pick[] = useMemo(() => { + const pending = userDepartments + .filter(({ departmentId }) => !availableDepartments.find((dep) => dep._id === departmentId)) + .map((dep) => ({ + _id: dep.departmentId, + name: dep.departmentName, + })); + + return [...availableDepartments, ...pending]; + }, [availableDepartments, userDepartments]); + const departmentsOptions: SelectOption[] = useMemo(() => { const archivedDepartment = (name: string, archived?: boolean) => (archived ? `${name} [${t('Archived')}]` : name); return ( - availableDepartments.map(({ _id, name, archived }) => + departments.map(({ _id, name, archived }) => name ? [_id, archivedDepartment(name, archived)] : [_id, archivedDepartment(_id, archived)], ) || [] ); - }, [availableDepartments, t]); + }, [departments, t]); const statusOptions: SelectOption[] = useMemo( () => [ diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-agents.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-agents.spec.ts index ad4657b1841c..239978928126 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-agents.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-agents.spec.ts @@ -105,4 +105,27 @@ test.describe.serial('OC - Manage Agents', () => { await poOmnichannelAgents.btnSave.click(); }); }); + + test('OC - Edit agent - Manage departments', async ({ page }) => { + await poOmnichannelAgents.selectUsername('user1'); + await poOmnichannelAgents.btnAdd.click(); + await poOmnichannelAgents.inputSearch.fill('user1'); + await poOmnichannelAgents.findRowByUsername('user1').click(); + + await poOmnichannelAgents.btnEdit.click(); + await poOmnichannelAgents.selectDepartment(department.data.name); + await poOmnichannelAgents.btnSave.click(); + + await test.step('expect the selected department is visible', async () => { + await poOmnichannelAgents.findRowByUsername('user1').click(); + + // mock the endpoint to use the one without pagination + await page.route('/api/v1/livechat/department?showArchived=true', async (route) => { + await route.fulfill({ json: { departments: [] } }); + }); + + await poOmnichannelAgents.btnEdit.click(); + await expect(poOmnichannelAgents.findSelectedDepartment(department.data.name)).toBeVisible(); + }); + }); }); diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-agents.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-agents.ts index d588e409423f..4bde20c1da20 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel-agents.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-agents.ts @@ -93,4 +93,8 @@ export class OmnichannelAgents { findRowByName(name: string) { return this.page.locator('tr', { has: this.page.locator(`td >> text="${name}"`) }); } + + findSelectedDepartment(name: string) { + return this.page.locator(`role=option[name="${name}"]`); + } } From 86b2f6bab94daf8a5fbd62ab09681ea22520702c Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 8 Apr 2024 19:27:10 -0300 Subject: [PATCH 57/80] chore: bump 7.0.0 --- apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/package.json | 2 +- package.json | 2 +- packages/core-typings/package.json | 3 ++- packages/rest-typings/package.json | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index faf0e8f47de6..34642c087e2e 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.12.0-develop" + "version": "7.0.0-develop" } diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 5addaf756f8a..a603548dd003 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.12.0-develop", + "version": "7.0.0-develop", "private": true, "author": { "name": "Rocket.Chat", diff --git a/package.json b/package.json index 29de436373e2..c45e5861bebe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.12.0-develop", + "version": "7.0.0-develop", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 267e75e5c177..7cb5870696d6 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,8 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.12.0-develop", + "private": true, + "version": "7.0.0-develop", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 6a5bf5464e98..17964c1c9b74 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.12.0-develop", + "version": "7.0.0-develop", "devDependencies": { "@rocket.chat/eslint-config": "workspace:~", "@types/jest": "~29.5.12", From 00c7c2bcf10a03d1c66e039468464bd850ce4f0e Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 9 Apr 2024 13:47:21 -0300 Subject: [PATCH 58/80] fix!: api login should not suggest which credential is wrong (#32159) --- .changeset/fuzzy-cherries-buy.md | 7 +++++++ .../lib/server/lib/loginErrorMessageOverride.js | 14 -------------- .../lib/server/lib/loginErrorMessageOverride.ts | 16 ++++++++++++++++ .../client/meteorOverrides/login/google.ts | 10 ---------- .../externals/meteor/accounts-base.d.ts | 10 +++++++++- .../end-to-end/api/failed-login-attempts.ts | 2 +- 6 files changed, 33 insertions(+), 26 deletions(-) create mode 100644 .changeset/fuzzy-cherries-buy.md delete mode 100644 apps/meteor/app/lib/server/lib/loginErrorMessageOverride.js create mode 100644 apps/meteor/app/lib/server/lib/loginErrorMessageOverride.ts diff --git a/.changeset/fuzzy-cherries-buy.md b/.changeset/fuzzy-cherries-buy.md new file mode 100644 index 000000000000..e185a148c917 --- /dev/null +++ b/.changeset/fuzzy-cherries-buy.md @@ -0,0 +1,7 @@ +--- +"@rocket.chat/meteor": major +--- + +Api login should not suggest which credential is wrong (password/username) + +Failed login attemps will always return `Unauthorized` instead of the internal fail reason diff --git a/apps/meteor/app/lib/server/lib/loginErrorMessageOverride.js b/apps/meteor/app/lib/server/lib/loginErrorMessageOverride.js deleted file mode 100644 index 4e054b81b2cf..000000000000 --- a/apps/meteor/app/lib/server/lib/loginErrorMessageOverride.js +++ /dev/null @@ -1,14 +0,0 @@ -// Do not disclose if user exists when password is invalid -import { Accounts } from 'meteor/accounts-base'; -import { Meteor } from 'meteor/meteor'; - -const { _runLoginHandlers } = Accounts; -Accounts._runLoginHandlers = function (methodInvocation, options) { - const result = _runLoginHandlers.call(Accounts, methodInvocation, options); - - if (result.error && result.error.reason === 'Incorrect password') { - result.error = new Meteor.Error(403, 'User not found'); - } - - return result; -}; diff --git a/apps/meteor/app/lib/server/lib/loginErrorMessageOverride.ts b/apps/meteor/app/lib/server/lib/loginErrorMessageOverride.ts new file mode 100644 index 000000000000..e2a6e0d10581 --- /dev/null +++ b/apps/meteor/app/lib/server/lib/loginErrorMessageOverride.ts @@ -0,0 +1,16 @@ +// Do not disclose if user exists when password is invalid +import { Accounts } from 'meteor/accounts-base'; +import { Meteor } from 'meteor/meteor'; + +const { _runLoginHandlers } = Accounts; + +Accounts._options.ambiguousErrorMessages = true; +Accounts._runLoginHandlers = async function (methodInvocation, options) { + const result = await _runLoginHandlers.call(Accounts, methodInvocation, options); + + if (result.error instanceof Meteor.Error) { + result.error = new Meteor.Error(401, 'User not found'); + } + + return result; +}; diff --git a/apps/meteor/client/meteorOverrides/login/google.ts b/apps/meteor/client/meteorOverrides/login/google.ts index 2742cade15d2..4e99ac3a281b 100644 --- a/apps/meteor/client/meteorOverrides/login/google.ts +++ b/apps/meteor/client/meteorOverrides/login/google.ts @@ -8,16 +8,6 @@ import { overrideLoginMethod, type LoginCallback } from '../../lib/2fa/overrideL import { wrapRequestCredentialFn } from '../../lib/wrapRequestCredentialFn'; import { createOAuthTotpLoginMethod } from './oauth'; -declare module 'meteor/accounts-base' { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Accounts { - export const _options: { - restrictCreationByEmailDomain?: string | (() => string); - forbidClientAccountCreation?: boolean | undefined; - }; - } -} - declare module 'meteor/meteor' { // eslint-disable-next-line @typescript-eslint/no-namespace namespace Meteor { diff --git a/apps/meteor/definition/externals/meteor/accounts-base.d.ts b/apps/meteor/definition/externals/meteor/accounts-base.d.ts index 3f0b148120e7..f51c2f383987 100644 --- a/apps/meteor/definition/externals/meteor/accounts-base.d.ts +++ b/apps/meteor/definition/externals/meteor/accounts-base.d.ts @@ -22,7 +22,7 @@ declare module 'meteor/accounts-base' { function _insertLoginToken(userId: string, token: { token: string; when: Date }): void; - function _runLoginHandlers(methodInvocation: T, loginRequest: Record): LoginMethodResult | undefined; + function _runLoginHandlers(methodInvocation: T, loginRequest: Record): Promise; function registerLoginHandler(name: string, handler: (options: any) => undefined | object): void; @@ -54,6 +54,14 @@ declare module 'meteor/accounts-base' { const _accountData: Record; + interface AccountsServerOptions { + ambiguousErrorMessages?: boolean; + restrictCreationByEmailDomain?: string | (() => string); + forbidClientAccountCreation?: boolean | undefined; + } + + export const _options: AccountsServerOptions; + // eslint-disable-next-line @typescript-eslint/no-namespace namespace oauth { function credentialRequestCompleteHandler( diff --git a/apps/meteor/tests/end-to-end/api/failed-login-attempts.ts b/apps/meteor/tests/end-to-end/api/failed-login-attempts.ts index ee0236c591b6..ebdc1737391b 100644 --- a/apps/meteor/tests/end-to-end/api/failed-login-attempts.ts +++ b/apps/meteor/tests/end-to-end/api/failed-login-attempts.ts @@ -54,7 +54,7 @@ describe('[Failed Login Attempts]', () => { .expect(401) .expect((res) => { expect(res.body).to.have.property('status', 'error'); - expect(res.body).to.have.property('message', 'Incorrect password'); + expect(res.body).to.have.property('message', 'Unauthorized'); }); } From 8cb4fc30532b6ab0217956991b177a0c9d534d70 Mon Sep 17 00:00:00 2001 From: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:00:50 -0300 Subject: [PATCH 59/80] chore!: remove hipchat importer (#32154) --- .changeset/quiet-kings-rhyme.md | 5 + FEATURES.md | 1 - .../server/HipChatEnterpriseImporter.js | 348 ------------------ .../server/index.ts | 8 - .../server/classes/ImportDataConverter.ts | 7 - .../server/classes/VirtualDataConverter.ts | 10 - apps/meteor/package.json | 1 - apps/meteor/server/importPackages.ts | 1 - apps/meteor/server/models/raw/ImportData.ts | 13 +- packages/i18n/src/locales/af.i18n.json | 2 - packages/i18n/src/locales/ar.i18n.json | 2 - packages/i18n/src/locales/az.i18n.json | 2 - packages/i18n/src/locales/be-BY.i18n.json | 2 - packages/i18n/src/locales/bg.i18n.json | 2 - packages/i18n/src/locales/bs.i18n.json | 2 - packages/i18n/src/locales/ca.i18n.json | 2 - packages/i18n/src/locales/cs.i18n.json | 2 - packages/i18n/src/locales/cy.i18n.json | 2 - packages/i18n/src/locales/da.i18n.json | 2 - packages/i18n/src/locales/de-AT.i18n.json | 2 - packages/i18n/src/locales/de-IN.i18n.json | 2 - packages/i18n/src/locales/de.i18n.json | 2 - packages/i18n/src/locales/el.i18n.json | 2 - packages/i18n/src/locales/en.i18n.json | 3 - packages/i18n/src/locales/eo.i18n.json | 2 - packages/i18n/src/locales/es.i18n.json | 2 - packages/i18n/src/locales/fa.i18n.json | 2 - packages/i18n/src/locales/fi.i18n.json | 2 - packages/i18n/src/locales/fr.i18n.json | 2 - packages/i18n/src/locales/hi-IN.i18n.json | 2 - packages/i18n/src/locales/hr.i18n.json | 2 - packages/i18n/src/locales/hu.i18n.json | 2 - packages/i18n/src/locales/id.i18n.json | 2 - packages/i18n/src/locales/it.i18n.json | 2 - packages/i18n/src/locales/ja.i18n.json | 2 - packages/i18n/src/locales/ka-GE.i18n.json | 2 - packages/i18n/src/locales/km.i18n.json | 2 - packages/i18n/src/locales/ko.i18n.json | 2 - packages/i18n/src/locales/ku.i18n.json | 2 - packages/i18n/src/locales/lo.i18n.json | 2 - packages/i18n/src/locales/lt.i18n.json | 2 - packages/i18n/src/locales/lv.i18n.json | 2 - packages/i18n/src/locales/mn.i18n.json | 2 - packages/i18n/src/locales/ms-MY.i18n.json | 2 - packages/i18n/src/locales/nl.i18n.json | 2 - packages/i18n/src/locales/no.i18n.json | 2 - packages/i18n/src/locales/pl.i18n.json | 2 - packages/i18n/src/locales/pt-BR.i18n.json | 2 - packages/i18n/src/locales/pt.i18n.json | 2 - packages/i18n/src/locales/ro.i18n.json | 2 - packages/i18n/src/locales/ru.i18n.json | 2 - packages/i18n/src/locales/sk-SK.i18n.json | 2 - packages/i18n/src/locales/sl-SI.i18n.json | 2 - packages/i18n/src/locales/sq.i18n.json | 2 - packages/i18n/src/locales/sr.i18n.json | 2 - packages/i18n/src/locales/sv.i18n.json | 2 - packages/i18n/src/locales/ta-IN.i18n.json | 2 - packages/i18n/src/locales/th-TH.i18n.json | 2 - packages/i18n/src/locales/tr.i18n.json | 2 - packages/i18n/src/locales/uk.i18n.json | 2 - packages/i18n/src/locales/vi-VN.i18n.json | 2 - packages/i18n/src/locales/zh-HK.i18n.json | 2 - packages/i18n/src/locales/zh-TW.i18n.json | 2 - packages/i18n/src/locales/zh.i18n.json | 2 - .../src/models/IImportDataModel.ts | 1 - yarn.lock | 3 +- 66 files changed, 7 insertions(+), 502 deletions(-) create mode 100644 .changeset/quiet-kings-rhyme.md delete mode 100644 apps/meteor/app/importer-hipchat-enterprise/server/HipChatEnterpriseImporter.js delete mode 100644 apps/meteor/app/importer-hipchat-enterprise/server/index.ts diff --git a/.changeset/quiet-kings-rhyme.md b/.changeset/quiet-kings-rhyme.md new file mode 100644 index 000000000000..0fd7fda7ea66 --- /dev/null +++ b/.changeset/quiet-kings-rhyme.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': major +--- + +Removed the ability to import data in the HipChat Enterprise format, as it was discontinued over five years ago. diff --git a/FEATURES.md b/FEATURES.md index 5601cc0c7ccc..67848389b593 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -33,7 +33,6 @@ - Incoming / Outgoing Webhooks - Data Importer - Import from Slack - - Import from Hipchat - Slack Bridge - Profiles - Custom avatars diff --git a/apps/meteor/app/importer-hipchat-enterprise/server/HipChatEnterpriseImporter.js b/apps/meteor/app/importer-hipchat-enterprise/server/HipChatEnterpriseImporter.js deleted file mode 100644 index 663300e44154..000000000000 --- a/apps/meteor/app/importer-hipchat-enterprise/server/HipChatEnterpriseImporter.js +++ /dev/null @@ -1,348 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import { Readable } from 'stream'; - -import { Settings } from '@rocket.chat/models'; -import { Meteor } from 'meteor/meteor'; - -import { Importer, ProgressStep } from '../../importer/server'; -import { notifyOnSettingChanged } from '../../lib/server/lib/notifyListener'; - -/** @deprecated HipChat was discontinued at 2019-02-15 */ -export class HipChatEnterpriseImporter extends Importer { - constructor(info, importRecord, converterOptions = {}) { - super(info, importRecord, converterOptions); - - this.Readable = Readable; - this.zlib = require('zlib'); - this.tarStream = require('tar-stream'); - this.extract = this.tarStream.extract(); - this.path = path; - } - - parseData(data) { - const dataString = data.toString(); - try { - this.logger.debug('parsing file contents'); - return JSON.parse(dataString); - } catch (e) { - this.logger.error(e); - return false; - } - } - - async prepareUsersFile(file) { - await super.updateProgress(ProgressStep.PREPARING_USERS); - let count = 0; - - for (const u of file) { - const newUser = { - emails: [], - importIds: [String(u.User.id)], - username: u.User.mention_name, - name: u.User.name, - avatarUrl: u.User.avatar && `data:image/png;base64,${u.User.avatar.replace(/\n/g, '')}`, - bio: u.User.title || undefined, - deleted: u.User.is_deleted, - type: 'user', - }; - count++; - - if (u.User.email) { - newUser.emails.push(u.User.email); - } - - this.converter.addUser(newUser); - } - - const { value } = await Settings.incrementValueById('Hipchat_Enterprise_Importer_Count', count, { returnDocument: 'after' }); - if (value) { - void notifyOnSettingChanged(value); - } - - await super.updateRecord({ 'count.users': count }); - await super.addCountToTotal(count); - } - - async prepareRoomsFile(file) { - await super.updateProgress(ProgressStep.PREPARING_CHANNELS); - let count = 0; - - for await (const r of file) { - await this.converter.addChannel({ - u: { - _id: r.Room.owner, - }, - importIds: [String(r.Room.id)], - name: r.Room.name, - users: r.Room.members, - t: r.Room.privacy === 'private' ? 'p' : 'c', - topic: r.Room.topic, - ts: new Date(r.Room.created), - archived: r.Room.is_archived, - }); - - count++; - } - - await super.updateRecord({ 'count.channels': count }); - await super.addCountToTotal(count); - } - - async prepareUserMessagesFile(file) { - this.logger.debug(`preparing room with ${file.length} messages `); - let count = 0; - const dmRooms = []; - - for await (const m of file) { - if (!m.PrivateUserMessage) { - continue; - } - - // If the message id is already on the list, skip it - if (this.preparedMessages[m.PrivateUserMessage.id] !== undefined) { - continue; - } - this.preparedMessages[m.PrivateUserMessage.id] = true; - - const senderId = String(m.PrivateUserMessage.sender.id); - const receiverId = String(m.PrivateUserMessage.receiver.id); - const users = [senderId, receiverId].sort(); - - if (!dmRooms[receiverId]) { - dmRooms[receiverId] = await this.converter.findDMForImportedUsers(senderId, receiverId); - - if (!dmRooms[receiverId]) { - const room = { - importIds: [users.join('')], - users, - t: 'd', - ts: new Date(m.PrivateUserMessage.timestamp.split(' ')[0]), - }; - await this.converter.addChannel(room); - dmRooms[receiverId] = room; - } - } - - const rid = dmRooms[receiverId].importIds[0]; - const newMessage = this.convertImportedMessage(m.PrivateUserMessage, rid, 'private'); - count++; - await this.converter.addMessage(newMessage); - } - - return count; - } - - async loadTurndownService() { - const TurndownService = (await import('turndown')).default; - - const turndownService = new TurndownService({ - strongDelimiter: '*', - hr: '', - br: '\n', - }); - - turndownService.addRule('strikethrough', { - filter: 'img', - - replacement(content, node) { - const src = node.getAttribute('src') || ''; - const alt = node.alt || node.title || src; - return src ? `[${alt}](${src})` : ''; - }, - }); - - this.turndownService = turndownService; - - return turndownService; - } - - convertImportedMessage(importedMessage, rid, type) { - const idType = type === 'private' ? type : `${rid}-${type}`; - const newId = `hipchatenterprise-${idType}-${importedMessage.id}`; - - const newMessage = { - _id: newId, - rid, - ts: new Date(importedMessage.timestamp.split(' ')[0]), - u: { - _id: String(importedMessage.sender.id), - }, - }; - - const text = importedMessage.message; - - if (importedMessage.message_format === 'html') { - newMessage.msg = this.turndownService.turndown(text); - } else if (text.startsWith('/me ')) { - newMessage.msg = `${text.replace(/\/me /, '_')}_`; - } else { - newMessage.msg = text; - } - - if (importedMessage.attachment?.url) { - const fileId = `${importedMessage.id}-${importedMessage.attachment.name || 'attachment'}`; - - newMessage._importFile = { - downloadUrl: importedMessage.attachment.url, - id: `${fileId}`, - size: importedMessage.attachment.size || 0, - name: importedMessage.attachment.name, - external: false, - source: 'hipchat-enterprise', - original: { - ...importedMessage.attachment, - }, - }; - } - - return newMessage; - } - - async prepareRoomMessagesFile(file, rid) { - this.logger.debug(`preparing room with ${file.length} messages `); - let count = 0; - - await this.loadTurndownService(); - - for await (const m of file) { - if (m.UserMessage) { - const newMessage = this.convertImportedMessage(m.UserMessage, rid, 'user'); - await this.converter.addMessage(newMessage); - count++; - } else if (m.NotificationMessage) { - const newMessage = this.convertImportedMessage(m.NotificationMessage, rid, 'notif'); - newMessage.u._id = 'rocket.cat'; - newMessage.alias = m.NotificationMessage.sender; - - await this.converter.addMessage(newMessage); - count++; - } else if (m.TopicRoomMessage) { - const newMessage = this.convertImportedMessage(m.TopicRoomMessage, rid, 'topic'); - newMessage.t = 'room_changed_topic'; - - await this.converter.addMessage(newMessage); - count++; - } else if (m.ArchiveRoomMessage) { - this.logger.warn('Archived Room Notification was ignored.'); - } else if (m.GuestAccessMessage) { - this.logger.warn('Guess Access Notification was ignored.'); - } else { - this.logger.error({ msg: "HipChat Enterprise importer isn't configured to handle this message:", file: m }); - } - } - - return count; - } - - async prepareMessagesFile(file, info) { - await super.updateProgress(ProgressStep.PREPARING_MESSAGES); - - const [type, id] = info.dir.split('/'); - const roomIdentifier = `${type}/${id}`; - - await super.updateRecord({ messagesstatus: roomIdentifier }); - - switch (type) { - case 'users': - return this.prepareUserMessagesFile(file); - case 'rooms': - return this.prepareRoomMessagesFile(file, id); - default: - this.logger.error(`HipChat Enterprise importer isn't configured to handle "${type}" files (${info.dir}).`); - return 0; - } - } - - async prepareFile(info, data, fileName) { - const file = this.parseData(data); - if (file === false) { - this.logger.error('failed to parse data'); - return false; - } - - switch (info.base) { - case 'users.json': - await this.prepareUsersFile(file); - break; - case 'rooms.json': - await this.prepareRoomsFile(file); - break; - case 'history.json': - return this.prepareMessagesFile(file, info); - case 'emoticons.json': - case 'metadata.json': - break; - default: - this.logger.error(`HipChat Enterprise importer doesn't know what to do with the file "${fileName}"`); - break; - } - - return 0; - } - - async prepareUsingLocalFile(fullFilePath) { - this.logger.debug('start preparing import operation'); - await this.converter.clearImportData(); - - // HipChat duplicates direct messages (one for each user) - // This object will keep track of messages that have already been prepared so it doesn't try to do it twice - this.preparedMessages = {}; - let messageCount = 0; - - const promise = new Promise((resolve, reject) => { - this.extract.on('entry', (header, stream, next) => { - this.logger.debug(`new entry from import file: ${header.name}`); - if (!header.name.endsWith('.json')) { - stream.resume(); - return next(); - } - - const info = this.path.parse(header.name); - let pos = 0; - let data = Buffer.allocUnsafe(header.size); - - stream.on('data', (chunk) => { - data.fill(chunk, pos, pos + chunk.length); - pos += chunk.length; - }); - - stream.on('end', async () => { - this.logger.info(`Processing the file: ${header.name}`); - const newMessageCount = await this.prepareFile(info, data, header.name); - - messageCount += newMessageCount; - await super.updateRecord({ 'count.messages': messageCount }); - await super.addCountToTotal(newMessageCount); - - data = undefined; - - this.logger.debug('next import entry'); - next(); - }); - - stream.on('error', () => next()); - stream.resume(); - }); - - this.extract.on('error', (err) => { - this.logger.error({ msg: 'extract error:', err }); - reject(new Meteor.Error('error-import-file-extract-error')); - }); - - this.extract.on('finish', resolve); - - const rs = fs.createReadStream(fullFilePath); - const gunzip = this.zlib.createGunzip(); - - gunzip.on('error', (err) => { - this.logger.error({ msg: 'extract error:', err }); - reject(new Meteor.Error('error-import-file-extract-error')); - }); - this.logger.debug('start extracting import file'); - rs.pipe(gunzip).pipe(this.extract); - }); - - return promise; - } -} diff --git a/apps/meteor/app/importer-hipchat-enterprise/server/index.ts b/apps/meteor/app/importer-hipchat-enterprise/server/index.ts deleted file mode 100644 index e50a9b9c4bd3..000000000000 --- a/apps/meteor/app/importer-hipchat-enterprise/server/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Importers } from '../../importer/server'; -import { HipChatEnterpriseImporter } from './HipChatEnterpriseImporter'; - -Importers.add({ - key: 'hipchatenterprise', - name: 'HipChat (tar.gz)', - importer: HipChatEnterpriseImporter, -}); diff --git a/apps/meteor/app/importer/server/classes/ImportDataConverter.ts b/apps/meteor/app/importer/server/classes/ImportDataConverter.ts index 7b1e71eaa0f0..fa254a1af2c3 100644 --- a/apps/meteor/app/importer/server/classes/ImportDataConverter.ts +++ b/apps/meteor/app/importer/server/classes/ImportDataConverter.ts @@ -839,13 +839,6 @@ export class ImportDataConverter { await this.updateRoomId(room._id, roomData); } - public async findDMForImportedUsers(...users: Array): Promise { - const record = await ImportData.findDMForImportedUsers(...users); - if (record) { - return record.data; - } - } - async findImportedRoomId(importId: string): Promise { if (this._roomCache.has(importId)) { return this._roomCache.get(importId) as string; diff --git a/apps/meteor/app/importer/server/classes/VirtualDataConverter.ts b/apps/meteor/app/importer/server/classes/VirtualDataConverter.ts index ef850226be5c..8ca9f3b5894c 100644 --- a/apps/meteor/app/importer/server/classes/VirtualDataConverter.ts +++ b/apps/meteor/app/importer/server/classes/VirtualDataConverter.ts @@ -6,7 +6,6 @@ import type { IImportRecord, IImportRecordType, IImportData, - IImportChannel, } from '@rocket.chat/core-typings'; import { Random } from '@rocket.chat/random'; @@ -47,15 +46,6 @@ export class VirtualDataConverter extends ImportDataConverter { this.clearVirtualData(); } - public async findDMForImportedUsers(...users: Array): Promise { - if (!this.useVirtual) { - return super.findDMForImportedUsers(...users); - } - - // The original method is only used by the hipchat importer so we probably don't need to implement this on the virtual converter. - return undefined; - } - public addUserSync(data: IImportUser, options?: Record): void { return this.addObjectSync('user', data, options); } diff --git a/apps/meteor/package.json b/apps/meteor/package.json index a603548dd003..17363b0d5358 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -425,7 +425,6 @@ "string-strip-html": "^7.0.3", "suretype": "~2.4.1", "swiper": "^9.3.2", - "tar-stream": "^1.6.2", "textarea-caret": "^3.1.0", "tinykeys": "^1.4.0", "turndown": "^7.1.2", diff --git a/apps/meteor/server/importPackages.ts b/apps/meteor/server/importPackages.ts index 2b4e3106ed45..dfda85e52a9e 100644 --- a/apps/meteor/server/importPackages.ts +++ b/apps/meteor/server/importPackages.ts @@ -26,7 +26,6 @@ import '../app/google-oauth/server'; import '../app/iframe-login/server'; import '../app/importer/server'; import '../app/importer-csv/server'; -import '../app/importer-hipchat-enterprise/server'; import '../app/importer-pending-files/server'; import '../app/importer-pending-avatars/server'; import '../app/importer-slack/server'; diff --git a/apps/meteor/server/models/raw/ImportData.ts b/apps/meteor/server/models/raw/ImportData.ts index e38670662a3f..19ec573fa239 100644 --- a/apps/meteor/server/models/raw/ImportData.ts +++ b/apps/meteor/server/models/raw/ImportData.ts @@ -6,7 +6,7 @@ import type { RocketChatRecordDeleted, } from '@rocket.chat/core-typings'; import type { IImportDataModel } from '@rocket.chat/model-typings'; -import type { Collection, FindCursor, Db, Filter, IndexDescription } from 'mongodb'; +import type { Collection, FindCursor, Db, IndexDescription } from 'mongodb'; import { BaseRaw } from './BaseRaw'; @@ -102,15 +102,4 @@ export class ImportDataRaw extends BaseRaw implements IImportData return channel?.data?.importIds?.shift(); } - - findDMForImportedUsers(...users: Array): Promise { - const query: Filter = { - 'dataType': 'channel', - 'data.users': { - $all: users, - }, - }; - - return this.findOne(query); - } } diff --git a/packages/i18n/src/locales/af.i18n.json b/packages/i18n/src/locales/af.i18n.json index 40ab367489b6..0e8f7acdbffd 100644 --- a/packages/i18n/src/locales/af.i18n.json +++ b/packages/i18n/src/locales/af.i18n.json @@ -1271,8 +1271,6 @@ "Importer_done": "Invoer voltooi!", "Importer_finishing": "Voltooi die invoer.", "Importer_From_Description": "Invoer {{from}} data in Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Wees asseblief bewus daarvan dat hierdie invoer nog steeds 'n werk aan die gang is, meld asseblief enige foute wat in GitHub voorkom:", - "Importer_HipChatEnterprise_Information": "Die opgelaaide lêer moet 'n gedecodeerde tar.gz wees, lees asseblief die dokumentasie vir verdere inligting:", "Importer_import_cancelled": "Invoer gekanselleer.", "Importer_import_failed": "'N Fout het voorgekom terwyl die invoer uitgevoer word.", "Importer_importing_channels": "Die kanale invoer.", diff --git a/packages/i18n/src/locales/ar.i18n.json b/packages/i18n/src/locales/ar.i18n.json index d3a86879f716..f39525bd3774 100644 --- a/packages/i18n/src/locales/ar.i18n.json +++ b/packages/i18n/src/locales/ar.i18n.json @@ -2143,8 +2143,6 @@ "Importer_finishing": "يتم إنهاء الاستيراد.", "Importer_From_Description": "استيراد بيانات {{from}} إلى Rocket.Chat.", "Importer_From_Description_CSV": "استيراد بيانات CSV إلى Rocket.Chat. يجب أن يكون الملف الذي تم رفعه بتنسيق ZIP.", - "Importer_HipChatEnterprise_BetaWarning": "يرجى العلم أن هذا الاستيراد لا يزال قيد التقدم، يُرجى الإبلاغ عن أي أخطاء تحدث في GitHub:", - "Importer_HipChatEnterprise_Information": "يجب أن يكون الملف الذي تم تحميله بتنسيق tar.gz غير مشفر، تُرجى قراءة الوثائق للحصول على مزيد من المعلومات:", "Importer_import_cancelled": "تم إلغاء الاستيراد.", "Importer_import_failed": "حدث خطأ أثناء تشغيل الاستيراد.", "Importer_importing_channels": "يتم استيراد القنوات.", diff --git a/packages/i18n/src/locales/az.i18n.json b/packages/i18n/src/locales/az.i18n.json index 118be4b37920..29b1c842aecd 100644 --- a/packages/i18n/src/locales/az.i18n.json +++ b/packages/i18n/src/locales/az.i18n.json @@ -1271,8 +1271,6 @@ "Importer_done": "Tamamilə idxal!", "Importer_finishing": "İthalatı bitirmək.", "Importer_From_Description": "Rocket.Chat'a {{from}} data verin.", - "Importer_HipChatEnterprise_BetaWarning": "Xahiş edirik, bu idxal hələ də davam edən bir iş olduğundan xəbərdar edin, GitHub'da meydana gələn hər hansı bir səhv bildirin:", - "Importer_HipChatEnterprise_Information": "Yüklənən fayl şifresi çözülmüş tar.gz olmalıdır, daha ətraflı məlumat üçün sənədləri oxuyun:", "Importer_import_cancelled": "İxrac ləğv edildi.", "Importer_import_failed": "İçeceğinizde çalışırken bir səhv baş verdi.", "Importer_importing_channels": "Kanalları idxal etmək.", diff --git a/packages/i18n/src/locales/be-BY.i18n.json b/packages/i18n/src/locales/be-BY.i18n.json index 858688468755..e8043211ede1 100644 --- a/packages/i18n/src/locales/be-BY.i18n.json +++ b/packages/i18n/src/locales/be-BY.i18n.json @@ -1287,8 +1287,6 @@ "Importer_done": "Імпарт завершаны!", "Importer_finishing": "Завяршэнне імпарту.", "Importer_From_Description": "Імпартуе {{from}} дадзеныя ў Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Звярніце ўвагу, што гэты імпарт па-ранейшаму знаходзіцца ў стадыі распрацоўкі, просьба паведамляць пра памылкі, якія адбываюцца ў GitHub:", - "Importer_HipChatEnterprise_Information": "Загружаны файл павінен быць расшыфраваны tar.gz, калі ласка, прачытайце дакументацыю для атрымання дадатковай інфармацыі:", "Importer_import_cancelled": "Імпарт адменены.", "Importer_import_failed": "пры выкананні імпарту адбылася памылка.", "Importer_importing_channels": "Імпарт каналаў.", diff --git a/packages/i18n/src/locales/bg.i18n.json b/packages/i18n/src/locales/bg.i18n.json index ac7c8ddcd000..d6a1f8503442 100644 --- a/packages/i18n/src/locales/bg.i18n.json +++ b/packages/i18n/src/locales/bg.i18n.json @@ -1269,8 +1269,6 @@ "Importer_CSV_Information": "CSV вносителят изисква специален формат, прочетете документацията за това как да структурирате файла с цип:", "Importer_done": "Импортирането е завършено!", "Importer_finishing": "Завършване на импортирането.", - "Importer_HipChatEnterprise_BetaWarning": "Имайте предвид, че този внос все още е в процес на разработка, моля, отчетете всички грешки, които възникват в GitHub:", - "Importer_HipChatEnterprise_Information": "Каченият файл трябва да е декриптиран tar.gz, моля прочетете документацията за допълнителна информация:", "Importer_import_cancelled": "Импортирането бе отменено.", "Importer_import_failed": "Възникна грешка при изпълнение на импортирането.", "Importer_importing_channels": "Импортиране на каналите.", diff --git a/packages/i18n/src/locales/bs.i18n.json b/packages/i18n/src/locales/bs.i18n.json index ebe0b045c418..7e29e01e2b45 100644 --- a/packages/i18n/src/locales/bs.i18n.json +++ b/packages/i18n/src/locales/bs.i18n.json @@ -1267,8 +1267,6 @@ "Importer_done": "Uvoz dovršen!", "Importer_finishing": "Završavanje uvoza.", "Importer_From_Description": "Uvezi {{from}} podatke u Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Imajte na umu da je taj uvoz još uvijek u tijeku, prijavite sve pogreške koje se pojavljuju u GitHubu:", - "Importer_HipChatEnterprise_Information": "Prenesena datoteka mora biti dekriptirana tar.gz, pročitajte dokumentaciju za daljnje informacije:", "Importer_import_cancelled": "Uvoz je otkazan.", "Importer_import_failed": "Došlo je do pogreške pri izvršavanju uvoza.", "Importer_importing_channels": "Prebacivanje kanala.", diff --git a/packages/i18n/src/locales/ca.i18n.json b/packages/i18n/src/locales/ca.i18n.json index 3f74fc967416..db9a0bd7175b 100644 --- a/packages/i18n/src/locales/ca.i18n.json +++ b/packages/i18n/src/locales/ca.i18n.json @@ -2111,8 +2111,6 @@ "Importer_finishing": "Finalitza la importació.", "Importer_From_Description": "Importa les dades de {{from}} a Rocket.Chat.", "Importer_From_Description_CSV": "Importa dades CSV a Rocket.Chat. El fitxer penjat ha de ser un fitxer ZIP.", - "Importer_HipChatEnterprise_BetaWarning": "Tingueu en compte que aquest sistema d'importació encara està en desenvolupament. Si us plau, notifiqueu-nos a GitHub els errors que es produeixin:", - "Importer_HipChatEnterprise_Information": "L'arxiu carregat ha de ser un tar.gz desxifrat, llegiu la documentació per obtenir més informació:", "Importer_import_cancelled": "Importació cancel·lada.", "Importer_import_failed": "S'ha produït un error durant la importació.", "Importer_importing_channels": "Important els canals.", diff --git a/packages/i18n/src/locales/cs.i18n.json b/packages/i18n/src/locales/cs.i18n.json index 914d6c35d485..ef640614d7a8 100644 --- a/packages/i18n/src/locales/cs.i18n.json +++ b/packages/i18n/src/locales/cs.i18n.json @@ -1814,8 +1814,6 @@ "Importer_ExternalUrl_Description": "Můžete také použít adresu URL pro veřejně přístupný soubor:", "Importer_finishing": "Dokončuji import.", "Importer_From_Description": "Import dat {{from}} do Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Mějte prosím na paměti, že tato funkcionalita je stále ve vývoji, prosím nahlašte nám jakékoliv chyby přes github:", - "Importer_HipChatEnterprise_Information": "Nahraný soubor musí být nešifrovaný tar.gz, Více informací naleznete v dokumentaci:", "Importer_import_cancelled": "Import zrušen.", "Importer_import_failed": "Došlo k chybě při importu.", "Importer_importing_channels": "Importuji místnosti.", diff --git a/packages/i18n/src/locales/cy.i18n.json b/packages/i18n/src/locales/cy.i18n.json index f9c7b4d7ec87..3398f0c7c6f3 100644 --- a/packages/i18n/src/locales/cy.i18n.json +++ b/packages/i18n/src/locales/cy.i18n.json @@ -1267,8 +1267,6 @@ "Importer_done": "Mewnforio yn gyflawn!", "Importer_finishing": "Gorffen y mewnforio.", "Importer_From_Description": "Mewnforion {{from}} data i Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Cofiwch fod y mewnforio hwn yn dal i fod yn waith ar y gweill, rhowch wybod am unrhyw wallau sy'n digwydd yn GitHub:", - "Importer_HipChatEnterprise_Information": "Rhaid i'r ffeil a lwythir i fyny fod yn tar.gz dadgryptiedig, darllenwch y dogfennau i gael rhagor o wybodaeth:", "Importer_import_cancelled": "Canslo mewnforio.", "Importer_import_failed": "Digwyddodd gwall wrth redeg y mewnforio.", "Importer_importing_channels": "Mewnforio y sianeli.", diff --git a/packages/i18n/src/locales/da.i18n.json b/packages/i18n/src/locales/da.i18n.json index a675ab4843c0..3c04eb8f128f 100644 --- a/packages/i18n/src/locales/da.i18n.json +++ b/packages/i18n/src/locales/da.i18n.json @@ -1906,8 +1906,6 @@ "Importer_ExternalUrl_Description": "Du kan også bruge en URL til en offentlig tilgængelig fil:", "Importer_finishing": "Afslutter importen.", "Importer_From_Description": "Importerer {{from}} data til Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Vær opmærksom på, at denne import stadig er under udvikling. Rapporter venligst eventuelle fejl der opstår til GitHub:", - "Importer_HipChatEnterprise_Information": "Den uploadede fil skal være en dekrypteret tar.gz. Du kan få mere at vide i dokumentationen:", "Importer_import_cancelled": "Import annulleret.", "Importer_import_failed": "Der opstod en fejl under udførelsen af importen.", "Importer_importing_channels": "Importerer kanalerne.", diff --git a/packages/i18n/src/locales/de-AT.i18n.json b/packages/i18n/src/locales/de-AT.i18n.json index 0be8030f5738..0c1d9134e6cb 100644 --- a/packages/i18n/src/locales/de-AT.i18n.json +++ b/packages/i18n/src/locales/de-AT.i18n.json @@ -1273,8 +1273,6 @@ "Importer_done": "Die Daten wurden erfolgreich importiert!", "Importer_finishing": "Import abgeschlossen.", "Importer_From_Description": "Importiert Daten von {{from}} nach Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Bitte beachten Sie, dass dieser Import noch in Arbeit ist. Bitte melden Sie alle Fehler, die in GitHub auftreten:", - "Importer_HipChatEnterprise_Information": "Die hochgeladene Datei muss eine entschlüsselte tar.gz sein. Bitte lesen Sie die Dokumentation für weitere Informationen:", "Importer_import_cancelled": "Der Import wurde abgebrochen.", "Importer_import_failed": "Während des Importierens ist ein Fehler aufgetreten.", "Importer_importing_channels": "Importiere die Kanäle.", diff --git a/packages/i18n/src/locales/de-IN.i18n.json b/packages/i18n/src/locales/de-IN.i18n.json index 41da8fb3c809..d670473c9ec1 100644 --- a/packages/i18n/src/locales/de-IN.i18n.json +++ b/packages/i18n/src/locales/de-IN.i18n.json @@ -1463,8 +1463,6 @@ "Importer_ExternalUrl_Description": "Du kannst eine öffentlich erreichbare URL zur Datei angeben.", "Importer_finishing": "Import abgeschlossen.", "Importer_From_Description": "Importiert Daten von {{from}} nach Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Bitte beachte, dass sich dieser Importer noch in der Entwicklung befindet. Bitte melde Fehler auf GitHub: ", - "Importer_HipChatEnterprise_Information": "Die hochgeladene Datei muss ein nicht-verschlüsseltes tar.gz sein. Bitte lies die Dokumentation für weiterführende Informationen.", "Importer_import_cancelled": "Der Import wurde abgebrochen.", "Importer_import_failed": "Während des Importierens ist ein Fehler aufgetreten.", "Importer_importing_channels": "Importiere die Kanäle.", diff --git a/packages/i18n/src/locales/de.i18n.json b/packages/i18n/src/locales/de.i18n.json index a67509672d33..d8540f9978e9 100644 --- a/packages/i18n/src/locales/de.i18n.json +++ b/packages/i18n/src/locales/de.i18n.json @@ -2389,8 +2389,6 @@ "Importer_finishing": "Import abgeschlossen.", "Importer_From_Description": "Importiert Daten von {{from}} nach Rocket.Chat.", "Importer_From_Description_CSV": "Importiert CSV-Daten in Rocket.Chat. Die hochgeladene Fatei muss eine ZIP-Datei sein.", - "Importer_HipChatEnterprise_BetaWarning": "Bitte beachten Sie, dass sich dieser Importer noch in der Entwicklung befindet. Bitte berichten Sie über Fehler auf GitHub: ", - "Importer_HipChatEnterprise_Information": "Die hochgeladene Datei muss ein nicht verschlüsseltes tar.gz sein. Bitte lesen Sie die Dokumentation für weiterführende Informationen:", "Importer_import_cancelled": "Der Import wurde abgebrochen.", "Importer_import_failed": "Während des Importierens ist ein Fehler aufgetreten.", "Importer_importing_channels": "Importiere die Kanäle.", diff --git a/packages/i18n/src/locales/el.i18n.json b/packages/i18n/src/locales/el.i18n.json index 731a56695f7a..2c9b3caa1f61 100644 --- a/packages/i18n/src/locales/el.i18n.json +++ b/packages/i18n/src/locales/el.i18n.json @@ -1278,8 +1278,6 @@ "Importer_done": "Εισαγωγή πλήρης!", "Importer_finishing": "Ολοκλήρωση της εισαγωγής.", "Importer_From_Description": "Οι εισαγωγές {{from}} δεδομένων's σε Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Λάβετε υπόψη ότι αυτή η εισαγωγή εξακολουθεί να είναι εργασία σε εξέλιξη, αναφέρετε τυχόν λάθη που εμφανίζονται στο GitHub:", - "Importer_HipChatEnterprise_Information": "Το φορτωμένο αρχείο πρέπει να είναι αποκρυπτογραφημένο tar.gz, διαβάστε την τεκμηρίωση για περισσότερες πληροφορίες:", "Importer_import_cancelled": "Εισαγωγής ακυρωθεί.", "Importer_import_failed": "Παρουσιάστηκε σφάλμα κατά την εκτέλεση της εισαγωγής.", "Importer_importing_channels": "Εισάγει τα κανάλια.", diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index c270bb9bffb1..d82a3c6da4a9 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -2584,7 +2584,6 @@ "Highlights": "Highlights", "Highlights_How_To": "To be notified when someone mentions a word or phrase, add it here. You can separate words or phrases with commas. Highlight Words are not case sensitive.", "Highlights_List": "Highlight words", - "HipChat (tar.gz)": "HipChat (tar.gz)", "History": "History", "Hold_Time": "Hold Time", "Hold": "Hold", @@ -2650,8 +2649,6 @@ "Importer_finishing": "Finishing up the import.", "Importer_From_Description": "Imports {{from}} data into Rocket.Chat.", "Importer_From_Description_CSV": "Imports CSV data into Rocket.Chat. The uploaded file must be a ZIP file.", - "Importer_HipChatEnterprise_BetaWarning": "Please be aware that this import is still a work in progress, please report any errors which occur in GitHub:", - "Importer_HipChatEnterprise_Information": "The file uploaded must be a decrypted tar.gz, please read the documentation for further information:", "Importer_import_cancelled": "Import cancelled.", "Importer_import_failed": "An error occurred while running the import.", "Importer_importing_channels": "Importing the channels.", diff --git a/packages/i18n/src/locales/eo.i18n.json b/packages/i18n/src/locales/eo.i18n.json index 1558424c9445..fdf468871aae 100644 --- a/packages/i18n/src/locales/eo.i18n.json +++ b/packages/i18n/src/locales/eo.i18n.json @@ -1271,8 +1271,6 @@ "Importer_done": "Importante kompletan!", "Importer_finishing": "Finante la importadon.", "Importer_From_Description": "Importas {{from}}-datumojn en Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Bonvolu konscii, ke ĉi tiu importado ankoraŭ estas progreso, bonvolu raporti iujn erarojn, kiuj okazas en GitHub:", - "Importer_HipChatEnterprise_Information": "La dosiero alŝutita devas esti senĉifrita tar.gz, bonvolu legi la dokumentadon por pliaj informoj:", "Importer_import_cancelled": "Importi nuligita.", "Importer_import_failed": "Eraro okazis dum ĝi funkciis la importadon.", "Importer_importing_channels": "Importante la kanaloj.", diff --git a/packages/i18n/src/locales/es.i18n.json b/packages/i18n/src/locales/es.i18n.json index a276a3c51690..03afdf5c79fe 100644 --- a/packages/i18n/src/locales/es.i18n.json +++ b/packages/i18n/src/locales/es.i18n.json @@ -2135,8 +2135,6 @@ "Importer_finishing": "Terminando la importación.", "Importer_From_Description": "Importa datos de {{from}} a Rocket.Chat.", "Importer_From_Description_CSV": "Importa datos en formato CSV a Rocket.Chat. El archivo subido debe ser un archivo ZIP.", - "Importer_HipChatEnterprise_BetaWarning": "Ten en cuenta que esta importación aún se está desarrollando. Informa acerca de cualquier error que ocurra en GitHub:", - "Importer_HipChatEnterprise_Information": "El archivo subido debe ser un archivo tar.gz descifrado. Consulta la documentación para obtener más información:", "Importer_import_cancelled": "Importación cancelada.", "Importer_import_failed": "Se ha producido un error durante la ejecución de la importación.", "Importer_importing_channels": "Importando los canales.", diff --git a/packages/i18n/src/locales/fa.i18n.json b/packages/i18n/src/locales/fa.i18n.json index c4850a7d30eb..6165446a581a 100644 --- a/packages/i18n/src/locales/fa.i18n.json +++ b/packages/i18n/src/locales/fa.i18n.json @@ -1530,8 +1530,6 @@ "Importer_done": "وارد کردن تمام شد!", "Importer_finishing": "پایان دادن به وارد کردن.", "Importer_From_Description": "داده های {{from}} را وارد Rocket.chat می کند.", - "Importer_HipChatEnterprise_BetaWarning": "لطفا توجه داشته باشید که این واردات همچنان یک کار در حال انجام است، لطفا هر خطایی که در GitHub رخ می دهد گزارش دهید:", - "Importer_HipChatEnterprise_Information": "فایل آپلود شده باید یک tar.gz رمزگشایی شود، لطفا مستندات بیشتری برای اطلاعات بیشتر بخوانید:", "Importer_import_cancelled": "وارد کردن لغو شد.", "Importer_import_failed": "هنگام وارد کردن خطایی رخ داد.", "Importer_importing_channels": "وارد کردن کانال ها.", diff --git a/packages/i18n/src/locales/fi.i18n.json b/packages/i18n/src/locales/fi.i18n.json index 17b5f65eab31..6fe476587007 100644 --- a/packages/i18n/src/locales/fi.i18n.json +++ b/packages/i18n/src/locales/fi.i18n.json @@ -2426,8 +2426,6 @@ "Importer_finishing": "Viimeistellään tuontia.", "Importer_From_Description": "Tuo tiedot kohteesta {{from}} Rocket.Chatiin.", "Importer_From_Description_CSV": "Tuo CSV-tiedot Rocket.Chatiin. Ladatun tiedoston on oltava ZIP-tiedosto.", - "Importer_HipChatEnterprise_BetaWarning": "Huomaa, että tuontitoiminto on edelleen kehitteillä. Ilmoita virheistä GitHubissa:", - "Importer_HipChatEnterprise_Information": "Ladattavan tiedoston on oltava purettu tar.gz-tiedosto. Katso lisätietoja oppaista:", "Importer_import_cancelled": "Tuonti peruutettu.", "Importer_import_failed": "Virhe tuotaessa.", "Importer_importing_channels": "Tuodaan kanavia.", diff --git a/packages/i18n/src/locales/fr.i18n.json b/packages/i18n/src/locales/fr.i18n.json index 84d33eaf5330..085451faee64 100644 --- a/packages/i18n/src/locales/fr.i18n.json +++ b/packages/i18n/src/locales/fr.i18n.json @@ -2129,8 +2129,6 @@ "Importer_finishing": "Finalisation de l'importation.", "Importer_From_Description": "Importer les données de {{from}} dans Rocket.Chat.", "Importer_From_Description_CSV": "Importe des données CSV dans Rocket.Chat. Le fichier chargé doit être un fichier ZIP.", - "Importer_HipChatEnterprise_BetaWarning": "Notez que la fonction d'importation est toujours en cours de développement, veuillez signaler toute erreur dans GitHub :", - "Importer_HipChatEnterprise_Information": "Le fichier chargé doit être au format tar.gz déchiffré, lisez la documentation pour plus d'informations :", "Importer_import_cancelled": "Importation annulée.", "Importer_import_failed": "Une erreur est survenue lors de l'importation.", "Importer_importing_channels": "Importation des canaux.", diff --git a/packages/i18n/src/locales/hi-IN.i18n.json b/packages/i18n/src/locales/hi-IN.i18n.json index 1049d8495d86..f6f94b4573bf 100644 --- a/packages/i18n/src/locales/hi-IN.i18n.json +++ b/packages/i18n/src/locales/hi-IN.i18n.json @@ -2529,8 +2529,6 @@ "Importer_finishing": "आयात समाप्त करना.", "Importer_From_Description": "Rocket.Chat में {{from}} डेटा आयात करता है।", "Importer_From_Description_CSV": "Rocket.Chat में CSV डेटा आयात करता है। अपलोड की गई फ़ाइल एक ज़िप फ़ाइल होनी चाहिए.", - "Importer_HipChatEnterprise_BetaWarning": "कृपया ध्यान रखें कि इस आयात पर अभी भी काम चल रहा है, कृपया GitHub में होने वाली किसी भी त्रुटि की रिपोर्ट करें:", - "Importer_HipChatEnterprise_Information": "अपलोड की गई फ़ाइल डिक्रिप्टेड tar.gz होनी चाहिए, कृपया अधिक जानकारी के लिए दस्तावेज़ पढ़ें:", "Importer_import_cancelled": "आयात रद्द कर दिया गया.", "Importer_import_failed": "आयात चलाते समय एक त्रुटि उत्पन्न हुई.", "Importer_importing_channels": "चैनल आयात करना.", diff --git a/packages/i18n/src/locales/hr.i18n.json b/packages/i18n/src/locales/hr.i18n.json index 84c4295d5201..f75d0e36e35e 100644 --- a/packages/i18n/src/locales/hr.i18n.json +++ b/packages/i18n/src/locales/hr.i18n.json @@ -1401,8 +1401,6 @@ "Importer_done": "Uvoz dovršen!", "Importer_finishing": "Završavanje uvoza.", "Importer_From_Description": "Uvezi {{from}} podatke u Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Imajte na umu da je taj uvoz još uvijek u tijeku, prijavite sve pogreške koje se pojavljuju u GitHubu:", - "Importer_HipChatEnterprise_Information": "Prenesena datoteka mora biti dekriptirana tar.gz, pročitajte dokumentaciju za daljnje informacije:", "Importer_import_cancelled": "Uvoz je otkazan.", "Importer_import_failed": "Došlo je do pogreške pri izvršavanju uvoza.", "Importer_importing_channels": "Prebacivanje kanala.", diff --git a/packages/i18n/src/locales/hu.i18n.json b/packages/i18n/src/locales/hu.i18n.json index f7f85536c183..1c58e7f0a3b3 100644 --- a/packages/i18n/src/locales/hu.i18n.json +++ b/packages/i18n/src/locales/hu.i18n.json @@ -2340,8 +2340,6 @@ "Importer_finishing": "Az importálás befejezése.", "Importer_From_Description": "{{from}}-adatokat importál a Rocket.Chatbe.", "Importer_From_Description_CSV": "CSV-adatokat importál a Rocket.Chatbe. A feltöltött fájlnak ZIP-fájlnak kell lennie.", - "Importer_HipChatEnterprise_BetaWarning": "Felhívjuk a figyelmét, hogy ennek az importálásnak a munkálatai még folyamatban vannak, az esetleges hibákat a GitHubon jelentse:", - "Importer_HipChatEnterprise_Information": "A feltöltött fájlnak visszafejtett tar.gz-nek kell lennie, olvassa el a dokumentációt további információkért:", "Importer_import_cancelled": "Az importálás megszakítva.", "Importer_import_failed": "Hiba történt az importálás futása során.", "Importer_importing_channels": "A csatornák importálása.", diff --git a/packages/i18n/src/locales/id.i18n.json b/packages/i18n/src/locales/id.i18n.json index 1abc2fadd68c..1c2b9a8605f9 100644 --- a/packages/i18n/src/locales/id.i18n.json +++ b/packages/i18n/src/locales/id.i18n.json @@ -1271,8 +1271,6 @@ "Importer_done": "Mengimpor lengkap!", "Importer_finishing": "Menyelesaikan impor.", "Importer_From_Description": "Impor {{from}} Data's menjadi Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Perlu diketahui bahwa impor ini masih dalam proses penyelesaian, laporkan kesalahan yang terjadi di GitHub:", - "Importer_HipChatEnterprise_Information": "File yang diunggah harus berupa tar.gz terdekrip, baca dokumentasi untuk informasi lebih lanjut:", "Importer_import_cancelled": "Impor dibatalkan.", "Importer_import_failed": "Terjadi kesalahan saat menjalankan impor.", "Importer_importing_channels": "Mengimpor saluran.", diff --git a/packages/i18n/src/locales/it.i18n.json b/packages/i18n/src/locales/it.i18n.json index 160dbe3cf40e..c837e6ba2b28 100644 --- a/packages/i18n/src/locales/it.i18n.json +++ b/packages/i18n/src/locales/it.i18n.json @@ -1677,8 +1677,6 @@ "Importer_done": "Importazione completata!", "Importer_finishing": "In fase di terminazione dell'importazione.", "Importer_From_Description": "Importa i dati da {{from}} in Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Nota che questa importazione è in sviluppo, riporta ogni errori che può avvenire su GitHub:", - "Importer_HipChatEnterprise_Information": "Il file caricato deve essere un file tar.gz decriptato, leggi la documentazione per altre informazioni:", "Importer_import_cancelled": "Importazione annullata.", "Importer_import_failed": "Si è verificato un errore durante l'esecuzione dell'importazione.", "Importer_importing_channels": "In fase d'importazione dei canali.", diff --git a/packages/i18n/src/locales/ja.i18n.json b/packages/i18n/src/locales/ja.i18n.json index 982f9495d914..3ae91c7438e5 100644 --- a/packages/i18n/src/locales/ja.i18n.json +++ b/packages/i18n/src/locales/ja.i18n.json @@ -2105,8 +2105,6 @@ "Importer_finishing": "インポートを終了しています。", "Importer_From_Description": "{{from}}のデータをRocket.Chatへインポートします。", "Importer_From_Description_CSV": "CSVデータをRocket.Chatにインポートします。アップロードするファイルはZIPファイルである必要があります。", - "Importer_HipChatEnterprise_BetaWarning": "このインポートはまだ進行中です。GitHubで発生したエラーを報告してください。", - "Importer_HipChatEnterprise_Information": "アップロードされるファイルは暗号化を解除されたtar.gzでなければなりません。詳細はドキュメントを参照してください。", "Importer_import_cancelled": "インポートをキャンセルしました。", "Importer_import_failed": "インポートの実行中にエラーが発生しました。", "Importer_importing_channels": "チャネルをインポートしています。", diff --git a/packages/i18n/src/locales/ka-GE.i18n.json b/packages/i18n/src/locales/ka-GE.i18n.json index 3c550632cc4c..95edad389a61 100644 --- a/packages/i18n/src/locales/ka-GE.i18n.json +++ b/packages/i18n/src/locales/ka-GE.i18n.json @@ -1716,8 +1716,6 @@ "Importer_ExternalUrl_Description": "თქვენ ასევე შეგიძლიათ ნახოთ ბმული საჯარო წვდომის ფაილისთვის", "Importer_finishing": "იმპორტი სრულდება", "Importer_From_Description": "მონაცემებს აიმპორტებს {{from}}-დან Rocket.Chat-ში", - "Importer_HipChatEnterprise_BetaWarning": "გთხოვთ გაითვალისწინოთ, რომ ეს იმპორტი კვლავ შემუშავების პროცესშია \n გთხოვთ, აცნობეთ შეცდომების შესახებ GitHub– ში:", - "Importer_HipChatEnterprise_Information": "ატვირთული ფაილი უნდა იყოს გაშიფრული tar.gz, დამატებითი ინფორმაციისთვის წაიკითხეთ დოკუმენტაცია:", "Importer_import_cancelled": "იმპორტი გაუქმდა.", "Importer_import_failed": "იმპორტისას მოხდა შეცდომა.", "Importer_importing_channels": "არხების იმპორტი.", diff --git a/packages/i18n/src/locales/km.i18n.json b/packages/i18n/src/locales/km.i18n.json index 997ee66a00e7..a01227e4efa8 100644 --- a/packages/i18n/src/locales/km.i18n.json +++ b/packages/i18n/src/locales/km.i18n.json @@ -1526,8 +1526,6 @@ "Importer_ExternalUrl_Description": "អ្នកក៏អាចប្រើ URL សម្រាប់ឯកសារអាចចូលដំណើរការជាសាធារណៈបានដែរ:", "Importer_finishing": "បញ្ចប់ការនាំចូល។", "Importer_From_Description": "ការនាំចូល {{from}} ទិន្នន័យ's បានចូលទៅក្នុង Rocket.Chat ។", - "Importer_HipChatEnterprise_BetaWarning": "សូមជ្រាបថាការនាំចូលនេះនៅតែជាការងារកំពុងដំណើរការសូមរាយការណ៍កំហុសទាំងឡាយដែលកើតឡើងនៅក្នុង GitHub:", - "Importer_HipChatEnterprise_Information": "ឯកសារដែលបានផ្ទុកឡើងត្រូវតែជាឌីជីថលដែលបានឌិគ្រីបសូមអានឯកសារសម្រាប់ព័ត៌មានបន្ថែម:", "Importer_import_cancelled": "នាំចូលលុបចោល។", "Importer_import_failed": "កំហុសមួយបានកើតឡើងខណៈពេលកំពុងរត់ការនាំចូល។", "Importer_importing_channels": "ការនាំចូលបណ្តាញនេះ។", diff --git a/packages/i18n/src/locales/ko.i18n.json b/packages/i18n/src/locales/ko.i18n.json index ad5818ab9f85..ecf9d26abba2 100644 --- a/packages/i18n/src/locales/ko.i18n.json +++ b/packages/i18n/src/locales/ko.i18n.json @@ -1867,8 +1867,6 @@ "Importer_ExternalUrl_Description": "외부에서 접근할 수 있는 파일의 URL을 사용할 수 있습니다.", "Importer_finishing": "가져오기 마무리 중..", "Importer_From_Description": "{{from}} 데이터를 Rocket.Chat으로 가져옵니다.", - "Importer_HipChatEnterprise_BetaWarning": "이 가져 오기가 아직 진행 중이므로 GitHub에서 발생하는 모든 오류를보고하십시오.", - "Importer_HipChatEnterprise_Information": "업로드 된 파일은 해독 된 tar.gz 여야합니다. 자세한 내용은 설명서를 참조하십시오.", "Importer_import_cancelled": "가져오기가 취소되었습니다.", "Importer_import_failed": "가져오기를 실행하는 동안 오류가 발생했습니다.", "Importer_importing_channels": "채널 가져오기", diff --git a/packages/i18n/src/locales/ku.i18n.json b/packages/i18n/src/locales/ku.i18n.json index 9b4a4d1aaeb2..3de6134ba003 100644 --- a/packages/i18n/src/locales/ku.i18n.json +++ b/packages/i18n/src/locales/ku.i18n.json @@ -1266,8 +1266,6 @@ "Importer_done": "Importing temam!", "Importer_finishing": "Despêk xwe import.", "Importer_From_Description": "Imports {{from}} welat's nav Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Ji kerema xwe bizanibin ku ev import jî hîn jî di pêşveçûnê de ye, kerema ku li GitHubê pêk tê rapor bikin:", - "Importer_HipChatEnterprise_Information": "Divê belgeyê belaş divê tar.gz, ji kerema xwe belgeyên bêtir agahdarî belgeyên bixwînin:", "Importer_import_cancelled": "Import betalkirin.", "Importer_import_failed": "dema ku li import An error teqîn pêk hat.", "Importer_importing_channels": "Importing kanalên.", diff --git a/packages/i18n/src/locales/lo.i18n.json b/packages/i18n/src/locales/lo.i18n.json index d427b251e863..127b97b760ed 100644 --- a/packages/i18n/src/locales/lo.i18n.json +++ b/packages/i18n/src/locales/lo.i18n.json @@ -1305,8 +1305,6 @@ "Importer_done": "ການນໍາເຂົ້າທີ່ສົມບູນ!", "Importer_finishing": "ສໍາເລັດເຖິງການນໍາເຂົ້າ.", "Importer_From_Description": "ການນໍາເຂົ້າ {{from}} ຂໍ້ມູນ's ເຂົ້າໄປໃນ Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "ໂປດທາບວ່າການນໍາເຂົ້ານີ້ຍັງຄົງເປັນວຽກທີ່ກໍາລັງດໍາເນີນການ, ກະລຸນາລາຍງານຂໍ້ຜິດພາດທີ່ເກີດຂື້ນໃນ GitHub:", - "Importer_HipChatEnterprise_Information": "ໄຟລ໌ທີ່ອັບໂຫລດຕ້ອງເປັນ tar.gz ທີ່ຖືກລະຫັດ, ກະລຸນາອ່ານເອກສານສໍາລັບຂໍ້ມູນເພີ່ມເຕີມ:", "Importer_import_cancelled": "ການນໍາເຂົ້າຍົກເລີກ.", "Importer_import_failed": "ເກີດຄວາມຜິດພາດໃນຂະນະທີ່ເຮັດວຽກການນໍາເຂົ້າ.", "Importer_importing_channels": "ການນໍາເຂົ້າຊ່ອງທາງການ.", diff --git a/packages/i18n/src/locales/lt.i18n.json b/packages/i18n/src/locales/lt.i18n.json index 88fb66dc554f..b1e7f54da0b0 100644 --- a/packages/i18n/src/locales/lt.i18n.json +++ b/packages/i18n/src/locales/lt.i18n.json @@ -1326,8 +1326,6 @@ "Importer_done": "Importavimas baigtas!", "Importer_finishing": "Užbaigti importą.", "Importer_From_Description": "Importuoja {{from}} duomenis į Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Atminkite, kad šis importas vis dar vyksta, prašome pranešti apie klaidas, kurios atsiranda \"GitHub\":", - "Importer_HipChatEnterprise_Information": "Įkeltas failas turi būti iššifruotas tar.gz, prašome perskaityti dokumentus, kad gautumėte papildomos informacijos:", "Importer_import_cancelled": "Importas atšauktas.", "Importer_import_failed": "Paleidus importą įvyko klaida.", "Importer_importing_channels": "Kanalų importavimas.", diff --git a/packages/i18n/src/locales/lv.i18n.json b/packages/i18n/src/locales/lv.i18n.json index 544eac3dbeb3..3035191ac1ef 100644 --- a/packages/i18n/src/locales/lv.i18n.json +++ b/packages/i18n/src/locales/lv.i18n.json @@ -1282,8 +1282,6 @@ "Importer_CSV_Information": "CSV importer ir nepieciešams noteikts formāts, lūdzu, izlasiet dokumentāciju, kā veidot savu zip failu:", "Importer_done": "Importēšana ir pabeigta.", "Importer_finishing": "Importēšanas pabeigšana.", - "Importer_HipChatEnterprise_BetaWarning": "Lūdzu, ņemiet vērā, ka šis importēšana joprojām turpinās darbu, lūdzu, ziņojiet par visām kļūdām, kas rodas GitHub:", - "Importer_HipChatEnterprise_Information": "Augšupielādētajam failam jābūt atšifrētam tar.gz, lūdzu, izlasiet dokumentāciju, lai saņemtu sīkāku informāciju:", "Importer_import_cancelled": "Imports ir atcelts.", "Importer_import_failed": "Veicot importēšanu, radās kļūda.", "Importer_importing_channels": "Kanālu importēšana.", diff --git a/packages/i18n/src/locales/mn.i18n.json b/packages/i18n/src/locales/mn.i18n.json index 60e18063b49f..c7ecf64af448 100644 --- a/packages/i18n/src/locales/mn.i18n.json +++ b/packages/i18n/src/locales/mn.i18n.json @@ -1266,8 +1266,6 @@ "Importer_CSV_Information": "CSV-ийн импортлогч тодорхой форматыг шаарддаг бөгөөд таны zip файлыг хэрхэн бүтээх талаар баримтжуулалтыг уншина уу:", "Importer_done": "Бүрэн импортлох!", "Importer_finishing": "Импортыг дуусгах.", - "Importer_HipChatEnterprise_BetaWarning": "Энэ импорт нь одоо ч ажил дуусч байгаа гэдгийг анхаарна уу, GitHub-д тохиолддог аливаа алдааг мэдээлнэ үү:", - "Importer_HipChatEnterprise_Information": "Байршуулсан файл нь шифрлэгдсэн tar.gz байна, дэлгэрэнгүй мэдээллийг баримтжуулж уншина уу:", "Importer_import_cancelled": "Импорт цуцлагдсан.", "Importer_import_failed": "Импортыг ажиллуулж байхад алдаа гарлаа.", "Importer_importing_channels": "Суваг оруулах.", diff --git a/packages/i18n/src/locales/ms-MY.i18n.json b/packages/i18n/src/locales/ms-MY.i18n.json index 524260560a3f..60d3d172e34f 100644 --- a/packages/i18n/src/locales/ms-MY.i18n.json +++ b/packages/i18n/src/locales/ms-MY.i18n.json @@ -1269,8 +1269,6 @@ "Importer_done": "Mengimport lengkap!", "Importer_finishing": "Hampir selesai import.", "Importer_From_Description": "Import {{from}} data's ke dalam Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Harap maklum bahawa import ini masih merupakan kerja yang sedang berjalan, sila laporkan kesilapan yang berlaku di GitHub:", - "Importer_HipChatEnterprise_Information": "Fail yang dimuat naik mestilah tar.gz disahsulit, sila baca dokumentasi untuk maklumat lanjut:", "Importer_import_cancelled": "Import dibatalkan.", "Importer_import_failed": "Ralat berlaku semasa berjalan import.", "Importer_importing_channels": "Mengimport saluran.", diff --git a/packages/i18n/src/locales/nl.i18n.json b/packages/i18n/src/locales/nl.i18n.json index bf7f7ffb780c..e60531dd46fd 100644 --- a/packages/i18n/src/locales/nl.i18n.json +++ b/packages/i18n/src/locales/nl.i18n.json @@ -2121,8 +2121,6 @@ "Importer_finishing": "Afwerking van de import.", "Importer_From_Description": "Impoort {{from}}-gegevens in Rocket.Chat.", "Importer_From_Description_CSV": "Importeert CSV-gegevens in Rocket.Chat. De geüploade file moet een ZIP-bestand zijn.", - "Importer_HipChatEnterprise_BetaWarning": "Houd er rekening mee dat deze import nog steeds in uitvoering is, meld eventuele fouten die optreden op GitHub:", - "Importer_HipChatEnterprise_Information": "Het geüploade bestand moet een gedecodeerde tar.gz zijn, lees de documentatie voor meer informatie:", "Importer_import_cancelled": "Import geannuleerd.", "Importer_import_failed": "Er is een fout opgetreden tijdens het importeren.", "Importer_importing_channels": "Kanalen aan het importeren.", diff --git a/packages/i18n/src/locales/no.i18n.json b/packages/i18n/src/locales/no.i18n.json index 5bdbf2fb89cc..b551543c37b1 100644 --- a/packages/i18n/src/locales/no.i18n.json +++ b/packages/i18n/src/locales/no.i18n.json @@ -2210,8 +2210,6 @@ "Importer_done": "Importerer komplett!", "Importer_finishing": "Fullfører importen.", "Importer_From_Description": "Importerer data fra {{from}} til Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Vær oppmerksom på at denne importen fortsatt er et pågående arbeid, vennligst rapporter eventuelle feil som oppstår i GitHub:", - "Importer_HipChatEnterprise_Information": "Filen som lastes opp må være en dekryptert tar.gz, vennligst les dokumentasjonen for ytterligere informasjon:", "Importer_import_cancelled": "Import avbrutt.", "Importer_import_failed": "Det oppsto en feil under kjøring av importen.", "Importer_importing_channels": "Importerer kanalene.", diff --git a/packages/i18n/src/locales/pl.i18n.json b/packages/i18n/src/locales/pl.i18n.json index b7d60c54ee2c..58c484e09aa7 100644 --- a/packages/i18n/src/locales/pl.i18n.json +++ b/packages/i18n/src/locales/pl.i18n.json @@ -2369,8 +2369,6 @@ "Importer_finishing": "Kończąc się na import.", "Importer_From_Description": "Import danych {{from}} 's do Rocket.Chat.", "Importer_From_Description_CSV": "Importuje dane CSV do Rocket.Chat. Przesłany plik musi być plikiem ZIP.", - "Importer_HipChatEnterprise_BetaWarning": "Należy pamiętać, że ten import jest nadal w toku, zgłoś wszelkie błędy występujące w GitHub:", - "Importer_HipChatEnterprise_Information": "Przesłany plik musi być odszyfrowanym tar.gz. Aby uzyskać więcej informacji, przeczytaj dokumentację:", "Importer_import_cancelled": "Importowanie anulowane.", "Importer_import_failed": "Wystąpił błąd podczas wykonywania importu.", "Importer_importing_channels": "Importowanie kanałów.", diff --git a/packages/i18n/src/locales/pt-BR.i18n.json b/packages/i18n/src/locales/pt-BR.i18n.json index 67c8f46888ad..318a5d38f617 100644 --- a/packages/i18n/src/locales/pt-BR.i18n.json +++ b/packages/i18n/src/locales/pt-BR.i18n.json @@ -2188,8 +2188,6 @@ "Importer_finishing": "Terminando a importação.", "Importer_From_Description": "Importa dados de {{from}} para o Rocket.Chat.", "Importer_From_Description_CSV": "Importa dados de CSV para o Rocket.Chat. O arquivo importado deve ser um arquivo ZIP.", - "Importer_HipChatEnterprise_BetaWarning": "Saiba que esta importação é ainda um trabalho em andamento; informe quaisquer erros que ocorrerem no GitHub:", - "Importer_HipChatEnterprise_Information": "O arquivo carregado deve ser um tar.gz descriptografado; leia a documentação para obter mais informações:", "Importer_import_cancelled": "Importação cancelada.", "Importer_import_failed": "Ocorreu um erro durante a execução da importação.", "Importer_importing_channels": "Importando os canais.", diff --git a/packages/i18n/src/locales/pt.i18n.json b/packages/i18n/src/locales/pt.i18n.json index 8f4acc81dbdd..da6177d0d799 100644 --- a/packages/i18n/src/locales/pt.i18n.json +++ b/packages/i18n/src/locales/pt.i18n.json @@ -1514,8 +1514,6 @@ "Importer_ExternalUrl_Description": "Você também pode usar um URL para um arquivo acessível publicamente:", "Importer_finishing": "A terminar importação.", "Importer_From_Description": "Importar dados de {{from}} para o Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Lembre-se de que esta importação ainda é um trabalho em andamento, informe quaisquer erros que ocorram no GitHub:", - "Importer_HipChatEnterprise_Information": "O arquivo carregado deve ser um tar.gz descienciado, leia a documentação para obter mais informações:", "Importer_import_cancelled": "Importação cancelada.", "Importer_import_failed": "Ocorreu um erro durante a execução da importação.", "Importer_importing_channels": "A importar os canais.", diff --git a/packages/i18n/src/locales/ro.i18n.json b/packages/i18n/src/locales/ro.i18n.json index aefc4d07065f..29495a860cc4 100644 --- a/packages/i18n/src/locales/ro.i18n.json +++ b/packages/i18n/src/locales/ro.i18n.json @@ -1270,8 +1270,6 @@ "Importer_done": "Import complet!", "Importer_finishing": "Se finalizează import.", "Importer_From_Description": "Importuri {{from}} 's date în Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Rețineți că acest import este încă o operațiune în curs, vă rugăm să raportați orice erori apărute în GitHub:", - "Importer_HipChatEnterprise_Information": "Fișierul încărcat trebuie să fie un tar.gz decriptat, citiți documentația pentru mai multe informații:", "Importer_import_cancelled": "Import anulat.", "Importer_import_failed": "A Apărut o eroare în timpul importului.", "Importer_importing_channels": "Se importă canalele.", diff --git a/packages/i18n/src/locales/ru.i18n.json b/packages/i18n/src/locales/ru.i18n.json index 1829f7f2eb08..340e74f8891b 100644 --- a/packages/i18n/src/locales/ru.i18n.json +++ b/packages/i18n/src/locales/ru.i18n.json @@ -2278,8 +2278,6 @@ "Importer_finishing": "Завершить импорт данных.", "Importer_From_Description": "Импортировать данные из {{from}} в Rocket.Chat.", "Importer_From_Description_CSV": "Импортирует данные файла CSV в Rocket.Chat. Загруженный файл должен быть в формате ZIP.", - "Importer_HipChatEnterprise_BetaWarning": "Имейте в виду, что импорт всё ещё продолжается. Пожалуйста, сообщите о любых возникающих ошибках на GitHub:", - "Importer_HipChatEnterprise_Information": "Загруженный файл должен быть расшифрованным tar.gz, пожалуйста, прочитайте документацию для получения дополнительной информации:", "Importer_import_cancelled": "Импорт данных отменен.", "Importer_import_failed": "Во время импорта данных возникла ошибка.", "Importer_importing_channels": "Импортировать каналы.", diff --git a/packages/i18n/src/locales/sk-SK.i18n.json b/packages/i18n/src/locales/sk-SK.i18n.json index f5bc7bfcbc58..aa2528eb8437 100644 --- a/packages/i18n/src/locales/sk-SK.i18n.json +++ b/packages/i18n/src/locales/sk-SK.i18n.json @@ -1281,8 +1281,6 @@ "Importer_done": "Import je dokončený!", "Importer_finishing": "Dokončenie importu.", "Importer_From_Description": "Importuje {{from}} dáta do Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Majte na pamäti, že tento import je stále prebiehajúcim procesom, nahláste všetky chyby, ktoré sa vyskytli v GitHub:", - "Importer_HipChatEnterprise_Information": "Nahraný súbor musí byť dešifrovaný tar.gz, prečítajte si prosím dokumentáciu pre ďalšie informácie:", "Importer_import_cancelled": "Import bol zrušený.", "Importer_import_failed": "Počas spúšťania importu sa vyskytla chyba.", "Importer_importing_channels": "Importovanie kanálov.", diff --git a/packages/i18n/src/locales/sl-SI.i18n.json b/packages/i18n/src/locales/sl-SI.i18n.json index 668bb94dc2c5..f6cbb8708438 100644 --- a/packages/i18n/src/locales/sl-SI.i18n.json +++ b/packages/i18n/src/locales/sl-SI.i18n.json @@ -1262,8 +1262,6 @@ "Importer_done": "Uvoz končan!", "Importer_finishing": "Končujem uvoz. ", "Importer_From_Description": "Uvozi {{from}} podatki v Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Upoštevajte, da uvoz še kar poteka, prijavite napake, ki so se zgodile v GitHub:", - "Importer_HipChatEnterprise_Information": "Naložena datoteka mora biti dešifrirana tar.gz, za več informacij preberite navodila. ", "Importer_import_cancelled": "Uvoz preklican. ", "Importer_import_failed": "Napaka med uvozom.", "Importer_importing_channels": "Uvažanje kanalov. ", diff --git a/packages/i18n/src/locales/sq.i18n.json b/packages/i18n/src/locales/sq.i18n.json index 312494da2e8d..8274830efc77 100644 --- a/packages/i18n/src/locales/sq.i18n.json +++ b/packages/i18n/src/locales/sq.i18n.json @@ -1270,8 +1270,6 @@ "Importer_done": "Importimi i plotë!", "Importer_finishing": "Përfunduar importin.", "Importer_From_Description": "Importet {{from}} dhënat's në Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Ju lutemi, kini parasysh se ky import ende është një punë në vazhdim, ju lutem raportoni çdo gabim që ndodh në GitHub:", - "Importer_HipChatEnterprise_Information": "Skedari i ngarkuar duhet të jetë tar.gz i dekriptuar, ju lutem lexoni dokumentacionin për informacione të mëtejshme:", "Importer_import_cancelled": "Import anuluar.", "Importer_import_failed": "Ndodhi një gabim gjatë drejtimin e importit.", "Importer_importing_channels": "Importimin e kanaleve.", diff --git a/packages/i18n/src/locales/sr.i18n.json b/packages/i18n/src/locales/sr.i18n.json index e26e8bd3862f..9ddef58a7960 100644 --- a/packages/i18n/src/locales/sr.i18n.json +++ b/packages/i18n/src/locales/sr.i18n.json @@ -1132,8 +1132,6 @@ "Importer_CSV_Information": "ЦСВ увознику је потребан одређени формат, молимо прочитајте документацију како структурирати своју зип датотеку:", "Importer_done": "Увоз завршен!", "Importer_finishing": "Завршавање увоза.", - "Importer_HipChatEnterprise_BetaWarning": "Имајте на уму да је овај увоз и даље посао у току, пријавите грешке које се јављају у ГитХуб-у:", - "Importer_HipChatEnterprise_Information": "Датотека која је отпремљена мора бити дешифрована тар.гз, прочитајте документацију за додатне информације:", "Importer_import_cancelled": "Увоз отказан.", "Importer_import_failed": "Дошло је до грешке приликом увоза.", "Importer_importing_channels": "Увожење канала.", diff --git a/packages/i18n/src/locales/sv.i18n.json b/packages/i18n/src/locales/sv.i18n.json index 4e436fe6c538..646778c274d9 100644 --- a/packages/i18n/src/locales/sv.i18n.json +++ b/packages/i18n/src/locales/sv.i18n.json @@ -2431,8 +2431,6 @@ "Importer_finishing": "Avslutar importen.", "Importer_From_Description": "Importera {{from}}s data till Rocket.Chat.", "Importer_From_Description_CSV": "Importerar CSV-data till Rocket.Chat. Den uppladdade filen måste vara en zip-fil.", - "Importer_HipChatEnterprise_BetaWarning": "Var medveten om att denna import fortfarande är ett pågående arbete, var god rapportera eventuella fel som uppstår i GitHub:", - "Importer_HipChatEnterprise_Information": "Den uppladdade filen måste vara en dekrypterad tar.gz, läs dokumentationen för ytterligare information:", "Importer_import_cancelled": "Import avbruten.", "Importer_import_failed": "Ett fel uppstod under importen.", "Importer_importing_channels": "Importerar kanalerna.", diff --git a/packages/i18n/src/locales/ta-IN.i18n.json b/packages/i18n/src/locales/ta-IN.i18n.json index 7a2c562d4fff..c49b0fd62255 100644 --- a/packages/i18n/src/locales/ta-IN.i18n.json +++ b/packages/i18n/src/locales/ta-IN.i18n.json @@ -1270,8 +1270,6 @@ "Importer_done": "முழுமையான இறக்குமதி!", "Importer_finishing": "இறக்குமதி முடிக்கிறது.", "Importer_From_Description": "இறக்குமதி Rocket.Chat ஒரு 'கள் தரவு {{from}}.", - "Importer_HipChatEnterprise_BetaWarning": "இந்த இறக்குமதி இன்னமும் முன்னேற்றம் அடைந்ததை நினைவில் கொள்ளுங்கள், தயவுசெய்து GitHub இல் ஏற்படும் எந்த பிழைகளையும் தெரிவிக்கவும்:", - "Importer_HipChatEnterprise_Information": "பதிவேற்றிய கோப்பு ஒரு குறியாக்கப்பட்ட tar.gz ஆக இருக்க வேண்டும், மேலும் தகவலுக்கு ஆவணங்களைப் படிக்கவும்:", "Importer_import_cancelled": "இறக்குமதி ரத்துசெய்யப்பட்டது.", "Importer_import_failed": "இறக்குமதி இயங்கும் போது ஒரு பிழை ஏற்பட்டது.", "Importer_importing_channels": "சேனல்கள் இறக்குமதி.", diff --git a/packages/i18n/src/locales/th-TH.i18n.json b/packages/i18n/src/locales/th-TH.i18n.json index 7d393a3034fb..303bc37cfc4b 100644 --- a/packages/i18n/src/locales/th-TH.i18n.json +++ b/packages/i18n/src/locales/th-TH.i18n.json @@ -1265,8 +1265,6 @@ "Importer_CSV_Information": "ตัวนำเข้า CSV ต้องการรูปแบบเฉพาะโปรดอ่านเอกสารสำหรับวิธีจัดโครงสร้างไฟล์ซิปของคุณ:", "Importer_done": "การนำเข้าเสร็จสมบูรณ์!", "Importer_finishing": "เสร็จสิ้นการนำเข้า", - "Importer_HipChatEnterprise_BetaWarning": "โปรดทราบว่าการนำเข้านี้ยังคงเป็นงานระหว่างดำเนินการโปรดรายงานข้อผิดพลาดที่เกิดขึ้นใน GitHub:", - "Importer_HipChatEnterprise_Information": "ไฟล์ที่อัปโหลดต้องเป็น tar.gad ถอดรหัสลับโปรดอ่านเอกสารประกอบสำหรับข้อมูลเพิ่มเติม:", "Importer_import_cancelled": "ยกเลิกการนำเข้าแล้ว", "Importer_import_failed": "เกิดข้อผิดพลาดขณะเรียกใช้งานนำเข้า", "Importer_importing_channels": "การนำเข้าช่อง", diff --git a/packages/i18n/src/locales/tr.i18n.json b/packages/i18n/src/locales/tr.i18n.json index 59b0c8927e23..6297c222ffec 100644 --- a/packages/i18n/src/locales/tr.i18n.json +++ b/packages/i18n/src/locales/tr.i18n.json @@ -1538,8 +1538,6 @@ "Importer_ExternalUrl_Description": "Herkesin erişebileceği dosya için bir URL de kullanabilirsiniz:", "Importer_finishing": "İçe aktarım tamamlanıyor.", "Importer_From_Description": "{{from}} verisini Rocket.Chat'e aktarır.", - "Importer_HipChatEnterprise_BetaWarning": "Bu içe aktarma işlemi halen devam etmekte olan bir çalışma olduğuna dikkat edin, lütfen GitHub'ta oluşan hataları bildirin:", - "Importer_HipChatEnterprise_Information": "Yüklenen dosya, şifresi çözülmüş bir tar.gz olmalıdır; daha fazla bilgi için lütfen belgeleri okuyun:", "Importer_import_cancelled": "İçe aktarım iptal edildi.", "Importer_import_failed": "İçe aktarım sırasında bir hata oluştu.", "Importer_importing_channels": "Kanallar içe aktarılıyor.", diff --git a/packages/i18n/src/locales/uk.i18n.json b/packages/i18n/src/locales/uk.i18n.json index b8e27a4f8c34..08712bb1f2be 100644 --- a/packages/i18n/src/locales/uk.i18n.json +++ b/packages/i18n/src/locales/uk.i18n.json @@ -1683,8 +1683,6 @@ "Importer_ExternalUrl_Description": "Ви також можете використовувати URL-адресу для загальнодоступного файлу:", "Importer_finishing": "Завершення імпорту.", "Importer_From_Description": "Imports {{from}} data в Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Будь ласка, пам'ятайте, що цей імпорт все ще працює, повідомте про всі помилки, які виникають в GitHub:", - "Importer_HipChatEnterprise_Information": "Завантажений файл повинен бути розшифрованим tar.gz, будь ласка, ознайомтеся з документацією для отримання додаткової інформації:", "Importer_import_cancelled": "Імпорт скасований.", "Importer_import_failed": "Сталася помилка під час виконання імпорту.", "Importer_importing_channels": "Імпорт каналів.", diff --git a/packages/i18n/src/locales/vi-VN.i18n.json b/packages/i18n/src/locales/vi-VN.i18n.json index bf073e9c6aee..f16b8dc9de23 100644 --- a/packages/i18n/src/locales/vi-VN.i18n.json +++ b/packages/i18n/src/locales/vi-VN.i18n.json @@ -1364,8 +1364,6 @@ "Importer_done": "Nhập đầy đủ!", "Importer_finishing": "Hoàn thành việc nhập dữ liệu.", "Importer_From_Description": "Nhập dữ liệu {{from}} vào Rocket.Chat.", - "Importer_HipChatEnterprise_BetaWarning": "Xin lưu ý rằng phần nhập dữ liệu này vẫn đang trong quá trình hoàn thiện, hãy báo cáo bất kỳ lỗi nào xảy ra tại GitHub:", - "Importer_HipChatEnterprise_Information": "Tệp được tải lên phải là tệp được giải mã tar.gz, vui lòng đọc tài liệu để biết thêm thông tin:", "Importer_import_cancelled": "Nhập dữ liệu bị hủy.", "Importer_import_failed": "Đã xảy ra lỗi khi chạy.", "Importer_importing_channels": "Nhập các kênh.", diff --git a/packages/i18n/src/locales/zh-HK.i18n.json b/packages/i18n/src/locales/zh-HK.i18n.json index e9821173dc0c..a91346afb586 100644 --- a/packages/i18n/src/locales/zh-HK.i18n.json +++ b/packages/i18n/src/locales/zh-HK.i18n.json @@ -1291,8 +1291,6 @@ "Importer_done": "导入完成!", "Importer_finishing": "完成进口。", "Importer_From_Description": "将{{from}}数据导入Rocket.Chat。", - "Importer_HipChatEnterprise_BetaWarning": "请注意,此导入仍在进行中,请报告GitHub中发生的任何错误:", - "Importer_HipChatEnterprise_Information": "上传的文件必须是解密的tar.gz,请阅读文档以获取更多信息:", "Importer_import_cancelled": "导入已取消。", "Importer_import_failed": "运行导入时发生错误。", "Importer_importing_channels": "导入频道。", diff --git a/packages/i18n/src/locales/zh-TW.i18n.json b/packages/i18n/src/locales/zh-TW.i18n.json index 741132996be6..44baef8a83b7 100644 --- a/packages/i18n/src/locales/zh-TW.i18n.json +++ b/packages/i18n/src/locales/zh-TW.i18n.json @@ -2082,8 +2082,6 @@ "Importer_finishing": "完成了匯入。", "Importer_From_Description": "匯入{{from}}的資料轉換成Rocket.Chat。", "Importer_From_Description_CSV": "匯入 CSV 資料到 Rocket.Chat。上傳的檔案必須為 ZIP 檔。", - "Importer_HipChatEnterprise_BetaWarning": "請注意,此匯入仍在進行中,請報告GitHub中發生的任何錯誤:", - "Importer_HipChatEnterprise_Information": "上傳的文件必須是解密的tar.gz,請閱讀文件以獲取更多訊息:", "Importer_import_cancelled": "匯入已取消。", "Importer_import_failed": "在執行匯入時出錯。", "Importer_importing_channels": "匯入頻道。", diff --git a/packages/i18n/src/locales/zh.i18n.json b/packages/i18n/src/locales/zh.i18n.json index 323da5954332..5f335e2b9c7d 100644 --- a/packages/i18n/src/locales/zh.i18n.json +++ b/packages/i18n/src/locales/zh.i18n.json @@ -1899,8 +1899,6 @@ "Importer_ExternalUrl_Description": "您还可以将URL用于可公开访问的文件:", "Importer_finishing": "导入即将完成。", "Importer_From_Description": "将 {{from}} 数据导入 Rocket.Chat。", - "Importer_HipChatEnterprise_BetaWarning": "请注意,导入功能尚处于开发阶段,如有错误发生请在 GitHub 向我们反馈:", - "Importer_HipChatEnterprise_Information": "上传的文件必须为未加密的 tar.gz 文件,请查阅文档进一步了解相关信息:", "Importer_import_cancelled": "已取消导入。", "Importer_import_failed": "导入过程中发生错误!", "Importer_importing_channels": "正在导入频道。", diff --git a/packages/model-typings/src/models/IImportDataModel.ts b/packages/model-typings/src/models/IImportDataModel.ts index 160eaaf604a0..95eaa8a4ce0d 100644 --- a/packages/model-typings/src/models/IImportDataModel.ts +++ b/packages/model-typings/src/models/IImportDataModel.ts @@ -12,5 +12,4 @@ export interface IImportDataModel extends IBaseModel { checkIfDirectMessagesExists(): Promise; countMessages(): Promise; findChannelImportIdByNameOrImportId(channelIdentifier: string): Promise; - findDMForImportedUsers(...users: Array): Promise; } diff --git a/yarn.lock b/yarn.lock index de477be8048a..c2ff40fec232 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9658,7 +9658,6 @@ __metadata: supports-color: ~7.2.0 suretype: ~2.4.1 swiper: ^9.3.2 - tar-stream: ^1.6.2 template-file: ^6.0.1 textarea-caret: ^3.1.0 tinykeys: ^1.4.0 @@ -39274,7 +39273,7 @@ __metadata: languageName: node linkType: hard -"tar-stream@npm:^1.5.2, tar-stream@npm:^1.6.2": +"tar-stream@npm:^1.5.2": version: 1.6.2 resolution: "tar-stream@npm:1.6.2" dependencies: From 49ca21c710237a74fdffd6627a9008026c037252 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 11 Apr 2024 23:57:14 -0300 Subject: [PATCH 60/80] chore!: Removed Mongo 4.4. support and added 7.0 (#32162) Co-authored-by: Diego Sampaio --- .changeset/fair-seahorses-laugh.md | 13 +++++++++++++ .changeset/fluffy-knives-count.md | 5 +++++ .github/workflows/ci-test-e2e.yml | 8 ++++---- .github/workflows/ci.yml | 8 ++++---- apps/meteor/server/startup/serverRunning.js | 10 +++++----- docker-compose-local.yml | 8 ++++---- 6 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 .changeset/fair-seahorses-laugh.md create mode 100644 .changeset/fluffy-knives-count.md diff --git a/.changeset/fair-seahorses-laugh.md b/.changeset/fair-seahorses-laugh.md new file mode 100644 index 000000000000..8f93695a8e17 --- /dev/null +++ b/.changeset/fair-seahorses-laugh.md @@ -0,0 +1,13 @@ +--- +'@rocket.chat/meteor': major +--- + +As per MongoDB Lifecycle Schedules ([mongodb.com/legal/support-policy/lifecycles](https://www.mongodb.com/legal/support-policy/lifecycles)) we're removing official support to MongoDB version 4.4 that has reached end of life in February 2024. + +We recommend upgrading to at least MongoDB 6.0+, though 5.0 is still a supported version. + +Here are official docs on how to upgrade to some of the supported versions: + +- [mongodb.com/docs/manual/release-notes/5.0-upgrade-replica-set](https://www.mongodb.com/docs/manual/release-notes/5.0-upgrade-replica-set/) +- [mongodb.com/docs/manual/release-notes/6.0-upgrade-replica-set](https://www.mongodb.com/docs/manual/release-notes/6.0-upgrade-replica-set/) +- [mongodb.com/docs/manual/release-notes/7.0-upgrade-replica-set](https://www.mongodb.com/docs/manual/release-notes/7.0-upgrade-replica-set/) diff --git a/.changeset/fluffy-knives-count.md b/.changeset/fluffy-knives-count.md new file mode 100644 index 000000000000..4e4e8aad3631 --- /dev/null +++ b/.changeset/fluffy-knives-count.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": major +--- + +Added MongoDB 7.0 support diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index 31a8bc2ea2b6..f08a4f1876ad 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -29,7 +29,7 @@ on: transporter: type: string mongodb-version: - default: "['4.4', '6.0']" + default: "['5.0', '7.0']" required: false type: string release: @@ -80,8 +80,8 @@ jobs: test: runs-on: ubuntu-20.04 env: - RC_DOCKERFILE: ${{ matrix.mongodb-version == '6.0' && inputs.rc-dockerfile-alpine || inputs.rc-dockerfile }} - RC_DOCKER_TAG: ${{ matrix.mongodb-version == '6.0' && inputs.rc-docker-tag-alpine || inputs.rc-docker-tag }} + RC_DOCKERFILE: ${{ matrix.mongodb-version == '7.0' && inputs.rc-dockerfile-alpine || inputs.rc-dockerfile }} + RC_DOCKER_TAG: ${{ matrix.mongodb-version == '7.0' && inputs.rc-docker-tag-alpine || inputs.rc-docker-tag }} strategy: fail-fast: false @@ -89,7 +89,7 @@ jobs: mongodb-version: ${{ fromJSON(inputs.mongodb-version) }} shard: ${{ fromJSON(inputs.shard) }} - name: MongoDB ${{ matrix.mongodb-version }}${{ inputs.db-watcher-disabled == 'true' && ' [no watchers]' || '' }} (${{ matrix.shard }}/${{ inputs.total-shard }})${{ matrix.mongodb-version == '6.0' && ' - Alpine' || '' }} + name: MongoDB ${{ matrix.mongodb-version }}${{ inputs.db-watcher-disabled == 'true' && ' [no watchers]' || '' }} (${{ matrix.shard }}/${{ inputs.total-shard }})${{ matrix.mongodb-version == '7.0' && ' - Alpine' || '' }} steps: - name: Collect Workflow Telemetry diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 246c34423bb1..390b00946711 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,7 +121,7 @@ jobs: fi; curl -H "Content-Type: application/json" -H "X-Update-Token: $UPDATE_TOKEN" -d \ - "{\"nodeVersion\": \"${{ needs.release-versions.outputs.node-version }}\", \"compatibleMongoVersions\": [\"4.4\", \"5.0\", \"6.0\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"draft\", \"draftAs\": \"$RC_RELEASE\"}" \ + "{\"nodeVersion\": \"${{ needs.release-versions.outputs.node-version }}\", \"compatibleMongoVersions\": [\"5.0\", \"6.0\", \"7.0\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"draft\", \"draftAs\": \"$RC_RELEASE\"}" \ https://releases.rocket.chat/update packages-build: @@ -366,7 +366,7 @@ jobs: release: ee transporter: 'nats://nats:4222' enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }} - mongodb-version: "['4.4']" + mongodb-version: "['5.0']" node-version: ${{ needs.release-versions.outputs.node-version }} lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} @@ -390,7 +390,7 @@ jobs: enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }} shard: '[1, 2, 3, 4, 5]' total-shard: 5 - mongodb-version: "['4.4']" + mongodb-version: "['5.0']" node-version: ${{ needs.release-versions.outputs.node-version }} lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} @@ -802,7 +802,7 @@ jobs: fi; curl -H "Content-Type: application/json" -H "X-Update-Token: $UPDATE_TOKEN" -d \ - "{\"nodeVersion\": \"${{ needs.release-versions.outputs.node-version }}\", \"compatibleMongoVersions\": [\"4.4\", \"5.0\", \"6.0\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"$RC_RELEASE\"}" \ + "{\"nodeVersion\": \"${{ needs.release-versions.outputs.node-version }}\", \"compatibleMongoVersions\": [\"5.0\", \"6.0\", \"7.0\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"$RC_RELEASE\"}" \ https://releases.rocket.chat/update # Makes build fail if the release isn't there diff --git a/apps/meteor/server/startup/serverRunning.js b/apps/meteor/server/startup/serverRunning.js index 8d572036f16a..d642c006c4d2 100644 --- a/apps/meteor/server/startup/serverRunning.js +++ b/apps/meteor/server/startup/serverRunning.js @@ -78,8 +78,8 @@ Meteor.startup(async () => { exitIfNotBypassed(process.env.BYPASS_NODEJS_VALIDATION); } - if (!semver.satisfies(semver.coerce(mongoVersion), '>=4.4.0')) { - msg += ['', '', 'YOUR CURRENT MONGODB VERSION IS NOT SUPPORTED,', 'PLEASE UPGRADE TO VERSION 4.4 OR LATER'].join('\n'); + if (semver.satisfies(semver.coerce(mongoVersion), '<5.0.0')) { + msg += ['', '', 'YOUR CURRENT MONGODB VERSION IS NOT SUPPORTED,', 'PLEASE UPGRADE TO VERSION 5.0 OR LATER'].join('\n'); showErrorBox('SERVER ERROR', msg); exitIfNotBypassed(process.env.BYPASS_MONGO_VALIDATION); @@ -88,11 +88,11 @@ Meteor.startup(async () => { showSuccessBox('SERVER RUNNING', msg); // Deprecation - if (!skipMongoDbDeprecationCheck && !semver.satisfies(semver.coerce(mongoVersion), '>=5.0.0')) { + if (!skipMongoDbDeprecationCheck && semver.satisfies(semver.coerce(mongoVersion), '<6.0.0')) { msg = [ `YOUR CURRENT MONGODB VERSION (${mongoVersion}) IS DEPRECATED.`, - 'IT WILL NOT BE SUPPORTED ON ROCKET.CHAT VERSION 7.0.0 AND GREATER,', - 'PLEASE UPGRADE MONGODB TO VERSION 5.0 OR GREATER', + 'IT WILL NOT BE SUPPORTED ON ROCKET.CHAT VERSION 8.0.0 AND GREATER,', + 'PLEASE UPGRADE MONGODB TO VERSION 6.0 OR GREATER', ].join('\n'); showWarningBox('DEPRECATION', msg); diff --git a/docker-compose-local.yml b/docker-compose-local.yml index 16c64187461a..812899c7d946 100644 --- a/docker-compose-local.yml +++ b/docker-compose-local.yml @@ -112,7 +112,7 @@ services: - 'host.docker.internal:host-gateway' depends_on: - nats - + queue-worker-service: platform: linux/amd64 build: @@ -128,7 +128,7 @@ services: - 'host.docker.internal:host-gateway' depends_on: - nats - + omnichannel-transcript-service: platform: linux/amd64 build: @@ -144,9 +144,9 @@ services: - 'host.docker.internal:host-gateway' depends_on: - nats - + mongo: - image: docker.io/bitnami/mongodb:4.4 + image: docker.io/bitnami/mongodb:7.0 restart: on-failure environment: MONGODB_REPLICA_SET_MODE: primary From 6e1486ecab3b4597f16e8bcb962c2f5686ec17e7 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Fri, 3 May 2024 10:30:41 -0300 Subject: [PATCH 61/80] chore!: Improve permissions check on channels endpoints (#32330) * chore: Improve permission check on channels endpoints --- apps/meteor/app/api/server/v1/channels.ts | 41 ++- apps/meteor/tests/end-to-end/api/channels.ts | 282 +++++++++++++------ 2 files changed, 218 insertions(+), 105 deletions(-) diff --git a/apps/meteor/app/api/server/v1/channels.ts b/apps/meteor/app/api/server/v1/channels.ts index 931cf4be2019..a713bfd29ac6 100644 --- a/apps/meteor/app/api/server/v1/channels.ts +++ b/apps/meteor/app/api/server/v1/channels.ts @@ -27,7 +27,7 @@ import { findUsersOfRoom } from '../../../../server/lib/findUsersOfRoom'; import { hideRoomMethod } from '../../../../server/methods/hideRoom'; import { removeUserFromRoomMethod } from '../../../../server/methods/removeUserFromRoom'; import { canAccessRoomAsync } from '../../../authorization/server'; -import { hasPermissionAsync, hasAtLeastOnePermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { saveRoomSettings } from '../../../channel-settings/server/methods/saveRoomSettings'; import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission'; import { addUsersToRoomMethod } from '../../../lib/server/methods/addUsersToRoom'; @@ -272,6 +272,7 @@ API.v1.addRoute( { authRequired: true, validateParams: isChannelsMessagesProps, + permissionsRequired: ['view-c-room'], }, { async get() { @@ -292,9 +293,6 @@ API.v1.addRoute( ) { return API.v1.unauthorized(); } - if (!(await hasPermissionAsync(this.userId, 'view-c-room'))) { - return API.v1.unauthorized(); - } const { cursor, totalCount } = await Messages.findPaginated(ourQuery, { sort: sort || { ts: -1 }, @@ -477,13 +475,10 @@ API.v1.addRoute( { authRequired: true, validateParams: isChannelsConvertToTeamProps, + permissionsRequired: ['create-team'], }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'create-team'))) { - return API.v1.unauthorized(); - } - const { channelId, channelName } = this.bodyParams; if (!channelId && !channelName) { @@ -855,20 +850,22 @@ API.v1.addRoute( API.v1.addRoute( 'channels.getIntegrations', - { authRequired: true }, { - async get() { - if ( - !(await hasAtLeastOnePermissionAsync(this.userId, [ + authRequired: true, + permissionsRequired: { + GET: { + permissions: [ 'manage-outgoing-integrations', 'manage-own-outgoing-integrations', 'manage-incoming-integrations', 'manage-own-incoming-integrations', - ])) - ) { - return API.v1.unauthorized(); - } - + ], + operation: 'hasAny', + }, + }, + }, + { + async get() { const findResult = await findChannelByIdOrName({ params: this.queryParams, checkedArchived: false, @@ -954,7 +951,12 @@ API.v1.addRoute( API.v1.addRoute( 'channels.list', - { authRequired: true }, + { + authRequired: true, + permissionsRequired: { + GET: { permissions: ['view-c-room', 'view-joined-room'], operation: 'hasAny' }, + }, + }, { async get() { const { offset, count } = await getPaginationItems(this.queryParams); @@ -964,9 +966,6 @@ API.v1.addRoute( const ourQuery: Record = { ...query, t: 'c' }; if (!hasPermissionToSeeAllPublicChannels) { - if (!(await hasPermissionAsync(this.userId, 'view-joined-room'))) { - return API.v1.unauthorized(); - } const roomIds = ( await Subscriptions.findByUserIdAndType(this.userId, 'c', { projection: { rid: 1 }, diff --git a/apps/meteor/tests/end-to-end/api/channels.ts b/apps/meteor/tests/end-to-end/api/channels.ts index 59ba102fe23a..7d4e6f3fa0c6 100644 --- a/apps/meteor/tests/end-to-end/api/channels.ts +++ b/apps/meteor/tests/end-to-end/api/channels.ts @@ -340,21 +340,98 @@ describe('[Channels]', () => { .end(done); }); - it('/channels.list', (done) => { - void request - .get(api('channels.list')) - .set(credentials) - .query({ - roomId: channel._id, - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.property('count'); - expect(res.body).to.have.property('total'); - }) - .end(done); + describe('/channels.list', () => { + let testChannel: IRoom; + before(async () => { + await updatePermission('view-c-room', ['admin', 'user', 'bot', 'app', 'anonymous']); + await updatePermission('view-joined-room', ['guest', 'bot', 'app', 'anonymous']); + testChannel = (await createRoom({ type: 'c', name: `channels.messages.test.${Date.now()}` })).body.channel; + }); + + after(async () => { + await updatePermission('view-c-room', ['admin', 'user', 'bot', 'app', 'anonymous']); + await updatePermission('view-joined-room', ['guest', 'bot', 'app', 'anonymous']); + await deleteRoom({ type: 'c', roomId: testChannel._id }); + }); + + it('should succesfully return a list of channels', async () => { + await request + .get(api('channels.list')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('channels').that.is.an('array'); + expect(res.body).to.have.property('count'); + expect(res.body).to.have.property('total'); + }); + }); + + it('should correctly filter channel by id', async () => { + await request + .get(api('channels.list')) + .set(credentials) + .query({ + query: JSON.stringify({ + _id: testChannel._id, + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('channels').that.is.an('array').of.length(1); + expect(res.body).to.have.property('count', 1); + expect(res.body).to.have.property('total'); + }); + }); + + it('should not be succesful when user does NOT have the permission to view channels or joined rooms', async () => { + await updatePermission('view-c-room', []); + await updatePermission('view-joined-room', []); + await request + .get(api('channels.list')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + + it('should be succesful when user does NOT have the permission to view channels, but can view joined rooms', async () => { + await updatePermission('view-c-room', []); + await updatePermission('view-joined-room', ['admin']); + await request + .get(api('channels.list')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('channels').that.is.an('array'); + expect(res.body).to.have.property('count'); + expect(res.body).to.have.property('total'); + }); + }); + + it('should be succesful when user does NOT have the permission to view joined rooms, but can view channels', async () => { + await updatePermission('view-c-room', ['admin']); + await updatePermission('view-joined-room', []); + await request + .get(api('channels.list')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('channels').that.is.an('array'); + expect(res.body).to.have.property('count'); + expect(res.body).to.have.property('total'); + }); + }); }); it('/channels.list.joined', (done) => { @@ -1400,79 +1477,70 @@ describe('[Channels]', () => { ]); }); - it('should return the list of integrations of created channel and it should contain the integration created by user when the admin DOES have the permission', (done) => { - void updatePermission('manage-incoming-integrations', ['admin']).then(() => { - void request - .get(api('channels.getIntegrations')) - .set(credentials) - .query({ - roomId: createdChannel._id, - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - const integrationCreated = (res.body.integrations as IIntegration[]).find( - (createdIntegration) => createdIntegration._id === integrationCreatedByAnUser._id, - ); - assert.isDefined(integrationCreated); - expect(integrationCreated).to.be.an('object'); - expect(integrationCreated._id).to.be.equal(integrationCreatedByAnUser._id); - expect(res.body).to.have.property('offset'); - expect(res.body).to.have.property('total'); - }) - .end(done); - }); + it('should return the list of integrations of created channel and it should contain the integration created by user when the admin DOES have the permission', async () => { + await updatePermission('manage-incoming-integrations', ['admin']); + await request + .get(api('channels.getIntegrations')) + .set(credentials) + .query({ + roomId: createdChannel._id, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + const integrationCreated = (res.body.integrations as IIntegration[]).find( + (createdIntegration) => createdIntegration._id === integrationCreatedByAnUser._id, + ); + assert.isDefined(integrationCreated); + expect(integrationCreated).to.be.an('object'); + expect(integrationCreated._id).to.be.equal(integrationCreatedByAnUser._id); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); + }); }); - it('should return the list of integrations created by the user only', (done) => { - void updatePermission('manage-own-incoming-integrations', ['admin']).then(() => { - void updatePermission('manage-incoming-integrations', []).then(() => { - void request - .get(api('channels.getIntegrations')) - .set(credentials) - .query({ - roomId: createdChannel._id, - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - const integrationCreated = (res.body.integrations as IIntegration[]).find( - (createdIntegration) => createdIntegration._id === integrationCreatedByAnUser._id, - ); - assert.isUndefined(integrationCreated); - expect(integrationCreated).to.be.equal(undefined); - expect(res.body).to.have.property('offset'); - expect(res.body).to.have.property('total'); - }) - .end(done); + it('should return the list of integrations created by the user only', async () => { + await updatePermission('manage-own-incoming-integrations', ['admin']); + await updatePermission('manage-incoming-integrations', []); + await request + .get(api('channels.getIntegrations')) + .set(credentials) + .query({ + roomId: createdChannel._id, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + const integrationCreated = (res.body.integrations as IIntegration[]).find( + (createdIntegration) => createdIntegration._id === integrationCreatedByAnUser._id, + ); + expect(integrationCreated).to.be.equal(undefined); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('total'); }); - }); }); - it('should return unauthorized error when the user does not have any integrations permissions', (done) => { - void updatePermission('manage-incoming-integrations', []).then(() => { - void updatePermission('manage-own-incoming-integrations', []).then(() => { - void updatePermission('manage-outgoing-integrations', []).then(() => { - void updatePermission('manage-own-outgoing-integrations', []).then(() => { - void request - .get(api('channels.getIntegrations')) - .set(credentials) - .query({ - roomId: createdChannel._id, - }) - .expect('Content-Type', 'application/json') - .expect(403) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); - }) - .end(done); - }); - }); + it('should return unauthorized error when the user does not have any integrations permissions', async () => { + await Promise.all([ + updatePermission('manage-incoming-integrations', []), + updatePermission('manage-own-incoming-integrations', []), + updatePermission('manage-outgoing-integrations', []), + updatePermission('manage-own-outgoing-integrations', []), + ]); + await request + .get(api('channels.getIntegrations')) + .set(credentials) + .query({ + roomId: createdChannel._id, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }); - }); }); }); @@ -2048,7 +2116,7 @@ describe('[Channels]', () => { ]); }); - it('should fail to convert channel if lacking edit-room permission', async () => { + it('should fail to convert channel if lacking create-team permission', async () => { await updatePermission('create-team', []); await updatePermission('edit-room', ['admin']); @@ -2062,7 +2130,7 @@ describe('[Channels]', () => { }); }); - it('should fail to convert channel if lacking create-team permission', async () => { + it('should fail to convert channel if lacking edit-room permission', async () => { await updatePermission('create-team', ['admin']); await updatePermission('edit-room', []); @@ -2243,4 +2311,50 @@ describe('[Channels]', () => { }); }); }); + + describe('[/channels.messages]', () => { + let testChannel: IRoom; + before(async () => { + await updatePermission('view-c-room', ['admin', 'user', 'bot', 'app', 'anonymous']); + testChannel = (await createRoom({ type: 'c', name: `channels.messages.test.${Date.now()}` })).body.channel; + }); + + after(async () => { + await updatePermission('view-c-room', ['admin', 'user', 'bot', 'app', 'anonymous']); + await deleteRoom({ type: 'c', roomId: testChannel._id }); + }); + + it('should return an empty array of messages when inspecting a new room', async () => { + await request + .get(api('channels.messages')) + .set(credentials) + .query({ + roomId: testChannel._id, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('messages').and.to.be.an('array').that.is.empty; + expect(res.body).to.have.property('count', 0); + expect(res.body).to.have.property('total', 0); + }); + }); + + it('should not return message when the user does NOT have the necessary permission', async () => { + await updatePermission('view-c-room', []); + await request + .get(api('channels.messages')) + .set(credentials) + .query({ + roomId: testChannel._id, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + }); }); From c777d78b463a5c130b641c07d79705fbfc2db2ca Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Fri, 3 May 2024 16:50:47 -0300 Subject: [PATCH 62/80] chore: Improve permissions check on cloud endpoints (#32331) --- apps/meteor/app/api/server/v1/cloud.ts | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/apps/meteor/app/api/server/v1/cloud.ts b/apps/meteor/app/api/server/v1/cloud.ts index 257612628bff..c0694deef4fa 100644 --- a/apps/meteor/app/api/server/v1/cloud.ts +++ b/apps/meteor/app/api/server/v1/cloud.ts @@ -2,7 +2,6 @@ import { check } from 'meteor/check'; import { CloudWorkspaceRegistrationError } from '../../../../lib/errors/CloudWorkspaceRegistrationError'; import { SystemLogger } from '../../../../server/lib/logger/system'; -import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { hasRoleAsync } from '../../../authorization/server/functions/hasRole'; import { getCheckoutUrl } from '../../../cloud/server/functions/getCheckoutUrl'; import { getConfirmationPoll } from '../../../cloud/server/functions/getConfirmationPoll'; @@ -20,17 +19,13 @@ import { API } from '../api'; API.v1.addRoute( 'cloud.manualRegister', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['register-on-cloud'] }, { async post() { check(this.bodyParams, { cloudBlob: String, }); - if (!(await hasPermissionAsync(this.userId, 'register-on-cloud'))) { - return API.v1.unauthorized(); - } - const registrationInfo = await retrieveRegistrationStatus(); if (registrationInfo.workspaceRegistered) { @@ -48,7 +43,7 @@ API.v1.addRoute( API.v1.addRoute( 'cloud.createRegistrationIntent', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-cloud'] }, { async post() { check(this.bodyParams, { @@ -56,10 +51,6 @@ API.v1.addRoute( email: String, }); - if (!(await hasPermissionAsync(this.userId, 'manage-cloud'))) { - return API.v1.unauthorized(); - } - const intentData = await startRegisterWorkspaceSetupWizard(this.bodyParams.resend, this.bodyParams.email); if (intentData) { @@ -73,13 +64,9 @@ API.v1.addRoute( API.v1.addRoute( 'cloud.registerPreIntent', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-cloud'] }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'manage-cloud'))) { - return API.v1.unauthorized(); - } - return API.v1.success({ offline: !(await registerPreIntentWorkspaceWizard()) }); }, }, @@ -87,7 +74,7 @@ API.v1.addRoute( API.v1.addRoute( 'cloud.confirmationPoll', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-cloud'] }, { async get() { const { deviceCode } = this.queryParams; @@ -95,10 +82,6 @@ API.v1.addRoute( deviceCode: String, }); - if (!(await hasPermissionAsync(this.userId, 'manage-cloud'))) { - return API.v1.unauthorized(); - } - if (!deviceCode) { return API.v1.failure('Invalid query'); } From efcfd20ff70091cda8617d620b3a2aa56dd8a3cc Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Fri, 3 May 2024 17:05:32 -0300 Subject: [PATCH 63/80] chore: Improve permissions check on instances endpoints (#32334) --- apps/meteor/app/api/server/v1/instances.ts | 7 +------ apps/meteor/tests/end-to-end/api/miscellaneous.ts | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/meteor/app/api/server/v1/instances.ts b/apps/meteor/app/api/server/v1/instances.ts index e5404ab3e53c..47f98c856f44 100644 --- a/apps/meteor/app/api/server/v1/instances.ts +++ b/apps/meteor/app/api/server/v1/instances.ts @@ -1,7 +1,6 @@ import { InstanceStatus } from '@rocket.chat/models'; import { isRunningMs } from '../../../../server/lib/isRunningMs'; -import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { API } from '../api'; import { getInstanceList } from '../helpers/getInstanceList'; @@ -15,13 +14,9 @@ const getConnections = (() => { API.v1.addRoute( 'instances.get', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['view-statistics'] }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'view-statistics'))) { - return API.v1.unauthorized(); - } - const instanceRecords = await InstanceStatus.find().toArray(); const connections = await getConnections(); diff --git a/apps/meteor/tests/end-to-end/api/miscellaneous.ts b/apps/meteor/tests/end-to-end/api/miscellaneous.ts index 613a874ecd8c..185c922c008d 100644 --- a/apps/meteor/tests/end-to-end/api/miscellaneous.ts +++ b/apps/meteor/tests/end-to-end/api/miscellaneous.ts @@ -540,7 +540,7 @@ describe('miscellaneous', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); From d461951d7ec2a188c6ba2252dfafe6660faec2a1 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Fri, 3 May 2024 17:29:50 -0300 Subject: [PATCH 64/80] chore: Improve permissions check on LDAP endpoints (#32335) --- apps/meteor/app/api/server/v1/ldap.ts | 13 +----- apps/meteor/tests/end-to-end/api/LDAP.ts | 55 +++++++++++++++++++++++- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/apps/meteor/app/api/server/v1/ldap.ts b/apps/meteor/app/api/server/v1/ldap.ts index 9a057c9b0afc..4b112cfbf335 100644 --- a/apps/meteor/app/api/server/v1/ldap.ts +++ b/apps/meteor/app/api/server/v1/ldap.ts @@ -2,23 +2,18 @@ import { LDAP } from '@rocket.chat/core-services'; import { Match, check } from 'meteor/check'; import { SystemLogger } from '../../../../server/lib/logger/system'; -import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { settings } from '../../../settings/server'; import { API } from '../api'; API.v1.addRoute( 'ldap.testConnection', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['test-admin-options'] }, { async post() { if (!this.userId) { throw new Error('error-invalid-user'); } - if (!(await hasPermissionAsync(this.userId, 'test-admin-options'))) { - throw new Error('error-not-authorized'); - } - if (settings.get('LDAP_Enable') !== true) { throw new Error('LDAP_disabled'); } @@ -39,7 +34,7 @@ API.v1.addRoute( API.v1.addRoute( 'ldap.testSearch', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['test-admin-options'] }, { async post() { check( @@ -53,10 +48,6 @@ API.v1.addRoute( throw new Error('error-invalid-user'); } - if (!(await hasPermissionAsync(this.userId, 'test-admin-options'))) { - throw new Error('error-not-authorized'); - } - if (settings.get('LDAP_Enable') !== true) { throw new Error('LDAP_disabled'); } diff --git a/apps/meteor/tests/end-to-end/api/LDAP.ts b/apps/meteor/tests/end-to-end/api/LDAP.ts index fc5c9d127836..d9ac0c65b8ca 100644 --- a/apps/meteor/tests/end-to-end/api/LDAP.ts +++ b/apps/meteor/tests/end-to-end/api/LDAP.ts @@ -1,10 +1,12 @@ import { expect } from 'chai'; -import { before, describe, it } from 'mocha'; +import { before, after, describe, it } from 'mocha'; import type { Response } from 'supertest'; import { getCredentials, api, request, credentials } from '../../data/api-data'; +import { updatePermission } from '../../data/permissions.helper'; -describe('LDAP', () => { +describe('LDAP', function () { + this.retries(0); before((done) => getCredentials(done)); describe('[/ldap.syncNow]', () => { @@ -42,4 +44,53 @@ describe('LDAP', () => { }); }); }); + + describe('[/ldap.testSearch]', () => { + before(async () => { + return updatePermission('test-admin-options', ['admin']); + }); + + after(async () => { + return updatePermission('test-admin-options', ['admin']); + }); + + it('should not allow testing LDAP search if user does NOT have the test-admin-options permission', async () => { + await updatePermission('test-admin-options', []); + await request + .post(api('ldap.testSearch')) + .set(credentials) + .send({ + username: 'test-search', + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + }); + + describe('[/ldap.testConnection]', () => { + before(async () => { + return updatePermission('test-admin-options', ['admin']); + }); + + after(async () => { + return updatePermission('test-admin-options', ['admin']); + }); + + it('should not allow testing LDAP connection if user does NOT have the test-admin-options permission', async () => { + await updatePermission('test-admin-options', []); + await request + .post(api('ldap.testConnection')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + }); }); From a3d1be99b340cba4f1d4ed9cde5541afcb4b9310 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Fri, 3 May 2024 17:30:48 -0300 Subject: [PATCH 65/80] chore!: Improve permissions check on mailer endpoints (#32336) --- apps/meteor/app/api/server/v1/mailer.ts | 6 +--- .../end-to-end/api/livechat/12-mailer.ts | 32 +++++++++++++++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/apps/meteor/app/api/server/v1/mailer.ts b/apps/meteor/app/api/server/v1/mailer.ts index 767868090b91..56229e26dc31 100644 --- a/apps/meteor/app/api/server/v1/mailer.ts +++ b/apps/meteor/app/api/server/v1/mailer.ts @@ -1,6 +1,5 @@ import { isMailerProps, isMailerUnsubscribeProps } from '@rocket.chat/rest-typings'; -import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { API } from '../api'; API.v1.addRoute( @@ -8,13 +7,10 @@ API.v1.addRoute( { authRequired: true, validateParams: isMailerProps, + permissionsRequired: ['send-mail'], }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'send-mail'))) { - throw new Error('error-not-allowed'); - } - const { from, subject, body, dryrun, query } = this.bodyParams; const result = await Meteor.callAsync('Mailer.sendMail', from, subject, body, Boolean(dryrun), query); diff --git a/apps/meteor/tests/end-to-end/api/livechat/12-mailer.ts b/apps/meteor/tests/end-to-end/api/livechat/12-mailer.ts index 01a47594620d..c9bdaa613985 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/12-mailer.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/12-mailer.ts @@ -1,13 +1,22 @@ import { expect } from 'chai'; -import { before, describe, it } from 'mocha'; +import { before, after, describe, it } from 'mocha'; import type { Response } from 'supertest'; import { api, request, credentials, getCredentials } from '../../../data/api-data'; +import { updatePermission } from '../../../data/permissions.helper'; describe('Mailer', () => { before((done) => getCredentials(done)); - describe('POST mailer', () => { + describe('POST mailer', async () => { + before(async () => { + return updatePermission('send-mail', ['admin']); + }); + + after(async () => { + return updatePermission('send-mail', ['admin']); + }); + it('should send an email if the payload is correct', async () => { await request .post(api('mailer')) @@ -58,6 +67,25 @@ describe('Mailer', () => { expect(res.body).to.have.property('success', false); }); }); + it('should throw an error if user does NOT have the send-mail permission', async () => { + await updatePermission('send-mail', []); + await request + .post(api('mailer')) + .set(credentials) + .send({ + from: 'test-mail@test.com', + subject: 'Test email subject', + body: 'Test email body', + dryrun: true, + query: '', + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); }); }); From 2dfd41b693b96d8e3a79d3b6977789b193bb6c2c Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Mon, 6 May 2024 21:24:13 -0300 Subject: [PATCH 66/80] chore: Improve permissions check on users endpoints (#32353) --- apps/meteor/app/api/server/v1/users.ts | 38 +++++++---------------- apps/meteor/tests/end-to-end/api/users.ts | 11 ++++--- 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/apps/meteor/app/api/server/v1/users.ts b/apps/meteor/app/api/server/v1/users.ts index 7ae585b89dfa..15f4d58ef011 100644 --- a/apps/meteor/app/api/server/v1/users.ts +++ b/apps/meteor/app/api/server/v1/users.ts @@ -323,13 +323,9 @@ API.v1.addRoute( API.v1.addRoute( 'users.delete', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['delete-user'] }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'delete-user'))) { - return API.v1.unauthorized(); - } - const user = await getUserFromParams(this.bodyParams); const { confirmRelinquish = false } = this.bodyParams; @@ -364,16 +360,15 @@ API.v1.addRoute( API.v1.addRoute( 'users.setActiveStatus', - { authRequired: true, validateParams: isUserSetActiveStatusParamsPOST }, + { + authRequired: true, + validateParams: isUserSetActiveStatusParamsPOST, + permissionsRequired: { + POST: { permissions: ['edit-other-user-active-status', 'manage-moderation-actions'], operation: 'hasAny' }, + }, + }, { async post() { - if ( - !(await hasPermissionAsync(this.userId, 'edit-other-user-active-status')) && - !(await hasPermissionAsync(this.userId, 'manage-moderation-actions')) - ) { - return API.v1.unauthorized(); - } - const { userId, activeStatus, confirmRelinquish = false } = this.bodyParams; await Meteor.callAsync('setUserActiveStatus', userId, activeStatus, confirmRelinquish); @@ -390,13 +385,9 @@ API.v1.addRoute( API.v1.addRoute( 'users.deactivateIdle', - { authRequired: true, validateParams: isUserDeactivateIdleParamsPOST }, + { authRequired: true, validateParams: isUserDeactivateIdleParamsPOST, permissionsRequired: ['edit-other-user-active-status'] }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'edit-other-user-active-status'))) { - return API.v1.unauthorized(); - } - const { daysIdle, role = 'user' } = this.bodyParams; const lastLoggedIn = new Date(); @@ -468,13 +459,10 @@ API.v1.addRoute( { authRequired: true, queryOperations: ['$or', '$and'], + permissionsRequired: ['view-d-room'], }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'view-d-room'))) { - return API.v1.unauthorized(); - } - if ( settings.get('API_Apply_permission_view-outside-room_on_users-list') && !(await hasPermissionAsync(this.userId, 'view-outside-room')) @@ -824,13 +812,9 @@ API.v1.addRoute( API.v1.addRoute( 'users.getPersonalAccessTokens', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['create-personal-access-tokens'] }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'create-personal-access-tokens'))) { - throw new Meteor.Error('not-authorized', 'Not Authorized'); - } - const user = (await Users.getLoginTokensByUserId(this.userId).toArray())[0] as unknown as IUser | undefined; const isPersonalAccessToken = (loginToken: ILoginToken | IPersonalAccessToken): loginToken is IPersonalAccessToken => diff --git a/apps/meteor/tests/end-to-end/api/users.ts b/apps/meteor/tests/end-to-end/api/users.ts index d6112dd2416b..265e41698aa3 100644 --- a/apps/meteor/tests/end-to-end/api/users.ts +++ b/apps/meteor/tests/end-to-end/api/users.ts @@ -2944,7 +2944,7 @@ describe('[Users]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }); }); @@ -3207,10 +3207,10 @@ describe('[Users]', () => { .get(api('users.getPersonalAccessTokens')) .set(credentials) .expect('Content-Type', 'application/json') - .expect(400) + .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body.errorType).to.be.equal('not-authorized'); + expect(res.body.error).to.be.equal('User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); @@ -3331,6 +3331,7 @@ describe('[Users]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); @@ -3347,6 +3348,7 @@ describe('[Users]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); @@ -3363,6 +3365,7 @@ describe('[Users]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); @@ -3577,7 +3580,7 @@ describe('[Users]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); From 05587e1721dc3cd54602f7e66288127a212d87c7 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Tue, 7 May 2024 12:54:20 -0300 Subject: [PATCH 67/80] chore!: Improve permissions check on groups endpoints (#32332) --- apps/meteor/app/api/server/v1/groups.ts | 31 +++++------- apps/meteor/tests/end-to-end/api/groups.ts | 58 ++++++++++++---------- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/apps/meteor/app/api/server/v1/groups.ts b/apps/meteor/app/api/server/v1/groups.ts index 34deb57304fc..df03e38dc147 100644 --- a/apps/meteor/app/api/server/v1/groups.ts +++ b/apps/meteor/app/api/server/v1/groups.ts @@ -9,11 +9,7 @@ import { findUsersOfRoom } from '../../../../server/lib/findUsersOfRoom'; import { hideRoomMethod } from '../../../../server/methods/hideRoom'; import { removeUserFromRoomMethod } from '../../../../server/methods/removeUserFromRoom'; import { canAccessRoomAsync, roomAccessAttributes } from '../../../authorization/server'; -import { - hasAllPermissionAsync, - hasAtLeastOnePermissionAsync, - hasPermissionAsync, -} from '../../../authorization/server/functions/hasPermission'; +import { hasAllPermissionAsync, hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { saveRoomSettings } from '../../../channel-settings/server/methods/saveRoomSettings'; import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission'; import { createPrivateGroupMethod } from '../../../lib/server/methods/createPrivateGroup'; @@ -412,20 +408,22 @@ API.v1.addRoute( API.v1.addRoute( 'groups.getIntegrations', - { authRequired: true }, { - async get() { - if ( - !(await hasAtLeastOnePermissionAsync(this.userId, [ + authRequired: true, + permissionsRequired: { + GET: { + permissions: [ 'manage-outgoing-integrations', 'manage-own-outgoing-integrations', 'manage-incoming-integrations', 'manage-own-incoming-integrations', - ])) - ) { - return API.v1.unauthorized(); - } - + ], + operation: 'hasAny', + }, + }, + }, + { + async get() { const findResult = await findPrivateGroupByIdOrName({ params: this.queryParams, userId: this.userId, @@ -670,12 +668,9 @@ API.v1.addRoute( API.v1.addRoute( 'groups.listAll', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['view-room-administration'] }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'view-room-administration'))) { - return API.v1.unauthorized(); - } const { offset, count } = await getPaginationItems(this.queryParams); const { sort, fields, query } = await this.parseJsonQuery(); const ourQuery = Object.assign({}, query, { t: 'p' as RoomType }); diff --git a/apps/meteor/tests/end-to-end/api/groups.ts b/apps/meteor/tests/end-to-end/api/groups.ts index 39fd30a3ae2f..af22c65c2a84 100644 --- a/apps/meteor/tests/end-to-end/api/groups.ts +++ b/apps/meteor/tests/end-to-end/api/groups.ts @@ -1154,33 +1154,37 @@ describe('[Groups]', () => { }); describe('/groups.listAll', () => { - it('should fail if the user doesnt have view-room-administration permission', (done) => { - void updatePermission('view-room-administration', []).then(() => { - void request - .get(api('groups.listAll')) - .set(credentials) - .expect('Content-Type', 'application/json') - .expect(403) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); - }) - .end(done); - }); + before(async () => { + return updatePermission('view-room-administration', ['admin']); }); - it('should succeed if user has view-room-administration permission', (done) => { - void updatePermission('view-room-administration', ['admin']).then(() => { - void request - .get(api('groups.listAll')) - .set(credentials) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.property('groups').and.to.be.an('array'); - }) - .end(done); - }); + + after(async () => { + return updatePermission('view-room-administration', ['admin']); + }); + + it('should succeed if user has view-room-administration permission', async () => { + await request + .get(api('groups.listAll')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('groups').and.to.be.an('array'); + }); + }); + + it('should fail if the user doesnt have view-room-administration permission', async () => { + await updatePermission('view-room-administration', []); + await request + .get(api('groups.listAll')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); }); }); @@ -1345,7 +1349,7 @@ describe('[Groups]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }); }); }); From 45c0da411f7a85c4a9a17b802c4f7eb203084de3 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Tue, 7 May 2024 15:13:42 -0300 Subject: [PATCH 68/80] chore!: Improve permissions check on integrations endpoints (#32355) --- apps/meteor/app/api/server/v1/integrations.ts | 54 ++++++++------- .../end-to-end/api/incoming-integrations.ts | 41 +++++------ .../end-to-end/api/outgoing-integrations.ts | 69 +++++++++---------- 3 files changed, 81 insertions(+), 83 deletions(-) diff --git a/apps/meteor/app/api/server/v1/integrations.ts b/apps/meteor/app/api/server/v1/integrations.ts index f7eb9e5a1467..5306e7fbbea3 100644 --- a/apps/meteor/app/api/server/v1/integrations.ts +++ b/apps/meteor/app/api/server/v1/integrations.ts @@ -11,7 +11,6 @@ import { Match, check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; import type { Filter } from 'mongodb'; -import { hasAtLeastOnePermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { mountIntegrationHistoryQueryBasedOnPermissions, mountIntegrationQueryBasedOnPermissions, @@ -43,15 +42,17 @@ API.v1.addRoute( API.v1.addRoute( 'integrations.history', - { authRequired: true, validateParams: isIntegrationsHistoryProps }, + { + authRequired: true, + validateParams: isIntegrationsHistoryProps, + permissionsRequired: { + GET: { permissions: ['manage-outgoing-integrations', 'manage-own-outgoing-integrations'], operation: 'hasAny' }, + }, + }, { async get() { const { userId, queryParams } = this; - if (!(await hasAtLeastOnePermissionAsync(userId, ['manage-outgoing-integrations', 'manage-own-outgoing-integrations']))) { - return API.v1.unauthorized(); - } - if (!queryParams.id || queryParams.id.trim() === '') { return API.v1.failure('Invalid integration id.'); } @@ -83,20 +84,22 @@ API.v1.addRoute( API.v1.addRoute( 'integrations.list', - { authRequired: true }, { - async get() { - if ( - !(await hasAtLeastOnePermissionAsync(this.userId, [ + authRequired: true, + permissionsRequired: { + GET: { + permissions: [ 'manage-outgoing-integrations', 'manage-own-outgoing-integrations', 'manage-incoming-integrations', 'manage-own-incoming-integrations', - ])) - ) { - return API.v1.unauthorized(); - } - + ], + operation: 'hasAny', + }, + }, + }, + { + async get() { const { offset, count } = await getPaginationItems(this.queryParams); const { sort, fields: projection, query } = await this.parseJsonQuery(); @@ -124,20 +127,23 @@ API.v1.addRoute( API.v1.addRoute( 'integrations.remove', - { authRequired: true, validateParams: isIntegrationsRemoveProps }, { - async post() { - if ( - !(await hasAtLeastOnePermissionAsync(this.userId, [ + authRequired: true, + validateParams: isIntegrationsRemoveProps, + permissionsRequired: { + POST: { + permissions: [ 'manage-outgoing-integrations', 'manage-own-outgoing-integrations', 'manage-incoming-integrations', 'manage-own-incoming-integrations', - ])) - ) { - return API.v1.unauthorized(); - } - + ], + operation: 'hasAny', + }, + }, + }, + { + async post() { const { bodyParams } = this; let integration: IIntegration | null = null; diff --git a/apps/meteor/tests/end-to-end/api/incoming-integrations.ts b/apps/meteor/tests/end-to-end/api/incoming-integrations.ts index ff475945a9ac..814f246623bb 100644 --- a/apps/meteor/tests/end-to-end/api/incoming-integrations.ts +++ b/apps/meteor/tests/end-to-end/api/incoming-integrations.ts @@ -308,7 +308,7 @@ describe('[Incoming Integrations]', () => { }); describe('[/integrations.history]', () => { - it('should return an error when trying to get history of incoming integrations', (done) => { + it('should return an error when trying to get history of incoming integrations if user does NOT have enough permissions', (done) => { void request .get(api('integrations.history')) .set(credentials) @@ -319,7 +319,7 @@ describe('[Incoming Integrations]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); @@ -397,25 +397,22 @@ describe('[Incoming Integrations]', () => { }); }); - it('should return unauthorized error when the user does not have any integrations permissions', (done) => { - void updatePermission('manage-incoming-integrations', []).then(() => { - void updatePermission('manage-own-incoming-integrations', []).then(() => { - void updatePermission('manage-outgoing-integrations', []).then(() => { - void updatePermission('manage-outgoing-integrations', []).then(() => { - void request - .get(api('integrations.list')) - .set(credentials) - .expect('Content-Type', 'application/json') - .expect(403) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); - }) - .end(done); - }); - }); + it('should return unauthorized error when the user does not have any integrations permissions', async () => { + await Promise.all([ + updatePermission('manage-incoming-integrations', []), + updatePermission('manage-own-incoming-integrations', []), + updatePermission('manage-outgoing-integrations', []), + updatePermission('manage-outgoing-integrations', []), + ]); + await request + .get(api('integrations.list')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }); - }); }); }); @@ -578,7 +575,7 @@ describe('[Incoming Integrations]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); @@ -597,7 +594,7 @@ describe('[Incoming Integrations]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); diff --git a/apps/meteor/tests/end-to-end/api/outgoing-integrations.ts b/apps/meteor/tests/end-to-end/api/outgoing-integrations.ts index 5ed7f8604db1..76a67c8b330d 100644 --- a/apps/meteor/tests/end-to-end/api/outgoing-integrations.ts +++ b/apps/meteor/tests/end-to-end/api/outgoing-integrations.ts @@ -289,47 +289,42 @@ describe('[Outgoing Integrations]', () => { }); }); - it('should return unauthorized error when the user does not have any integrations permissions', (done) => { - void updatePermission('manage-incoming-integrations', []).then(() => { - void updatePermission('manage-own-incoming-integrations', []).then(() => { - void updatePermission('manage-outgoing-integrations', []).then(() => { - void updatePermission('manage-outgoing-integrations', []).then(() => { - void request - .get(api('integrations.list')) - .set(credentials) - .expect('Content-Type', 'application/json') - .expect(403) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); - }) - .end(done); - }); - }); + it('should return unauthorized error when the user does not have any integrations permissions', async () => { + await Promise.all([ + updatePermission('manage-incoming-integrations', []), + updatePermission('manage-own-incoming-integrations', []), + updatePermission('manage-outgoing-integrations', []), + updatePermission('manage-outgoing-integrations', []), + ]); + + await request + .get(api('integrations.list')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }); - }); }); }); describe('[/integrations.history]', () => { - it('should return an error when the user DOES NOT the necessary permission', (done) => { - void updatePermission('manage-outgoing-integrations', []).then(() => { - void updatePermission('manage-own-outgoing-integrations', []).then(() => { - void request - .get(api('integrations.history')) - .set(credentials) - .query({ - id: integration._id, - }) - .expect('Content-Type', 'application/json') - .expect(403) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); - }) - .end(done); + it('should return an error when the user DOES NOT the necessary permission', async () => { + await updatePermission('manage-outgoing-integrations', []); + await updatePermission('manage-own-outgoing-integrations', []); + await request + .get(api('integrations.history')) + .set(credentials) + .query({ + id: integration._id, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }); - }); }); it('should return the history of outgoing integrations', (done) => { @@ -467,7 +462,7 @@ describe('[Outgoing Integrations]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); @@ -486,7 +481,7 @@ describe('[Outgoing Integrations]', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); From 605a639d091ec7c3259b38c46a3413dc83e465ec Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Thu, 9 May 2024 17:48:28 -0300 Subject: [PATCH 69/80] chore!: Improve permissions check on oauth-apps endpoints (#32338) Co-authored-by: Marcos Spessatto Defendi --- apps/meteor/app/api/server/v1/oauthapps.ts | 28 +--- apps/meteor/tests/end-to-end/api/oauthapps.ts | 131 ++++++++++++------ 2 files changed, 92 insertions(+), 67 deletions(-) diff --git a/apps/meteor/app/api/server/v1/oauthapps.ts b/apps/meteor/app/api/server/v1/oauthapps.ts index 034a73f54104..d338eb6ee33f 100644 --- a/apps/meteor/app/api/server/v1/oauthapps.ts +++ b/apps/meteor/app/api/server/v1/oauthapps.ts @@ -1,20 +1,15 @@ import { OAuthApps } from '@rocket.chat/models'; import { isUpdateOAuthAppParams, isOauthAppsGetParams, isOauthAppsAddParams, isDeleteOAuthAppParams } from '@rocket.chat/rest-typings'; -import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; import { addOAuthApp } from '../../../oauth2-server-config/server/admin/functions/addOAuthApp'; import { API } from '../api'; API.v1.addRoute( 'oauth-apps.list', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-oauth-apps'] }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'manage-oauth-apps'))) { - throw new Error('error-not-allowed'); - } - return API.v1.success({ oauthApps: await OAuthApps.find().toArray(), }); @@ -24,13 +19,9 @@ API.v1.addRoute( API.v1.addRoute( 'oauth-apps.get', - { authRequired: true, validateParams: isOauthAppsGetParams }, + { authRequired: true, validateParams: isOauthAppsGetParams, permissionsRequired: ['manage-oauth-apps'] }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'manage-oauth-apps'))) { - return API.v1.unauthorized(); - } - const oauthApp = await OAuthApps.findOneAuthAppByIdOrClientId(this.queryParams); if (!oauthApp) { @@ -53,13 +44,10 @@ API.v1.addRoute( { authRequired: true, validateParams: isUpdateOAuthAppParams, + permissionsRequired: ['manage-oauth-apps'], }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'manage-oauth-apps'))) { - return API.v1.unauthorized(); - } - const { appId } = this.bodyParams; const result = await Meteor.callAsync('updateOAuthApp', appId, this.bodyParams); @@ -74,13 +62,10 @@ API.v1.addRoute( { authRequired: true, validateParams: isDeleteOAuthAppParams, + permissionsRequired: ['manage-oauth-apps'], }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'manage-oauth-apps'))) { - return API.v1.unauthorized(); - } - const { appId } = this.bodyParams; const result = await Meteor.callAsync('deleteOAuthApp', appId); @@ -95,13 +80,10 @@ API.v1.addRoute( { authRequired: true, validateParams: isOauthAppsAddParams, + permissionsRequired: ['manage-oauth-apps'], }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'manage-oauth-apps'))) { - return API.v1.unauthorized(); - } - const application = await addOAuthApp(this.bodyParams, this.userId); return API.v1.success({ application }); diff --git a/apps/meteor/tests/end-to-end/api/oauthapps.ts b/apps/meteor/tests/end-to-end/api/oauthapps.ts index 7bffa3297bfc..4f9bd8aa1418 100644 --- a/apps/meteor/tests/end-to-end/api/oauthapps.ts +++ b/apps/meteor/tests/end-to-end/api/oauthapps.ts @@ -27,10 +27,10 @@ describe('[OAuthApps]', () => { void request .get(api('oauth-apps.list')) .set(credentials) - .expect(400) + .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body.error).to.be.equal('error-not-allowed'); + expect(res.body.error).to.be.equal('User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); @@ -77,33 +77,29 @@ describe('[OAuthApps]', () => { }) .end(done); }); - it('should return a 403 Forbidden error when the user does not have the necessary permission by client id', (done) => { - void updatePermission('manage-oauth-apps', []).then(() => { - void request - .get(api('oauth-apps.get')) - .query({ clientId: 'zapier' }) - .set(credentials) - .expect(403) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body.error).to.be.equal('unauthorized'); - }) - .end(done); - }); + it('should return a 403 Forbidden error when the user does not have the necessary permission by client id', async () => { + await updatePermission('manage-oauth-apps', []); + await request + .get(api('oauth-apps.get')) + .query({ clientId: 'zapier' }) + .set(credentials) + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body.error).to.be.equal('User does not have the permissions required for this action [error-unauthorized]'); + }); }); - it('should return a 403 Forbidden error when the user does not have the necessary permission by app id', (done) => { - void updatePermission('manage-oauth-apps', []).then(() => { - void request - .get(api('oauth-apps.get')) - .query({ appId: 'zapier' }) - .set(credentials) - .expect(403) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body.error).to.be.equal('unauthorized'); - }) - .end(done); - }); + it('should return a 403 Forbidden error when the user does not have the necessary permission by app id', async () => { + await updatePermission('manage-oauth-apps', []); + await request + .get(api('oauth-apps.get')) + .query({ appId: 'zapier' }) + .set(credentials) + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body.error).to.be.equal('User does not have the permissions required for this action [error-unauthorized]'); + }); }); }); @@ -120,7 +116,11 @@ describe('[OAuthApps]', () => { active: false, }) .expect('Content-Type', 'application/json') - .expect(403); + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body.error).to.be.equal('User does not have the permissions required for this action [error-unauthorized]'); + }); await updatePermission('manage-oauth-apps', ['admin']); }); @@ -203,11 +203,12 @@ describe('[OAuthApps]', () => { describe('[/oauth-apps.update]', () => { let appId: IOAuthApps['_id']; - before((done) => { + before(async () => { + await updatePermission('manage-oauth-apps', ['admin']); const name = 'test-oauth-app'; const redirectUri = 'https://test.com'; const active = true; - void request + const res = await request .post(api('oauth-apps.create')) .set(credentials) .send({ @@ -216,12 +217,13 @@ describe('[OAuthApps]', () => { active, }) .expect('Content-Type', 'application/json') - .expect(200) - .end((_err, res) => { - appId = res.body.application._id; - createdAppsIds.push(appId); - done(); - }); + .expect(200); + appId = res.body.application._id; + createdAppsIds.push(appId); + }); + + after(async () => { + await updatePermission('manage-oauth-apps', ['admin']); }); it("should update an app's name, its Active and Redirect URI fields correctly by its id", async () => { @@ -247,16 +249,40 @@ describe('[OAuthApps]', () => { expect(res.body).to.have.property('name', name); }); }); + + it('should fail updating an app if user does NOT have the manage-oauth-apps permission', async () => { + const name = `new app ${Date.now()}`; + const redirectUri = 'http://localhost:3000'; + const active = false; + + await updatePermission('manage-oauth-apps', []); + await request + .post(api(`oauth-apps.update`)) + .set(credentials) + .send({ + appId, + name, + redirectUri, + active, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body.error).to.be.equal('User does not have the permissions required for this action [error-unauthorized]'); + }); + }); }); describe('[/oauth-apps.delete]', () => { let appId: IOAuthApps['_id']; - before((done) => { + before(async () => { + await updatePermission('manage-oauth-apps', ['admin']); const name = 'test-oauth-app'; const redirectUri = 'https://test.com'; const active = true; - void request + const res = await request .post(api('oauth-apps.create')) .set(credentials) .send({ @@ -265,11 +291,12 @@ describe('[OAuthApps]', () => { active, }) .expect('Content-Type', 'application/json') - .expect(200) - .end((_err, res) => { - appId = res.body.application._id; - done(); - }); + .expect(200); + appId = res.body.application._id; + }); + + after(async () => { + await updatePermission('manage-oauth-apps', ['admin']); }); it('should delete an app by its id', async () => { @@ -285,5 +312,21 @@ describe('[OAuthApps]', () => { expect(res.body).to.equals(true); }); }); + + it('should fail deleting an app by its id if user does NOT have the manage-oauth-apps permission', async () => { + await updatePermission('manage-oauth-apps', []); + await request + .post(api(`oauth-apps.delete`)) + .set(credentials) + .send({ + appId, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body.error).to.be.equal('User does not have the permissions required for this action [error-unauthorized]'); + }); + }); }); }); From 7a476f26b86f683c5d8344f7b15c7fc49ea48b48 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Thu, 9 May 2024 17:49:56 -0300 Subject: [PATCH 70/80] chore!: Improve permissions check on teams endpoints (#32351) --- apps/meteor/app/api/server/v1/teams.ts | 17 +---- apps/meteor/tests/end-to-end/api/teams.ts | 77 +++++++++++++++++++++++ 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/apps/meteor/app/api/server/v1/teams.ts b/apps/meteor/app/api/server/v1/teams.ts index f64f8c820575..c111bc482360 100644 --- a/apps/meteor/app/api/server/v1/teams.ts +++ b/apps/meteor/app/api/server/v1/teams.ts @@ -44,13 +44,9 @@ API.v1.addRoute( API.v1.addRoute( 'teams.listAll', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['view-all-teams'] }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'view-all-teams'))) { - return API.v1.unauthorized(); - } - const { offset, count } = await getPaginationItems(this.queryParams); const { records, total } = await Team.listAll({ offset, count }); @@ -67,13 +63,9 @@ API.v1.addRoute( API.v1.addRoute( 'teams.create', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['create-team'] }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'create-team'))) { - return API.v1.unauthorized(); - } - check( this.bodyParams, Match.ObjectIncluding({ @@ -290,10 +282,7 @@ API.v1.addRoute( const allowPrivateTeam: boolean = await hasPermissionAsync(this.userId, 'view-all-teams', team.roomId); - let getAllRooms = false; - if (await hasPermissionAsync(this.userId, 'view-all-team-channels', team.roomId)) { - getAllRooms = true; - } + const getAllRooms = await hasPermissionAsync(this.userId, 'view-all-team-channels', team.roomId); const listFilter = { name: filter ?? undefined, diff --git a/apps/meteor/tests/end-to-end/api/teams.ts b/apps/meteor/tests/end-to-end/api/teams.ts index 425d0039e502..f52b3044f7c8 100644 --- a/apps/meteor/tests/end-to-end/api/teams.ts +++ b/apps/meteor/tests/end-to-end/api/teams.ts @@ -50,6 +50,13 @@ describe('[Teams]', () => { }); after(() => Promise.all([...createdTeams.map((team) => deleteTeam(credentials, team.name)), deleteUser(testUser)])); + before(async () => { + return updatePermission('create-team', ['admin', 'user']); + }); + + after(async () => { + return updatePermission('create-team', ['admin', 'user']); + }); it('should create a public team', (done) => { void request @@ -250,6 +257,22 @@ describe('[Teams]', () => { .expect('Content-Type', 'application/json') .expect(400); }); + it('should not allow creating a team when the user does NOT have the create-team permission', async () => { + await updatePermission('create-team', []); + await request + .post(api('teams.create')) + .set(credentials) + .send({ + name: `test-team-${Date.now()}`, + type: 0, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); }); describe('/teams.convertToChannel', () => { @@ -734,6 +757,60 @@ describe('[Teams]', () => { }); }); + describe('/teams.listAll', () => { + let teamName: string; + before(async () => { + await updatePermission('view-all-teams', ['admin']); + teamName = `test-team-${Date.now()}`; + await request.post(api('teams.create')).set(credentials).send({ + name: teamName, + type: 0, + }); + }); + + after(() => Promise.all([deleteTeam(credentials, teamName), updatePermission('view-all-teams', ['admin'])])); + + it('should list all teams', async () => { + await request + .get(api('teams.listAll')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('count'); + expect(res.body).to.have.property('offset', 0); + expect(res.body).to.have.property('total'); + expect(res.body).to.have.property('teams'); + expect(res.body.teams).to.be.an('array').that.is.not.empty; + expect(res.body.teams[0]).to.have.property('_id'); + expect(res.body.teams[0]).to.have.property('_updatedAt'); + expect(res.body.teams[0]).to.have.property('name'); + expect(res.body.teams[0]).to.have.property('type'); + expect(res.body.teams[0]).to.have.property('roomId'); + expect(res.body.teams[0]).to.have.property('createdBy'); + expect(res.body.teams[0].createdBy).to.have.property('_id'); + expect(res.body.teams[0].createdBy).to.have.property('username'); + expect(res.body.teams[0]).to.have.property('createdAt'); + expect(res.body.teams[0]).to.have.property('rooms'); + expect(res.body.teams[0]).to.have.property('numberOfUsers'); + }); + }); + + it('should return an error when the user does NOT have the view-all-teams permission', async () => { + await updatePermission('view-all-teams', []); + await request + .get(api('teams.listAll')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + }); + describe('/teams.updateMember', () => { let testTeam: ITeam; const teamName = `test-team-update-member-${Date.now()}`; From 6a5e4ba1b0e4408ab78c1e450fce98bde3d80ffd Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Mon, 13 May 2024 08:48:41 -0300 Subject: [PATCH 71/80] chore!: Improve permissions check on im endpoints (#32333) --- apps/meteor/app/api/server/v1/im.ts | 12 +- .../tests/end-to-end/api/direct-message.ts | 182 ++++++++++-------- 2 files changed, 108 insertions(+), 86 deletions(-) diff --git a/apps/meteor/app/api/server/v1/im.ts b/apps/meteor/app/api/server/v1/im.ts index a640318a9cd0..1084ac96a188 100644 --- a/apps/meteor/app/api/server/v1/im.ts +++ b/apps/meteor/app/api/server/v1/im.ts @@ -395,7 +395,7 @@ API.v1.addRoute( API.v1.addRoute( ['dm.messages.others', 'im.messages.others'], - { authRequired: true }, + { authRequired: true, permissionsRequired: ['view-room-administration'] }, { async get() { if (settings.get('API_Enable_Direct_Message_History_EndPoint') !== true) { @@ -404,10 +404,6 @@ API.v1.addRoute( }); } - if (!(await hasPermissionAsync(this.userId, 'view-room-administration'))) { - return API.v1.unauthorized(); - } - const { roomId } = this.queryParams; if (!roomId) { throw new Meteor.Error('error-roomid-param-not-provided', 'The parameter "roomId" is required'); @@ -483,13 +479,9 @@ API.v1.addRoute( API.v1.addRoute( ['dm.list.everyone', 'im.list.everyone'], - { authRequired: true }, + { authRequired: true, permissionsRequired: ['view-room-administration'] }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'view-room-administration'))) { - return API.v1.unauthorized(); - } - const { offset, count }: { offset: number; count: number } = await getPaginationItems(this.queryParams); const { sort, fields, query } = await this.parseJsonQuery(); diff --git a/apps/meteor/tests/end-to-end/api/direct-message.ts b/apps/meteor/tests/end-to-end/api/direct-message.ts index afe33c1c5fc3..090eae0d7944 100644 --- a/apps/meteor/tests/end-to-end/api/direct-message.ts +++ b/apps/meteor/tests/end-to-end/api/direct-message.ts @@ -216,29 +216,51 @@ describe('[Direct Messages]', () => { .end(done); }); - it('/im.list.everyone', (done) => { - void request - .get(api('im.list.everyone')) - .set(credentials) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.property('count'); - expect(res.body).to.have.property('total'); - expect(res.body).to.have.property('ims').and.to.be.an('array'); - const im = (res.body.ims as IRoom[]).find((dm) => dm._id === testDM._id); - expect(im).to.have.property('_id'); - expect(im).to.have.property('t').and.to.be.eq('d'); - expect(im).to.have.property('msgs').and.to.be.a('number'); - expect(im).to.have.property('usernames').and.to.be.an('array'); - expect(im).to.have.property('ro'); - expect(im).to.have.property('sysMes'); - expect(im).to.have.property('_updatedAt'); - expect(im).to.have.property('ts'); - expect(im).to.have.property('lastMessage'); - }) - .end(done); + describe('/im.list.everyone', () => { + before(async () => { + return updatePermission('view-room-administration', ['admin']); + }); + + after(async () => { + return updatePermission('view-room-administration', ['admin']); + }); + + it('should succesfully return a list of direct messages', async () => { + await request + .get(api('im.list.everyone')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('count', 1); + expect(res.body).to.have.property('total', 1); + expect(res.body).to.have.property('ims').and.to.be.an('array'); + const im = res.body.ims[0]; + expect(im).to.have.property('_id'); + expect(im).to.have.property('t').and.to.be.eq('d'); + expect(im).to.have.property('msgs').and.to.be.a('number'); + expect(im).to.have.property('usernames').and.to.be.an('array'); + expect(im).to.have.property('ro'); + expect(im).to.have.property('sysMes'); + expect(im).to.have.property('_updatedAt'); + expect(im).to.have.property('ts'); + expect(im).to.have.property('lastMessage'); + }); + }); + + it('should fail if user does NOT have the view-room-administration permission', async () => { + await updatePermission('view-room-administration', []); + await request + .get(api('im.list.everyone')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); }); describe("Setting: 'Use Real Name': true", () => { @@ -365,63 +387,71 @@ describe('[Direct Messages]', () => { }); describe('/im.messages.others', () => { - it('should fail when the endpoint is disabled', (done) => { - void updateSetting('API_Enable_Direct_Message_History_EndPoint', false).then(() => { - void request - .get(api('im.messages.others')) - .set(credentials) - .query({ - roomId: directMessage._id, - }) - .expect('Content-Type', 'application/json') - .expect(400) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('errorType', 'error-endpoint-disabled'); - }) - .end(done); - }); + it('should fail when the endpoint is disabled and the user has permissions', async () => { + await updateSetting('API_Enable_Direct_Message_History_EndPoint', false); + await request + .get(api('im.messages.others')) + .set(credentials) + .query({ + roomId: directMessage._id, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-endpoint-disabled'); + }); }); - it('should fail when the endpoint is enabled but the user doesnt have permission', (done) => { - void updateSetting('API_Enable_Direct_Message_History_EndPoint', true).then(() => { - void updatePermission('view-room-administration', []).then(() => { - void request - .get(api('im.messages.others')) - .set(credentials) - .query({ - roomId: directMessage._id, - }) - .expect('Content-Type', 'application/json') - .expect(403) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); - }) - .end(done); + it('should fail when the endpoint is disabled and the user doesnt have permission', async () => { + await updateSetting('API_Enable_Direct_Message_History_EndPoint', false); + await updatePermission('view-room-administration', ['admin']); + await request + .get(api('im.messages.others')) + .set(credentials) + .query({ + roomId: directMessage._id, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }); - }); }); - it('should succeed when the endpoint is enabled and user has permission', (done) => { - void updateSetting('API_Enable_Direct_Message_History_EndPoint', true).then(() => { - void updatePermission('view-room-administration', ['admin']).then(() => { - void request - .get(api('im.messages.others')) - .set(credentials) - .query({ - roomId: directMessage._id, - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.property('messages').and.to.be.an('array'); - expect(res.body).to.have.property('offset'); - expect(res.body).to.have.property('count'); - expect(res.body).to.have.property('total'); - }) - .end(done); + it('should fail when the endpoint is enabled but the user doesnt have permission', async () => { + await updateSetting('API_Enable_Direct_Message_History_EndPoint', true); + await updatePermission('view-room-administration', []); + await request + .get(api('im.messages.others')) + .set(credentials) + .query({ + roomId: directMessage._id, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + it('should succeed when the endpoint is enabled and user has permission', async () => { + await updateSetting('API_Enable_Direct_Message_History_EndPoint', true); + await updatePermission('view-room-administration', ['admin']); + await request + .get(api('im.messages.others')) + .set(credentials) + .query({ + roomId: directMessage._id, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('messages').and.to.be.an('array'); + expect(res.body).to.have.property('offset'); + expect(res.body).to.have.property('count'); + expect(res.body).to.have.property('total'); }); - }); }); }); From f4c349b650671f7d14fb2553a96cff7db1080ae1 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Mon, 13 May 2024 08:49:58 -0300 Subject: [PATCH 72/80] chore!: Improve permissions check on permissions endpoints (#32343) --- apps/meteor/app/api/server/v1/permissions.ts | 7 +--- .../tests/end-to-end/api/permissions.ts | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/apps/meteor/app/api/server/v1/permissions.ts b/apps/meteor/app/api/server/v1/permissions.ts index 3613cc171354..65dfafe5ccce 100644 --- a/apps/meteor/app/api/server/v1/permissions.ts +++ b/apps/meteor/app/api/server/v1/permissions.ts @@ -3,7 +3,6 @@ import { Permissions, Roles } from '@rocket.chat/models'; import { isBodyParamsValidPermissionUpdate } from '@rocket.chat/rest-typings'; import { Meteor } from 'meteor/meteor'; -import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener'; import { API } from '../api'; @@ -41,13 +40,9 @@ API.v1.addRoute( API.v1.addRoute( 'permissions.update', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['access-permissions'] }, { async post() { - if (!(await hasPermissionAsync(this.userId, 'access-permissions'))) { - return API.v1.failure('Editing permissions is not allowed', 'error-edit-permissions-not-allowed'); - } - const { bodyParams } = this; if (!isBodyParamsValidPermissionUpdate(bodyParams)) { diff --git a/apps/meteor/tests/end-to-end/api/permissions.ts b/apps/meteor/tests/end-to-end/api/permissions.ts index 55bd724dad45..ef2dee4378f9 100644 --- a/apps/meteor/tests/end-to-end/api/permissions.ts +++ b/apps/meteor/tests/end-to-end/api/permissions.ts @@ -1,8 +1,13 @@ +import type { Credentials } from '@rocket.chat/api-client'; +import type { IUser } from '@rocket.chat/core-typings'; import { expect } from 'chai'; import { before, describe, it, after } from 'mocha'; import { getCredentials, api, request, credentials } from '../../data/api-data'; import { updatePermission } from '../../data/permissions.helper'; +import { password } from '../../data/user'; +import { createUser, deleteUser, login } from '../../data/users.helper'; +import type { TestUser } from '../../data/users.helper.js'; describe('[Permissions]', () => { before((done) => getCredentials(done)); @@ -54,6 +59,19 @@ describe('[Permissions]', () => { }); describe('[/permissions.update]', () => { + let testUser: TestUser; + let testUserCredentials: Credentials; + before(async () => { + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + await updatePermission('access-permissions', ['admin']); + }); + + after(async () => { + await updatePermission('access-permissions', ['admin']); + await deleteUser(testUser); + }); + it('should change the permissions on the server', (done) => { const permissions = [ { @@ -127,5 +145,23 @@ describe('[Permissions]', () => { }) .end(done); }); + it('should fail updating permission if user does NOT have the access-permissions permission', async () => { + const permissions = [ + { + _id: 'add-oauth-service', + roles: ['admin', 'user'], + }, + ]; + await request + .post(api('permissions.update')) + .set(testUserCredentials) + .send({ permissions }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); }); }); From bced162b2b6b3b4e891703e732401bc4cf8e48c9 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Mon, 13 May 2024 08:51:56 -0300 Subject: [PATCH 73/80] chore!: Improve permissions check on settings endpoints (#32350) --- apps/meteor/app/api/server/v1/settings.ts | 15 +++-- apps/meteor/tests/end-to-end/api/settings.ts | 60 ++++++++++++++++++-- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/apps/meteor/app/api/server/v1/settings.ts b/apps/meteor/app/api/server/v1/settings.ts index 574f4ee64194..a77c0a248627 100644 --- a/apps/meteor/app/api/server/v1/settings.ts +++ b/apps/meteor/app/api/server/v1/settings.ts @@ -150,12 +150,15 @@ API.v1.addRoute( API.v1.addRoute( 'settings/:_id', - { authRequired: true }, + { + authRequired: true, + permissionsRequired: { + GET: { permissions: ['view-privileged-setting'], operation: 'hasAll' }, + POST: { permissions: ['edit-privileged-setting'], operation: 'hasAll' }, + }, + }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'view-privileged-setting'))) { - return API.v1.unauthorized(); - } const setting = await Settings.findOneNotHiddenById(this.urlParams._id); if (!setting) { return API.v1.failure(); @@ -165,10 +168,6 @@ API.v1.addRoute( post: { twoFactorRequired: true, async action(): Promise> { - if (!(await hasPermissionAsync(this.userId, 'edit-privileged-setting'))) { - return API.v1.unauthorized(); - } - if (typeof this.urlParams._id !== 'string') { throw new Meteor.Error('error-id-param-not-provided', 'The parameter "id" is required'); } diff --git a/apps/meteor/tests/end-to-end/api/settings.ts b/apps/meteor/tests/end-to-end/api/settings.ts index 3a03ecbe9226..c596954ad065 100644 --- a/apps/meteor/tests/end-to-end/api/settings.ts +++ b/apps/meteor/tests/end-to-end/api/settings.ts @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { before, describe, it, after } from 'mocha'; import { getCredentials, api, request, credentials } from '../../data/api-data'; -import { updateSetting } from '../../data/permissions.helper'; +import { updatePermission, updateSetting } from '../../data/permissions.helper'; describe('[Settings]', () => { before((done) => getCredentials(done)); @@ -56,8 +56,18 @@ describe('[Settings]', () => { }); describe('[/settings/:_id]', () => { - it('should return one setting', (done) => { - void request + before(async () => { + await updatePermission('view-privileged-setting', ['admin']); + await updatePermission('edit-privileged-setting', ['admin']); + }); + + after(async () => { + await updatePermission('view-privileged-setting', ['admin']); + await updatePermission('edit-privileged-setting', ['admin']); + }); + + it('should succesfully return one setting (GET)', async () => { + return request .get(api('settings/Site_Url')) .set(credentials) .expect('Content-Type', 'application/json') @@ -66,8 +76,50 @@ describe('[Settings]', () => { expect(res.body).to.have.property('success', true); expect(res.body).to.have.property('_id', 'Site_Url'); expect(res.body).to.have.property('value'); + }); + }); + + it('should fail returning a setting if user does NOT have the view-privileged-setting permission (GET)', async () => { + await updatePermission('view-privileged-setting', []); + return request + .get(api('settings/Site_Url')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + + it('should succesfully set the value of a setting (POST)', async () => { + return request + .post(api('settings/LDAP_Enable')) + .set(credentials) + .send({ + value: false, }) - .end(done); + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }); + }); + + it('should fail updating the value of a setting if user does NOT have the edit-privileged-setting permission (POST)', async () => { + await updatePermission('edit-privileged-setting', []); + return request + .post(api('settings/LDAP_Enable')) + .set(credentials) + .send({ + value: false, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); }); }); From ede52cf20b158b924d5bc86305400d20e022aa9d Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Mon, 13 May 2024 09:00:35 -0300 Subject: [PATCH 74/80] chore!: Improve permissions check on licenses endpoints (#32354) --- apps/meteor/ee/server/api/licenses.ts | 6 +----- apps/meteor/tests/end-to-end/api/licenses.ts | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/meteor/ee/server/api/licenses.ts b/apps/meteor/ee/server/api/licenses.ts index 28b0b2e080f3..22ddbda9e31e 100644 --- a/apps/meteor/ee/server/api/licenses.ts +++ b/apps/meteor/ee/server/api/licenses.ts @@ -41,17 +41,13 @@ API.v1.addRoute( API.v1.addRoute( 'licenses.add', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['edit-privileged-setting'] }, { async post() { check(this.bodyParams, { license: String, }); - if (!(await hasPermissionAsync(this.userId, 'edit-privileged-setting'))) { - return API.v1.unauthorized(); - } - const { license } = this.bodyParams; if (!(await License.validateFormat(license))) { return API.v1.failure('Invalid license'); diff --git a/apps/meteor/tests/end-to-end/api/licenses.ts b/apps/meteor/tests/end-to-end/api/licenses.ts index 7792d497fe1b..10dce4177aec 100644 --- a/apps/meteor/tests/end-to-end/api/licenses.ts +++ b/apps/meteor/tests/end-to-end/api/licenses.ts @@ -48,7 +48,7 @@ describe('licenses', () => { .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body).to.have.property('error', 'unauthorized'); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); }) .end(done); }); From 73c8cf56cfeb7b82ff44fc28bc35dc5b1eaeb66f Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Tue, 14 May 2024 16:20:12 -0300 Subject: [PATCH 75/80] test: fix im.messages.others endpoint tests (#32426) --- apps/meteor/tests/end-to-end/api/direct-message.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/tests/end-to-end/api/direct-message.ts b/apps/meteor/tests/end-to-end/api/direct-message.ts index 090eae0d7944..e4ebaced41f7 100644 --- a/apps/meteor/tests/end-to-end/api/direct-message.ts +++ b/apps/meteor/tests/end-to-end/api/direct-message.ts @@ -404,7 +404,7 @@ describe('[Direct Messages]', () => { }); it('should fail when the endpoint is disabled and the user doesnt have permission', async () => { await updateSetting('API_Enable_Direct_Message_History_EndPoint', false); - await updatePermission('view-room-administration', ['admin']); + await updatePermission('view-room-administration', []); await request .get(api('im.messages.others')) .set(credentials) From 517538f19918ae45d02d61e7e8c344f9ac397b02 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Tue, 14 May 2024 18:10:09 -0300 Subject: [PATCH 76/80] chore!: Improve permissions check on misc endpoints (#32337) --- apps/meteor/app/api/server/v1/misc.ts | 6 +-- .../tests/end-to-end/api/miscellaneous.ts | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/apps/meteor/app/api/server/v1/misc.ts b/apps/meteor/app/api/server/v1/misc.ts index dd4da47bff05..77d8eeaa5b46 100644 --- a/apps/meteor/app/api/server/v1/misc.ts +++ b/apps/meteor/app/api/server/v1/misc.ts @@ -22,7 +22,6 @@ import { v4 as uuidv4 } from 'uuid'; import { i18n } from '../../../../server/lib/i18n'; import { SystemLogger } from '../../../../server/lib/logger/system'; import { getLogs } from '../../../../server/stream/stdout'; -import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { passwordPolicy } from '../../../lib/server'; import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener'; import { settings } from '../../../settings/server'; @@ -473,12 +472,9 @@ API.v1.addRoute( */ API.v1.addRoute( 'stdout.queue', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['view-logs'] }, { async get() { - if (!(await hasPermissionAsync(this.userId, 'view-logs'))) { - return API.v1.unauthorized(); - } return API.v1.success({ queue: getLogs() }); }, }, diff --git a/apps/meteor/tests/end-to-end/api/miscellaneous.ts b/apps/meteor/tests/end-to-end/api/miscellaneous.ts index 185c922c008d..e584b5479145 100644 --- a/apps/meteor/tests/end-to-end/api/miscellaneous.ts +++ b/apps/meteor/tests/end-to-end/api/miscellaneous.ts @@ -703,4 +703,43 @@ describe('miscellaneous', () => { .end(done); }); }); + + describe('/stdout.queue', () => { + before(async () => { + return updatePermission('view-logs', ['admin']); + }); + + after(async () => { + return updatePermission('view-logs', ['admin']); + }); + + it('should return server logs', async () => { + return request + .get(api('stdout.queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('queue').and.to.be.an('array').that.is.not.empty; + expect(res.body.queue[0]).to.be.an('object'); + expect(res.body.queue[0]).to.have.property('id').and.to.be.a('string'); + expect(res.body.queue[0]).to.have.property('string').and.to.be.a('string'); + expect(res.body.queue[0]).to.have.property('ts').and.to.be.a('string'); + }); + }); + + it('should not return server logs if user does NOT have the view-logs permission', async () => { + await updatePermission('view-logs', []); + return request + .get(api('stdout.queue')) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + }); }); From 9d48b04f5ac08b8368a1572d2d2a5e9643066178 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Mon, 20 May 2024 14:11:44 -0300 Subject: [PATCH 77/80] chore!: Improve permissions check on roles endpoints (#32347) --- apps/meteor/app/api/server/v1/roles.ts | 17 +- apps/meteor/tests/end-to-end/api/roles.ts | 419 +++++++++++++++++++++- 2 files changed, 421 insertions(+), 15 deletions(-) diff --git a/apps/meteor/app/api/server/v1/roles.ts b/apps/meteor/app/api/server/v1/roles.ts index 66c6677a9eed..fc9bd273996d 100644 --- a/apps/meteor/app/api/server/v1/roles.ts +++ b/apps/meteor/app/api/server/v1/roles.ts @@ -91,7 +91,7 @@ API.v1.addRoute( API.v1.addRoute( 'roles.getUsersInRole', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['access-permissions'] }, { async get() { const { roomId, role } = this.queryParams; @@ -109,9 +109,6 @@ API.v1.addRoute( if (!role) { throw new Meteor.Error('error-param-not-provided', 'Query param "role" is required'); } - if (!(await hasPermissionAsync(this.userId, 'access-permissions'))) { - throw new Meteor.Error('error-not-allowed', 'Not allowed'); - } if (roomId && !(await hasPermissionAsync(this.userId, 'view-other-user-channels'))) { throw new Meteor.Error('error-not-allowed', 'Not allowed'); } @@ -150,7 +147,7 @@ API.v1.addRoute( API.v1.addRoute( 'roles.delete', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['access-permissions'] }, { async post() { const { bodyParams } = this; @@ -158,10 +155,6 @@ API.v1.addRoute( throw new Meteor.Error('error-invalid-role-properties', 'The role properties are invalid.'); } - if (!(await hasPermissionAsync(this.userId, 'access-permissions'))) { - throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed'); - } - const role = await Roles.findOneByIdOrName(bodyParams.roleId); if (!role) { @@ -189,7 +182,7 @@ API.v1.addRoute( API.v1.addRoute( 'roles.removeUserFromRole', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['access-permissions'] }, { async post() { const { bodyParams } = this; @@ -199,10 +192,6 @@ API.v1.addRoute( const { roleId, roleName, username, scope } = bodyParams; - if (!(await hasPermissionAsync(this.userId, 'access-permissions'))) { - throw new Meteor.Error('error-not-allowed', 'Accessing permissions is not allowed'); - } - if (!roleId) { if (!roleName) { return API.v1.failure('error-invalid-role-properties'); diff --git a/apps/meteor/tests/end-to-end/api/roles.ts b/apps/meteor/tests/end-to-end/api/roles.ts index 91f7a30ef2f5..393883dfc0bd 100644 --- a/apps/meteor/tests/end-to-end/api/roles.ts +++ b/apps/meteor/tests/end-to-end/api/roles.ts @@ -1,10 +1,15 @@ +import type { IUser } from '@rocket.chat/core-typings'; import { expect } from 'chai'; import { after, before, describe, it } from 'mocha'; import type { Response } from 'supertest'; import { getCredentials, api, request, credentials } from '../../data/api-data'; +import { updatePermission } from '../../data/permissions.helper'; +import { password, adminUsername } from '../../data/user'; +import { createUser, deleteUser, login } from '../../data/users.helper'; -describe('[Roles]', () => { +describe('[Roles]', function () { + this.retries(0); const isEnterprise = Boolean(process.env.IS_EE); before((done) => getCredentials(done)); @@ -138,4 +143,416 @@ describe('[Roles]', () => { }); }); }); + + describe('[/roles.getUsersInRole]', () => { + let testUser: IUser; + let testUserCredentials: { 'X-Auth-Token': string; 'X-User-Id': string }; + const testRoleName = `role.getUsersInRole.${Date.now()}`; + let testRoleId = ''; + + before(async () => { + await updatePermission('access-permissions', ['admin']); + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + + if (!isEnterprise) { + return; + } + + await request + .post(api('roles.create')) + .set(credentials) + .send({ + name: testRoleName, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('role'); + expect(res.body.role).to.have.property('name', testRoleName); + testRoleId = res.body.role._id; + }); + }); + + after(async () => { + await deleteUser(testUser); + if (!isEnterprise) { + return; + } + + await request.post(api('roles.delete')).set(credentials).send({ + roleId: testRoleId, + }); + }); + + it('should successfully get an empty list of users in a role if no user has been assigned to it', async function () { + if (!isEnterprise) { + this.skip(); + return; + } + + await request + .get(api('roles.getUsersInRole')) + .set(credentials) + .query({ + role: testRoleId, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('total', 0); + expect(res.body).to.have.property('users').that.is.an('array').that.is.empty; + }); + }); + + it('should successfully get a list of users in a role', async function () { + if (!isEnterprise) { + this.skip(); + return; + } + + await request + .post(api('roles.addUserToRole')) + .set(credentials) + .send({ + roleId: testRoleId, + username: adminUsername, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }); + + await request + .get(api('roles.getUsersInRole')) + .set(credentials) + .query({ + role: testRoleId, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('total', 1); + expect(res.body).to.have.property('users').that.is.an('array').of.length(1); + expect(res.body.users[0]).to.have.property('_id', credentials['X-User-Id']); + }); + }); + + it('should fail getting a list of users in a role in case an invalid role is provided', async function () { + if (!isEnterprise) { + this.skip(); + return; + } + + await request + .get(api('roles.getUsersInRole')) + .set(credentials) + .query({ + role: 'invalid-role', + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-invalid-roleId'); + }); + }); + + it('should fail when user does NOT have the access-permissions permission', async () => { + await request + .get(api('roles.getUsersInRole')) + .set(testUserCredentials) + .query({ + role: 'admin', + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + }); + + describe('[/roles.delete]', () => { + let testUser: IUser; + let testUserCredentials: { 'X-Auth-Token': string; 'X-User-Id': string }; + const testRoleName = `role.delete.${Date.now()}`; + let testRoleId = ''; + + before(async () => { + if (!isEnterprise) { + return; + } + + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + await updatePermission('access-permissions', ['admin']); + await request + .post(api('roles.create')) + .set(credentials) + .send({ + name: testRoleName, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('role'); + expect(res.body.role).to.have.property('name', testRoleName); + testRoleId = res.body.role._id; + }); + }); + + after(async () => { + if (!isEnterprise) { + return; + } + await deleteUser(testUser); + }); + + it('should fail deleting a role when user does NOT have the access-permissions permission', 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 (!isEnterprise) { + this.skip(); + return; + } + + await request + .post(api('roles.delete')) + .set(testUserCredentials) + .send({ + roleId: testRoleId, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + + it('should fail deleting a role in EE in case an invalid role is provided', 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 (!isEnterprise) { + this.skip(); + return; + } + + await request + .post(api('roles.delete')) + .set(credentials) + .send({ + roleId: 'invalid-role', + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-invalid-roleId'); + expect(res.body).to.have.property('error', 'This role does not exist [error-invalid-roleId]'); + }); + }); + + it('should successfully delete a role in EE', 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 (!isEnterprise) { + this.skip(); + return; + } + + await request + .post(api('roles.delete')) + .set(credentials) + .send({ + roleId: testRoleId, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + }); + }); + }); + + describe('[/roles.removeUserFromRole]', () => { + let testUser: IUser; + let testUserCredentials: { 'X-Auth-Token': string; 'X-User-Id': string }; + const testRoleName = `role.removeUsersFromRole.${Date.now()}`; + let testRoleId = ''; + + before(async () => { + await updatePermission('access-permissions', ['admin']); + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + if (!isEnterprise) { + return; + } + + await request + .post(api('roles.create')) + .set(credentials) + .send({ + name: testRoleName, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('role'); + expect(res.body.role).to.have.property('name', testRoleName); + testRoleId = res.body.role._id; + }); + await request + .post(api('roles.addUserToRole')) + .set(credentials) + .send({ + roleId: testRoleId, + username: testUser.username, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }); + }); + + after(async () => { + await request.post(api('roles.delete')).set(credentials).send({ + roleId: testRoleId, + }); + await deleteUser(testUser); + }); + + it('should fail removing a user from a role when user does NOT have the access-permissions permission', async () => { + await request + .post(api('roles.removeUserFromRole')) + .set(testUserCredentials) + .send({ + roleId: testRoleId, + username: testUser.username, + }) + .expect('Content-Type', 'application/json') + .expect(403) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]'); + }); + }); + + it('should fail removing an invalid user from a role', 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 (!isEnterprise) { + this.skip(); + return; + } + + await request + .post(api('roles.removeUserFromRole')) + .set(credentials) + .send({ + roleId: testRoleId, + username: 'invalid-username', + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-invalid-user'); + expect(res.body).to.have.property('error', 'There is no user with this username [error-invalid-user]'); + }); + }); + + it('should fail removing a user from an invalid role', 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 (!isEnterprise) { + this.skip(); + return; + } + + await request + .post(api('roles.removeUserFromRole')) + .set(credentials) + .send({ + roleId: 'invalid-role', + username: testUser.username, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-invalid-roleId'); + expect(res.body).to.have.property('error', 'This role does not exist [error-invalid-roleId]'); + }); + }); + + it('should fail removing a user from a role they do not have', 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 (!isEnterprise) { + this.skip(); + return; + } + + await request + .post(api('roles.removeUserFromRole')) + .set(credentials) + .send({ + roleId: 'admin', + username: testUser.username, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res: Response) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-user-not-in-role'); + expect(res.body).to.have.property('error', 'User is not in this role [error-user-not-in-role]'); + }); + }); + + it('should successfully remove a user from a role', 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 (!isEnterprise) { + this.skip(); + return; + } + + await request + .post(api('roles.removeUserFromRole')) + .set(credentials) + .send({ + roleId: testRoleId, + username: testUser.username, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + }); + await request + .get(api('roles.getUsersInRole')) + .set(credentials) + .query({ + role: testRoleId, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res: Response) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('total', 0); + expect(res.body).to.have.property('users'); + expect(res.body.users).to.be.an('array').that.is.empty; + }); + }); + }); }); From 16217509635d4322f62d1ec0f7170fc0e6b296c6 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Tue, 25 Jun 2024 01:23:57 +0530 Subject: [PATCH 78/80] refactor!: removed listEmojiCustom method (#32542) --- apps/meteor/app/emoji-custom/server/index.ts | 1 - .../server/methods/listEmojiCustom.ts | 35 ------------------- 2 files changed, 36 deletions(-) delete mode 100644 apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.ts diff --git a/apps/meteor/app/emoji-custom/server/index.ts b/apps/meteor/app/emoji-custom/server/index.ts index 83866b83b569..3ec2051f8fff 100644 --- a/apps/meteor/app/emoji-custom/server/index.ts +++ b/apps/meteor/app/emoji-custom/server/index.ts @@ -1,5 +1,4 @@ import './startup/emoji-custom'; -import './methods/listEmojiCustom'; import './methods/deleteEmojiCustom'; import './methods/insertOrUpdateEmoji'; import './methods/uploadEmojiCustom'; diff --git a/apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.ts b/apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.ts deleted file mode 100644 index a16d536d92d4..000000000000 --- a/apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { IEmojiCustom } from '@rocket.chat/core-typings'; -import type { ServerMethods } from '@rocket.chat/ddp-client'; -import { EmojiCustom } from '@rocket.chat/models'; -import { check, Match } from 'meteor/check'; -import { Meteor } from 'meteor/meteor'; - -import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; - -declare module '@rocket.chat/ddp-client' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface ServerMethods { - listEmojiCustom(options?: { name?: string; aliases?: string[] }): IEmojiCustom[]; - } -} - -Meteor.methods({ - async listEmojiCustom(options = {}) { - methodDeprecationLogger.method('listEmojiCustom', '7.0.0'); - - const user = await Meteor.userAsync(); - - if (!user) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'listEmojiCustom', - }); - } - - check(options, { - name: Match.Optional(String), - aliases: Match.Optional([String]), - }); - - return EmojiCustom.find(options).toArray(); - }, -}); From ca668650a60dee42f4dd4ae86179ed0e269ff04e Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Thu, 15 Aug 2024 16:46:40 -0300 Subject: [PATCH 79/80] chore!: removes view-history permission (#33042) Co-authored-by: Guilherme Gazzo --- .changeset/lovely-trees-call.md | 5 +++++ .../app/authorization/server/constant/permissions.ts | 1 - apps/meteor/server/startup/migrations/index.ts | 1 + apps/meteor/server/startup/migrations/v305.ts | 11 +++++++++++ packages/i18n/src/locales/af.i18n.json | 2 -- packages/i18n/src/locales/ar.i18n.json | 2 -- packages/i18n/src/locales/az.i18n.json | 2 -- packages/i18n/src/locales/be-BY.i18n.json | 2 -- packages/i18n/src/locales/bg.i18n.json | 2 -- packages/i18n/src/locales/bs.i18n.json | 2 -- packages/i18n/src/locales/ca.i18n.json | 2 -- packages/i18n/src/locales/cs.i18n.json | 2 -- packages/i18n/src/locales/cy.i18n.json | 2 -- packages/i18n/src/locales/da.i18n.json | 2 -- packages/i18n/src/locales/de-AT.i18n.json | 2 -- packages/i18n/src/locales/de-IN.i18n.json | 2 -- packages/i18n/src/locales/de.i18n.json | 2 -- packages/i18n/src/locales/el.i18n.json | 2 -- packages/i18n/src/locales/en.i18n.json | 2 -- packages/i18n/src/locales/eo.i18n.json | 2 -- packages/i18n/src/locales/es.i18n.json | 2 -- packages/i18n/src/locales/fa.i18n.json | 2 -- packages/i18n/src/locales/fi.i18n.json | 2 -- packages/i18n/src/locales/fr.i18n.json | 2 -- packages/i18n/src/locales/hi-IN.i18n.json | 2 -- packages/i18n/src/locales/hr.i18n.json | 2 -- packages/i18n/src/locales/hu.i18n.json | 2 -- packages/i18n/src/locales/id.i18n.json | 2 -- packages/i18n/src/locales/it.i18n.json | 2 -- packages/i18n/src/locales/ja.i18n.json | 2 -- packages/i18n/src/locales/ka-GE.i18n.json | 2 -- packages/i18n/src/locales/km.i18n.json | 2 -- packages/i18n/src/locales/ko.i18n.json | 2 -- packages/i18n/src/locales/ku.i18n.json | 2 -- packages/i18n/src/locales/lo.i18n.json | 2 -- packages/i18n/src/locales/lt.i18n.json | 2 -- packages/i18n/src/locales/lv.i18n.json | 2 -- packages/i18n/src/locales/mn.i18n.json | 2 -- packages/i18n/src/locales/ms-MY.i18n.json | 2 -- packages/i18n/src/locales/nl.i18n.json | 2 -- packages/i18n/src/locales/no.i18n.json | 2 -- packages/i18n/src/locales/pl.i18n.json | 2 -- packages/i18n/src/locales/pt-BR.i18n.json | 2 -- packages/i18n/src/locales/pt.i18n.json | 2 -- packages/i18n/src/locales/ro.i18n.json | 2 -- packages/i18n/src/locales/ru.i18n.json | 2 -- packages/i18n/src/locales/sk-SK.i18n.json | 2 -- packages/i18n/src/locales/sl-SI.i18n.json | 2 -- packages/i18n/src/locales/sq.i18n.json | 2 -- packages/i18n/src/locales/sr.i18n.json | 2 -- packages/i18n/src/locales/sv.i18n.json | 2 -- packages/i18n/src/locales/ta-IN.i18n.json | 2 -- packages/i18n/src/locales/th-TH.i18n.json | 2 -- packages/i18n/src/locales/tr.i18n.json | 2 -- packages/i18n/src/locales/uk.i18n.json | 2 -- packages/i18n/src/locales/vi-VN.i18n.json | 2 -- packages/i18n/src/locales/zh-HK.i18n.json | 2 -- packages/i18n/src/locales/zh-TW.i18n.json | 2 -- packages/i18n/src/locales/zh.i18n.json | 2 -- 59 files changed, 17 insertions(+), 111 deletions(-) create mode 100644 .changeset/lovely-trees-call.md create mode 100644 apps/meteor/server/startup/migrations/v305.ts diff --git a/.changeset/lovely-trees-call.md b/.changeset/lovely-trees-call.md new file mode 100644 index 000000000000..fcbfb4303ac5 --- /dev/null +++ b/.changeset/lovely-trees-call.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": major +--- + +Removes `view-history` permission due to lack of usage diff --git a/apps/meteor/app/authorization/server/constant/permissions.ts b/apps/meteor/app/authorization/server/constant/permissions.ts index 6efe99e14d0e..81f953fa0c56 100644 --- a/apps/meteor/app/authorization/server/constant/permissions.ts +++ b/apps/meteor/app/authorization/server/constant/permissions.ts @@ -74,7 +74,6 @@ export const permissions = [ { _id: 'view-device-management', roles: ['admin'] }, { _id: 'view-engagement-dashboard', roles: ['admin'] }, { _id: 'view-full-other-user-info', roles: ['admin'] }, - { _id: 'view-history', roles: ['admin', 'user', 'anonymous'] }, { _id: 'view-joined-room', roles: ['guest', 'bot', 'app', 'anonymous'] }, { _id: 'view-join-code', roles: ['admin'] }, { _id: 'view-logs', roles: ['admin'] }, diff --git a/apps/meteor/server/startup/migrations/index.ts b/apps/meteor/server/startup/migrations/index.ts index 4cda096b151c..e7a18e836722 100644 --- a/apps/meteor/server/startup/migrations/index.ts +++ b/apps/meteor/server/startup/migrations/index.ts @@ -37,5 +37,6 @@ import './v300'; import './v301'; import './v303'; import './v304'; +import './v305'; export * from './xrun'; diff --git a/apps/meteor/server/startup/migrations/v305.ts b/apps/meteor/server/startup/migrations/v305.ts new file mode 100644 index 000000000000..b840965458b8 --- /dev/null +++ b/apps/meteor/server/startup/migrations/v305.ts @@ -0,0 +1,11 @@ +import { Permissions } from '@rocket.chat/models'; + +import { addMigration } from '../../lib/migrations'; + +addMigration({ + version: 305, + name: 'Remove unused view-history permission', + async up() { + await Permissions.deleteOne({ _id: 'view-history' }); + }, +}); diff --git a/packages/i18n/src/locales/af.i18n.json b/packages/i18n/src/locales/af.i18n.json index 0e8f7acdbffd..d42cd2d8c3eb 100644 --- a/packages/i18n/src/locales/af.i18n.json +++ b/packages/i18n/src/locales/af.i18n.json @@ -2628,8 +2628,6 @@ "view-d-room_description": "Toestemming om direkte boodskappe te sien", "view-full-other-user-info": "Bekyk volledige ander gebruikersinligting", "view-full-other-user-info_description": "Toestemming om die volledige profiel van ander gebruikers te sien, insluitend die rekening skep datum, laaste login, ens.", - "view-history": "Bekyk Geskiedenis", - "view-history_description": "Toestemming om die kanaalgeskiedenis te sien", "view-join-code": "View Sluit by Kode aan", "view-join-code_description": "Toestemming om die kanaalkode te sien", "view-joined-room": "Bekyk aangeslote kamer", diff --git a/packages/i18n/src/locales/ar.i18n.json b/packages/i18n/src/locales/ar.i18n.json index f39525bd3774..a474156996f5 100644 --- a/packages/i18n/src/locales/ar.i18n.json +++ b/packages/i18n/src/locales/ar.i18n.json @@ -4558,8 +4558,6 @@ "View_full_conversation": "عرض المحادثة بالكامل", "view-full-other-user-info": "عرض كل معلومات المستخدمين الآخرين", "view-full-other-user-info_description": "إذن لعرض الملف الشخصي الكامل للمستخدمين الآخرين بما في ذلك تاريخ إنشاء الحساب وآخر تسجيل دخول، وما إلى ذلك.", - "view-history": "عرض المحفوظات", - "view-history_description": "إذن لعرض محفوظات القناة", "view-join-code": "عرض رمز الانضمام", "view-join-code_description": "إذن لعرض رمز الانضمام للقناة", "view-joined-room": "عرض Room التي تم الانضمام إليها", diff --git a/packages/i18n/src/locales/az.i18n.json b/packages/i18n/src/locales/az.i18n.json index 29b1c842aecd..ce043817dfc3 100644 --- a/packages/i18n/src/locales/az.i18n.json +++ b/packages/i18n/src/locales/az.i18n.json @@ -2628,8 +2628,6 @@ "view-d-room_description": "Birbaşa mesajları görmək icazəsi", "view-full-other-user-info": "Tam Digər İstifadəçi Bilgilerini Baxın", "view-full-other-user-info_description": "Hesab yaratma tarixi, son giriş və s. Daxil olmaqla, digər istifadəçilərin tam profilini görmək üçün icazə.", - "view-history": "Tarix bax", - "view-history_description": "Kanalın tarixini görmək üçün icazə", "view-join-code": "Görünüşü Qəbul et", "view-join-code_description": "Kanala qoşulmaq kodunu keçirmək üçün icazə", "view-joined-room": "Qəbul otağını göstərin", diff --git a/packages/i18n/src/locales/be-BY.i18n.json b/packages/i18n/src/locales/be-BY.i18n.json index e8043211ede1..072e039e81d2 100644 --- a/packages/i18n/src/locales/be-BY.i18n.json +++ b/packages/i18n/src/locales/be-BY.i18n.json @@ -2646,8 +2646,6 @@ "view-d-room_description": "Дазвол для прагляду прамых паведамленняў", "view-full-other-user-info": "Прагляд поўнага Іншая Інфармацыя пра карыстальніка", "view-full-other-user-info_description": "Дазвол для прагляду ў поўны профіль іншых карыстальнікаў, уключаючы дату стварэння ўліковага запісу, апошні ўваход і г.д.", - "view-history": "прагляд гісторыі", - "view-history_description": "Дазвол для прагляду гісторыі канала", "view-join-code": "Прагледзець Рэгістрацыя код", "view-join-code_description": "Дазвол для прагляду канала далучыцца код", "view-joined-room": "Паглядзець Дата нумар", diff --git a/packages/i18n/src/locales/bg.i18n.json b/packages/i18n/src/locales/bg.i18n.json index d6a1f8503442..e843342caf69 100644 --- a/packages/i18n/src/locales/bg.i18n.json +++ b/packages/i18n/src/locales/bg.i18n.json @@ -2624,8 +2624,6 @@ "view-d-room_description": "Разрешение за преглеждане на директни съобщения", "view-full-other-user-info": "Преглед на пълната друга информация за потребителя", "view-full-other-user-info_description": "Разрешение за преглед на пълния потребителски профил на други потребители, включително датата на създаване на сметката, последното влизане и др.", - "view-history": "Преглед на историята", - "view-history_description": "Разрешение за преглед на историята на канала", "view-join-code": "Вижте кода за присъединяване", "view-join-code_description": "Разрешение за преглеждане на кода за присъединяване на канала", "view-joined-room": "Преглед на присъединилата се стая", diff --git a/packages/i18n/src/locales/bs.i18n.json b/packages/i18n/src/locales/bs.i18n.json index 7e29e01e2b45..c87a4c921597 100644 --- a/packages/i18n/src/locales/bs.i18n.json +++ b/packages/i18n/src/locales/bs.i18n.json @@ -2621,8 +2621,6 @@ "view-d-room_description": "Dopuštenje za prikaz izravnih poruka", "view-full-other-user-info": "Pogledajte ostale korisničke informacije", "view-full-other-user-info_description": "Dopuštenje za pregled cijelog profila drugih korisnika, uključujući datum stvaranja računa, posljednju prijavu itd.", - "view-history": "Prikaži povijest", - "view-history_description": "Dopuštenje za prikaz povijesti kanala", "view-join-code": "Pogledajte pridruživanje kodu", "view-join-code_description": "Dopuštenje za pregled kanala za pridruživanje kanalu", "view-joined-room": "Pogledajte povezanu sobu", diff --git a/packages/i18n/src/locales/ca.i18n.json b/packages/i18n/src/locales/ca.i18n.json index db9a0bd7175b..0b106ffd4961 100644 --- a/packages/i18n/src/locales/ca.i18n.json +++ b/packages/i18n/src/locales/ca.i18n.json @@ -4466,8 +4466,6 @@ "View_full_conversation": "Veure conversa completa", "view-full-other-user-info": "Veure tota la info d'usuaris", "view-full-other-user-info_description": "Permís per veure el perfil complet d'altres usuaris, incloent la data de creació del compte, el darrer accés, etcètera.", - "view-history": "Veure historial", - "view-history_description": "Permís per veure l'historial del canal", "view-join-code": "Veure el codi per unir-se", "view-join-code_description": "Permís per veure el codi per unir-se al canal", "view-joined-room": "Veure Room unida", diff --git a/packages/i18n/src/locales/cs.i18n.json b/packages/i18n/src/locales/cs.i18n.json index ef640614d7a8..2c2c598f2963 100644 --- a/packages/i18n/src/locales/cs.i18n.json +++ b/packages/i18n/src/locales/cs.i18n.json @@ -3787,8 +3787,6 @@ "view-d-room_description": "Právo zobrazit soukromé zprávy", "view-full-other-user-info": "Zobrazit veškeré informace uživatele", "view-full-other-user-info_description": "Právo zobrazit veškeré informace uživatele včetně data vytvoření, posledního přihlášení, atd.", - "view-history": "Zobrazit historii", - "view-history_description": "Právo zobrazit historii místnosti", "view-join-code": "Zobrazit kód místnosti", "view-join-code_description": "Právo zobrazit kód místnosti", "view-joined-room": "Zobrazit připojené místnosti", diff --git a/packages/i18n/src/locales/cy.i18n.json b/packages/i18n/src/locales/cy.i18n.json index 3398f0c7c6f3..f5873f257d69 100644 --- a/packages/i18n/src/locales/cy.i18n.json +++ b/packages/i18n/src/locales/cy.i18n.json @@ -2622,8 +2622,6 @@ "view-d-room_description": "Caniatâd i weld negeseuon uniongyrchol", "view-full-other-user-info": "Edrychwch ar Wybodaeth Defnyddiwr Llawn Arall", "view-full-other-user-info_description": "Caniatâd i weld proffil llawn defnyddwyr eraill gan gynnwys dyddiad creu cyfrif, mewngofnodi diwethaf, ac ati.", - "view-history": "Gweld Hanes", - "view-history_description": "Caniatâd i weld hanes y sianel", "view-join-code": "Gweld Ymuno â'r Cod", "view-join-code_description": "Caniatâd i weld y sianel ymuno â'r cod", "view-joined-room": "Gweld yr Ystafell Gyfun", diff --git a/packages/i18n/src/locales/da.i18n.json b/packages/i18n/src/locales/da.i18n.json index 3c04eb8f128f..cb3a94733a9c 100644 --- a/packages/i18n/src/locales/da.i18n.json +++ b/packages/i18n/src/locales/da.i18n.json @@ -3896,8 +3896,6 @@ "view-d-room_description": "Tilladelse til at se direkte meddelelser", "view-full-other-user-info": "Se fuld anden brugerinformation", "view-full-other-user-info_description": "Tilladelse til at se fuld profil for andre brugere, herunder oprettelse af konto, sidste login osv.", - "view-history": "Se historik", - "view-history_description": "Tilladelse til at se kanalhistorikken", "view-join-code": "View Tilmeld Kode", "view-join-code_description": "Tilladelse til at se kanalens adgangskode", "view-joined-room": "Se det tilsluttede rum", diff --git a/packages/i18n/src/locales/de-AT.i18n.json b/packages/i18n/src/locales/de-AT.i18n.json index 0c1d9134e6cb..5a8ceae29113 100644 --- a/packages/i18n/src/locales/de-AT.i18n.json +++ b/packages/i18n/src/locales/de-AT.i18n.json @@ -2630,8 +2630,6 @@ "view-d-room_description": "Berechtigung zum Anzeigen von direkten Nachrichten", "view-full-other-user-info": "Vollständige Benutzerinformationen anzeigen", "view-full-other-user-info_description": "Berechtigung zum Anzeigen des vollständigen Profils anderer Benutzer, einschließlich Kontoerstellungsdatum, letzte Anmeldung usw.", - "view-history": "Siehe Verlauf", - "view-history_description": "Berechtigung zum Anzeigen des Kanalverlaufs", "view-join-code": "Zeigen Sie den Verbindungscode an", "view-join-code_description": "Berechtigung zum Anzeigen des Channel-Join-Codes", "view-joined-room": "Verbundenen Raum anzeigen", diff --git a/packages/i18n/src/locales/de-IN.i18n.json b/packages/i18n/src/locales/de-IN.i18n.json index d670473c9ec1..63c55e01f7f9 100644 --- a/packages/i18n/src/locales/de-IN.i18n.json +++ b/packages/i18n/src/locales/de-IN.i18n.json @@ -2963,8 +2963,6 @@ "view-d-room_description": "Berechtigung, Direktnachrichten zu erhalten", "view-full-other-user-info": "Vollständige Benutzerinformation einsehen", "view-full-other-user-info_description": "Berechtigung, die vollständigen Benutzerinformation anderer Benutzer einzusehen (inkl. Erstelldatum, letztem Login etc.)", - "view-history": "Historie anzeigen", - "view-history_description": "Berechtigung, die Kanal-Historie anzuzeigen", "view-join-code": "Beitritts-Code anzeigen", "view-join-code_description": "Berechtigung, den Beitritts-Code zu einem Kanal anzuzeigen", "view-joined-room": "Beigetretenen Raum anzeigen", diff --git a/packages/i18n/src/locales/de.i18n.json b/packages/i18n/src/locales/de.i18n.json index d8540f9978e9..d07663ce6b9a 100644 --- a/packages/i18n/src/locales/de.i18n.json +++ b/packages/i18n/src/locales/de.i18n.json @@ -5130,8 +5130,6 @@ "View_full_conversation": "Vollständige Konversation anzeigen", "view-full-other-user-info": "Vollständige Benutzerinformation einsehen", "view-full-other-user-info_description": "Berechtigung, die vollständigen Benutzerinformation anderer Benutzer einzusehen (inkl. Erstelldatum, letztem Login etc.)", - "view-history": "Verlauf anzeigen", - "view-history_description": "Berechtigung, den Channel-Verlauf anzuzeigen", "view-join-code": "Beitritts-Code anzeigen", "view-join-code_description": "Berechtigung, den Beitritts-Code zu einem Channel anzuzeigen", "view-joined-room": "Beigetretenen Room anzeigen", diff --git a/packages/i18n/src/locales/el.i18n.json b/packages/i18n/src/locales/el.i18n.json index 2c9b3caa1f61..2004ff45d92d 100644 --- a/packages/i18n/src/locales/el.i18n.json +++ b/packages/i18n/src/locales/el.i18n.json @@ -2635,8 +2635,6 @@ "view-d-room_description": "Άδεια προβολής άμεσων μηνυμάτων", "view-full-other-user-info": "Δείτε όλες τις άλλες πληροφορίες χρήστη", "view-full-other-user-info_description": "Άδεια προβολής πλήρους προφίλ άλλων χρηστών, συμπεριλαμβανομένης της ημερομηνίας δημιουργίας λογαριασμού, της τελευταίας σύνδεσης, κλπ.", - "view-history": "Προβολή ιστορικού", - "view-history_description": "Άδεια προβολής ιστορικού καναλιών", "view-join-code": "Προβολή σύνδεσης κώδικα", "view-join-code_description": "Άδεια προβολής του κωδικού πρόσθεσης καναλιού", "view-joined-room": "Δείτε την ενταγμένη αίθουσα", diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index d82a3c6da4a9..d35e07a85ffa 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -5808,8 +5808,6 @@ "View_full_conversation": "View full conversation", "view-full-other-user-info": "View Full Other User Info", "view-full-other-user-info_description": "Permission to view full profile of other users including account creation date, last login, etc.", - "view-history": "View History", - "view-history_description": "Permission to view the channel history", "onboarding.component.form.action.registerNow": "Register now", "view-join-code": "View Join Code", "view-join-code_description": "Permission to view the channel join code", diff --git a/packages/i18n/src/locales/eo.i18n.json b/packages/i18n/src/locales/eo.i18n.json index fdf468871aae..0dc37b142e31 100644 --- a/packages/i18n/src/locales/eo.i18n.json +++ b/packages/i18n/src/locales/eo.i18n.json @@ -2628,8 +2628,6 @@ "view-d-room_description": "Permeso por vidi rektajn mesaĝojn", "view-full-other-user-info": "Vidi Plena Aliaj Uzaj Informoj", "view-full-other-user-info_description": "Permeso por vidi plenan profilon de aliaj uzantoj inkluzive de kreo de konto dato, lasta ensaluto, ktp.", - "view-history": "Vidi historion", - "view-history_description": "Permeso por vidi la kanalan historion", "view-join-code": "Vidi Aliĝilon", "view-join-code_description": "Permeso por vidi la kanalon kunigi kodon", "view-joined-room": "Vidi Joined Room", diff --git a/packages/i18n/src/locales/es.i18n.json b/packages/i18n/src/locales/es.i18n.json index 03afdf5c79fe..6a8151845e57 100644 --- a/packages/i18n/src/locales/es.i18n.json +++ b/packages/i18n/src/locales/es.i18n.json @@ -4538,8 +4538,6 @@ "View_full_conversation": "Ver conversación completa", "view-full-other-user-info": "Ver toda la información de otro usuario", "view-full-other-user-info_description": "Permiso para ver el perfil completo de otros usuarios, incluida la fecha de creación de la cuenta, el último inicio de sesión, etc.", - "view-history": "Ver historial", - "view-history_description": "Permiso para ver el historial del canal", "view-join-code": "Ver código de participación", "view-join-code_description": "Permiso para ver el código de participación en un canal", "view-joined-room": "Ver Room de participación", diff --git a/packages/i18n/src/locales/fa.i18n.json b/packages/i18n/src/locales/fa.i18n.json index 6165446a581a..ec38be574ccf 100644 --- a/packages/i18n/src/locales/fa.i18n.json +++ b/packages/i18n/src/locales/fa.i18n.json @@ -2963,8 +2963,6 @@ "view-d-room_description": "اجازه مشاهده پیام های مستقیم", "view-full-other-user-info": "مشاهده سایر اطلاعات کاربر", "view-full-other-user-info_description": "اجازه مشاهده نمایه کامل سایر کاربران از جمله تاریخ ایجاد حساب، آخرین ورود و غیره", - "view-history": "مشاهده تاریخچه", - "view-history_description": "اجازه مشاهده تاریخچه کانال", "view-join-code": "مشاهده تاریخ کد", "view-join-code_description": "مجاز به مشاهده کد کانال کانال", "view-joined-room": "مشاهده اتاق اعضا", diff --git a/packages/i18n/src/locales/fi.i18n.json b/packages/i18n/src/locales/fi.i18n.json index 6fe476587007..3a1de590e796 100644 --- a/packages/i18n/src/locales/fi.i18n.json +++ b/packages/i18n/src/locales/fi.i18n.json @@ -5246,8 +5246,6 @@ "View_full_conversation": "Näytä koko keskustelu", "view-full-other-user-info": "Näytä täydelliset muut käyttäjän tiedot", "view-full-other-user-info_description": "Oikeus tarkastella muiden käyttäjien täydellistä profiilia, mukaan lukien tilin luontipäivä, viimeinen sisäänkirjautuminen jne.", - "view-history": "Näytä historia", - "view-history_description": "Oikeus tarkastella kanavan historiaa", "onboarding.component.form.action.registerNow": "Rekisteröidy nyt", "view-join-code": "Näytä liittymiskoodi", "view-join-code_description": "Oikeus tarkastella kanavan liittymiskoodia", diff --git a/packages/i18n/src/locales/fr.i18n.json b/packages/i18n/src/locales/fr.i18n.json index 085451faee64..5cef1fe10494 100644 --- a/packages/i18n/src/locales/fr.i18n.json +++ b/packages/i18n/src/locales/fr.i18n.json @@ -4556,8 +4556,6 @@ "View_full_conversation": "Afficher la conversation complète", "view-full-other-user-info": "Voir les informations des autres utilisateurs", "view-full-other-user-info_description": "Autorisation d'afficher le profil complet des autres utilisateurs, y compris la date de création du compte, la dernière connexion, etc.", - "view-history": "Voir l'historique", - "view-history_description": "Autorisation de consulter l'historique du canal", "view-join-code": "Afficher le code de participation", "view-join-code_description": "Autorisation d'afficher le code de participation au canal", "view-joined-room": "Voir le salon rejoint", diff --git a/packages/i18n/src/locales/hi-IN.i18n.json b/packages/i18n/src/locales/hi-IN.i18n.json index f6f94b4573bf..26bb264f5987 100644 --- a/packages/i18n/src/locales/hi-IN.i18n.json +++ b/packages/i18n/src/locales/hi-IN.i18n.json @@ -5528,8 +5528,6 @@ "View_full_conversation": "पूरी बातचीत देखें", "view-full-other-user-info": "अन्य उपयोगकर्ता की पूरी जानकारी देखें", "view-full-other-user-info_description": "खाता निर्माण तिथि, अंतिम लॉगिन आदि सहित अन्य उपयोगकर्ताओं की पूरी प्रोफ़ाइल देखने की अनुमति।", - "view-history": "इतिहास देखें", - "view-history_description": "चैनल इतिहास देखने की अनुमति", "view-join-code": "जॉइन कोड देखें", "view-join-code_description": "चैनल जॉइन कोड देखने की अनुमति", "view-joined-room": "सम्मिलित कक्ष देखें", diff --git a/packages/i18n/src/locales/hr.i18n.json b/packages/i18n/src/locales/hr.i18n.json index f75d0e36e35e..546eb81ba205 100644 --- a/packages/i18n/src/locales/hr.i18n.json +++ b/packages/i18n/src/locales/hr.i18n.json @@ -2762,8 +2762,6 @@ "view-d-room_description": "Dopuštenje za prikaz izravnih poruka", "view-full-other-user-info": "Pogledajte ostale korisničke informacije", "view-full-other-user-info_description": "Dopuštenje za pregled cijelog profila drugih korisnika, uključujući datum stvaranja računa, posljednju prijavu itd.", - "view-history": "Prikaži povijest", - "view-history_description": "Dopuštenje za prikaz povijesti kanala", "view-join-code": "Pogledajte pridruživanje kodu", "view-join-code_description": "Dopuštenje za pregled kanala za pridruživanje kanalu", "view-joined-room": "Pogledajte povezanu sobu", diff --git a/packages/i18n/src/locales/hu.i18n.json b/packages/i18n/src/locales/hu.i18n.json index 1c58e7f0a3b3..6c35f6c9173e 100644 --- a/packages/i18n/src/locales/hu.i18n.json +++ b/packages/i18n/src/locales/hu.i18n.json @@ -5045,8 +5045,6 @@ "View_full_conversation": "Teljes beszélgetés megtekintése", "view-full-other-user-info": "Mások teljes felhasználó-információinak megtekintése", "view-full-other-user-info_description": "Jogosultság más felhasználók teljes profiljának megtekintéséhez, beleértve a fiók létrehozásának dátumát, az utolsó bejelentkezést stb.", - "view-history": "Előzmények megtekintése", - "view-history_description": "Jogosultság a csatorna előzményeinek megtekintéséhez", "view-join-code": "Csatlakozási kód megtekintése", "view-join-code_description": "Jogosultság a csatorna csatlakozási kódjának megtekintéséhez", "view-joined-room": "Csatlakozott szoba megtekintése", diff --git a/packages/i18n/src/locales/id.i18n.json b/packages/i18n/src/locales/id.i18n.json index 1c2b9a8605f9..7fc3662dd76b 100644 --- a/packages/i18n/src/locales/id.i18n.json +++ b/packages/i18n/src/locales/id.i18n.json @@ -2636,8 +2636,6 @@ "view-d-room_description": "Izin untuk melihat pesan langsung", "view-full-other-user-info": "Lihat Info Pengguna Lengkap Lainnya", "view-full-other-user-info_description": "Izin untuk melihat profil lengkap pengguna lain termasuk tanggal pembuatan akun, login terakhir, dll.", - "view-history": "Lihat Riwayat", - "view-history_description": "Izin untuk melihat riwayat saluran", "view-join-code": "Lihat Kode Gabung", "view-join-code_description": "Izin untuk melihat kode join channel", "view-joined-room": "Lihat Ruang Bergabung", diff --git a/packages/i18n/src/locales/it.i18n.json b/packages/i18n/src/locales/it.i18n.json index c837e6ba2b28..8edc430118de 100644 --- a/packages/i18n/src/locales/it.i18n.json +++ b/packages/i18n/src/locales/it.i18n.json @@ -3215,8 +3215,6 @@ "view-d-room_description": "Autorizzazione a visualizzare i messaggi diretti", "view-full-other-user-info": "Visualizza tutte le altre informazioni utente", "view-full-other-user-info_description": "Autorizzazione a visualizzare il profilo completo di altri utenti tra cui data di creazione dell'account, ultimo accesso, ecc.", - "view-history": "Visualizza cronologia", - "view-history_description": "Autorizzazione a visualizzare la cronologia del canale", "view-join-code": "Visualizza unire il codice", "view-join-code_description": "Autorizzazione a visualizzare il codice di unione del canale", "view-joined-room": "Visualizza camera unita", diff --git a/packages/i18n/src/locales/ja.i18n.json b/packages/i18n/src/locales/ja.i18n.json index 3ae91c7438e5..d4c7f364c117 100644 --- a/packages/i18n/src/locales/ja.i18n.json +++ b/packages/i18n/src/locales/ja.i18n.json @@ -4499,8 +4499,6 @@ "View_full_conversation": "すべての会話を表示", "view-full-other-user-info": "他のすべてのユーザー情報の表示", "view-full-other-user-info_description": "アカウント作成日、最終ログインなど、他のユーザーの完全なプロフィールを表示する権限", - "view-history": "履歴の表示", - "view-history_description": "チャネル履歴を表示する権限", "view-join-code": "参加コードの表示", "view-join-code_description": "チャネル参加コードを表示する権限", "view-joined-room": "参加したRoomの表示", diff --git a/packages/i18n/src/locales/ka-GE.i18n.json b/packages/i18n/src/locales/ka-GE.i18n.json index 95edad389a61..9f8ae2099a16 100644 --- a/packages/i18n/src/locales/ka-GE.i18n.json +++ b/packages/i18n/src/locales/ka-GE.i18n.json @@ -3514,8 +3514,6 @@ "view-d-room_description": "პირდაპირი შეტყობინებების ნახვის უფლება", "view-full-other-user-info": "იხილეთ სხვა მომხმარებლის დრული ინფორმაცია", "view-full-other-user-info_description": "სხვა მომხმარებლების სრული პროფილის ნახვის ნებართვა, მათ შორის ანგარიშის შექმნის თარიღის, ბოლო შესვლის და ა.შ.", - "view-history": "ისტორიის ნახვა", - "view-history_description": "არხის ისტორიის ნახვის ნებართვა", "view-join-code": "იხილეთ გაწევრიანების კოდი", "view-join-code_description": "არხში გაწევრიანების კოდის ნახვის ნებართვა", "view-joined-room": "ნახეთ შეერთებული ოთახი", diff --git a/packages/i18n/src/locales/km.i18n.json b/packages/i18n/src/locales/km.i18n.json index a01227e4efa8..d31fb132f62b 100644 --- a/packages/i18n/src/locales/km.i18n.json +++ b/packages/i18n/src/locales/km.i18n.json @@ -2977,8 +2977,6 @@ "view-d-room_description": "ការអនុញ្ញាតដើម្បីមើលសារដោយផ្ទាល់", "view-full-other-user-info": "មើលពេញលេញព័ត៌មានអ្នកប្រើផ្សេងទៀត", "view-full-other-user-info_description": "ការអនុញ្ញាតដើម្បីមើលទម្រង់ពេញលេញនៃអ្នកប្រើផ្សេងទៀតរួមបញ្ចូលកាលបរិច្ឆេទបង្កើតគណនីការចូលចុងក្រោយ។ ល។", - "view-history": "មើលប្រវត្តិ", - "view-history_description": "សិទ្ធិដើម្បីមើលប្រវត្តិឆានែល", "view-join-code": "មើលភ្ជាប់កូដ", "view-join-code_description": "សិទ្ធិដើម្បីមើលឆានែលភ្ជាប់កូដ", "view-joined-room": "មើលបន្ទប់ចូលរួម", diff --git a/packages/i18n/src/locales/ko.i18n.json b/packages/i18n/src/locales/ko.i18n.json index ecf9d26abba2..25a5b03e9987 100644 --- a/packages/i18n/src/locales/ko.i18n.json +++ b/packages/i18n/src/locales/ko.i18n.json @@ -3844,8 +3844,6 @@ "view-d-room_description": "개인 대화방을 볼 수 있는 권한", "view-full-other-user-info": "다른 사용자 전체 정보 보기", "view-full-other-user-info_description": "계정 생성 날짜, 마지막 로그인 등 다른 사용자의 전체 프로필을 볼 수 있는 권한", - "view-history": "기록 보기", - "view-history_description": "채널 기록을 볼 수 있는 권한", "view-join-code": "가입 코드 보기", "view-join-code_description": "채널 가입 코드를 볼 수 있는 권한", "view-joined-room": "참여한 대화방 보기", diff --git a/packages/i18n/src/locales/ku.i18n.json b/packages/i18n/src/locales/ku.i18n.json index 3de6134ba003..1f8a2a1657b0 100644 --- a/packages/i18n/src/locales/ku.i18n.json +++ b/packages/i18n/src/locales/ku.i18n.json @@ -2621,8 +2621,6 @@ "view-d-room_description": "Destûra ku peyamên rasterast bibînin", "view-full-other-user-info": "Agahdariya din Full Info Bikarhêner", "view-full-other-user-info_description": "Destûra ku ji bo bikarhênerên çêkirina hesab, navnîşana dawîn, etc.", - "view-history": "Dîroka View", - "view-history_description": "Destûrkirina dîroka kanala xwe bibînin", "view-join-code": "Dîtin beşdar bikin", "view-join-code_description": "Destûra ku kanala kanalê kodê bibin", "view-joined-room": "Nêrîngeha Xwendegehê bibînin", diff --git a/packages/i18n/src/locales/lo.i18n.json b/packages/i18n/src/locales/lo.i18n.json index 127b97b760ed..ed995b4f6b44 100644 --- a/packages/i18n/src/locales/lo.i18n.json +++ b/packages/i18n/src/locales/lo.i18n.json @@ -2665,8 +2665,6 @@ "view-d-room_description": "ການອະນຸຍາດໃຫ້ເບິ່ງຂໍ້ຄວາມໂດຍກົງ", "view-full-other-user-info": "ເບິ່ງຂໍ້ມູນຜູ້ໃຊ້ອື່ນໆຢ່າງເຕັມທີ່", "view-full-other-user-info_description": "ການອະນຸຍາດໃຫ້ເບິ່ງລາຍລະອຽດຂອງຜູ້ໃຊ້ອື່ນໆລວມທັງວັນສ້າງບັນຊີ, ການເຂົ້າສູ່ລະບົບຄັ້ງສຸດທ້າຍ, ແລະອື່ນໆ.", - "view-history": "ເບິ່ງປະຫວັດສາດ", - "view-history_description": "ການອະນຸຍາດໃຫ້ເບິ່ງປະຫວັດຂອງຊ່ອງທາງ", "view-join-code": "ເບິ່ງລະຫັດເຂົ້າຮ່ວມ", "view-join-code_description": "ການອະນຸຍາດໃຫ້ເບິ່ງຊ່ອງເຂົ້າຮ່ວມລະຫັດ", "view-joined-room": "ເບິ່ງຫ້ອງທີ່ເຂົ້າຮ່ວມ", diff --git a/packages/i18n/src/locales/lt.i18n.json b/packages/i18n/src/locales/lt.i18n.json index b1e7f54da0b0..e5819f139741 100644 --- a/packages/i18n/src/locales/lt.i18n.json +++ b/packages/i18n/src/locales/lt.i18n.json @@ -2683,8 +2683,6 @@ "view-d-room_description": "Leidimas peržiūrėti tiesioginius pranešimus", "view-full-other-user-info": "Peržiūrėti visą kitą vartotojo informaciją", "view-full-other-user-info_description": "Leidimas peržiūrėti visus naudotojų profilius, įskaitant paskyros sukūrimo datą, paskutinį prisijungimą ir kt.", - "view-history": "Žiūrėti istoriją", - "view-history_description": "Leidimas peržiūrėti kanalo istoriją", "view-join-code": "Peržiūrėti prisijungimo kodą", "view-join-code_description": "Leidimas peržiūrėti kanalo prisijungimo kodą", "view-joined-room": "Žiūrėti įjungtą kambarį", diff --git a/packages/i18n/src/locales/lv.i18n.json b/packages/i18n/src/locales/lv.i18n.json index 3035191ac1ef..d5149968ce3c 100644 --- a/packages/i18n/src/locales/lv.i18n.json +++ b/packages/i18n/src/locales/lv.i18n.json @@ -2626,8 +2626,6 @@ "view-d-room_description": "Atļauja skatīt ziņojumus", "view-full-other-user-info": "Skatīt citu lietotāju informāciju", "view-full-other-user-info_description": "Atļauja, lai skatītu citu lietotāju pilnu profilu, tostarp konta izveides datumu, pēdējo pieteikšanos u.c.", - "view-history": "Skatīt vēsturi", - "view-history_description": "Atļauja skatīt kanāla vēsturi", "view-join-code": "Skatīt pievienošanās kodu", "view-join-code_description": "Atļauja skatīt kanāla pievienošanās kodu", "view-joined-room": "Skatīt istabu kurā pievienojies", diff --git a/packages/i18n/src/locales/mn.i18n.json b/packages/i18n/src/locales/mn.i18n.json index c7ecf64af448..3cdf003175b6 100644 --- a/packages/i18n/src/locales/mn.i18n.json +++ b/packages/i18n/src/locales/mn.i18n.json @@ -2618,8 +2618,6 @@ "view-d-room_description": "Шууд мессеж харах зөвшөөрөл", "view-full-other-user-info": "Бүрэн Бусад Хэрэглэгчийн мэдээллийг харах", "view-full-other-user-info_description": "Бүртгэл үүсгэх огноо, сүүлчийн нэвтрэх гэх мэт бусад хэрэглэгчдийн бүрэн профайлыг үзэх зөвшөөрөл.", - "view-history": "Түүхийг харах", - "view-history_description": "Сувгийн түүхийг харах зөвшөөрөл", "view-join-code": "Сумтай кодыг харах", "view-join-code_description": "Суваг харах кодыг зөвшөөрөх", "view-joined-room": "Гишүүн элсүүлэх өрөө харах", diff --git a/packages/i18n/src/locales/ms-MY.i18n.json b/packages/i18n/src/locales/ms-MY.i18n.json index 60d3d172e34f..85aec3d2d5a1 100644 --- a/packages/i18n/src/locales/ms-MY.i18n.json +++ b/packages/i18n/src/locales/ms-MY.i18n.json @@ -2632,8 +2632,6 @@ "view-d-room_description": "Kebenaran untuk melihat mesej langsung", "view-full-other-user-info": "Lihat Maklumat Pengguna Lain Penuh", "view-full-other-user-info_description": "Kebenaran untuk melihat profil pengguna lain termasuk tarikh penciptaan akaun, log masuk terakhir, dan sebagainya.", - "view-history": "Lihat Sejarah", - "view-history_description": "Kebenaran untuk melihat sejarah saluran", "view-join-code": "Lihat Sertai Kod", "view-join-code_description": "Kebenaran untuk melihat saluran menyertai kod", "view-joined-room": "Lihat Bilik Gabung", diff --git a/packages/i18n/src/locales/nl.i18n.json b/packages/i18n/src/locales/nl.i18n.json index e60531dd46fd..c7f5bf39bcaa 100644 --- a/packages/i18n/src/locales/nl.i18n.json +++ b/packages/i18n/src/locales/nl.i18n.json @@ -4541,8 +4541,6 @@ "View_full_conversation": "Bekijk het volledige gesprek", "view-full-other-user-info": "Bekijk volledige andere gebruikersinformatie", "view-full-other-user-info_description": "Toestemming om het volledige profiel van andere gebruikers te bekijken, inclusief aanmaakdatum van het account, laatste login, enz.", - "view-history": "Bekijk geschiedenis", - "view-history_description": "Toestemming om de kanaalgeschiedenis te bekijken", "view-join-code": "Bekijk de deelnamecode", "view-join-code_description": "Toestemming om de kanaalverbindingscode te bekijken", "view-joined-room": "Bekijk toegetreden kamers", diff --git a/packages/i18n/src/locales/no.i18n.json b/packages/i18n/src/locales/no.i18n.json index b551543c37b1..61275c8362c0 100644 --- a/packages/i18n/src/locales/no.i18n.json +++ b/packages/i18n/src/locales/no.i18n.json @@ -4329,8 +4329,6 @@ "view-device-management": "Se enhetsstyring", "view-full-other-user-info": "Se full annen brukerinformasjon", "view-full-other-user-info_description": "Tillatelse til å se hele profilen til andre brukere, inkludert kontoopprettelsesdato, siste innlogging, etc.", - "view-history": "Se historikk", - "view-history_description": "Tillatelse til å se kanalhistorikken", "onboarding.component.form.action.registerNow": "Registrer deg nå", "view-join-code": "Vis Bli medlem", "view-join-code_description": "Tillatelse til å vise kanalen bli med koden", diff --git a/packages/i18n/src/locales/pl.i18n.json b/packages/i18n/src/locales/pl.i18n.json index 58c484e09aa7..eb33c170b930 100644 --- a/packages/i18n/src/locales/pl.i18n.json +++ b/packages/i18n/src/locales/pl.i18n.json @@ -5040,8 +5040,6 @@ "View_full_conversation": "Zobacz pełną rozmowę", "view-full-other-user-info": "Wyświetl pełną informację o użytkowniku", "view-full-other-user-info_description": "Zezwolenie na wyświetlanie pełnego profilu innych użytkowników, w tym daty utworzenia konta, ostatniego logowania itp.", - "view-history": "Wyświetl historię", - "view-history_description": "Zezwolenie na przeglądanie historii kanału", "view-join-code": "Wyświetl kod dołączenia do kanału", "view-join-code_description": "Zezwolenie na przeglądanie kodu dołączenia do kanału", "view-joined-room": "Wyświetl Połączone pokoje", diff --git a/packages/i18n/src/locales/pt-BR.i18n.json b/packages/i18n/src/locales/pt-BR.i18n.json index 318a5d38f617..3054fafd295e 100644 --- a/packages/i18n/src/locales/pt-BR.i18n.json +++ b/packages/i18n/src/locales/pt-BR.i18n.json @@ -4668,8 +4668,6 @@ "View_full_conversation": "Visualizar conversa completa", "view-full-other-user-info": "Visualizar informações completas de outros usuários", "view-full-other-user-info_description": "Permissão para visualizar o perfil completo de outros usuários, incluindo a data de criação da conta, último login, etc.", - "view-history": "Ver histórico", - "view-history_description": "Permissão para visualizar o histórico de canais", "view-join-code": "Ver código de associação", "view-join-code_description": "Permissão para visualizar o código de associação do canal", "view-joined-room": "Ver sala incorporada", diff --git a/packages/i18n/src/locales/pt.i18n.json b/packages/i18n/src/locales/pt.i18n.json index da6177d0d799..f482812c2b19 100644 --- a/packages/i18n/src/locales/pt.i18n.json +++ b/packages/i18n/src/locales/pt.i18n.json @@ -3032,8 +3032,6 @@ "view-d-room_description": "Permissão para visualizar mensagens directas", "view-full-other-user-info": "Visualizar informações completas de outros utilizadores", "view-full-other-user-info_description": "Permissão para visualizar o perfil completo de outros utilizadores, incluindo a data de criação da conta, último login, etc.", - "view-history": "Ver histórico", - "view-history_description": "Permissão para visualizar o histórico de canais", "view-join-code": "Ver código de associação", "view-join-code_description": "Permissão para visualizar o código de associação do canal", "view-joined-room": "Exibir canal ligado", diff --git a/packages/i18n/src/locales/ro.i18n.json b/packages/i18n/src/locales/ro.i18n.json index 29495a860cc4..2bd345e3e5c6 100644 --- a/packages/i18n/src/locales/ro.i18n.json +++ b/packages/i18n/src/locales/ro.i18n.json @@ -2625,8 +2625,6 @@ "view-d-room_description": "Permisiune pentru a vedea mesaje directe", "view-full-other-user-info": "Vizualizați alte informații despre utilizatori", "view-full-other-user-info_description": "Permisiunea de a vizualiza profilul complet al altor utilizatori, inclusiv data creării contului, ultima autentificare etc.", - "view-history": "Vezi istoricul", - "view-history_description": "Permisiune pentru a vedea istoricul canalului", "view-join-code": "Afișați codul de conectare", "view-join-code_description": "Permisiune pentru a vedea codul de intrare a canalului", "view-joined-room": "Afișați camera asociată", diff --git a/packages/i18n/src/locales/ru.i18n.json b/packages/i18n/src/locales/ru.i18n.json index 340e74f8891b..ea6811635a4a 100644 --- a/packages/i18n/src/locales/ru.i18n.json +++ b/packages/i18n/src/locales/ru.i18n.json @@ -4748,8 +4748,6 @@ "View_full_conversation": "Просмотр полный текст разговора", "view-full-other-user-info": "Просмотр полной информации о других пользователях", "view-full-other-user-info_description": "Разрешение на просмотр полных профилей других пользователей, включая дату создания аккаунта, последнего входа и т. д.", - "view-history": "Просматривать историю", - "view-history_description": "Разрешение на просмотр истории канала", "view-join-code": "Просмотр кода присоединения", "view-join-code_description": "Разрешение на просмотр кода присоединения к каналу", "view-joined-room": "Просматривать чаты, к которым присоединился", diff --git a/packages/i18n/src/locales/sk-SK.i18n.json b/packages/i18n/src/locales/sk-SK.i18n.json index aa2528eb8437..892dce740ad6 100644 --- a/packages/i18n/src/locales/sk-SK.i18n.json +++ b/packages/i18n/src/locales/sk-SK.i18n.json @@ -2636,8 +2636,6 @@ "view-d-room_description": "Povolenie na zobrazenie priamych správ", "view-full-other-user-info": "Zobraziť úplné ďalšie informácie o používateľovi", "view-full-other-user-info_description": "Povolenie na zobrazenie úplného profilu ostatných používateľov vrátane dátumu vytvorenia účtu, posledného prihlásenia atď.", - "view-history": "Zobraziť históriu", - "view-history_description": "Povolenie na zobrazenie histórie kanálov", "view-join-code": "Zobraziť kód pripojenia", "view-join-code_description": "Povolenie na zobrazenie kódu pripojenia kanála", "view-joined-room": "Zobraziť spojenú miestnosť", diff --git a/packages/i18n/src/locales/sl-SI.i18n.json b/packages/i18n/src/locales/sl-SI.i18n.json index f6cbb8708438..637410484a3c 100644 --- a/packages/i18n/src/locales/sl-SI.i18n.json +++ b/packages/i18n/src/locales/sl-SI.i18n.json @@ -2616,8 +2616,6 @@ "view-d-room_description": "Dovoljenje za ogled neposrednih sporočil", "view-full-other-user-info": "Ogled polnih drugih informacij o uporabnikih", "view-full-other-user-info_description": "Dovoljenje za ogled celotnega profila drugih uporabnikov, vključno z datumom ustvarjanja računa, zadnjo prijavo itd.", - "view-history": "Ogled zgodovine", - "view-history_description": "Dovoljenje za ogled zgodovine kanalov", "view-join-code": "Ogled kode za pridružitev", "view-join-code_description": "Dovoljenje za ogled kode za pridružitev kanala", "view-joined-room": "Ogled pridružene sobe", diff --git a/packages/i18n/src/locales/sq.i18n.json b/packages/i18n/src/locales/sq.i18n.json index 8274830efc77..0e2bdd98a363 100644 --- a/packages/i18n/src/locales/sq.i18n.json +++ b/packages/i18n/src/locales/sq.i18n.json @@ -2626,8 +2626,6 @@ "view-d-room_description": "Leja për të parë mesazhe të drejtpërdrejta", "view-full-other-user-info": "Shiko Informacionin e plotë të Përdoruesit të Plotë", "view-full-other-user-info_description": "Leja për të parë profilin e plotë të përdoruesve të tjerë, përfshirë datën e krijimit të llogarisë, hyrjen e fundit, etj.", - "view-history": "Shiko historikun", - "view-history_description": "Leje për të parë historinë e kanalit", "view-join-code": "Shiko bashkësinë e kodit", "view-join-code_description": "Leja për të parë kodin e bashkëngjitjes së kanalit", "view-joined-room": "Shiko Dhomën e Bashkangjitur", diff --git a/packages/i18n/src/locales/sr.i18n.json b/packages/i18n/src/locales/sr.i18n.json index 9ddef58a7960..a1de2ca99ad3 100644 --- a/packages/i18n/src/locales/sr.i18n.json +++ b/packages/i18n/src/locales/sr.i18n.json @@ -2419,8 +2419,6 @@ "view-d-room_description": "Дозвола за преглед директних порука", "view-full-other-user-info": "Погледај остале информације о корисницима", "view-full-other-user-info_description": "Дозвола за преглед целог профила других корисника укључујући датум креирања налога, последње пријаве итд.", - "view-history": "Преглед историје", - "view-history_description": "Дозвола за преглед историје канала", "view-join-code": "Погледајте придружени код", "view-join-code_description": "Дозвола за преглед канала за придруживање", "view-joined-room": "Погледајте придружену собу", diff --git a/packages/i18n/src/locales/sv.i18n.json b/packages/i18n/src/locales/sv.i18n.json index 646778c274d9..9e33ca2a560a 100644 --- a/packages/i18n/src/locales/sv.i18n.json +++ b/packages/i18n/src/locales/sv.i18n.json @@ -5255,8 +5255,6 @@ "View_full_conversation": "Visa hela konversationen", "view-full-other-user-info": "Visa fullständig annan användarinformation", "view-full-other-user-info_description": "Tillstånd att visa fullständig profil för andra användare, inklusive datum för registrering av konto, senaste inloggning etc.", - "view-history": "Se historik", - "view-history_description": "Tillstånd att visa kanalhistoriken", "onboarding.component.form.action.registerNow": "Registrera dig nu", "view-join-code": "Visa koden för deltagande", "view-join-code_description": "Tillstånd att se koden för kanalanslutning", diff --git a/packages/i18n/src/locales/ta-IN.i18n.json b/packages/i18n/src/locales/ta-IN.i18n.json index c49b0fd62255..c84f16e91d59 100644 --- a/packages/i18n/src/locales/ta-IN.i18n.json +++ b/packages/i18n/src/locales/ta-IN.i18n.json @@ -2627,8 +2627,6 @@ "view-d-room_description": "நேரடி செய்திகளைக் காண அனுமதி", "view-full-other-user-info": "முழு பிற பயனர் தகவலைக் காண்க", "view-full-other-user-info_description": "கணக்கு உருவாக்கம் தேதி, கடைசி உள்நுழைவு, முதலியன உட்பட பிற பயனர்களின் முழு சுயவிவரத்தைக் காண அனுமதி.", - "view-history": "வரலாறு காண்க", - "view-history_description": "சேனல் வரலாற்றைக் காண அனுமதி", "view-join-code": "கோட் சேர", "view-join-code_description": "சேனல் சேர்ப்பதற்கான குறியீட்டைக் காண அனுமதி", "view-joined-room": "இணைக்கப்பட்ட அறை காண்க", diff --git a/packages/i18n/src/locales/th-TH.i18n.json b/packages/i18n/src/locales/th-TH.i18n.json index 303bc37cfc4b..945f4e52a594 100644 --- a/packages/i18n/src/locales/th-TH.i18n.json +++ b/packages/i18n/src/locales/th-TH.i18n.json @@ -2614,8 +2614,6 @@ "view-d-room_description": "อนุญาตให้ดูข้อความโดยตรง", "view-full-other-user-info": "ดูข้อมูลผู้ใช้อื่น ๆ", "view-full-other-user-info_description": "อนุญาตให้ดูโปรไฟล์แบบเต็มของผู้ใช้รายอื่นรวมถึงวันที่สร้างบัญชีการเข้าสู่ระบบครั้งสุดท้าย ฯลฯ", - "view-history": "ดูประวัติ", - "view-history_description": "อนุญาตให้ดูประวัติช่อง", "view-join-code": "ดูรหัสการเข้าร่วม", "view-join-code_description": "อนุญาตให้ดูรหัสเข้าร่วมช่อง", "view-joined-room": "ดูห้องที่เข้าร่วม", diff --git a/packages/i18n/src/locales/tr.i18n.json b/packages/i18n/src/locales/tr.i18n.json index 6297c222ffec..13f59ca30229 100644 --- a/packages/i18n/src/locales/tr.i18n.json +++ b/packages/i18n/src/locales/tr.i18n.json @@ -3117,8 +3117,6 @@ "view-d-room_description": "Doğrudan iletileri görüntüleme izni", "view-full-other-user-info": "Tam Diğer Kullanıcı Bilgisi", "view-full-other-user-info_description": "Hesap oluşturma tarihi, son giriş, vb. De dahil olmak üzere diğer kullanıcıların tam profilini görüntüleme izni.", - "view-history": "Geçmişi Görüntüle", - "view-history_description": "Kanal geçmişini görüntüleme izni", "view-join-code": "Katılma Kodunu Görüntüle", "view-join-code_description": "Kanal katılma kodunu görüntüleme izni", "view-joined-room": "Katılınmış Oda Görüntüle", diff --git a/packages/i18n/src/locales/uk.i18n.json b/packages/i18n/src/locales/uk.i18n.json index 08712bb1f2be..4b3f720afc80 100644 --- a/packages/i18n/src/locales/uk.i18n.json +++ b/packages/i18n/src/locales/uk.i18n.json @@ -3203,8 +3203,6 @@ "view-d-room_description": "Дозвіл на перегляд прямих повідомлень", "view-full-other-user-info": "Переглянути іншу інформацію про користувача", "view-full-other-user-info_description": "Дозвіл на перегляд повного профілю інших користувачів, включаючи дату створення облікового запису, останню реєстраційну інформацію тощо.", - "view-history": "Переглянути історію", - "view-history_description": "Дозвіл на перегляд історії каналу", "view-join-code": "Переглянути код приєднання", "view-join-code_description": "Дозвіл переглядати код приєднання каналу", "view-joined-room": "Переглянути зареєстрований номер", diff --git a/packages/i18n/src/locales/vi-VN.i18n.json b/packages/i18n/src/locales/vi-VN.i18n.json index f16b8dc9de23..dfc95e22193a 100644 --- a/packages/i18n/src/locales/vi-VN.i18n.json +++ b/packages/i18n/src/locales/vi-VN.i18n.json @@ -2724,8 +2724,6 @@ "view-d-room_description": "Cho phép xem tin nhắn trực tiếp", "view-full-other-user-info": "Xem thông tin người dùng đầy đủ khác", "view-full-other-user-info_description": "Cho phép xem hồ sơ đầy đủ của người dùng khác bao gồm ngày tạo tài khoản, đăng nhập lần cuối, v.v ...", - "view-history": "Xem lịch sử", - "view-history_description": "Cho phép xem lịch sử kênh", "view-join-code": "View Join Code", "view-join-code_description": "Cho phép xem mã kết nối kênh", "view-joined-room": "Xem phòng gia nhập", diff --git a/packages/i18n/src/locales/zh-HK.i18n.json b/packages/i18n/src/locales/zh-HK.i18n.json index a91346afb586..041700483eeb 100644 --- a/packages/i18n/src/locales/zh-HK.i18n.json +++ b/packages/i18n/src/locales/zh-HK.i18n.json @@ -2648,8 +2648,6 @@ "view-d-room_description": "查看直接信息的权限", "view-full-other-user-info": "查看完整的其他用户信息", "view-full-other-user-info_description": "允许查看其他用户的完整个人资料,包括帐户创建日期,上次登录等。", - "view-history": "查看历史", - "view-history_description": "查看频道历史记录的权限", "view-join-code": "查看加入代码", "view-join-code_description": "查看频道连接代码的权限", "view-joined-room": "查看加入的房间", diff --git a/packages/i18n/src/locales/zh-TW.i18n.json b/packages/i18n/src/locales/zh-TW.i18n.json index 44baef8a83b7..474d79ed26b2 100644 --- a/packages/i18n/src/locales/zh-TW.i18n.json +++ b/packages/i18n/src/locales/zh-TW.i18n.json @@ -4289,8 +4289,6 @@ "view-d-room_description": "檢視直接訊息的權限", "view-full-other-user-info": "檢視完整的其他使用者訊息", "view-full-other-user-info_description": "允許檢視其他使用者的完整個人資料,包括帳號建立日期,上次登入等。", - "view-history": "檢視歷史", - "view-history_description": "檢視頻道歷史記錄的權限", "view-join-code": "檢視加入代碼", "view-join-code_description": "檢視頻道連接代碼的權限", "view-joined-room": "檢視加入的 Room", diff --git a/packages/i18n/src/locales/zh.i18n.json b/packages/i18n/src/locales/zh.i18n.json index 5f335e2b9c7d..b0fc6c203124 100644 --- a/packages/i18n/src/locales/zh.i18n.json +++ b/packages/i18n/src/locales/zh.i18n.json @@ -3943,8 +3943,6 @@ "view-d-room_description": "查看私聊信息的权限", "view-full-other-user-info": "查看完整的其他用户信息", "view-full-other-user-info_description": "查看其他用户的完整个人资料的权限,包括帐户创建日期,上次登录等。", - "view-history": "查看历史", - "view-history_description": "查看频道历史记录的权限", "view-join-code": "查看加入代码", "view-join-code_description": "查看频道加入码的权限", "view-joined-room": "查看加入的Room", From 8c447cf24bdd9d87397364f1110a4a0e25f252c5 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Thu, 15 Aug 2024 16:51:25 -0300 Subject: [PATCH 80/80] chore!: Remove unused `omnichannelExternalFrameGenerateKey` (#32921) --- .../client/externalFrame/generateNewKey.ts | 12 ------------ .../app/livechat/client/externalFrame/index.ts | 1 - apps/meteor/app/livechat/client/index.ts | 1 - .../server/externalFrame/generateNewKey.ts | 18 ------------------ .../app/livechat/server/externalFrame/index.ts | 1 - apps/meteor/app/livechat/server/index.ts | 1 - apps/meteor/server/settings/omnichannel.ts | 9 --------- 7 files changed, 43 deletions(-) delete mode 100644 apps/meteor/app/livechat/client/externalFrame/generateNewKey.ts delete mode 100644 apps/meteor/app/livechat/client/externalFrame/index.ts delete mode 100644 apps/meteor/app/livechat/server/externalFrame/generateNewKey.ts delete mode 100644 apps/meteor/app/livechat/server/externalFrame/index.ts diff --git a/apps/meteor/app/livechat/client/externalFrame/generateNewKey.ts b/apps/meteor/app/livechat/client/externalFrame/generateNewKey.ts deleted file mode 100644 index 54c6ba4d75f1..000000000000 --- a/apps/meteor/app/livechat/client/externalFrame/generateNewKey.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ServerMethods } from '@rocket.chat/ddp-client'; -import { Meteor } from 'meteor/meteor'; - -import { sdk } from '../../../utils/client/lib/SDKClient'; -import { generateKey } from './crypto'; - -Meteor.methods({ - async omnichannelExternalFrameGenerateKey() { - const key = await generateKey(); - await sdk.call('saveSetting', 'Omnichannel_External_Frame_Encryption_JWK', key); - }, -}); diff --git a/apps/meteor/app/livechat/client/externalFrame/index.ts b/apps/meteor/app/livechat/client/externalFrame/index.ts deleted file mode 100644 index 5f05d53f1ccc..000000000000 --- a/apps/meteor/app/livechat/client/externalFrame/index.ts +++ /dev/null @@ -1 +0,0 @@ -import './generateNewKey'; diff --git a/apps/meteor/app/livechat/client/index.ts b/apps/meteor/app/livechat/client/index.ts index bc00a95bcdcd..c6884923db30 100644 --- a/apps/meteor/app/livechat/client/index.ts +++ b/apps/meteor/app/livechat/client/index.ts @@ -2,4 +2,3 @@ import '../lib/messageTypes'; import './voip'; import './ui'; import './stylesheets/livechat.css'; -import './externalFrame'; diff --git a/apps/meteor/app/livechat/server/externalFrame/generateNewKey.ts b/apps/meteor/app/livechat/server/externalFrame/generateNewKey.ts deleted file mode 100644 index a8f145f47d39..000000000000 --- a/apps/meteor/app/livechat/server/externalFrame/generateNewKey.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { ServerMethods } from '@rocket.chat/ddp-client'; -import { Meteor } from 'meteor/meteor'; - -declare module '@rocket.chat/ddp-client' { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface ServerMethods { - omnichannelExternalFrameGenerateKey(): unknown; - } -} - -Meteor.methods({ - // eslint-disable-next-line @typescript-eslint/no-empty-function - omnichannelExternalFrameGenerateKey() { - return { - message: 'Generating_key', - }; - }, // only to prevent error when calling the client method -}); diff --git a/apps/meteor/app/livechat/server/externalFrame/index.ts b/apps/meteor/app/livechat/server/externalFrame/index.ts deleted file mode 100644 index 5f05d53f1ccc..000000000000 --- a/apps/meteor/app/livechat/server/externalFrame/index.ts +++ /dev/null @@ -1 +0,0 @@ -import './generateNewKey'; diff --git a/apps/meteor/app/livechat/server/index.ts b/apps/meteor/app/livechat/server/index.ts index 9a1f40238df5..357d444ac474 100644 --- a/apps/meteor/app/livechat/server/index.ts +++ b/apps/meteor/app/livechat/server/index.ts @@ -74,5 +74,4 @@ import './lib/stream/agentStatus'; import './sendMessageBySMS'; import './api'; import './api/rest'; -import './externalFrame'; import './methods/saveBusinessHour'; diff --git a/apps/meteor/server/settings/omnichannel.ts b/apps/meteor/server/settings/omnichannel.ts index ed1daa8ce228..dd78831a5960 100644 --- a/apps/meteor/server/settings/omnichannel.ts +++ b/apps/meteor/server/settings/omnichannel.ts @@ -845,14 +845,5 @@ await settingsRegistry.addGroup('SMS', async function () { value: true, }, }); - - await this.add('Omnichannel_External_Frame_GenerateKey', 'omnichannelExternalFrameGenerateKey', { - type: 'action', - actionText: 'Generate_new_key', - enableQuery: { - _id: 'Omnichannel_External_Frame_Enabled', - value: true, - }, - }); }); });