From 18a9d658b2468fd3654b3f1dd0ac8dc644a74521 Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Wed, 3 Jan 2024 12:28:24 -0300 Subject: [PATCH 01/13] fix: engagement dashboard timezone selector (#31248) --- .changeset/rude-spoons-pump.md | 5 + .../users/UsersByTimeOfTheDaySection.tsx | 65 +-- apps/meteor/package.json | 10 +- yarn.lock | 468 ++++++++++++------ 4 files changed, 342 insertions(+), 206 deletions(-) create mode 100644 .changeset/rude-spoons-pump.md diff --git a/.changeset/rude-spoons-pump.md b/.changeset/rude-spoons-pump.md new file mode 100644 index 000000000000..3743d1d4b897 --- /dev/null +++ b/.changeset/rude-spoons-pump.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed Engagement Dashboard timezone selector freezing UI diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx index fa5664ebca27..7f7b11d013fc 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx @@ -1,10 +1,10 @@ -import { ResponsiveHeatMap } from '@nivo/heatmap'; +import { ResponsiveHeatMapCanvas } from '@nivo/heatmap'; import { Box, Flex, Skeleton, Tooltip } from '@rocket.chat/fuselage'; import colors from '@rocket.chat/fuselage-tokens/colors.json'; import { useTranslation } from '@rocket.chat/ui-contexts'; import moment from 'moment'; import type { ReactElement } from 'react'; -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import DownloadDataButton from '../../../../components/dashboards/DownloadDataButton'; import PeriodSelector from '../../../../components/dashboards/PeriodSelector'; @@ -21,43 +21,30 @@ const UsersByTimeOfTheDaySection = ({ timezone }: UsersByTimeOfTheDaySectionProp const utc = timezone === 'utc'; - const { data } = useUsersByTimeOfTheDay({ period, utc }); + const { data, isLoading } = useUsersByTimeOfTheDay({ period, utc }); const t = useTranslation(); const [dates, values] = useMemo(() => { - if (!data) { + if (!data || isLoading) { return []; } - const dates = Array.from( - { - length: utc ? moment(data.end).diff(data.start, 'days') + 1 : moment(data.end).diff(data.start, 'days') - 1, - }, - (_, i) => - utc - ? moment.utc(data.start).endOf('day').add(i, 'days') - : moment(data.start) - .endOf('day') - .add(i + 1, 'days'), - ); - - const values = Array.from( - { length: 24 }, - ( - _, - hour, - ): { - id: string; - data: { - x: string; - y: number; - }[]; - } => ({ - id: String(hour), - data: dates.map((date) => ({ x: date.toISOString(), y: 0 })), - }), - ); + const length = utc ? moment(data.end).diff(data.start, 'days') + 1 : moment(data.end).diff(data.start, 'days') - 1; + const start = utc ? moment.utc(data.start).endOf('day') : moment(data.start).endOf('day').add(1, 'days'); + + const dates = new Array(length); + for (let i = 0; i < length; i++) { + dates[i] = start.clone().add(i, 'days').toISOString(); + } + + const values = new Array(24); + for (let hour = 0; hour < 24; hour++) { + values[hour] = { + id: hour.toString(), + data: dates.map((x) => ({ x, y: 0 })), + }; + } const timezoneOffset = moment().utcOffset() / 60; @@ -65,15 +52,17 @@ const UsersByTimeOfTheDaySection = ({ timezone }: UsersByTimeOfTheDaySectionProp const date = utc ? moment.utc([year, month - 1, day, hour]) : moment([year, month - 1, day, hour]).add(timezoneOffset, 'hours'); if (utc || (!date.isSame(data.end) && !date.clone().startOf('day').isSame(data.start))) { - const dataPoint = values[date.hour()].data.find((point) => point.x === date.endOf('day').toISOString()); + const dataPoint = values[date.hour()].data.find((point: { x: string }) => point.x === date.endOf('day').toISOString()); if (dataPoint) { dataPoint.y += users; } } } - return [dates.map((date) => date.toISOString()), values]; - }, [data, utc]); + return [dates, values]; + }, [data, isLoading, utc]); + + const tooltip = useCallback(({ cell }): ReactElement => {t('Value_users', { value: cell.data.y })}, [t]); return ( <> @@ -95,7 +84,7 @@ const UsersByTimeOfTheDaySection = ({ timezone }: UsersByTimeOfTheDaySectionProp /> - {values ? ( + {!isLoading && values && dates ? ( @@ -106,7 +95,7 @@ const UsersByTimeOfTheDaySection = ({ timezone }: UsersByTimeOfTheDaySectionProp height: '100%', }} > - {t('Value_users', { value: cell.data.y })}} + tooltip={tooltip} /> diff --git a/apps/meteor/package.json b/apps/meteor/package.json index b39003ae60ff..4077a7c1087d 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -214,11 +214,11 @@ "@bugsnag/plugin-react": "~7.19.0", "@google-cloud/storage": "^6.11.0", "@kaciras/deasync": "^1.0.3", - "@nivo/bar": "0.80.0", - "@nivo/core": "0.80.0", - "@nivo/heatmap": "0.80.0", - "@nivo/line": "0.80.0", - "@nivo/pie": "0.80.0", + "@nivo/bar": "0.84.0", + "@nivo/core": "0.84.0", + "@nivo/heatmap": "0.84.0", + "@nivo/line": "0.84.0", + "@nivo/pie": "0.84.0", "@react-aria/color": "^3.0.0-beta.15", "@react-pdf/renderer": "^3.1.14", "@rocket.chat/account-utils": "workspace:^", diff --git a/yarn.lock b/yarn.lock index a2c7160bbc00..7c1a736f70e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5416,219 +5416,247 @@ __metadata: languageName: node linkType: hard -"@nivo/annotations@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/annotations@npm:0.80.0" - dependencies: - "@nivo/colors": 0.80.0 - "@react-spring/web": 9.4.5 +"@nivo/annotations@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/annotations@npm:0.84.0" + dependencies: + "@nivo/colors": 0.84.0 + "@nivo/core": 0.84.0 + "@react-spring/web": 9.4.5 || ^9.7.2 + "@types/prop-types": ^15.7.2 lodash: ^4.17.21 + prop-types: ^15.7.2 peerDependencies: - "@nivo/core": 0.80.0 react: ">= 16.14.0 < 19.0.0" - checksum: 6b2dcc3cc443a660b10feab378b816e84f8aff4390345f8316852d88dcd893af0c8de63aad6bb6296ae13c55e4cce4a57f3f3898f5fdac03bb756df24a81d3fd + checksum: ae3936c6cd5b2ea4fd06635572618086db900c4f455992332a47b190263e993cbbffc9f0169102d23cd46f80ce08e25bb35ea098d09b64286c570294e65e6c0e languageName: node linkType: hard -"@nivo/arcs@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/arcs@npm:0.80.0" +"@nivo/arcs@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/arcs@npm:0.84.0" dependencies: - "@nivo/colors": 0.80.0 - "@react-spring/web": 9.4.5 + "@nivo/colors": 0.84.0 + "@nivo/core": 0.84.0 + "@react-spring/web": 9.4.5 || ^9.7.2 + "@types/d3-shape": ^2.0.0 d3-shape: ^1.3.5 peerDependencies: - "@nivo/core": 0.80.0 react: ">= 16.14.0 < 19.0.0" - checksum: 2cc210d9c62b35713eb19a2f5ffbe7138d9133519f9a8092d5a59c7388bce3bedbf13f0b5b344b31db36f52ee0fe5bde31058f5ef0628e84e994d942d01a63a4 + checksum: 306deb912bb54871ea94321a1b0b0e8391dbb2e4437e43696d399c072553713f217692799ad45308723d16c40e478709700d1ffb70e6a83f4a91a811c87c347a languageName: node linkType: hard -"@nivo/axes@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/axes@npm:0.80.0" +"@nivo/axes@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/axes@npm:0.84.0" dependencies: - "@nivo/scales": 0.80.0 - "@react-spring/web": 9.4.5 + "@nivo/core": 0.84.0 + "@nivo/scales": 0.84.0 + "@react-spring/web": 9.4.5 || ^9.7.2 + "@types/d3-format": ^1.4.1 + "@types/d3-time-format": ^2.3.1 + "@types/prop-types": ^15.7.2 d3-format: ^1.4.4 d3-time-format: ^3.0.0 + prop-types: ^15.7.2 peerDependencies: - "@nivo/core": 0.80.0 - prop-types: ">= 15.5.10 < 16.0.0" react: ">= 16.14.0 < 19.0.0" - checksum: 59cea2b3f2dc547f3ebbe920b4c789ac8c5dd4b3e5ba3c323d84f63d052faf813655cca8bb861a035ee064a8d71931bb35e956fc581051c0e86c4a80a1e581df + checksum: 29ad1233935f11f659b1ee18b55f8cb235b6d5eee402381ae7e89c47de565afa81fe30fcf769d28f1cacbc9d2c961d220554089a0a48c742a90cb7c4afc29e51 languageName: node linkType: hard -"@nivo/bar@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/bar@npm:0.80.0" +"@nivo/bar@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/bar@npm:0.84.0" dependencies: - "@nivo/annotations": 0.80.0 - "@nivo/axes": 0.80.0 - "@nivo/colors": 0.80.0 - "@nivo/legends": 0.80.0 - "@nivo/scales": 0.80.0 - "@nivo/tooltip": 0.80.0 - "@react-spring/web": 9.4.5 + "@nivo/annotations": 0.84.0 + "@nivo/axes": 0.84.0 + "@nivo/colors": 0.84.0 + "@nivo/core": 0.84.0 + "@nivo/legends": 0.84.0 + "@nivo/scales": 0.84.0 + "@nivo/tooltip": 0.84.0 + "@react-spring/web": 9.4.5 || ^9.7.2 + "@types/d3-scale": ^3.2.3 + "@types/d3-shape": ^2.0.0 d3-scale: ^3.2.3 d3-shape: ^1.3.5 lodash: ^4.17.21 peerDependencies: - "@nivo/core": 0.80.0 react: ">= 16.14.0 < 19.0.0" - checksum: ab1a243b256970fd4b8a7874e67bbc95aac8d175865ba87b2c1fbc04394d823a752f13b485250aa53528790b5fa8c015a5a66e858ad43883bc6ec8cb49587a52 + checksum: abe7178cbcd2b57fa10804998055e093fa852b99c1296cd09eb202423e8f1f502fe010743c25c2cb2d2f7028560634c266f0a3d94182db82d9fbf767f824ad5d languageName: node linkType: hard -"@nivo/colors@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/colors@npm:0.80.0" +"@nivo/colors@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/colors@npm:0.84.0" dependencies: - d3-color: ^2.0.0 + "@nivo/core": 0.84.0 + "@types/d3-color": ^2.0.0 + "@types/d3-scale": ^3.2.3 + "@types/d3-scale-chromatic": ^2.0.0 + "@types/prop-types": ^15.7.2 + d3-color: ^3.1.0 d3-scale: ^3.2.3 d3-scale-chromatic: ^2.0.0 lodash: ^4.17.21 + prop-types: ^15.7.2 peerDependencies: - "@nivo/core": 0.80.0 - prop-types: ">= 15.5.10 < 16.0.0" react: ">= 16.14.0 < 19.0.0" - checksum: 0dc2044c984d8180d2f0a13fba6b6cdda0a18eec6ef71e9e523794f7ba70ed896231840f22c93f7e30b8730fde26ec07fff8e3d08fef120e91c8a9d552aa1fca + checksum: a319a4d860bf8c6489efa069bcec8e7bc09e859d14e81cfb8e1972fc09ae294ad1e5ca347287846eb41a2e382dd08063b427d942f1030d1dec74049b1bef2f95 languageName: node linkType: hard -"@nivo/core@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/core@npm:0.80.0" +"@nivo/core@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/core@npm:0.84.0" dependencies: - "@nivo/recompose": 0.80.0 - "@react-spring/web": 9.4.5 - d3-color: ^2.0.0 + "@nivo/recompose": 0.84.0 + "@nivo/tooltip": 0.84.0 + "@react-spring/web": 9.4.5 || ^9.7.2 + "@types/d3-shape": ^2.0.0 + d3-color: ^3.1.0 d3-format: ^1.4.4 - d3-interpolate: ^2.0.1 + d3-interpolate: ^3.0.1 d3-scale: ^3.2.3 - d3-scale-chromatic: ^2.0.0 + d3-scale-chromatic: ^3.0.0 d3-shape: ^1.3.5 d3-time-format: ^3.0.0 lodash: ^4.17.21 peerDependencies: - "@nivo/tooltip": 0.80.0 prop-types: ">= 15.5.10 < 16.0.0" react: ">= 16.14.0 < 19.0.0" - checksum: 05fd9ccc9d9876affea17498a2007f5974641c7a2bb1c12c4d8f97bdae48519dd5882c65653074b6756d14eef47dbaeaf8b8243d3e5389efd3d1e180ecbfde75 + checksum: 0b76c624c3f43e07f306cfbc18c86205011cb9928d62322d1ac37784353fd11e95381f4250b8546e536e26c79dda096011fbc4f14778236f7d43b60085ac622b languageName: node linkType: hard -"@nivo/heatmap@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/heatmap@npm:0.80.0" +"@nivo/heatmap@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/heatmap@npm:0.84.0" dependencies: - "@nivo/annotations": 0.80.0 - "@nivo/axes": 0.80.0 - "@nivo/colors": 0.80.0 - "@nivo/legends": 0.80.0 - "@nivo/tooltip": 0.80.0 - "@react-spring/web": 9.4.5 + "@nivo/annotations": 0.84.0 + "@nivo/axes": 0.84.0 + "@nivo/colors": 0.84.0 + "@nivo/core": 0.84.0 + "@nivo/legends": 0.84.0 + "@nivo/scales": 0.84.0 + "@nivo/tooltip": 0.84.0 + "@react-spring/web": 9.4.5 || ^9.7.2 + "@types/d3-scale": ^3.2.3 d3-scale: ^3.2.3 peerDependencies: - "@nivo/core": 0.80.0 react: ">= 16.14.0 < 19.0.0" - checksum: a2bd7693b80bb6ea995a34ad1c6a789d123a8fc9cff7919183f854d4ad49374f80f4c7086d44640b09e0dea5a5fd5c07b3738d35dc7c49c2ad92d1b02d8e0e48 + checksum: f7cf0e843e7ce5c3b8f5310a788ef17e7385371cc668e6920c169545d4d763b2574fe645cacc6009a3ab4f23b4430c606ef0de98da681fb4e0352045e0b74143 languageName: node linkType: hard -"@nivo/legends@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/legends@npm:0.80.0" +"@nivo/legends@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/legends@npm:0.84.0" + dependencies: + "@nivo/colors": 0.84.0 + "@nivo/core": 0.84.0 + "@types/d3-scale": ^3.2.3 + "@types/prop-types": ^15.7.2 + d3-scale: ^3.2.3 + prop-types: ^15.7.2 peerDependencies: - "@nivo/core": 0.80.0 - prop-types: ">= 15.5.10 < 16.0.0" react: ">= 16.14.0 < 19.0.0" - checksum: 659aba35105143ac7da663a51bc6a69f815e23efd278b8b1314bd48b9c853f4c3b7e9cf61de1439390eff3983b754eaea5dd3923fa2caad97b0fca6133a05ae9 + checksum: 321c44b168d8fe8f3133182c398a339b77c2105a0f5522093e08e4beb0aeecaec8ecc50c9fe92ecac98d94013b21243892b51a0ba95b5c36b2017c70161290a5 languageName: node linkType: hard -"@nivo/line@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/line@npm:0.80.0" +"@nivo/line@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/line@npm:0.84.0" dependencies: - "@nivo/annotations": 0.80.0 - "@nivo/axes": 0.80.0 - "@nivo/colors": 0.80.0 - "@nivo/legends": 0.80.0 - "@nivo/scales": 0.80.0 - "@nivo/tooltip": 0.80.0 - "@nivo/voronoi": 0.80.0 - "@react-spring/web": 9.4.5 + "@nivo/annotations": 0.84.0 + "@nivo/axes": 0.84.0 + "@nivo/colors": 0.84.0 + "@nivo/core": 0.84.0 + "@nivo/legends": 0.84.0 + "@nivo/scales": 0.84.0 + "@nivo/tooltip": 0.84.0 + "@nivo/voronoi": 0.84.0 + "@react-spring/web": 9.4.5 || ^9.7.2 d3-shape: ^1.3.5 + prop-types: ^15.7.2 peerDependencies: - "@nivo/core": 0.80.0 - prop-types: ">= 15.5.10 < 16.0.0" react: ">= 16.14.0 < 19.0.0" - checksum: e2d83971e5d530b4465e628f926d2b311a39ce0fa137b0c942532ca58959d78ced21166e83ce9644c91bf2a2929ac539fdd4307fc7ceda986050346b662de1a3 + checksum: 70dc4caf8335d0eaab76610a11fcbf63dc2ea0d9a2bf7f4c177972de5acf071478c8d02599ec32caf2bf130106304c6b5a0991da760512d2808ad222d84dba3e languageName: node linkType: hard -"@nivo/pie@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/pie@npm:0.80.0" +"@nivo/pie@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/pie@npm:0.84.0" dependencies: - "@nivo/arcs": 0.80.0 - "@nivo/colors": 0.80.0 - "@nivo/legends": 0.80.0 - "@nivo/tooltip": 0.80.0 + "@nivo/arcs": 0.84.0 + "@nivo/colors": 0.84.0 + "@nivo/core": 0.84.0 + "@nivo/legends": 0.84.0 + "@nivo/tooltip": 0.84.0 + "@types/d3-shape": ^2.0.0 d3-shape: ^1.3.5 peerDependencies: - "@nivo/core": 0.80.0 react: ">= 16.14.0 < 19.0.0" - checksum: 7267588118b21c01573ffb498e2c24b560a50097900dc4d6426cd4633c9dade51fd4a5fa868747fe9f190eb5e336892461985424cc2f4c990707f7ac610931db + checksum: 5308b191c9aceba492785b36885eea50187aedf489523b45b580b9f8bccaf6c0477cc9a19a7264345bcb6288cbd0096524af69cab8253936d3bacad1a0d45231 languageName: node linkType: hard -"@nivo/recompose@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/recompose@npm:0.80.0" +"@nivo/recompose@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/recompose@npm:0.84.0" dependencies: + "@types/prop-types": ^15.7.2 + "@types/react-lifecycles-compat": ^3.0.1 + prop-types: ^15.7.2 react-lifecycles-compat: ^3.0.4 peerDependencies: react: ">= 16.14.0 < 19.0.0" - checksum: 5495eeba137f4d3a46d1ada99948c5b097ccf00c532f10a627bb0525c6fbab14d93c9297a25d90c0041f72432efbd4e9a2ef5d408063e2c4cf25d05f33b1fcc5 + checksum: 7b1dbd32a3ffa35332e30f4bb642413ca5a9f999de042e0e63d933b619ed8da2f1d57a7fa524b10a7a571fc2e1aa39ea9dca026e9d536efd3aacbd53fbe4a1a8 languageName: node linkType: hard -"@nivo/scales@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/scales@npm:0.80.0" +"@nivo/scales@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/scales@npm:0.84.0" dependencies: + "@types/d3-scale": ^3.2.3 + "@types/d3-time": ^1.1.1 + "@types/d3-time-format": ^3.0.0 d3-scale: ^3.2.3 d3-time: ^1.0.11 d3-time-format: ^3.0.0 lodash: ^4.17.21 - checksum: 75bdc838ab593306268cda2c098430cb5ff1f20ab73dd5d61845fa013e30fd85020c910c9dd0a7641d90ee04f86031af71a250f5f5992fe74a23bcf4fb954f95 + checksum: 0f1f6dcfa8963baabefde0aea11bcc208f54f137d776df20a251912254ed6815b3a880d12e256cdd649053c5123ef5018b8fb6798fb0fa8653f021421d43ce03 languageName: node linkType: hard -"@nivo/tooltip@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/tooltip@npm:0.80.0" +"@nivo/tooltip@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/tooltip@npm:0.84.0" dependencies: - "@react-spring/web": 9.4.5 - peerDependencies: - "@nivo/core": 0.80.0 - checksum: bc0eec5d0d05f653186b040105d7451c823d8ee0844b7767f3d827424346d6379966452055be168994132ca8610f1956798274701a1bb948d3e8d961f23a07b7 + "@nivo/core": 0.84.0 + "@react-spring/web": 9.4.5 || ^9.7.2 + checksum: 110f924bd8dda5c9e921bba8e143557e3ecd3de46ae7acffb47c6f954f1080269d3cf1e187e62edb94fb512708bd531d34cc33533a039b1d72ec9faabbf98f19 languageName: node linkType: hard -"@nivo/voronoi@npm:0.80.0": - version: 0.80.0 - resolution: "@nivo/voronoi@npm:0.80.0" +"@nivo/voronoi@npm:0.84.0": + version: 0.84.0 + resolution: "@nivo/voronoi@npm:0.84.0" dependencies: + "@nivo/core": 0.84.0 + "@types/d3-delaunay": ^5.3.0 + "@types/d3-scale": ^3.2.3 d3-delaunay: ^5.3.0 d3-scale: ^3.2.3 peerDependencies: - "@nivo/core": 0.80.0 react: ">= 16.14.0 < 19.0.0" - checksum: 7b4f844611f64742c5ed14e94fa7a3f813d0b6cde04c40c3d597e0d4180977db8fe957ff4f4b1c5a131e4c43e20a01e684c8b934e0b9583d726b2b13986e9efb + checksum: 1f3dd880ae10e6b230a678830cea1f8d6b7218ba551e350fe6bd21bcf378bad74ff5e3460696e387c7839c92b862268277e4e2750b3e0afbb9272c28e1779bb6 languageName: node linkType: hard @@ -7620,70 +7648,61 @@ __metadata: languageName: node linkType: hard -"@react-spring/animated@npm:~9.4.5": - version: 9.4.5 - resolution: "@react-spring/animated@npm:9.4.5" +"@react-spring/animated@npm:~9.7.3": + version: 9.7.3 + resolution: "@react-spring/animated@npm:9.7.3" dependencies: - "@react-spring/shared": ~9.4.5 - "@react-spring/types": ~9.4.5 + "@react-spring/shared": ~9.7.3 + "@react-spring/types": ~9.7.3 peerDependencies: - react: ^16.8.0 || >=17.0.0 || >=18.0.0 - checksum: e85c0bd65bd76e1c8ca830b22e31956401e29593cbc1df7560f5b77bd7b31acded61e1732717803cdfd993f30c2559ffbd6fb5f0d48b1c749323bee3597d7834 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 468942ca3a11c02c3e56def26b2da9dd10ddbed548004245c4ac309cce00b58d971e781abed67db0d652f72737eaa73766ea9a43b8ef3b08a7ed2eddc04d4c39 languageName: node linkType: hard -"@react-spring/core@npm:~9.4.5": - version: 9.4.5 - resolution: "@react-spring/core@npm:9.4.5" +"@react-spring/core@npm:~9.7.3": + version: 9.7.3 + resolution: "@react-spring/core@npm:9.7.3" dependencies: - "@react-spring/animated": ~9.4.5 - "@react-spring/rafz": ~9.4.5 - "@react-spring/shared": ~9.4.5 - "@react-spring/types": ~9.4.5 + "@react-spring/animated": ~9.7.3 + "@react-spring/shared": ~9.7.3 + "@react-spring/types": ~9.7.3 peerDependencies: - react: ^16.8.0 || >=17.0.0 || >=18.0.0 - checksum: e5aee7f68f15c9d5d6f230703d22cb34edb8aae3ba0d70c01847f7c78e47f9f8177f87c095aff5ed1b98c2a218238d5ec28f9bf451f3e13bfdad6e3170a60226 - languageName: node - linkType: hard - -"@react-spring/rafz@npm:~9.4.5": - version: 9.4.5 - resolution: "@react-spring/rafz@npm:9.4.5" - checksum: 0ac722881b107baf55338a0123bc889d88faca53f034eb6d26ebab3ae6e4dc1717654b09d0e6e5e9bf587c2ba182d6aae90ca22c833dc55024ee52d88f8579a2 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 8a80a07276458fd14099320eda824e58a11ce3a9b03a5c9cd3f4252adb4d26da04ee5caf5cbc961199f55c2d58a99638d5ea292cdb6aa029208dbab741b5c531 languageName: node linkType: hard -"@react-spring/shared@npm:~9.4.5": - version: 9.4.5 - resolution: "@react-spring/shared@npm:9.4.5" +"@react-spring/shared@npm:~9.7.3": + version: 9.7.3 + resolution: "@react-spring/shared@npm:9.7.3" dependencies: - "@react-spring/rafz": ~9.4.5 - "@react-spring/types": ~9.4.5 + "@react-spring/types": ~9.7.3 peerDependencies: - react: ^16.8.0 || >=17.0.0 || >=18.0.0 - checksum: 2f20e410c03166de19b2d668d6841d24778c37da3083d37fe70acfcf2cf0cb3bd4a5cf92d42f1590b9de5d0a6603dc75cf8c319c0089df4e713226364a204b51 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 912b5e567eb5345c9a6c8e8c0c2d69b1f411af72a0685b95831809c267c89846a31341ca071f284ace98b3cb5de647054dc76f6ace81d6379513eaf96b52f195 languageName: node linkType: hard -"@react-spring/types@npm:~9.4.5": - version: 9.4.5 - resolution: "@react-spring/types@npm:9.4.5" - checksum: f8fecb54015de23899cc595d949e3676835e612d4dda05af470cab9ee20dd98c86ebca1c4ba75d2a9f63a4acba4b75febf6bab71da0b2e9556e6ff684b22f139 +"@react-spring/types@npm:~9.7.3": + version: 9.7.3 + resolution: "@react-spring/types@npm:9.7.3" + checksum: f47b81fe556464aa54a78603311cb584d6a0f03088522229afb058265bbe2ade2095a55ec7f4e960c3b9cceaa5d47865bc41fc6643c0f5f4bd3d8650203d8389 languageName: node linkType: hard -"@react-spring/web@npm:9.4.5": - version: 9.4.5 - resolution: "@react-spring/web@npm:9.4.5" +"@react-spring/web@npm:9.4.5 || ^9.7.2": + version: 9.7.3 + resolution: "@react-spring/web@npm:9.7.3" dependencies: - "@react-spring/animated": ~9.4.5 - "@react-spring/core": ~9.4.5 - "@react-spring/shared": ~9.4.5 - "@react-spring/types": ~9.4.5 + "@react-spring/animated": ~9.7.3 + "@react-spring/core": ~9.7.3 + "@react-spring/shared": ~9.7.3 + "@react-spring/types": ~9.7.3 peerDependencies: - react: ^16.8.0 || >=17.0.0 || >=18.0.0 - react-dom: ^16.8.0 || >=17.0.0 || >=18.0.0 - checksum: 9d7eea4b8b0399c205743acade141679f3f729a64631f8480d44d14bb59781ea807977a4671cbe1d56e31389b69ef325ec975275446f08997f555f2981d220c8 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 7f5cd05b2314b7f2f715e1926abcf9aa0a539399b222ab34e989144f48350adfcd2edab65d41425570f72c57f602fc6994d6730fbeed902171ac527b630a8a9b languageName: node linkType: hard @@ -9425,11 +9444,11 @@ __metadata: "@faker-js/faker": ~8.0.2 "@google-cloud/storage": ^6.11.0 "@kaciras/deasync": ^1.0.3 - "@nivo/bar": 0.80.0 - "@nivo/core": 0.80.0 - "@nivo/heatmap": 0.80.0 - "@nivo/line": 0.80.0 - "@nivo/pie": 0.80.0 + "@nivo/bar": 0.84.0 + "@nivo/core": 0.84.0 + "@nivo/heatmap": 0.84.0 + "@nivo/line": 0.84.0 + "@nivo/pie": 0.84.0 "@playwright/test": ^1.37.1 "@react-aria/color": ^3.0.0-beta.15 "@react-pdf/renderer": ^3.1.14 @@ -13062,6 +13081,87 @@ __metadata: languageName: node linkType: hard +"@types/d3-color@npm:^2.0.0": + version: 2.0.6 + resolution: "@types/d3-color@npm:2.0.6" + checksum: 0b8394204345424f8a38f7b185bcf1346080be040bceebd5ca912ffdb9072a7f89d42d82713dcbd3341eb820f1430f03353b55ed02bb3385f4fd7942fbba22a9 + languageName: node + linkType: hard + +"@types/d3-delaunay@npm:^5.3.0": + version: 5.3.4 + resolution: "@types/d3-delaunay@npm:5.3.4" + checksum: d4568c19a7d2566b6bd49351f15f755809aff69e24939df50e4ad1a5e4363c6c65cd365c4978e90dd44d393fd8b52f1b99ce9960e8f2205e6a03e539f74e1905 + languageName: node + linkType: hard + +"@types/d3-format@npm:^1.4.1": + version: 1.4.5 + resolution: "@types/d3-format@npm:1.4.5" + checksum: f284da718785080cc3ee598c3585285c04585e4dc57631aca1051bda43bd6348e8256399b5f8a4f3af99809acedde3a74cd41aebdd4ce4c714f7cc554552e29b + languageName: node + linkType: hard + +"@types/d3-path@npm:^2": + version: 2.0.4 + resolution: "@types/d3-path@npm:2.0.4" + checksum: 054005eeef4420a1d2867509e25da419521086b9d2aa22b45095b77604cfef1b8208742063cac3bfd82e4ff8b0214d4c64bf5f0e08fa4c7919114d30af4fdf9d + languageName: node + linkType: hard + +"@types/d3-scale-chromatic@npm:^2.0.0": + version: 2.0.4 + resolution: "@types/d3-scale-chromatic@npm:2.0.4" + checksum: d598c0bc45463275fceeb07983969007cd67f2083ba814bd14949ababff4e458398f20b0cf2229df355a81c657effe14be4469f89c75157563d792c62c560e94 + languageName: node + linkType: hard + +"@types/d3-scale@npm:^3.2.3": + version: 3.3.5 + resolution: "@types/d3-scale@npm:3.3.5" + dependencies: + "@types/d3-time": ^2 + checksum: e6ffe97c3022c857a88f73775930bd577fa55460f65eaf68038cd39d1b5d8e4a9941440b5ac8d382568463f04ca68d6b7c3e596f4ec6575c388db17305ca1524 + languageName: node + linkType: hard + +"@types/d3-shape@npm:^2.0.0": + version: 2.1.7 + resolution: "@types/d3-shape@npm:2.1.7" + dependencies: + "@types/d3-path": ^2 + checksum: c83f53a016e1ccfaa6104458b73ae2b1c87de0e4ddf8c43a11ceba87652965273a4b33e49d552be34f7d04b24fc380f21a1958f86ab1fd863da78e957e88af34 + languageName: node + linkType: hard + +"@types/d3-time-format@npm:^2.3.1": + version: 2.3.4 + resolution: "@types/d3-time-format@npm:2.3.4" + checksum: 5351ee0bcd5d181dfc120b5652802ae4cd8f8def60b9e3638a83464456d376e8fce7a6c50e2b4d7f186fb8a31aa28fda9b8d3e7b3c816941da71b66938e4fb9f + languageName: node + linkType: hard + +"@types/d3-time-format@npm:^3.0.0": + version: 3.0.4 + resolution: "@types/d3-time-format@npm:3.0.4" + checksum: d2aa42854b833342d0536927deae533eb2302232ee253cf271ee9f935784b61eb9605ab706fbcba72b83564ffce88c02fd437f72bc068779ed9166a5de019637 + languageName: node + linkType: hard + +"@types/d3-time@npm:^1.1.1": + version: 1.1.4 + resolution: "@types/d3-time@npm:1.1.4" + checksum: a794a2e05365de5bd4b139d7ff94f0d9eeb362116677f1edadb1aa08d5ddb93c4e50ace092f8fa9d7358efab5073770654ac6d294a2a39ca5106c0a55f38c22e + languageName: node + linkType: hard + +"@types/d3-time@npm:^2": + version: 2.1.4 + resolution: "@types/d3-time@npm:2.1.4" + checksum: e5898c5520a536ea65b18d003d6d89e2def04c23ad15977240fe27558e8cc7ea5d0c362850090d5850d5fcd788cc6c6b16802c6826f932456aeebe9e2ddbce8a + languageName: node + linkType: hard + "@types/debug@npm:^4.1.10": version: 4.1.10 resolution: "@types/debug@npm:4.1.10" @@ -13795,6 +13895,13 @@ __metadata: languageName: node linkType: hard +"@types/prop-types@npm:^15.7.2": + version: 15.7.11 + resolution: "@types/prop-types@npm:15.7.11" + checksum: 7519ff11d06fbf6b275029fe03fff9ec377b4cb6e864cac34d87d7146c7f5a7560fd164bdc1d2dbe00b60c43713631251af1fd3d34d46c69cd354602bc0c7c54 + languageName: node + linkType: hard + "@types/proxy-from-env@npm:^1.0.3": version: 1.0.3 resolution: "@types/proxy-from-env@npm:1.0.3" @@ -13866,6 +13973,15 @@ __metadata: 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" + dependencies: + "@types/react": "*" + checksum: 504665a1a83be43ab43cbd3d19fd94d0de6634543f06351cce80c844628048650f2cf063048e5dc39effdf0053565ae60a04427e79d094714d6aeb84d5c9643e + languageName: node + linkType: hard + "@types/react-redux@npm:^7.1.20": version: 7.1.25 resolution: "@types/react-redux@npm:7.1.25" @@ -19608,13 +19724,20 @@ __metadata: languageName: node linkType: hard -"d3-color@npm:1 - 2, d3-color@npm:^2.0.0": +"d3-color@npm:1 - 2": version: 2.0.0 resolution: "d3-color@npm:2.0.0" checksum: b887354aa383937abd04fbffed3e26e5d6a788472cd3737fb10735930e427763e69fe93398663bccf88c0b53ee3e638ac6fcf0c02226b00ed9e4327c2dfbf3dc languageName: node linkType: hard +"d3-color@npm:1 - 3, d3-color@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-color@npm:3.1.0" + checksum: 4931fbfda5d7c4b5cfa283a13c91a954f86e3b69d75ce588d06cde6c3628cebfc3af2069ccf225e982e8987c612aa7948b3932163ce15eb3c11cd7c003f3ee3b + languageName: node + linkType: hard + "d3-delaunay@npm:^5.3.0": version: 5.3.0 resolution: "d3-delaunay@npm:5.3.0" @@ -19638,7 +19761,7 @@ __metadata: languageName: node linkType: hard -"d3-interpolate@npm:1 - 2, d3-interpolate@npm:1.2.0 - 2, d3-interpolate@npm:^2.0.1": +"d3-interpolate@npm:1 - 2, d3-interpolate@npm:1.2.0 - 2": version: 2.0.1 resolution: "d3-interpolate@npm:2.0.1" dependencies: @@ -19647,6 +19770,15 @@ __metadata: languageName: node linkType: hard +"d3-interpolate@npm:1 - 3, d3-interpolate@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-interpolate@npm:3.0.1" + dependencies: + d3-color: 1 - 3 + checksum: a42ba314e295e95e5365eff0f604834e67e4a3b3c7102458781c477bd67e9b24b6bb9d8e41ff5521050a3f2c7c0c4bbbb6e187fd586daa3980943095b267e78b + languageName: node + linkType: hard + "d3-path@npm:1": version: 1.0.9 resolution: "d3-path@npm:1.0.9" @@ -19664,6 +19796,16 @@ __metadata: languageName: node linkType: hard +"d3-scale-chromatic@npm:^3.0.0": + version: 3.0.0 + resolution: "d3-scale-chromatic@npm:3.0.0" + dependencies: + d3-color: 1 - 3 + d3-interpolate: 1 - 3 + checksum: a8ce4cb0267a17b28ebbb929f5e3071d985908a9c13b6fcaa2a198e1e018f275804d691c5794b970df0049725b7944f32297b31603d235af6414004f0c7f82c0 + languageName: node + linkType: hard + "d3-scale@npm:^3.2.3": version: 3.3.0 resolution: "d3-scale@npm:3.3.0" From 4d473bb7a53936fce4d800f21fc9378c5e3aaabf Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Wed, 3 Jan 2024 13:53:21 -0300 Subject: [PATCH 02/13] chore: add aria-label to Select Inputs at Engagement Dashboard (#31249) --- .../ee/client/components/dashboards/PeriodSelector.tsx | 10 +++++++++- .../engagementDashboard/EngagementDashboardPage.tsx | 7 ++++++- .../users/BusiestChatTimesSection.tsx | 7 ++++++- apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json | 3 ++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/meteor/ee/client/components/dashboards/PeriodSelector.tsx b/apps/meteor/ee/client/components/dashboards/PeriodSelector.tsx index 7d84a4df62d2..6977e3334f4f 100644 --- a/apps/meteor/ee/client/components/dashboards/PeriodSelector.tsx +++ b/apps/meteor/ee/client/components/dashboards/PeriodSelector.tsx @@ -18,7 +18,15 @@ const PeriodSelector = ({ periods, value, name, o const options = useMemo<[string, string][]>(() => periods.map((period) => [period, t(...getPeriod(period).label)]), [periods, t]); - return onChange(value as TPeriod)} + aria-label={t('Select_period')} + /> + ); }; export default PeriodSelector; diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx index 711798dc4907..de40e04dcfca 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx @@ -35,7 +35,12 @@ const EngagementDashboardPage = ({ tab = 'users', onSelectTab }: EngagementDashb return ( - handleTimezoneChange(String(value))} + aria-label={t('Default_Timezone_For_Reporting')} + /> diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/users/BusiestChatTimesSection.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/users/BusiestChatTimesSection.tsx index de8ebee6dfe3..f70acde3a8e4 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/users/BusiestChatTimesSection.tsx +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/users/BusiestChatTimesSection.tsx @@ -45,7 +45,12 @@ const BusiestChatTimesSection = ({ timezone }: BusiestChatTimesSectionProps): Re return ( <> - handleTimeUnitChange(String(value))} + aria-label={t('Select_period')} + /> Date: Wed, 3 Jan 2024 23:19:22 +0530 Subject: [PATCH 03/13] fix: Attachments not collapsing when using incoming webhook (#31318) Co-authored-by: Hugo Costa <20212776+hugocostadev@users.noreply.github.com> --- .changeset/attachment-collapse.md | 5 +++++ .../meteor/client/components/message/content/Attachments.tsx | 5 ++--- .../message/content/attachments/QuoteAttachment.tsx | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 .changeset/attachment-collapse.md diff --git a/.changeset/attachment-collapse.md b/.changeset/attachment-collapse.md new file mode 100644 index 000000000000..b4302b83fe76 --- /dev/null +++ b/.changeset/attachment-collapse.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed Attachments not respecting collapse property when using incoming webhook diff --git a/apps/meteor/client/components/message/content/Attachments.tsx b/apps/meteor/client/components/message/content/Attachments.tsx index 2c1b6675cb7b..ea9c03b9e7d3 100644 --- a/apps/meteor/client/components/message/content/Attachments.tsx +++ b/apps/meteor/client/components/message/content/Attachments.tsx @@ -6,15 +6,14 @@ import AttachmentsItem from './attachments/AttachmentsItem'; type AttachmentsProps = { attachments: MessageAttachmentBase[]; - collapsed?: boolean; id?: string | undefined; }; -const Attachments = ({ attachments, collapsed, id }: AttachmentsProps): ReactElement => { +const Attachments = ({ attachments, id }: AttachmentsProps): ReactElement => { return ( <> {attachments?.map((attachment, index) => ( - + ))} ); diff --git a/apps/meteor/client/components/message/content/attachments/QuoteAttachment.tsx b/apps/meteor/client/components/message/content/attachments/QuoteAttachment.tsx index 67232cbd441f..16f4764fb63c 100644 --- a/apps/meteor/client/components/message/content/attachments/QuoteAttachment.tsx +++ b/apps/meteor/client/components/message/content/attachments/QuoteAttachment.tsx @@ -68,7 +68,7 @@ export const QuoteAttachment = ({ attachment }: QuoteAttachmentProps): ReactElem {attachment.md ? : attachment.text.substring(attachment.text.indexOf('\n') + 1)} {attachment.attachments && ( - + )} From 0da74237d4cc9ab283a89238bca9579a46072dbe Mon Sep 17 00:00:00 2001 From: Jean Brito Date: Wed, 3 Jan 2024 11:35:27 -0800 Subject: [PATCH 04/13] feat: Add Desktop PDF viewer (#31279) Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Co-authored-by: Tasso Evangelista <2263066+tassoevan@users.noreply.github.com> --- .../file/GenericFileAttachment.tsx | 27 ++++++++++++++++--- .../client/definitions/IRocketChatDesktop.ts | 10 +++++++ apps/meteor/client/definitions/global.d.ts | 8 ++++++ .../lib/utils/window.RocketChatDesktop.d.ts | 14 ---------- 4 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 apps/meteor/client/definitions/IRocketChatDesktop.ts create mode 100644 apps/meteor/client/definitions/global.d.ts delete mode 100644 apps/meteor/client/lib/utils/window.RocketChatDesktop.d.ts diff --git a/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx b/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx index cbf1749b9dcd..8610ae26ff6f 100644 --- a/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx +++ b/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx @@ -7,7 +7,7 @@ import { MessageGenericPreviewDescription, } from '@rocket.chat/fuselage'; import { useMediaUrl } from '@rocket.chat/ui-contexts'; -import type { FC } from 'react'; +import type { UIEvent } from 'react'; import React from 'react'; import { getFileExtension } from '../../../../../../lib/utils/getFileExtension'; @@ -16,7 +16,11 @@ import MessageCollapsible from '../../../MessageCollapsible'; import MessageContentBody from '../../../MessageContentBody'; import AttachmentSize from '../structure/AttachmentSize'; -export const GenericFileAttachment: FC = ({ +const openDocumentViewer = window.RocketChatDesktop?.openDocumentViewer; + +type GenericFileAttachmentProps = MessageAttachmentBase; + +export const GenericFileAttachment = ({ title, description, descriptionMd, @@ -25,9 +29,24 @@ export const GenericFileAttachment: FC = ({ size, format, collapsed, -}) => { +}: GenericFileAttachmentProps) => { const getURL = useMediaUrl(); + const handleTitleClick = (event: UIEvent): void => { + if (openDocumentViewer && link && format === 'PDF') { + event.preventDefault(); + openDocumentViewer(getURL(link), format, ''); + } + }; + + const getExternalUrl = () => { + if (!hasDownload || !link) return undefined; + + if (openDocumentViewer) return `${getURL(link)}?download`; + + return getURL(link); + }; + return ( <> {descriptionMd ? : } @@ -36,7 +55,7 @@ export const GenericFileAttachment: FC = ({ } > - + {title} {size && ( diff --git a/apps/meteor/client/definitions/IRocketChatDesktop.ts b/apps/meteor/client/definitions/IRocketChatDesktop.ts new file mode 100644 index 000000000000..52bc172d719b --- /dev/null +++ b/apps/meteor/client/definitions/IRocketChatDesktop.ts @@ -0,0 +1,10 @@ +type OutlookEventsResponse = { status: 'success' | 'canceled' }; + +export interface IRocketChatDesktop { + openInternalVideoChatWindow?: (url: string, options: { providerName: string | undefined }) => void; + getOutlookEvents?: (date: Date) => Promise; + setOutlookExchangeUrl?: (url: string, userId: string) => Promise; + hasOutlookCredentials?: () => Promise; + clearOutlookCredentials?: () => void; + openDocumentViewer?: (url: string, format: string, options: any) => void; +} diff --git a/apps/meteor/client/definitions/global.d.ts b/apps/meteor/client/definitions/global.d.ts new file mode 100644 index 000000000000..8b20108e8e48 --- /dev/null +++ b/apps/meteor/client/definitions/global.d.ts @@ -0,0 +1,8 @@ +import type { IRocketChatDesktop } from './IRocketChatDesktop'; + +declare global { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Window { + RocketChatDesktop?: IRocketChatDesktop; + } +} diff --git a/apps/meteor/client/lib/utils/window.RocketChatDesktop.d.ts b/apps/meteor/client/lib/utils/window.RocketChatDesktop.d.ts deleted file mode 100644 index a7f625fc0705..000000000000 --- a/apps/meteor/client/lib/utils/window.RocketChatDesktop.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -type OutlookEventsResponse = { status: 'success' | 'canceled' }; - -// eslint-disable-next-line @typescript-eslint/naming-convention -interface Window { - RocketChatDesktop: - | { - openInternalVideoChatWindow?: (url: string, options: { providerName: string | undefined }) => void; - getOutlookEvents?: (date: Date) => Promise; - setOutlookExchangeUrl?: (url: string, userId: string) => Promise; - hasOutlookCredentials?: () => Promise; - clearOutlookCredentials?: () => void; - } - | undefined; -} From 8677f15612aad73cafa10eb91af6cca72eff2fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?= <60678893+juliajforesti@users.noreply.github.com> Date: Thu, 4 Jan 2024 12:01:11 -0300 Subject: [PATCH 05/13] regression: `AppRow` bundleIn verification (#31373) --- apps/meteor/client/views/marketplace/AppsList/AppRow.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx b/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx index 4fba7de54e0d..dffa23d7a2c8 100644 --- a/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx +++ b/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx @@ -66,7 +66,7 @@ const AppRow = ({ className, ...props }: App & { className?: string }): ReactEle {name} - {Boolean(bundledIn.length) && } + {Boolean(bundledIn?.length) && } {shortDescription && {shortDescription}} From 9fd77ee9596663a368e1cc3266ccc94b8a05a92d Mon Sep 17 00:00:00 2001 From: Harsh <102225113+senbo1@users.noreply.github.com> Date: Fri, 5 Jan 2024 05:20:21 +0530 Subject: [PATCH 06/13] i18n: adds video call translations for Persian language (#30406) --- apps/meteor/packages/rocketchat-i18n/i18n/fa.i18n.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/fa.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/fa.i18n.json index 724f3d3e7948..a4a6d7e4e879 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/fa.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/fa.i18n.json @@ -1667,6 +1667,7 @@ "Job_Title": "عنوان شغلی", "Join": "پیوستن", "Join_audio_call": "پیوستن به تماس صوتی", + "Join_call":"پیوستن به تماس.", "Join_Chat": "عضویت در چت", "Join_default_channels": "پیوستن به کانال های پیشفرض", "Join_the_Community": "پیوستن به جامعه", @@ -2949,6 +2950,7 @@ "Video_Conference": "ویدیو کنفرانس", "Video_message": "پیام ویدویی", "Videocall_declined": "تماس ویدیویی رد شد", + "video_livechat_started": "شروع یک تماس ویدیویی." , "View_mode": "شیوه نمایش", "View_All": "مشاهده همه", "View_Logs": "نمایش سیاهههای مربوط", From d754d76c11f0f06d20e7e0eae1f675cd7fd9abc7 Mon Sep 17 00:00:00 2001 From: lestercoyoy <52750976+lestercoyoyjr@users.noreply.github.com> Date: Thu, 4 Jan 2024 20:14:13 -0600 Subject: [PATCH 07/13] i18n: update translations (#29462) --- apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index 78080fd282b5..013f79e23b2d 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -4200,7 +4200,7 @@ "Quote": "Quote", "Random": "Random", "Rate Limiter": "Rate Limiter", - "Rate Limiter_Description": "Control the rate of requests sent or recieved by your server to prevent cyber attacks and scraping.", + "Rate Limiter_Description": "Control the rate of requests sent or received by your server to prevent cyber attacks and scraping.", "Rate_Limiter_Limit_RegisterUser": "Default number calls to the rate limiter for registering a user", "Rate_Limiter_Limit_RegisterUser_Description": "Number of default calls for user registering endpoints(REST and real-time API's), allowed within the time range defined in the API Rate Limiter section.", "React_when_read_only": "Allow Reacting", From b07873407f3de22b5433a2f1e70d41a99a1a965d Mon Sep 17 00:00:00 2001 From: Marcos Spessatto Defendi Date: Fri, 5 Jan 2024 08:55:26 -0300 Subject: [PATCH 08/13] test: bump playwright (#31376) --- .github/workflows/ci-test-e2e.yml | 2 +- apps/meteor/package.json | 2 +- yarn.lock | 40 +++++++++++++++++++------------ 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index eb7b228022c3..3f75695b4877 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -160,7 +160,7 @@ jobs: path: | ~/.cache/ms-playwright # This is the version of Playwright that we are using, if you are willing to upgrade, you should update this. - key: playwright-1.37.1 + key: playwright-1.40.1 - name: Install Playwright if: inputs.type == 'ui' && steps.cache-playwright.outputs.cache-hit != 'true' diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 4077a7c1087d..2db612565917 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -73,7 +73,7 @@ "@babel/preset-react": "~7.22.15", "@babel/register": "~7.22.15", "@faker-js/faker": "~8.0.2", - "@playwright/test": "^1.37.1", + "@playwright/test": "^1.40.1", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/livechat": "workspace:^", "@rocket.chat/mock-providers": "workspace:^", diff --git a/yarn.lock b/yarn.lock index 7c1a736f70e9..b3d14ad61044 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5898,19 +5898,14 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:^1.37.1": - version: 1.37.1 - resolution: "@playwright/test@npm:1.37.1" +"@playwright/test@npm:^1.40.1": + version: 1.40.1 + resolution: "@playwright/test@npm:1.40.1" dependencies: - "@types/node": "*" - fsevents: 2.3.2 - playwright-core: 1.37.1 - dependenciesMeta: - fsevents: - optional: true + playwright: 1.40.1 bin: playwright: cli.js - checksum: b7038f29000289103c08b215eff7aabdda70cdc1375fa7dad0e81651be71086a1e2fc0e0e29dc70348037c366cf0cc69f762373fda34ba1a74aa1658741d9195 + checksum: ae094e6cb809365c0707ee2b184e42d2a2542569ada020d2d44ca5866066941262bd9a67af185f86c2fb0133c9b712ea8cb73e2959a289e4261c5fd17077283c languageName: node linkType: hard @@ -9449,7 +9444,7 @@ __metadata: "@nivo/heatmap": 0.84.0 "@nivo/line": 0.84.0 "@nivo/pie": 0.84.0 - "@playwright/test": ^1.37.1 + "@playwright/test": ^1.40.1 "@react-aria/color": ^3.0.0-beta.15 "@react-pdf/renderer": ^3.1.14 "@rocket.chat/account-utils": "workspace:^" @@ -32526,12 +32521,12 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.37.1": - version: 1.37.1 - resolution: "playwright-core@npm:1.37.1" +"playwright-core@npm:1.40.1": + version: 1.40.1 + resolution: "playwright-core@npm:1.40.1" bin: playwright-core: cli.js - checksum: 69f818da2230057584140d5b3af7778a4f4a822b5b18d133abfc5d259128becb943c343a2ddf6b0635277a69f28983e83e2bc3fce23595ececb1e410475b6368 + checksum: 84d92fb9b86e3c225b16b6886bf858eb5059b4e60fa1205ff23336e56a06dcb2eac62650992dede72f406c8e70a7b6a5303e511f9b4bc0b85022ede356a01ee0 languageName: node linkType: hard @@ -32546,6 +32541,21 @@ __metadata: languageName: node linkType: hard +"playwright@npm:1.40.1": + version: 1.40.1 + resolution: "playwright@npm:1.40.1" + dependencies: + fsevents: 2.3.2 + playwright-core: 1.40.1 + dependenciesMeta: + fsevents: + optional: true + bin: + playwright: cli.js + checksum: 9e36791c1b4a649c104aa365fdd9d049924eeb518c5967c0e921aa38b9b00994aa6ee54784d6c2af194b3b494b6f69772673081ef53c6c4a4b2065af9955c4ba + languageName: node + linkType: hard + "please-upgrade-node@npm:^3.2.0": version: 3.2.0 resolution: "please-upgrade-node@npm:3.2.0" From bef7db1a7350abe833ac753977a637df2524e428 Mon Sep 17 00:00:00 2001 From: Marcos Spessatto Defendi Date: Fri, 5 Jan 2024 09:03:14 -0300 Subject: [PATCH 09/13] chore: services changes on lifecycle methods + throw if svc is not available (#31375) --- .../app/statistics/server/lib/statistics.ts | 6 +- apps/meteor/ee/server/NetworkBroker.ts | 1 + .../server/local-services/instance/service.ts | 14 ++-- .../server/services/authorization/service.ts | 20 +++--- ee/apps/ddp-streamer/src/DDPStreamer.ts | 70 ++++++++++--------- ee/apps/ddp-streamer/src/configureServer.ts | 4 +- packages/core-services/src/LocalBroker.ts | 6 ++ 7 files changed, 74 insertions(+), 47 deletions(-) diff --git a/apps/meteor/app/statistics/server/lib/statistics.ts b/apps/meteor/app/statistics/server/lib/statistics.ts index c0ef16b5025b..166e5553df2b 100644 --- a/apps/meteor/app/statistics/server/lib/statistics.ts +++ b/apps/meteor/app/statistics/server/lib/statistics.ts @@ -592,7 +592,11 @@ export const statistics = { const defaultLoggedInCustomScript = (await Settings.findOneById('Custom_Script_Logged_In'))?.packageValue; statistics.loggedInCustomScriptChanged = settings.get('Custom_Script_Logged_In') !== defaultLoggedInCustomScript; - statistics.dailyPeakConnections = await Presence.getPeakConnections(true); + try { + statistics.dailyPeakConnections = await Presence.getPeakConnections(true); + } catch { + statistics.dailyPeakConnections = 0; + } const peak = await Statistics.findMonthlyPeakConnections(); statistics.maxMonthlyPeakConnections = Math.max(statistics.dailyPeakConnections, peak?.dailyPeakConnections || 0); diff --git a/apps/meteor/ee/server/NetworkBroker.ts b/apps/meteor/ee/server/NetworkBroker.ts index cbfbb3875f4a..3af389e4f3e7 100644 --- a/apps/meteor/ee/server/NetworkBroker.ts +++ b/apps/meteor/ee/server/NetworkBroker.ts @@ -60,6 +60,7 @@ export class NetworkBroker implements IBroker { await this.broker.waitForServices(method.split('.')[0], waitForServicesTimeout); } catch (err) { console.error(err); + throw new Error('Dependent services not available'); } const context = asyncLocalStorage.getStore(); diff --git a/apps/meteor/ee/server/local-services/instance/service.ts b/apps/meteor/ee/server/local-services/instance/service.ts index 5bb755ee347f..4caab1ba9f16 100644 --- a/apps/meteor/ee/server/local-services/instance/service.ts +++ b/apps/meteor/ee/server/local-services/instance/service.ts @@ -143,12 +143,16 @@ export class InstanceService extends ServiceClassInternal implements IInstanceSe await InstanceStatus.registerInstance('rocket.chat', instance); - const hasLicense = await License.hasModule('scalability'); - if (!hasLicense) { - return; - } + try { + const hasLicense = await License.hasModule('scalability'); + if (!hasLicense) { + return; + } - await this.startBroadcast(); + await this.startBroadcast(); + } catch (error) { + console.error('Instance service did not start correctly', error); + } } private async startBroadcast() { diff --git a/apps/meteor/server/services/authorization/service.ts b/apps/meteor/server/services/authorization/service.ts index 6918d40af871..075fe569bfff 100644 --- a/apps/meteor/server/services/authorization/service.ts +++ b/apps/meteor/server/services/authorization/service.ts @@ -39,16 +39,20 @@ export class Authorization extends ServiceClass implements IAuthorization { } async started(): Promise { - if (!(await License.hasValidLicense())) { - return; - } + try { + if (!(await License.hasValidLicense())) { + return; + } - const permissions = await License.getGuestPermissions(); - if (!permissions) { - return; - } + const permissions = await License.getGuestPermissions(); + if (!permissions) { + return; + } - AuthorizationUtils.addRolePermissionWhiteList('guest', permissions); + AuthorizationUtils.addRolePermissionWhiteList('guest', permissions); + } catch (error) { + console.error('Authorization Service did not start correctly', error); + } } async hasAllPermission(userId: string, permissions: string[], scope?: string): Promise { diff --git a/ee/apps/ddp-streamer/src/DDPStreamer.ts b/ee/apps/ddp-streamer/src/DDPStreamer.ts index bccb35d2b326..8cc55a09134c 100644 --- a/ee/apps/ddp-streamer/src/DDPStreamer.ts +++ b/ee/apps/ddp-streamer/src/DDPStreamer.ts @@ -154,44 +154,50 @@ export class DDPStreamer extends ServiceClass { async started(): Promise { // TODO this call creates a dependency to MeteorService, should it be a hard dependency? or can this call fail and be ignored? - const versions = await MeteorService.getAutoUpdateClientVersions(); - - Object.keys(versions).forEach((key) => { - Autoupdate.updateVersion(versions[key]); - }); - - this.app = polka() - .use(proxy()) - .get('/health', async (_req, res) => { - try { - if (!this.api) { - throw new Error('API not available'); + try { + const versions = await MeteorService.getAutoUpdateClientVersions(); + + Object.keys(versions || {}).forEach((key) => { + Autoupdate.updateVersion(versions[key]); + }); + + this.app = polka() + .use(proxy()) + .get('/health', async (_req, res) => { + try { + if (!this.api) { + throw new Error('API not available'); + } + + await this.api.nodeList(); + res.end('ok'); + } catch (err) { + console.error('Service not healthy', err); + + res.writeHead(500); + res.end('not healthy'); } + }) + .get('*', function (_req, res) { + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Content-Type', 'application/json'); - await this.api.nodeList(); - res.end('ok'); - } catch (err) { - console.error('Service not healthy', err); + res.writeHead(200); - res.writeHead(500); - res.end('not healthy'); - } - }) - .get('*', function (_req, res) { - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Content-Type', 'application/json'); + res.end( + `{"websocket":true,"origins":["*:*"],"cookie_needed":false,"entropy":${crypto.randomBytes(4).readUInt32LE(0)},"ms":true}`, + ); + }) + .listen(PORT); - res.writeHead(200); + this.wss = new WebSocket.Server({ server: this.app.server }); - res.end(`{"websocket":true,"origins":["*:*"],"cookie_needed":false,"entropy":${crypto.randomBytes(4).readUInt32LE(0)},"ms":true}`); - }) - .listen(PORT); + this.wss.on('connection', (ws, req) => new Client(ws, req.url !== '/websocket', req)); - this.wss = new WebSocket.Server({ server: this.app.server }); - - this.wss.on('connection', (ws, req) => new Client(ws, req.url !== '/websocket', req)); - - InstanceStatus.registerInstance('ddp-streamer', {}); + InstanceStatus.registerInstance('ddp-streamer', {}); + } catch (err) { + console.error('DDPStreamer did not start correctly', err); + } } async stopped(): Promise { diff --git a/ee/apps/ddp-streamer/src/configureServer.ts b/ee/apps/ddp-streamer/src/configureServer.ts index bad70254f3b8..ed187db498cc 100644 --- a/ee/apps/ddp-streamer/src/configureServer.ts +++ b/ee/apps/ddp-streamer/src/configureServer.ts @@ -15,7 +15,9 @@ const loginServiceConfigurationCollection = 'meteor_accounts_loginServiceConfigu const loginServiceConfigurationPublication = 'meteor.loginServiceConfiguration'; const loginServices = new Map(); -MeteorService.getLoginServiceConfiguration().then((records = []) => records.forEach((record) => loginServices.set(record._id, record))); +MeteorService.getLoginServiceConfiguration() + .then((records = []) => records.forEach((record) => loginServices.set(record._id, record))) + .catch((err) => console.error('DDPStreamer not able to retrieve login services configuration', err)); server.publish(loginServiceConfigurationPublication, async function () { loginServices.forEach((record) => this.added(loginServiceConfigurationCollection, record._id, record)); diff --git a/packages/core-services/src/LocalBroker.ts b/packages/core-services/src/LocalBroker.ts index cdedd4fa7057..47f4aaba3c80 100644 --- a/packages/core-services/src/LocalBroker.ts +++ b/packages/core-services/src/LocalBroker.ts @@ -8,6 +8,8 @@ import type { IBroker, IBrokerNode } from './types/IBroker'; import type { ServiceClass, IServiceClass } from './types/ServiceClass'; export class LocalBroker implements IBroker { + private started = false; + private methods = new Map any>(); private events = new EventEmitter(); @@ -73,6 +75,9 @@ export class LocalBroker implements IBroker { this.methods.set(`${namespace}.${method}`, i[method].bind(i)); } + if (this.started) { + void instance.started(); + } } onBroadcast(callback: (eventName: string, args: unknown[]) => void): void { @@ -106,5 +111,6 @@ export class LocalBroker implements IBroker { async start(): Promise { await Promise.all([...this.services].map((service) => service.started())); + this.started = true; } } From 9c59a87c451de2b998dbc47a20f4f151310d2976 Mon Sep 17 00:00:00 2001 From: Heitor Tanoue <68477006+heitortanoue@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:01:52 -0300 Subject: [PATCH 10/13] fix: not being able to access or create rooms with join code (#31270) --- .changeset/stale-monkeys-yell.md | 5 + apps/meteor/server/models/raw/Rooms.ts | 9 + apps/meteor/server/services/room/service.ts | 22 ++- .../tests/end-to-end/api/02-channels.js | 163 +++++++++++------- .../model-typings/src/models/IRoomsModel.ts | 2 + 5 files changed, 125 insertions(+), 76 deletions(-) create mode 100644 .changeset/stale-monkeys-yell.md diff --git a/.changeset/stale-monkeys-yell.md b/.changeset/stale-monkeys-yell.md new file mode 100644 index 000000000000..7f80c152b888 --- /dev/null +++ b/.changeset/stale-monkeys-yell.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed an issue where room access and creation were hindered due to join codes not being fetched correctly in the API. diff --git a/apps/meteor/server/models/raw/Rooms.ts b/apps/meteor/server/models/raw/Rooms.ts index 9c1b14dc3f35..06b6d030424b 100644 --- a/apps/meteor/server/models/raw/Rooms.ts +++ b/apps/meteor/server/models/raw/Rooms.ts @@ -562,6 +562,15 @@ export class RoomsRaw extends BaseRaw implements IRoomsModel { return this.findOne(query, options); } + findOneByJoinCodeAndId(joinCode: string, rid: IRoom['_id'], options: FindOptions = {}): Promise { + const query: Filter = { + _id: rid, + joinCode, + }; + + return this.findOne(query, options); + } + async findOneByNonValidatedName(name: NonNullable, options: FindOptions = {}) { const room = await this.findOneByNameOrFname(name, options); if (room) { diff --git a/apps/meteor/server/services/room/service.ts b/apps/meteor/server/services/room/service.ts index 7b9b85cecbd0..dcfb4276bb0c 100644 --- a/apps/meteor/server/services/room/service.ts +++ b/apps/meteor/server/services/room/service.ts @@ -1,7 +1,7 @@ import { ServiceClassInternal, Authorization, MeteorError } from '@rocket.chat/core-services'; import type { ICreateRoomParams, IRoomService } from '@rocket.chat/core-services'; import { type AtLeast, type IRoom, type IUser, isRoomWithJoinCode } from '@rocket.chat/core-typings'; -import { Users } from '@rocket.chat/models'; +import { Rooms, Users } from '@rocket.chat/models'; import { saveRoomTopic } from '../../../app/channel-settings/server/functions/saveRoomTopic'; import { addUserToRoom } from '../../../app/lib/server/functions/addUserToRoom'; @@ -106,14 +106,18 @@ export class RoomService extends ServiceClassInternal implements IRoomService { throw new MeteorError('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); } - if ( - isRoomWithJoinCode(room) && - (!joinCode || joinCode !== room.joinCode) && - !(await Authorization.hasPermission(user._id, 'join-without-join-code')) - ) { - throw new MeteorError('error-code-invalid', 'Invalid Room Password', { - method: 'joinRoom', - }); + if (isRoomWithJoinCode(room) && !(await Authorization.hasPermission(user._id, 'join-without-join-code'))) { + if (!joinCode) { + throw new MeteorError('error-code-required', 'Code required', { method: 'joinRoom' }); + } + + const isCorrectJoinCode = !!(await Rooms.findOneByJoinCodeAndId(joinCode, room._id, { + projection: { _id: 1 }, + })); + + if (!isCorrectJoinCode) { + throw new MeteorError('error-code-invalid', 'Invalid code', { method: 'joinRoom' }); + } } return addUserToRoom(room._id, user); diff --git a/apps/meteor/tests/end-to-end/api/02-channels.js b/apps/meteor/tests/end-to-end/api/02-channels.js index 6976caa849bf..f0f61aa5661e 100644 --- a/apps/meteor/tests/end-to-end/api/02-channels.js +++ b/apps/meteor/tests/end-to-end/api/02-channels.js @@ -491,88 +491,117 @@ describe('[Channels]', function () { .end(done); }); - it('should succeed when joining code-free channel without join code', (done) => { - request - .post(api('channels.join')) - .set(credentials) - .send({ - roomId: testChannelNoCode._id, - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('channel._id', testChannelNoCode._id); - }) - .end(done); - }); - - it('should fail when joining code-needed channel without join code and no join-without-join-code permission', (done) => { - updatePermission('join-without-join-code', []).then(() => { - request - .post(api('channels.join')) - .set(credentials) - .send({ - roomId: testChannelWithCode._id, - }) - .expect('Content-Type', 'application/json') - .expect(400) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body).to.have.nested.property('errorType', 'error-code-invalid'); - }) - .end(done); - }); - }); - - it('should succeed when joining code-needed channel without join code and with join-without-join-code permission', (done) => { - updatePermission('join-without-join-code', ['admin']).then(() => { + describe('code-free channel', () => { + it('should succeed when joining code-free channel without join code', (done) => { request .post(api('channels.join')) .set(credentials) .send({ - roomId: testChannelWithCode._id, + roomId: testChannelNoCode._id, }) .expect('Content-Type', 'application/json') .expect(200) .expect((res) => { expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('channel._id', testChannelWithCode._id); + expect(res.body).to.have.nested.property('channel._id', testChannelNoCode._id); }) .end(done); }); }); - it('leave channel', (done) => { - request - .post(api('channels.leave')) - .set(credentials) - .send({ - roomId: testChannelWithCode._id, - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - }) - .end(done); - }); + describe('code-needed channel', () => { + describe('without join-without-join-code permission', () => { + before('set join-without-join-code permission to false', async () => { + await updatePermission('join-without-join-code', []); + }); - it('should succeed when joining code-needed channel with join code', (done) => { - request - .post(api('channels.join')) - .set(credentials) - .send({ - roomId: testChannelWithCode._id, - joinCode: '123', - }) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('channel._id', testChannelWithCode._id); - }) - .end(done); + it('should fail when joining code-needed channel without join code and no join-without-join-code permission', (done) => { + request + .post(api('channels.join')) + .set(credentials) + .send({ + roomId: testChannelWithCode._id, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.nested.property('errorType', 'error-code-required'); + }) + .end(done); + }); + + it('should fail when joining code-needed channel with incorrect join code and no join-without-join-code permission', (done) => { + request + .post(api('channels.join')) + .set(credentials) + .send({ + roomId: testChannelWithCode._id, + joinCode: 'WRONG_CODE', + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.nested.property('errorType', 'error-code-invalid'); + }) + .end(done); + }); + + it('should succeed when joining code-needed channel with join code', (done) => { + request + .post(api('channels.join')) + .set(credentials) + .send({ + roomId: testChannelWithCode._id, + joinCode: '123', + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('channel._id', testChannelWithCode._id); + }) + .end(done); + }); + }); + + describe('with join-without-join-code permission', () => { + before('set join-without-join-code permission to true', async () => { + await updatePermission('join-without-join-code', ['admin']); + }); + + before('leave channel', (done) => { + request + .post(api('channels.leave')) + .set(credentials) + .send({ + roomId: testChannelWithCode._id, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + + it('should succeed when joining code-needed channel without join code and with join-without-join-code permission', (done) => { + request + .post(api('channels.join')) + .set(credentials) + .send({ + roomId: testChannelWithCode._id, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('channel._id', testChannelWithCode._id); + }) + .end(done); + }); + }); }); }); diff --git a/packages/model-typings/src/models/IRoomsModel.ts b/packages/model-typings/src/models/IRoomsModel.ts index 215eac8b232d..a4743216f7d4 100644 --- a/packages/model-typings/src/models/IRoomsModel.ts +++ b/packages/model-typings/src/models/IRoomsModel.ts @@ -110,6 +110,8 @@ export interface IRoomsModel extends IBaseModel { findOneByNameOrFname(name: NonNullable, options?: FindOptions): Promise; + findOneByJoinCodeAndId(joinCode: string, rid: IRoom['_id'], options?: FindOptions): Promise; + findOneByNonValidatedName(name: NonNullable, options?: FindOptions): Promise; allRoomSourcesCount(): AggregationCursor<{ _id: Required; count: number }>; From 47331bacc3e789db6d4cdd88afb271dc6c3eddb5 Mon Sep 17 00:00:00 2001 From: Sayan4444 <112304873+Sayan4444@users.noreply.github.com> Date: Fri, 5 Jan 2024 21:15:13 +0530 Subject: [PATCH 11/13] feat: added modal confirmation before pinning message (#31348) Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com> Co-authored-by: Hugo Costa <20212776+hugocostadev@users.noreply.github.com> --- .changeset/swift-beans-reflect.md | 5 +++ .../{pinMessage.ts => pinMessage.tsx} | 28 +++++++++--- .../PinMessageModal/PinMessageModal.tsx | 45 +++++++++++++++++++ .../room/modals/PinMessageModal/index.ts | 1 + .../rocketchat-i18n/i18n/en.i18n.json | 4 ++ 5 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 .changeset/swift-beans-reflect.md rename apps/meteor/client/startup/actionButtons/{pinMessage.ts => pinMessage.tsx} (66%) create mode 100644 apps/meteor/client/views/room/modals/PinMessageModal/PinMessageModal.tsx create mode 100644 apps/meteor/client/views/room/modals/PinMessageModal/index.ts diff --git a/.changeset/swift-beans-reflect.md b/.changeset/swift-beans-reflect.md new file mode 100644 index 000000000000..f8e8a487493d --- /dev/null +++ b/.changeset/swift-beans-reflect.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": minor +--- + +Added a modal to confirm the intention to pin a message, preventing users from doing it by mistake diff --git a/apps/meteor/client/startup/actionButtons/pinMessage.ts b/apps/meteor/client/startup/actionButtons/pinMessage.tsx similarity index 66% rename from apps/meteor/client/startup/actionButtons/pinMessage.ts rename to apps/meteor/client/startup/actionButtons/pinMessage.tsx index 970eb28349c0..b383b4a3c648 100644 --- a/apps/meteor/client/startup/actionButtons/pinMessage.ts +++ b/apps/meteor/client/startup/actionButtons/pinMessage.tsx @@ -4,10 +4,12 @@ import { hasAtLeastOnePermission } from '../../../app/authorization/client'; import { settings } from '../../../app/settings/client'; import { MessageAction } from '../../../app/ui-utils/client'; import { sdk } from '../../../app/utils/client/lib/SDKClient'; +import { imperativeModal } from '../../lib/imperativeModal'; import { queryClient } from '../../lib/queryClient'; import { roomCoordinator } from '../../lib/rooms/roomCoordinator'; import { dispatchToastMessage } from '../../lib/toast'; import { messageArgs } from '../../lib/utils/messageArgs'; +import PinMessageModal from '../../views/room/modals/PinMessageModal'; Meteor.startup(() => { MessageAction.addButton({ @@ -18,13 +20,25 @@ Meteor.startup(() => { context: ['pinned', 'message', 'message-mobile', 'threads', 'direct', 'videoconf', 'videoconf-threads'], async action(_, props) { const { message = messageArgs(this).msg } = props; - message.pinned = true; - try { - await sdk.call('pinMessage', message); - queryClient.invalidateQueries(['rooms', message.rid, 'pinned-messages']); - } catch (error) { - dispatchToastMessage({ type: 'error', message: error }); - } + const onConfirm = async () => { + message.pinned = true; + try { + await sdk.call('pinMessage', message); + queryClient.invalidateQueries(['rooms', message.rid, 'pinned-messages']); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + imperativeModal.close(); + }; + + imperativeModal.open({ + component: PinMessageModal, + props: { + message, + onConfirm, + onCancel: () => imperativeModal.close(), + }, + }); }, condition({ message, subscription, room }) { if (!settings.get('Message_AllowPinning') || message.pinned || !subscription) { diff --git a/apps/meteor/client/views/room/modals/PinMessageModal/PinMessageModal.tsx b/apps/meteor/client/views/room/modals/PinMessageModal/PinMessageModal.tsx new file mode 100644 index 000000000000..a9fd5c461ac7 --- /dev/null +++ b/apps/meteor/client/views/room/modals/PinMessageModal/PinMessageModal.tsx @@ -0,0 +1,45 @@ +import type { MessageQuoteAttachment, IMessage } from '@rocket.chat/core-typings'; +import { Box } from '@rocket.chat/fuselage'; +import { useTranslation, useUserAvatarPath } from '@rocket.chat/ui-contexts'; +import type { ComponentProps, ReactElement } from 'react'; +import React from 'react'; + +import GenericModal from '../../../../components/GenericModal'; +import { QuoteAttachment } from '../../../../components/message/content/attachments/QuoteAttachment'; +import { useUserDisplayName } from '../../../../hooks/useUserDisplayName'; + +type PinMessageModalProps = { message: IMessage } & ComponentProps; + +const PinMessageModal = ({ message, ...props }: PinMessageModalProps): ReactElement => { + const t = useTranslation(); + const getUserAvatarPath = useUserAvatarPath(); + const displayName = useUserDisplayName(message.u); + const avatarUrl = getUserAvatarPath(message.u.username); + + const attachment = { + author_name: String(displayName), + author_link: '', + author_icon: avatarUrl, + message_link: '', + text: message.msg, + attachments: message.attachments as MessageQuoteAttachment[], + md: message.md, + }; + + return ( + + + {t('Are_you_sure_you_want_to_pin_this_message')} + + + + {t('Pinned_messages_are_visible_to_everyone')} + + + {t('Starred_messages_are_only_visible_to_you')} + + + ); +}; + +export default PinMessageModal; diff --git a/apps/meteor/client/views/room/modals/PinMessageModal/index.ts b/apps/meteor/client/views/room/modals/PinMessageModal/index.ts new file mode 100644 index 000000000000..041ad7aa2808 --- /dev/null +++ b/apps/meteor/client/views/room/modals/PinMessageModal/index.ts @@ -0,0 +1 @@ +export { default } from './PinMessageModal'; diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index 013f79e23b2d..79bdfbf74a0f 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -672,6 +672,7 @@ "Are_you_sure_you_want_to_delete_this_record": "Are you sure you want to delete this record?", "Are_you_sure_you_want_to_delete_your_account": "Are you sure you want to delete your account?", "Are_you_sure_you_want_to_disable_Facebook_integration": "Are you sure you want to disable Facebook integration?", + "Are_you_sure_you_want_to_pin_this_message": "Are you sure you want to pin this message?", "Are_you_sure_you_want_to_reset_the_name_of_all_priorities": "Are you sure you want to reset the name of all priorities?", "Assets": "Assets", "Assets_Description": "Modify your workspace's logo, icon, favicon and more.", @@ -4043,6 +4044,7 @@ "pin-message_description": "Permission to pin a message in a channel", "Pinned_a_message": "Pinned a message:", "Pinned_Messages": "Pinned Messages", + "Pinned_messages_are_visible_to_everyone": "Pinned messages are visible to everyone", "Pinned_messages_unavailable_for_federation": "Pinned Messages are not available for federated rooms.", "pinning-not-allowed": "Pinning is not allowed", "PiwikAdditionalTrackers": "Additional Piwik Sites", @@ -4883,6 +4885,7 @@ "Star": "Star", "Star_Message": "Star Message", "Starred_Messages": "Starred Messages", + "Starred_messages_are_only_visible_to_you": "Starred messages are only visible to you", "Start": "Start", "Start_a_call": "Start a call", "Start_a_call_with": "Start a call with", @@ -5820,6 +5823,7 @@ "Yes_leave_it": "Yes, leave it!", "Yes_mute_user": "Yes, mute user!", "Yes_prune_them": "Yes, prune them!", + "Yes_pin_message": "Yes, pin message", "Yes_remove_user": "Yes, remove user!", "Yes_unarchive_it": "Yes, unarchive it!", "yesterday": "yesterday", From cf3f91fa404b8413eef189a30a31e158a7f2633f Mon Sep 17 00:00:00 2001 From: Masaki Miura <55912665+gracefulm@users.noreply.github.com> Date: Sat, 6 Jan 2024 03:50:38 +0900 Subject: [PATCH 12/13] feat: Allow user to set timeout of outgoing webhook (#31222) --- apps/meteor/app/integrations/server/lib/triggerHandler.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/meteor/app/integrations/server/lib/triggerHandler.js b/apps/meteor/app/integrations/server/lib/triggerHandler.js index b5050b8c4716..07f7a3d903a2 100644 --- a/apps/meteor/app/integrations/server/lib/triggerHandler.js +++ b/apps/meteor/app/integrations/server/lib/triggerHandler.js @@ -503,6 +503,7 @@ class RocketChatIntegrationHandler { { method: opts.method, headers: opts.headers, + ...(opts.timeout && { timeout: opts.timeout }), ...(opts.data && { body: opts.data }), }, settings.get('Allow_Invalid_SelfSigned_Certs'), From d5d7d5074bf3f4abc63fdf93cb44b0a6d66962b3 Mon Sep 17 00:00:00 2001 From: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com> Date: Sat, 6 Jan 2024 01:46:16 +0530 Subject: [PATCH 13/13] chore: add gitpod config file for quick setup (#30921) Co-authored-by: Debdut Chakraborty <76006232+debdutdeb@users.noreply.github.com> --- .gitpod.yml | 26 ++++++++++++++++++++++++++ README.md | 8 ++++++++ 2 files changed, 34 insertions(+) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 000000000000..e24ff7d2ebf1 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,26 @@ +tasks: + - init: | + nvm install $(jq -r .engines.node package.json) && + curl https://install.meteor.com/ | sh && + export PATH="$PATH:$HOME/.meteor" && + yarn && + export ROOT_URL=$(gp url 3000) + command: yarn build && yarn dev + +ports: + - port: 3000 + visibility: public + onOpen: open-preview + +github: + prebuilds: + master: true + pullRequests: true + pullRequestsFromForks: true + addCheck: true + addComment: true + addBadge: true + +vscode: + extensions: + - esbenp.prettier-vscode \ No newline at end of file diff --git a/README.md b/README.md index a63baba65dd0..64dec811e1ca 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,14 @@ yarn dsv # run only meteor (front and back) with pre-built packages After initialized, you can access the server at http://localhost:3000 +# Gitpod Setup + +1. Click the button below to open this project in Gitpod. + +2. This will open a fully configured workspace in your browser with all the necessary dependencies already installed. + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/RocketChat/Rocket.Chat) + **Starting Rocket.Chat in microservices mode:** ```bash