From db919f9b23b81c13b653303faab5500cc8a2564e Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 5 Sep 2023 20:13:30 +0000 Subject: [PATCH 01/49] Bump 6.3.4 --- .changeset/bump-patch-1693944810152.md | 5 +++++ yarn.lock | 16 ++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 .changeset/bump-patch-1693944810152.md diff --git a/.changeset/bump-patch-1693944810152.md b/.changeset/bump-patch-1693944810152.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1693944810152.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/yarn.lock b/yarn.lock index 251222652634..95498d62f3b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9898,9 +9898,9 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-contexts": 1.0.2 + "@rocket.chat/ui-contexts": 1.0.3 "@rocket.chat/ui-kit": "*" - "@rocket.chat/ui-video-conf": 1.0.2 + "@rocket.chat/ui-video-conf": 1.0.3 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -9982,14 +9982,14 @@ __metadata: ts-jest: ~29.0.5 typescript: ~5.1.3 peerDependencies: - "@rocket.chat/core-typings": 6.3.2 + "@rocket.chat/core-typings": 6.3.3 "@rocket.chat/css-in-js": "*" "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 1.0.2 - "@rocket.chat/ui-contexts": 1.0.2 + "@rocket.chat/ui-client": 1.0.3 + "@rocket.chat/ui-contexts": 1.0.3 katex: "*" react: "*" languageName: unknown @@ -11048,7 +11048,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 1.0.2 + "@rocket.chat/ui-contexts": 1.0.3 react: ~17.0.2 languageName: unknown linkType: soft @@ -11202,7 +11202,7 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-contexts": 1.0.2 + "@rocket.chat/ui-contexts": 1.0.3 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -11268,7 +11268,7 @@ __metadata: typescript: ~5.1.3 peerDependencies: "@rocket.chat/layout": "*" - "@rocket.chat/ui-contexts": 1.0.2 + "@rocket.chat/ui-contexts": 1.0.3 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From ebeb088441777a3c32bba0d4d50a048e3e9f5b8c Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 4 Sep 2023 13:33:57 -0600 Subject: [PATCH 02/49] fix: Prevent `RoomProvider.useEffect` from subscribing multiple times (#30273) --- .changeset/forty-hotels-pretend.md | 5 +++++ .../views/room/providers/RoomProvider.tsx | 22 ++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 .changeset/forty-hotels-pretend.md diff --git a/.changeset/forty-hotels-pretend.md b/.changeset/forty-hotels-pretend.md new file mode 100644 index 000000000000..b23825d5a02a --- /dev/null +++ b/.changeset/forty-hotels-pretend.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +fix: Prevent `RoomProvider.useEffect` from subscribing to room-data stream multiple times diff --git a/apps/meteor/client/views/room/providers/RoomProvider.tsx b/apps/meteor/client/views/room/providers/RoomProvider.tsx index b2935f4702ea..20da5194895f 100644 --- a/apps/meteor/client/views/room/providers/RoomProvider.tsx +++ b/apps/meteor/client/views/room/providers/RoomProvider.tsx @@ -1,5 +1,4 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { isOmnichannelRoom } from '@rocket.chat/core-typings'; import { usePermission, useStream, useUserId, useRouter } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import type { ReactNode, ContextType, ReactElement } from 'react'; @@ -36,17 +35,18 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { const queryClient = useQueryClient(); const userId = useUserId(); const isLivechatAdmin = usePermission('view-livechat-rooms'); + const { t: roomType } = room ?? {}; // TODO: move this to omnichannel context only useEffect(() => { - if (!room || !isOmnichannelRoom(room)) { + if (roomType !== 'l') { return; } return subscribeToRoom(rid, (room) => { queryClient.setQueryData(['rooms', rid], room); }); - }, [subscribeToRoom, rid, queryClient, room]); + }, [subscribeToRoom, rid, queryClient, roomType]); // TODO: the following effect is a workaround while we don't have a general and definitive solution for it const router = useRouter(); @@ -56,19 +56,21 @@ const RoomProvider = ({ rid, children }: RoomProviderProps): ReactElement => { } }, [isSuccess, room, router]); + const { _id: servedById } = room?.servedBy ?? {}; + // TODO: Review the necessity of this effect when we move away from cached collections useEffect(() => { - if (!room || !isOmnichannelRoom(room) || !room.servedBy) { + if (roomType !== 'l' || !servedById) { return; } - if (!isLivechatAdmin && room.servedBy._id !== userId) { - ChatRoom.remove(room._id); - queryClient.removeQueries(['rooms', room._id]); - queryClient.removeQueries(['rooms', { reference: room._id, type: 'l' }]); - queryClient.removeQueries(['/v1/rooms.info', room._id]); + if (!isLivechatAdmin && servedById !== userId) { + ChatRoom.remove(rid); + queryClient.removeQueries(['rooms', rid]); + queryClient.removeQueries(['rooms', { reference: rid, type: 'l' }]); + queryClient.removeQueries(['/v1/rooms.info', rid]); } - }, [isLivechatAdmin, queryClient, userId, room]); + }, [isLivechatAdmin, queryClient, userId, rid, roomType, servedById]); const subscriptionQuery = useReactiveQuery(['subscriptions', { rid }], () => ChatSubscription.findOne({ rid }) ?? null); From d418d0e752a69abecfe41ef84d1f7abf70a03d20 Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Wed, 6 Sep 2023 12:45:10 -0300 Subject: [PATCH 03/49] fix: added debounce to units and custom fields search (#30291) --- .../views/omnichannel/customFields/CustomFieldsTable.tsx | 7 ++++--- apps/meteor/ee/client/omnichannel/units/UnitsTable.tsx | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/meteor/client/views/omnichannel/customFields/CustomFieldsTable.tsx b/apps/meteor/client/views/omnichannel/customFields/CustomFieldsTable.tsx index b92fad97633a..d9ef416226cc 100644 --- a/apps/meteor/client/views/omnichannel/customFields/CustomFieldsTable.tsx +++ b/apps/meteor/client/views/omnichannel/customFields/CustomFieldsTable.tsx @@ -1,5 +1,5 @@ import { Pagination } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useRoute, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { MutableRefObject } from 'react'; @@ -24,18 +24,19 @@ const CustomFieldsTable = ({ reload }: { reload: MutableRefObject<() => void> }) const t = useTranslation(); const [filter, setFilter] = useState(''); const departmentsRoute = useRoute('omnichannel-customfields'); + const debouncedFilter = useDebouncedValue(filter, 500); const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination(); const { sortBy, sortDirection, setSort } = useSort<'_id' | 'label' | 'scope' | 'visibility'>('_id'); const query = useMemo( () => ({ - text: filter, + text: debouncedFilter, sort: `{ "${sortBy}": ${sortDirection === 'asc' ? 1 : -1} }`, ...(itemsPerPage && { count: itemsPerPage }), ...(current && { offset: current }), }), - [filter, itemsPerPage, current, sortBy, sortDirection], + [debouncedFilter, itemsPerPage, current, sortBy, sortDirection], ); const getCustomFields = useEndpoint('GET', '/v1/livechat/custom-fields'); diff --git a/apps/meteor/ee/client/omnichannel/units/UnitsTable.tsx b/apps/meteor/ee/client/omnichannel/units/UnitsTable.tsx index a9ab094229f6..f85b73216612 100644 --- a/apps/meteor/ee/client/omnichannel/units/UnitsTable.tsx +++ b/apps/meteor/ee/client/omnichannel/units/UnitsTable.tsx @@ -1,5 +1,5 @@ import { Pagination } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useEndpoint, useRoute, useTranslation } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { MutableRefObject } from 'react'; @@ -24,6 +24,7 @@ const UnitsTable = ({ reload }: { reload: MutableRefObject<() => void> }) => { const t = useTranslation(); const [filter, setFilter] = useState(''); const unitsRoute = useRoute('omnichannel-units'); + const debouncedFilter = useDebouncedValue(filter, 500); const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination(); const { sortBy, sortDirection, setSort } = useSort<'name' | 'visibility'>('name'); @@ -31,12 +32,12 @@ const UnitsTable = ({ reload }: { reload: MutableRefObject<() => void> }) => { const query = useMemo( () => ({ fields: JSON.stringify({ name: 1 }), - text: filter, + text: debouncedFilter, sort: JSON.stringify({ [sortBy]: sortDirection === 'asc' ? 1 : -1 }), ...(itemsPerPage && { count: itemsPerPage }), ...(current && { offset: current }), }), - [filter, itemsPerPage, current, sortBy, sortDirection], + [debouncedFilter, itemsPerPage, current, sortBy, sortDirection], ); const getUnits = useEndpoint('GET', '/v1/livechat/units'); From ace35997a635328e9d2b645bae6db475784d00f7 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Wed, 6 Sep 2023 09:59:09 -0600 Subject: [PATCH 04/49] chore: Increase cache time to 10s on `getUnits` function (#30285) --- .changeset/three-birds-tickle.md | 5 +++++ apps/meteor/ee/app/livechat-enterprise/server/lib/units.ts | 2 +- .../server/methods/getUnitsFromUserRoles.ts | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/three-birds-tickle.md diff --git a/.changeset/three-birds-tickle.md b/.changeset/three-birds-tickle.md new file mode 100644 index 000000000000..0ce911d9f6fa --- /dev/null +++ b/.changeset/three-birds-tickle.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +chore: Increase cache time from 5s to 10s on `getUnits` helpers. This should reduce the number of DB calls made by this method to fetch the unit limitations for a user. diff --git a/apps/meteor/ee/app/livechat-enterprise/server/lib/units.ts b/apps/meteor/ee/app/livechat-enterprise/server/lib/units.ts index d550b1335978..58a75abc943c 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/lib/units.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/lib/units.ts @@ -8,7 +8,7 @@ async function hasUnits(): Promise { } // Units should't change really often, so we can cache the result -const memoizedHasUnits = mem(hasUnits, { maxAge: 5000 }); +const memoizedHasUnits = mem(hasUnits, { maxAge: 10000 }); export async function getUnitsFromUser(): Promise<{ [k: string]: any }[] | undefined> { if (!(await memoizedHasUnits())) { diff --git a/apps/meteor/ee/app/livechat-enterprise/server/methods/getUnitsFromUserRoles.ts b/apps/meteor/ee/app/livechat-enterprise/server/methods/getUnitsFromUserRoles.ts index 0a6663c1f0b3..dd0f3867f574 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/methods/getUnitsFromUserRoles.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/methods/getUnitsFromUserRoles.ts @@ -17,7 +17,7 @@ async function getUnitsFromUserRoles(user: string | null): Promise Date: Wed, 6 Sep 2023 15:02:39 -0300 Subject: [PATCH 05/49] chore: prevent unneeded calls to EE settings service (#30249) --- .../modules/listeners/listeners.module.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/meteor/server/modules/listeners/listeners.module.ts b/apps/meteor/server/modules/listeners/listeners.module.ts index 973b542bf54a..f21081e43d0a 100644 --- a/apps/meteor/server/modules/listeners/listeners.module.ts +++ b/apps/meteor/server/modules/listeners/listeners.module.ts @@ -2,8 +2,9 @@ import type { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; import type { ISetting as AppsSetting } from '@rocket.chat/apps-engine/definition/settings'; import type { IServiceClass } from '@rocket.chat/core-services'; import { EnterpriseSettings } from '@rocket.chat/core-services'; -import { UserStatus, isSettingColor } from '@rocket.chat/core-typings'; +import { UserStatus, isSettingColor, isSettingEnterprise } from '@rocket.chat/core-typings'; import type { IUser, IRoom, VideoConference, ISetting, IOmnichannelRoom } from '@rocket.chat/core-typings'; +import { Logger } from '@rocket.chat/logger'; import { parse } from '@rocket.chat/message-parser'; import { settings } from '../../../app/settings/server/cached'; @@ -26,6 +27,8 @@ const minimongoChangeMap: Record = { export class ListenersModule { constructor(service: IServiceClass, notifications: NotificationsModule) { + const logger = new Logger('ListenersModule'); + service.onEvent('emoji.deleteCustom', (emoji) => { notifications.notifyLoggedInThisInstance('deleteEmojiCustom', { emojiData: emoji, @@ -247,11 +250,16 @@ export class ListenersModule { }); service.onEvent('watch.settings', async ({ clientAction, setting }): Promise => { - if (clientAction !== 'removed') { - // TODO check if setting is EE before calling this - const result = await EnterpriseSettings.changeSettingValue(setting); - if (result !== undefined && !(result instanceof Error)) { - setting.value = result; + // if a EE setting changed make sure we broadcast the correct value according to license + if (clientAction !== 'removed' && isSettingEnterprise(setting)) { + try { + const result = await EnterpriseSettings.changeSettingValue(setting); + if (result !== undefined && !(result instanceof Error)) { + setting.value = result; + } + } catch (err: unknown) { + logger.error({ msg: 'Error getting proper enterprise setting value. Returning `invalidValue` instead.', err }); + setting.value = setting.invalidValue; } } From 69bb4771d76fdeaf95c439a90597223397d9e3eb Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 6 Sep 2023 15:02:39 -0300 Subject: [PATCH 06/49] chore: prevent unneeded calls to EE settings service (#30249) --- .../modules/listeners/listeners.module.ts | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/meteor/server/modules/listeners/listeners.module.ts b/apps/meteor/server/modules/listeners/listeners.module.ts index 5c46343f67a4..856b91efce56 100644 --- a/apps/meteor/server/modules/listeners/listeners.module.ts +++ b/apps/meteor/server/modules/listeners/listeners.module.ts @@ -1,10 +1,11 @@ import type { ISetting as AppsSetting } from '@rocket.chat/apps-engine/definition/settings'; -import { UserStatus, isSettingColor } from '@rocket.chat/core-typings'; +import { UserStatus, isSettingColor, isSettingEnterprise } from '@rocket.chat/core-typings'; import type { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; -import type { IUser, IRoom, VideoConference, ISetting, IOmnichannelRoom } from '@rocket.chat/core-typings'; -import { parse } from '@rocket.chat/message-parser'; import type { IServiceClass } from '@rocket.chat/core-services'; import { EnterpriseSettings } from '@rocket.chat/core-services'; +import type { IUser, IRoom, VideoConference, ISetting, IOmnichannelRoom } from '@rocket.chat/core-typings'; +import { Logger } from '@rocket.chat/logger'; +import { parse } from '@rocket.chat/message-parser'; import type { NotificationsModule } from '../notifications/notifications.module'; import { settings } from '../../../app/settings/server/cached'; @@ -26,6 +27,8 @@ const minimongoChangeMap: Record = { export class ListenersModule { constructor(service: IServiceClass, notifications: NotificationsModule) { + const logger = new Logger('ListenersModule'); + service.onEvent('emoji.deleteCustom', (emoji) => { notifications.notifyLoggedInThisInstance('deleteEmojiCustom', { emojiData: emoji, @@ -247,11 +250,16 @@ export class ListenersModule { }); service.onEvent('watch.settings', async ({ clientAction, setting }): Promise => { - if (clientAction !== 'removed') { - // TODO check if setting is EE before calling this - const result = await EnterpriseSettings.changeSettingValue(setting); - if (result !== undefined && !(result instanceof Error)) { - setting.value = result; + // if a EE setting changed make sure we broadcast the correct value according to license + if (clientAction !== 'removed' && isSettingEnterprise(setting)) { + try { + const result = await EnterpriseSettings.changeSettingValue(setting); + if (result !== undefined && !(result instanceof Error)) { + setting.value = result; + } + } catch (err: unknown) { + logger.error({ msg: 'Error getting proper enterprise setting value. Returning `invalidValue` instead.', err }); + setting.value = setting.invalidValue; } } From 8ca4ac78cf5584bc02b6faa92781d1171ebcd01f Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 6 Sep 2023 16:56:47 -0300 Subject: [PATCH 07/49] chore: fix logger import --- apps/meteor/server/modules/listeners/listeners.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/server/modules/listeners/listeners.module.ts b/apps/meteor/server/modules/listeners/listeners.module.ts index 856b91efce56..06e494fdb556 100644 --- a/apps/meteor/server/modules/listeners/listeners.module.ts +++ b/apps/meteor/server/modules/listeners/listeners.module.ts @@ -4,11 +4,11 @@ import type { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; import type { IServiceClass } from '@rocket.chat/core-services'; import { EnterpriseSettings } from '@rocket.chat/core-services'; import type { IUser, IRoom, VideoConference, ISetting, IOmnichannelRoom } from '@rocket.chat/core-typings'; -import { Logger } from '@rocket.chat/logger'; import { parse } from '@rocket.chat/message-parser'; import type { NotificationsModule } from '../notifications/notifications.module'; import { settings } from '../../../app/settings/server/cached'; +import { Logger } from '../../lib/logger/Logger'; const isMessageParserDisabled = process.env.DISABLE_MESSAGE_PARSER === 'true'; From 03bda64be6853e9e858a961ec64e0b4a7030917f Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 6 Sep 2023 16:57:19 -0300 Subject: [PATCH 08/49] chore: Add `body` on axe scope to avoid false positive results (#30311) --- apps/meteor/tests/e2e/utils/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/tests/e2e/utils/test.ts b/apps/meteor/tests/e2e/utils/test.ts index 5ccea233d88a..81479231fd65 100644 --- a/apps/meteor/tests/e2e/utils/test.ts +++ b/apps/meteor/tests/e2e/utils/test.ts @@ -117,7 +117,7 @@ export const test = baseTest.extend({ makeAxeBuilder: async ({ page }, use) => { const SELECT_KNOW_ISSUES = ['aria-hidden-focus', 'nested-interactive'] - const makeAxeBuilder = () => new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']).disableRules(['document-title', ...SELECT_KNOW_ISSUES]); + const makeAxeBuilder = () => new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']).include('body').disableRules([...SELECT_KNOW_ISSUES]); await use(makeAxeBuilder); } }); From 516658dcfcc27169c6ebfebf82dd27a5d7801b80 Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Wed, 6 Sep 2023 18:37:45 -0300 Subject: [PATCH 09/49] fix: Selected options not being displayed for monitors and departments (#30292) Co-authored-by: Kevin Aleman <11577696+KevLehman@users.noreply.github.com> --- .../views/hooks/useDepartmentsByUnitsList.ts | 1 - .../client/views/hooks/useMonitorsList.ts | 12 ++++----- .../server/lib/Department.ts | 2 +- .../ee/client/omnichannel/units/UnitEdit.js | 25 +++++++++---------- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts b/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts index ceb7dc933df5..6c402a199ded 100644 --- a/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts +++ b/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts @@ -45,7 +45,6 @@ export const useDepartmentsByUnitsList = ( name: department.archived ? `${name} [${t('Archived')}]` : name, label: name, value: _id, - ...(_updatedAt && { _updatedAt: new Date(_updatedAt) }), }; }), itemCount: total, diff --git a/apps/meteor/client/views/hooks/useMonitorsList.ts b/apps/meteor/client/views/hooks/useMonitorsList.ts index 4d9ccba5c883..512b49d49d8e 100644 --- a/apps/meteor/client/views/hooks/useMonitorsList.ts +++ b/apps/meteor/client/views/hooks/useMonitorsList.ts @@ -33,15 +33,15 @@ export const useMonitorsList = ( text: options.filter, offset: start, count: end + start, + sort: JSON.stringify({ username: 1 }), }); return { - items: monitors.map((members: any) => { - members._updatedAt = new Date(members._updatedAt); - members.label = members.username; - members.value = members._id; - return members; - }), + items: monitors.map((members: any) => ({ + ...members, + label: members.username, + value: members._id, + })), itemCount: total, }; }, diff --git a/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.ts b/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.ts index b70ee79b6a94..094f0c9000d4 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.ts @@ -24,7 +24,7 @@ export const findAllDepartmentsAvailable = async ( query = await callbacks.run('livechat.applyDepartmentRestrictions', query, { userId: uid }); } - const { cursor, totalCount } = LivechatDepartment.findPaginated(query, { limit: count, offset }); + const { cursor, totalCount } = LivechatDepartment.findPaginated(query, { limit: count, offset, sort: { name: 1 } }); const [departments, total] = await Promise.all([cursor.toArray(), totalCount]); diff --git a/apps/meteor/ee/client/omnichannel/units/UnitEdit.js b/apps/meteor/ee/client/omnichannel/units/UnitEdit.js index 297a25d4a4c1..2c172bcf38c6 100644 --- a/apps/meteor/ee/client/omnichannel/units/UnitEdit.js +++ b/apps/meteor/ee/client/omnichannel/units/UnitEdit.js @@ -33,17 +33,6 @@ function UnitEdit({ title, data, unitId, isNew, unitMonitors, unitDepartments, r const { phase: departmentsPhase, items: departmentsItems, itemCount: departmentsTotal } = useRecordList(departmentsList); - const departmentsSortedByName = departmentsItems.sort((a, b) => { - if (a.name > b.name) { - return 1; - } - if (a.name < b.name) { - return -1; - } - - return 0; - }); - const unit = data || {}; const currUnitMonitors = useMemo( @@ -82,6 +71,16 @@ function UnitEdit({ title, data, unitId, isNew, unitMonitors, unitDepartments, r const { handleName, handleVisibility, handleDepartments, handleMonitors } = handlers; const { name, visibility, departments, monitors } = values; + const departmentsOptions = useMemo(() => { + const pending = departments.filter(({ value }) => !departmentsItems.find((dep) => dep.value === value)); + return [...departmentsItems, ...pending]; + }, [departments, departmentsItems]); + + const monitorsOptions = useMemo(() => { + const pending = monitors.filter(({ value }) => !monitorsItems.find((mon) => mon.value === value)); + return [...monitorsItems, ...pending]; + }, [monitors, monitorsItems]); + const nameError = useMemo(() => (!name || name.length === 0 ? t('The_field_is_required', t('name')) : undefined), [name, t]); const visibilityError = useMemo( () => (!visibility || visibility.length === 0 ? t('The_field_is_required', t('description')) : undefined), @@ -172,7 +171,7 @@ function UnitEdit({ title, data, unitId, isNew, unitMonitors, unitDepartments, r withTitle filter={departmentsFilter} setFilter={setDepartmentsFilter} - options={departmentsSortedByName} + options={departmentsOptions} value={departments} error={hasUnsavedChanges && departmentError} maxWidth='100%' @@ -194,7 +193,7 @@ function UnitEdit({ title, data, unitId, isNew, unitMonitors, unitDepartments, r withTitle filter={monitorsFilter} setFilter={setMonitorsFilter} - options={monitorsItems} + options={monitorsOptions} value={monitors} error={hasUnsavedChanges && unitMonitorsError} maxWidth='100%' From 0409097ff0ea411586704bc0a75844f8dffa3c4a Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 6 Sep 2023 19:57:57 -0300 Subject: [PATCH 10/49] test: codecov flags (#30302) --- .github/workflows/ci-test-e2e.yml | 3 +++ .github/workflows/ci-test-unit.yml | 4 ++++ .github/workflows/ci.yml | 3 +++ codecov.yml | 9 +++++++++ 4 files changed, 19 insertions(+) diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index 9a05543605db..e14857a97a09 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -57,6 +57,8 @@ on: required: false REPORTER_ROCKETCHAT_API_KEY: required: false + CODECOV_TOKEN: + required: false env: MONGO_URL: mongodb://localhost:27017/rocketchat?replicaSet=rs0&directConnection=true @@ -237,6 +239,7 @@ jobs: directory: ./apps/meteor flags: e2e verbose: true + token: ${{ secrets.CODECOV_TOKEN }} - name: Store e2e-ee-coverage if: inputs.type == 'ui' && inputs.release == 'ee' diff --git a/.github/workflows/ci-test-unit.yml b/.github/workflows/ci-test-unit.yml index 03c6bc2352ab..b4ef5cb273ad 100644 --- a/.github/workflows/ci-test-unit.yml +++ b/.github/workflows/ci-test-unit.yml @@ -6,6 +6,9 @@ on: node-version: required: true type: string + secrets: + CODECOV_TOKEN: + required: false env: MONGO_URL: mongodb://localhost:27017/rocketchat?replicaSet=rs0&directConnection=true @@ -36,3 +39,4 @@ jobs: with: flags: unit verbose: true + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3fe46ecf66c3..70ec4dcba6ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -337,6 +337,8 @@ jobs: uses: ./.github/workflows/ci-test-unit.yml with: node-version: ${{ needs.release-versions.outputs.node-version }} + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} test-api: name: 🔨 Test API (CE) @@ -431,6 +433,7 @@ jobs: QASE_API_TOKEN: ${{ secrets.QASE_API_TOKEN }} REPORTER_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_ROCKETCHAT_API_KEY }} REPORTER_ROCKETCHAT_URL: ${{ secrets.REPORTER_ROCKETCHAT_URL }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} tests-done: name: ✅ Tests Done diff --git a/codecov.yml b/codecov.yml index 0a3501678c1e..2fe2eaf32b42 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,3 +1,5 @@ +codecov: + max_report_age: off coverage: status: patch: off @@ -10,6 +12,13 @@ coverage: flags: - client flags: + unit: + carryforward: true + e2e: + paths: + - apps/meteor/ + carryforward: true + client: paths: - apps/meteor/client From fb98eebb1101182f65054ab586fffa5dc7427f63 Mon Sep 17 00:00:00 2001 From: Tiago Evangelista Pinto Date: Wed, 6 Sep 2023 20:43:28 -0300 Subject: [PATCH 11/49] regression: Change UiKit buttons event handler (#30310) --- .../fuselage-ui-kit/src/elements/ButtonElement.tsx | 10 +++++++--- packages/fuselage-ui-kit/src/hooks/useUiKitState.ts | 5 +++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/fuselage-ui-kit/src/elements/ButtonElement.tsx b/packages/fuselage-ui-kit/src/elements/ButtonElement.tsx index c7fe05971e27..1f80358b3d93 100644 --- a/packages/fuselage-ui-kit/src/elements/ButtonElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/ButtonElement.tsx @@ -1,6 +1,6 @@ import { Button, Throbber } from '@rocket.chat/fuselage'; import * as UiKit from '@rocket.chat/ui-kit'; -import type { ReactElement } from 'react'; +import type { MouseEventHandler, ReactElement } from 'react'; import { useUiKitState } from '../hooks/useUiKitState'; import type { BlockProps } from '../utils/BlockProps'; @@ -15,6 +15,10 @@ const ButtonElement = ({ const [{ loading }, action] = useUiKitState(block, context); const { style, url, text, value, secondary } = block; + const handleClick: MouseEventHandler = (e) => { + action({ target: e.currentTarget }); + }; + if (url) { return ( - + diff --git a/apps/meteor/client/views/account/accessibility/HighContrastUpsellModal.tsx b/apps/meteor/client/views/account/accessibility/HighContrastUpsellModal.tsx index c06501aae282..bcb28ea587d1 100644 --- a/apps/meteor/client/views/account/accessibility/HighContrastUpsellModal.tsx +++ b/apps/meteor/client/views/account/accessibility/HighContrastUpsellModal.tsx @@ -33,7 +33,7 @@ const HighContrastUpsellModal = ({ onClose }: { onClose: () => void }) => { onClose={onClose} onCancel={handleTalkToSales} onConfirm={handleGoFullyFeatured} - cancelText={t('Talk_to_sales')} + cancelText={t('Talk_to_an_expert')} confirmText={t('Start_free_trial')} /> ); diff --git a/apps/meteor/client/views/account/accessibility/MentionsWithSymbolUpsellModal.tsx b/apps/meteor/client/views/account/accessibility/MentionsWithSymbolUpsellModal.tsx new file mode 100644 index 000000000000..8a998af348c0 --- /dev/null +++ b/apps/meteor/client/views/account/accessibility/MentionsWithSymbolUpsellModal.tsx @@ -0,0 +1,41 @@ +import { useRole, useTranslation } from '@rocket.chat/ui-contexts'; +import React from 'react'; + +import GenericUpsellModal from '../../../components/GenericUpsellModal'; +import { useUpsellActions } from '../../../components/GenericUpsellModal/hooks'; + +const MentionsWithSymbolUpsellModal = ({ onClose }: { onClose: () => void }) => { + const t = useTranslation(); + + const isAdmin = useRole('admin'); + const { handleGoFullyFeatured, handleTalkToSales } = useUpsellActions(); + + if (!isAdmin) { + return ( + + ); + } + return ( + + ); +}; +export default MentionsWithSymbolUpsellModal; diff --git a/apps/meteor/client/views/account/accessibility/hooks/useAcessibilityPreferencesValues.ts b/apps/meteor/client/views/account/accessibility/hooks/useAcessibilityPreferencesValues.ts new file mode 100644 index 000000000000..339cdcff7dd9 --- /dev/null +++ b/apps/meteor/client/views/account/accessibility/hooks/useAcessibilityPreferencesValues.ts @@ -0,0 +1,31 @@ +import type { FontSize } from '@rocket.chat/rest-typings'; +import { useUserPreference } from '@rocket.chat/ui-contexts'; +import type { ThemePreference } from '@rocket.chat/ui-theming/src/types/themes'; + +export type AccessibilityPreferencesData = { + themeAppearence?: ThemePreference; + fontSize?: FontSize; + fontSizePreference?: FontSize; + mentionsWithSymbol?: boolean; + clockMode?: 0 | 1 | 2; + hideUsernames?: boolean; + hideRoles?: boolean; +}; + +export const useAccessiblityPreferencesValues = (): AccessibilityPreferencesData => { + const themeAppearence = useUserPreference('themeAppearence') || 'auto'; + const fontSize = useUserPreference('fontSize') || '100%'; + const mentionsWithSymbol = useUserPreference('mentionsWithSymbol') || false; + const clockMode = useUserPreference<0 | 1 | 2>('clockMode') ?? 0; + const hideUsernames = useUserPreference('hideUsernames'); + const hideRoles = useUserPreference('hideRoles'); + + return { + themeAppearence, + fontSize, + mentionsWithSymbol, + clockMode, + hideUsernames, + hideRoles, + }; +}; diff --git a/apps/meteor/client/views/account/accessibility/hooks/useAdsjustableFontSize.tsx b/apps/meteor/client/views/account/accessibility/hooks/useAdsjustableFontSize.tsx deleted file mode 100644 index 35607de1f9b5..000000000000 --- a/apps/meteor/client/views/account/accessibility/hooks/useAdsjustableFontSize.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import type { FontSize } from '@rocket.chat/rest-typings'; -import { useUserPreference } from '@rocket.chat/ui-contexts'; -import { useState } from 'react'; - -import { useCreateFontStyleElement } from './useCreateFontStyleElement'; - -export const useAdjustableFontSize = (): [FontSize, (value: FontSize) => void] => { - const fontSizePreference = useUserPreference('fontSize') || '100%'; - const [fontSize, setFontSize] = useState(fontSizePreference); - - useCreateFontStyleElement(fontSize); - - return [fontSize, setFontSize]; -}; diff --git a/apps/meteor/client/views/account/accessibility/hooks/useCreateFontStyleElement.ts b/apps/meteor/client/views/account/accessibility/hooks/useCreateFontStyleElement.ts index 63ecd3c0cf4b..923b3af88c60 100644 --- a/apps/meteor/client/views/account/accessibility/hooks/useCreateFontStyleElement.ts +++ b/apps/meteor/client/views/account/accessibility/hooks/useCreateFontStyleElement.ts @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useMemo } from 'react'; const createStyleElement = (id: string) => { const styleElement = document.getElementById(id); @@ -10,11 +10,14 @@ const createStyleElement = (id: string) => { return newStyleElement; }; -export const useCreateFontStyleElement = (fontSize: string): void => { - useEffect(() => { - const styleElement = createStyleElement('rcx-font-size'); - const css = `html { font-size: ${fontSize}; }`; - styleElement.innerHTML = css; - document.head.appendChild(styleElement); - }, [fontSize]); +export const useCreateFontStyleElement = (): ((fontSize: string) => void) => { + return useMemo( + () => (fontSize: string) => { + const styleElement = createStyleElement('rcx-font-size'); + const css = `html { font-size: ${fontSize}; }`; + styleElement.innerHTML = css; + document.head.appendChild(styleElement); + }, + [], + ); }; diff --git a/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx b/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx index e5157d517967..30c4c5fe6725 100644 --- a/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx +++ b/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx @@ -1,14 +1,16 @@ import type { SelectOption } from '@rocket.chat/fuselage'; -import { Accordion, Field, Select, FieldGroup, ToggleSwitch, Box } from '@rocket.chat/fuselage'; +import { FieldDescription, FieldLabel, Accordion, Field, Select, FieldGroup, ToggleSwitch, Box } from '@rocket.chat/fuselage'; import { useUniqueId } from '@rocket.chat/fuselage-hooks'; -import { useSetting, useTranslation } from '@rocket.chat/ui-contexts'; +import { useRouter, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useMemo } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; const PreferencesMessagesSection = () => { const t = useTranslation(); - const displayRolesEnabled = useSetting('UI_DisplayRoles'); const { control } = useFormContext(); + const router = useRouter(); + + const handleGoToAccessibilityPage = () => router.navigate('/account/accessibility-and-appearance'); const alsoSendThreadMessageToChannelOptions = useMemo( (): SelectOption[] => [ @@ -19,15 +21,6 @@ const PreferencesMessagesSection = () => { [t], ); - const timeFormatOptions = useMemo( - (): SelectOption[] => [ - ['0', t('Default')], // TO DO: update SelectOption type to accept number as first item - ['1', t('12_Hour')], - ['2', t('24_Hour')], - ], - [t], - ); - const sendOnEnterOptions = useMemo( (): SelectOption[] => [ ['normal', t('Enter_Normal')], @@ -40,14 +33,11 @@ const PreferencesMessagesSection = () => { const unreadAlertId = useUniqueId(); const showThreadsInMainChannelId = useUniqueId(); const alsoSendThreadToChannelId = useUniqueId(); - const clockModeId = useUniqueId(); const useEmojisId = useUniqueId(); const convertAsciiEmojiId = useUniqueId(); const autoImageLoadId = useUniqueId(); const saveMobileBandwidthId = useUniqueId(); const collapseMediaByDefaultId = useUniqueId(); - const hideUsernamesId = useUniqueId(); - const hideRolesId = useUniqueId(); const hideFlexTabId = useUniqueId(); const displayAvatarsId = useUniqueId(); const sendOnEnterId = useUniqueId(); @@ -114,16 +104,10 @@ const PreferencesMessagesSection = () => { - {t('Message_TimeFormat')} - - ( -