From 7dffec2e2fe536bb04f8c58bcab789d0b58e32cb Mon Sep 17 00:00:00 2001 From: csuadev <72958726+csuadev@users.noreply.github.com> Date: Mon, 4 Sep 2023 14:13:33 -0500 Subject: [PATCH 01/66] chore: Add danger variant to apps action button menus (#30214) --- .changeset/honest-glasses-roll.md | 5 +++++ apps/meteor/client/hooks/useAppActionButtons.ts | 1 + .../client/views/room/contexts/RoomToolboxContext.ts | 1 + .../views/room/providers/hooks/useAppsRoomActions.ts | 1 + apps/meteor/package.json | 2 +- yarn.lock | 10 +++++----- 6 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 .changeset/honest-glasses-roll.md diff --git a/.changeset/honest-glasses-roll.md b/.changeset/honest-glasses-roll.md new file mode 100644 index 000000000000..679f46fb8420 --- /dev/null +++ b/.changeset/honest-glasses-roll.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +chore: Add danger variant to apps action button menus diff --git a/apps/meteor/client/hooks/useAppActionButtons.ts b/apps/meteor/client/hooks/useAppActionButtons.ts index 8895535f9c26..28d62ef1b75a 100644 --- a/apps/meteor/client/hooks/useAppActionButtons.ts +++ b/apps/meteor/client/hooks/useAppActionButtons.ts @@ -146,6 +146,7 @@ export const useMessageActionAppsActionButtons = (context?: MessageActionContext label: Utilities.getI18nKeyForApp(action.labelI18n, action.appId), order: 7, type: 'apps', + variant: action.variant, action: (_, params) => { void actionManager.triggerActionButtonAction({ rid: params.message.rid, diff --git a/apps/meteor/client/views/room/contexts/RoomToolboxContext.ts b/apps/meteor/client/views/room/contexts/RoomToolboxContext.ts index fbf4fe5e7764..7f58eec3aa4c 100644 --- a/apps/meteor/client/views/room/contexts/RoomToolboxContext.ts +++ b/apps/meteor/client/views/room/contexts/RoomToolboxContext.ts @@ -28,6 +28,7 @@ export type RoomToolboxActionConfig = { onClickBack?: () => void; }>; type?: 'organization' | 'communication' | 'customization' | 'apps'; + variant?: 'danger'; }; export type RoomToolboxContextValue = { diff --git a/apps/meteor/client/views/room/providers/hooks/useAppsRoomActions.ts b/apps/meteor/client/views/room/providers/hooks/useAppsRoomActions.ts index e20f1465e2dc..935da2a23c46 100644 --- a/apps/meteor/client/views/room/providers/hooks/useAppsRoomActions.ts +++ b/apps/meteor/client/views/room/providers/hooks/useAppsRoomActions.ts @@ -19,6 +19,7 @@ export const useAppsRoomActions = () => { (action): RoomToolboxActionConfig => ({ id: action.actionId, icon: undefined, + variant: action.variant, order: 300, title: Utilities.getI18nKeyForApp(action.labelI18n, action.appId), groups: ['group', 'channel', 'live', 'team', 'direct', 'direct_multiple'], diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 17ca54920e7b..427ad86ddca3 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -225,7 +225,7 @@ "@rocket.chat/account-utils": "workspace:^", "@rocket.chat/agenda": "workspace:^", "@rocket.chat/api-client": "workspace:^", - "@rocket.chat/apps-engine": "1.41.0-alpha.305", + "@rocket.chat/apps-engine": "1.41.0-alpha.312", "@rocket.chat/base64": "workspace:^", "@rocket.chat/cas-validate": "workspace:^", "@rocket.chat/core-services": "workspace:^", diff --git a/yarn.lock b/yarn.lock index 092691ec4014..d14adeed87af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7763,9 +7763,9 @@ __metadata: languageName: node linkType: hard -"@rocket.chat/apps-engine@npm:1.41.0-alpha.305": - version: 1.41.0-alpha.305 - resolution: "@rocket.chat/apps-engine@npm:1.41.0-alpha.305" +"@rocket.chat/apps-engine@npm:1.41.0-alpha.312": + version: 1.41.0-alpha.312 + resolution: "@rocket.chat/apps-engine@npm:1.41.0-alpha.312" dependencies: adm-zip: ^0.5.9 cryptiles: ^4.1.3 @@ -7777,7 +7777,7 @@ __metadata: vm2: ^3.9.19 peerDependencies: "@rocket.chat/ui-kit": "*" - checksum: 83ec73dac6e1f25722080cf32143ada914c4adb9aef8ebf770af13a5456cef1c81d1a9eedc4063549b8105277f2254d6c307c3c0c5f6ed7f99233a2d464bf6da + checksum: 003853d3c4d4374ab984474026e4ae657daf4591fe4c375b914aa57c27f576af0fcba66e70c539e056b5d80a1ef655775f6f3a07bf81a36ab6fd438ce464e70f languageName: node linkType: hard @@ -8564,7 +8564,7 @@ __metadata: "@rocket.chat/account-utils": "workspace:^" "@rocket.chat/agenda": "workspace:^" "@rocket.chat/api-client": "workspace:^" - "@rocket.chat/apps-engine": 1.41.0-alpha.305 + "@rocket.chat/apps-engine": 1.41.0-alpha.312 "@rocket.chat/base64": "workspace:^" "@rocket.chat/cas-validate": "workspace:^" "@rocket.chat/core-services": "workspace:^" From 42644a6e4451728226b11e376898cf1e922d4b92 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 4 Sep 2023 13:33:57 -0600 Subject: [PATCH 02/66] 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 a0be7bf64f39..e19fa8136f59 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'; @@ -35,17 +34,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(); @@ -55,19 +55,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 778fc6168e57a862bd596384bf10572b6a292c53 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Mon, 4 Sep 2023 19:25:09 -0300 Subject: [PATCH 03/66] fix: Remove options on `Chat Now` page (#30196) --- packages/livechat/src/routes/Chat/component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/livechat/src/routes/Chat/component.js b/packages/livechat/src/routes/Chat/component.js index 6ba1788b4bcb..98991ab72b53 100644 --- a/packages/livechat/src/routes/Chat/component.js +++ b/packages/livechat/src/routes/Chat/component.js @@ -186,7 +186,7 @@ class Chat extends Component { {onChangeDepartment && ( From e077fd1cb6f5a1811be0e557b916b0b39f8c9fdc Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Mon, 4 Sep 2023 20:08:31 -0300 Subject: [PATCH 04/66] chore: add missing voip setting translation on pt-BR (#30210) --- apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index bf2f838d442a..931bb7bda467 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -4717,6 +4717,8 @@ "VoIP_Management_Server_Name": "Nome do servidor", "VoIP_Management_Server_Username": "Nome de usuário", "VoIP_Management_Server_Password": "Senha", + "VoIP_Retry_Count": "Número de tentativas", + "VoIP_Retry_Count_Description": "Define quantas vezes o cliente tentará se reconectar ao servidor VoIP caso a conexão seja perdida.", "Voip_call_started": "Chamada iniciada às", "Voip_call_duration": "Chamada com duração de {{duration}}", "Voip_call_declined": "Chamada finalizada pelo agente", From 8e95d589aa758a0554dc06b24406a10142f939f0 Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Tue, 5 Sep 2023 08:46:00 -0300 Subject: [PATCH 05/66] regression: Webhook / bot message without link previews (#30271) --- apps/meteor/app/oembed/server/server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/oembed/server/server.ts b/apps/meteor/app/oembed/server/server.ts index 3bf1ae3245be..256722cdd3d4 100644 --- a/apps/meteor/app/oembed/server/server.ts +++ b/apps/meteor/app/oembed/server/server.ts @@ -290,7 +290,7 @@ const rocketUrlParser = async function (message: IMessage): Promise { log.debug('URLs found', message.urls.length); if ( - message.attachments || + (message.attachments && message.attachments.length > 0) || message.urls.filter((item) => !item.url.includes(settings.get('Site_Url'))).length > MAX_EXTERNAL_URL_PREVIEWS ) { log.debug('All URL ignored'); @@ -330,7 +330,7 @@ const rocketUrlParser = async function (message: IMessage): Promise { changed = true; } } - if (attachments.length) { + if (attachments.length > 0) { await Messages.setMessageAttachments(message._id, attachments); } if (changed === true) { From 019e13c0073945e88763891c352dcb0192dc84f6 Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Tue, 5 Sep 2023 10:59:16 -0300 Subject: [PATCH 06/66] test: flaky homepage tests (#30200) --- apps/meteor/tests/e2e/homepage.spec.ts | 205 ++++++++++++------------- 1 file changed, 98 insertions(+), 107 deletions(-) diff --git a/apps/meteor/tests/e2e/homepage.spec.ts b/apps/meteor/tests/e2e/homepage.spec.ts index d9999e6fb502..465ecea03cbf 100644 --- a/apps/meteor/tests/e2e/homepage.spec.ts +++ b/apps/meteor/tests/e2e/homepage.spec.ts @@ -19,44 +19,46 @@ test.describe.serial('homepage', () => { let regularUserPage: Page; let adminPage: Page; - test.describe('layout for admins', () => { + test.describe('for admins', () => { test.beforeAll(async ({ browser }) => { adminPage = await browser.newPage({ storageState: Users.admin.state }); await adminPage.goto('/home'); await adminPage.waitForSelector('[data-qa-id="home-header"]'); }); - test('expect show customize button', async () => { - await expect(adminPage.locator('role=button[name="Customize"]')).toBeVisible(); - }); - test.describe('cards', () => { - for (const id of Object.values(CardIds)) { - // eslint-disable-next-line no-loop-func - test(`expect ${id} card to be visible`, async () => { - await expect(adminPage.locator(`[data-qa-id="${id}"]`)).toBeVisible(); - }); - } - }); + test('layout', async () => { + await test.step('expect show customize button', async () => { + await expect(adminPage.locator('role=button[name="Customize"]')).toBeVisible(); + }); + + await test.step('expect all cards to be visible', async () => { + await Promise.all(Object.values(CardIds).map((id) => expect(adminPage.locator(`[data-qa-id="${id}"]`)).toBeVisible())); + }); + }) + - test.describe('custom body with empty custom content', () => { + test.describe('custom body with empty custom content', async () => { test.beforeAll(async ({ api }) => { await expect((await api.post('/settings/Layout_Home_Body', { value: '' })).status()).toBe(200); }); - test('expect default value in custom body', async () => { - await expect( - adminPage.locator('role=status[name="Admins may insert content html to be rendered in this white space."]'), - ).toBeVisible(); - }); - - test('expect both change visibility and show only custom content buttons to be disabled', async () => { - await expect(adminPage.locator('role=button[name="Show to workspace"]')).toBeDisabled(); - await expect(adminPage.locator('role=button[name="Show only this content"]')).toBeDisabled(); - }); + test('layout', async () => { + await test.step('expect default value in custom body', async () => { + await expect( + adminPage.locator('role=status[name="Admins may insert content html to be rendered in this white space."]'), + ).toBeVisible(); + }); + + await test.step('expect both change visibility and show only custom content buttons to be disabled', async () => { + await expect(adminPage.locator('role=button[name="Show to workspace"]')).toBeDisabled(); + await expect(adminPage.locator('role=button[name="Show only this content"]')).toBeDisabled(); + }); + + await test.step('expect visibility tag to show "not visible"', async () => { + await expect(adminPage.locator('role=status[name="Not visible to workspace"]')).toBeVisible(); + }); + }) - test('expect visibility tag to show "not visible"', async () => { - await expect(adminPage.locator('role=status[name="Not visible to workspace"]')).toBeVisible(); - }); }); test.describe('custom body with custom content', () => { @@ -64,35 +66,38 @@ test.describe.serial('homepage', () => { await expect((await api.post('/settings/Layout_Home_Body', { value: 'Hello admin' })).status()).toBe(200); }); - test('expect custom body to be visible', async () => { - await expect(adminPage.locator('role=status[name="Hello admin"]')).toBeVisible(); - }); + test('layout', async() => { + await test.step('expect custom body to be visible', async () => { + await expect(adminPage.locator('role=status[name="Hello admin"]')).toBeVisible(); + }); + + await test.step('expect correct state for card buttons', async () => { + await expect(adminPage.locator('role=button[name="Show to workspace"]')).not.toBeDisabled(); + await expect(adminPage.locator('role=button[name="Show only this content"]')).toBeDisabled(); + }); + }) - test('expect correct state for card buttons', async () => { - await expect(adminPage.locator('role=button[name="Show to workspace"]')).not.toBeDisabled(); - await expect(adminPage.locator('role=button[name="Show only this content"]')).toBeDisabled(); - }); test.describe('enterprise edition', () => { test.skip(!IS_EE, 'Enterprise Only'); - test.describe('display custom content only', () => { - test.beforeAll(async ({ api }) => { - await expect((await api.post('/settings/Layout_Home_Body', { value: 'Hello admin' })).status()).toBe(200); - await expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: true })).status()).toBe(200); - await expect((await api.post('/settings/Layout_Custom_Body_Only', { value: true })).status()).toBe(200); - }); + test.beforeAll(async ({ api }) => { + await expect((await api.post('/settings/Layout_Home_Body', { value: 'Hello admin' })).status()).toBe(200); + await expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: true })).status()).toBe(200); + await expect((await api.post('/settings/Layout_Custom_Body_Only', { value: true })).status()).toBe(200); + }); - test('expect default layout to not be visible (show only custom content card)', async () => { + test('display custom content only', async () => { + await test.step('expect default layout to not be visible (show only custom content card)', async () => { await expect(adminPage.locator('role=heading[name="Welcome to Rocket.Chat"]')).not.toBeVisible(); }); - test('expect correct state for card buttons', async () => { + await test.step('expect correct state for card buttons', async () => { await expect(adminPage.locator('role=button[name="Hide on workspace"]')).toBeDisabled(); await expect(adminPage.locator('role=button[name="Show default content"]')).not.toBeDisabled(); }); - test('expect visibility tag to show "visible to workspace"', async () => { + await test.step('expect visibility tag to show "visible to workspace"', async () => { await expect(adminPage.locator('role=status[name="Visible to workspace"]')).toBeVisible(); }); }); @@ -100,97 +105,80 @@ test.describe.serial('homepage', () => { }); test.afterAll(async ({ api }) => { - await expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: false })).status()).toBe(200); - await expect((await api.post('/settings/Layout_Custom_Body_Only', { value: false })).status()).toBe(200); + expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: false })).status()).toBe(200); + expect((await api.post('/settings/Layout_Custom_Body_Only', { value: false })).status()).toBe(200); await adminPage.close(); }); }); - test.describe('layout for regular users', () => { - test.beforeAll(async ({ api }) => { - await expect((await api.post('/settings/Layout_Home_Body', { value: '' })).status()).toBe(200); - }); + test.describe('for regular users', () => { + const notVisibleCards = [CardIds.Users, CardIds.Custom]; - test.beforeAll(async ({ browser }) => { + test.beforeAll(async ({ api, browser }) => { + expect((await api.post('/settings/Layout_Home_Body', { value: '' })).status()).toBe(200); regularUserPage = await browser.newPage({ storageState: Users.user2.state }); await regularUserPage.goto('/home'); await regularUserPage.waitForSelector('[data-qa-id="home-header"]'); }); - test('expect to not show customize button', async () => { - await expect(regularUserPage.locator('role=button[name="Customize"]')).not.toBeVisible(); - }); - - test.describe('cards', () => { - for (const id of Object.values(CardIds)) { - if (id === CardIds.Users || id === CardIds.Custom) { - // eslint-disable-next-line no-loop-func - test(`expect ${id} card to not be visible`, async () => { - await expect(regularUserPage.locator(`[data-qa-id="${id}"]`)).not.toBeVisible(); - }); - } else { - // eslint-disable-next-line no-loop-func - test(`expect ${id} card to be visible`, async () => { - await expect(regularUserPage.locator(`[data-qa-id="${id}"]`)).toBeVisible(); - }); - } - } - }); - - test.describe('default values', () => { - test('expect welcome text to use Site_Name default setting', async () => { + test('layout', async () => { + await test.step('expect to not show customize button', async () => { + await expect(regularUserPage.locator('role=button[name="Customize"]')).not.toBeVisible(); + }); + + await test.step(`expect ${notVisibleCards.join(' and ')} cards to not be visible`, async () => { + await Promise.all(notVisibleCards.map((id) => expect(regularUserPage.locator(`[data-qa-id="${id}"]`)).not.toBeVisible())); + }); + + await test.step('expect all other cards to be visible', async () => { + await Promise.all(Object.values(CardIds).filter((id) => !notVisibleCards.includes(id)).map((id) => expect(regularUserPage.locator(`[data-qa-id="${id}"]`)).toBeVisible())); + }); + + await test.step('expect welcome text to use Site_Name default setting', async () => { await expect(regularUserPage.locator('role=heading[name="Welcome to Rocket.Chat"]')).toBeVisible(); }); - - test('expect header text to use Layout_Home_Title default setting', async () => { + + await test.step('expect header text to use Layout_Home_Title default setting', async () => { await expect(regularUserPage.locator('[data-qa-type="PageHeader-title"]')).toContainText('Home'); }); }); test.describe('custom values', () => { test.beforeAll(async ({ api }) => { - await expect((await api.post('/settings/Site_Name', { value: 'NewSiteName' })).status()).toBe(200); - await expect((await api.post('/settings/Layout_Home_Title', { value: 'NewTitle' })).status()).toBe(200); - }); + expect((await api.post('/settings/Site_Name', { value: 'NewSiteName' })).status()).toBe(200); + expect((await api.post('/settings/Layout_Home_Title', { value: 'NewTitle' })).status()).toBe(200); - test.beforeAll(async ({ browser }) => { - regularUserPage = await browser.newPage({ storageState: Users.user2.state }); await regularUserPage.goto('/home'); await regularUserPage.waitForSelector('[data-qa-id="home-header"]'); }); - test('expect welcome text to be NewSiteName', async () => { - await expect(regularUserPage.locator('role=heading[name="Welcome to NewSiteName"]')).toBeVisible(); - }); + test('layout', async () => { + await test.step('expect welcome text to be NewSiteName', async () => { + await expect(regularUserPage.locator('role=heading[name="Welcome to NewSiteName"]')).toBeVisible(); + }); + + await test.step('expect header text to be Layout_Home_Title setting', async () => { + await expect(regularUserPage.locator('[data-qa-type="PageHeader-title"]')).toContainText('NewTitle'); + }); + }) - test('expect header text to be Layout_Home_Title setting', async () => { - await expect(regularUserPage.locator('[data-qa-type="PageHeader-title"]')).toContainText('NewTitle'); - }); test.afterAll(async ({ api }) => { - await expect((await api.post('/settings/Site_Name', { value: 'Rocket.Chat' })).status()).toBe(200); - await expect((await api.post('/settings/Layout_Home_Title', { value: 'Home' })).status()).toBe(200); - }); - }); - - test.describe('custom body with empty content', () => { - test('expect to not show custom content card', async () => { - await expect(regularUserPage.locator('role=status')).not.toBeVisible(); + expect((await api.post('/settings/Site_Name', { value: 'Rocket.Chat' })).status()).toBe(200); + expect((await api.post('/settings/Layout_Home_Title', { value: 'Home' })).status()).toBe(200); }); }); test.describe('custom body with content', () => { test.beforeAll(async ({ api }) => { - await expect((await api.post('/settings/Layout_Home_Body', { value: 'Hello' })).status()).toBe(200); - await expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: true })).status()).toBe(200); - }); + expect((await api.post('/settings/Layout_Home_Body', { value: 'Hello' })).status()).toBe(200); + expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: true })).status()).toBe(200); - test.beforeAll(async ({ browser }) => { - regularUserPage = await browser.newPage({ storageState: Users.user2.state }); await regularUserPage.goto('/home'); await regularUserPage.waitForSelector('[data-qa-id="home-header"]'); }); + test('expect custom body to be visible', async () => { await expect(regularUserPage.locator('role=status[name="Hello"]')).toBeVisible(); }); @@ -199,25 +187,28 @@ test.describe.serial('homepage', () => { test.skip(!IS_EE, 'Enterprise Only'); test.beforeAll(async ({ api }) => { - await expect((await api.post('/settings/Layout_Custom_Body_Only', { value: true })).status()).toBe(200); + expect((await api.post('/settings/Layout_Custom_Body_Only', { value: true })).status()).toBe(200); }); - test('expect default layout to not be visible', async () => { - await expect(regularUserPage.locator('[data-qa-id="homepage-welcome-text"]')).not.toBeVisible(); - }); + test('layout', async () => { + await test.step('expect default layout to not be visible', async () => { + await expect(regularUserPage.locator('[data-qa-id="homepage-welcome-text"]')).not.toBeVisible(); + }); + + await test.step('expect custom body to be visible', async () => { + await expect(regularUserPage.locator('role=status[name="Hello"]')).toBeVisible(); + }); + }) - test('expect custom body to be visible', async () => { - await expect(regularUserPage.locator('role=status[name="Hello"]')).toBeVisible(); - }); test.afterAll(async ({ api }) => { - await expect((await api.post('/settings/Layout_Custom_Body_Only', { value: false })).status()).toBe(200); + expect((await api.post('/settings/Layout_Custom_Body_Only', { value: false })).status()).toBe(200); }); }); test.afterAll(async ({ api }) => { - await expect((await api.post('/settings/Layout_Home_Body', { value: '' })).status()).toBe(200); - await expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: false })).status()).toBe(200); + expect((await api.post('/settings/Layout_Home_Body', { value: '' })).status()).toBe(200); + expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: false })).status()).toBe(200); }); }); }); From a08898232c724de5918b589ae482db437eec533b Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Tue, 5 Sep 2023 11:23:37 -0300 Subject: [PATCH 07/66] chore: AppsList semantics improvements (#30256) --- .../views/admin/users/AdminUsersPage.tsx | 2 +- .../client/views/marketplace/AppMenu.js | 2 +- .../views/marketplace/AppsList/AppRow.tsx | 81 +++++++++---------- .../views/marketplace/AppsList/AppsList.tsx | 31 ++++--- .../marketplace/AppsPage/AppsPageContent.tsx | 5 -- .../AppsPage/AppsPageContentBody.tsx | 6 +- .../AppsPage/FeaturedAppsSections.tsx | 6 +- .../fragments/admin-flextab-users.ts | 8 ++ .../meteor/tests/e2e/user-invitations.spec.ts | 10 ++- 9 files changed, 83 insertions(+), 68 deletions(-) diff --git a/apps/meteor/client/views/admin/users/AdminUsersPage.tsx b/apps/meteor/client/views/admin/users/AdminUsersPage.tsx index 24622a44bcc6..aae06b177cce 100644 --- a/apps/meteor/client/views/admin/users/AdminUsersPage.tsx +++ b/apps/meteor/client/views/admin/users/AdminUsersPage.tsx @@ -66,7 +66,7 @@ const UsersPage = (): ReactElement => { {context && ( - + {context === 'info' && t('User_Info')} diff --git a/apps/meteor/client/views/marketplace/AppMenu.js b/apps/meteor/client/views/marketplace/AppMenu.js index ba843321395c..f50651ac4f53 100644 --- a/apps/meteor/client/views/marketplace/AppMenu.js +++ b/apps/meteor/client/views/marketplace/AppMenu.js @@ -425,7 +425,7 @@ function AppMenu({ app, isAppDetailsPage, ...props }) { return null; } - return ; + return ; } export default AppMenu; diff --git a/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx b/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx index a8a664fb148a..3005b706326b 100644 --- a/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx +++ b/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx @@ -62,55 +62,54 @@ const AppRow = (props: App): ReactElement => { const canUpdate = installed && version && marketplaceVersion && semver.lt(version, marketplaceVersion); return ( - - - - - +
+ + + + {name} + + {bundledIn && Boolean(bundledIn.length) && ( + + + + )} + {shortDescription && !isMobile && ( + + {shortDescription} + + )} + - - {bundledIn && Boolean(bundledIn.length) && ( - - - - )} - {shortDescription && !isMobile && ( - - {shortDescription} + + {canUpdate && ( + + )} - - - - {canUpdate && ( - - - - )} - - + - +
); }; diff --git a/apps/meteor/client/views/marketplace/AppsList/AppsList.tsx b/apps/meteor/client/views/marketplace/AppsList/AppsList.tsx index 7855bbdc8f94..27d25a566f80 100644 --- a/apps/meteor/client/views/marketplace/AppsList/AppsList.tsx +++ b/apps/meteor/client/views/marketplace/AppsList/AppsList.tsx @@ -7,20 +7,25 @@ import AppRow from './AppRow'; type AppsListProps = { apps: App[]; - title: string; + title?: string; + appsListId: string; }; -const AppsList = ({ apps, title }: AppsListProps): ReactElement => ( - <> - - {title} - - - {apps.map((app) => ( - - ))} - - -); +const AppsList = ({ apps, title, appsListId }: AppsListProps): ReactElement => { + return ( + <> + {title && ( + + {title} + + )} + + {apps.map((app) => ( + + ))} + + + ); +}; export default AppsList; diff --git a/apps/meteor/client/views/marketplace/AppsPage/AppsPageContent.tsx b/apps/meteor/client/views/marketplace/AppsPage/AppsPageContent.tsx index b652aba5ca27..40d90b56e046 100644 --- a/apps/meteor/client/views/marketplace/AppsPage/AppsPageContent.tsx +++ b/apps/meteor/client/views/marketplace/AppsPage/AppsPageContent.tsx @@ -184,9 +184,7 @@ const AppsPageContent = (): ReactElement => { statusFilterOnSelected={statusFilterOnSelected} context={context || 'explore'} /> - {appsResult.phase === AsyncStatePhase.LOADING && } - {appsResult.phase === AsyncStatePhase.RESOLVED && noErrorsOcurred && ( { noErrorsOcurred={noErrorsOcurred} /> )} - {noAppRequests && } - {noMarketplaceOrInstalledAppMatches && ( )} - {noInstalledAppMatches && ( { const t = useTranslation(); const scrollableRef = useRef(null); + const appsListId = useUniqueId(); return ( <> {noErrorsOcurred && ( - {isMarketplace && !isFiltered && } - + {isMarketplace && !isFiltered && } + )} diff --git a/apps/meteor/client/views/marketplace/AppsPage/FeaturedAppsSections.tsx b/apps/meteor/client/views/marketplace/AppsPage/FeaturedAppsSections.tsx index ee6904499af9..71d9ac62fcc0 100644 --- a/apps/meteor/client/views/marketplace/AppsPage/FeaturedAppsSections.tsx +++ b/apps/meteor/client/views/marketplace/AppsPage/FeaturedAppsSections.tsx @@ -9,17 +9,19 @@ import { useFeaturedApps } from '../hooks/useFeaturedApps'; type FeaturedSectionsProps = { appsResult: App[]; + appsListId: string; }; -const FeaturedAppsSections = ({ appsResult }: FeaturedSectionsProps): ReactElement | null => { +const FeaturedAppsSections = ({ appsResult, appsListId }: FeaturedSectionsProps): ReactElement | null => { const t = useTranslation(); const featuredApps = useFeaturedApps(); if (featuredApps.isSuccess) { return ( <> - {featuredApps.data.sections.map((section) => ( + {featuredApps.data.sections.map((section, index) => ( > text="Invite Members"'); + } + + get setupSmtpLink(): Locator { + return this.page.locator('role=link[name="Set up SMTP"]') + } } diff --git a/apps/meteor/tests/e2e/user-invitations.spec.ts b/apps/meteor/tests/e2e/user-invitations.spec.ts index f5eaac3c688f..4bcdf82d6f43 100644 --- a/apps/meteor/tests/e2e/user-invitations.spec.ts +++ b/apps/meteor/tests/e2e/user-invitations.spec.ts @@ -1,19 +1,23 @@ import { Users } from './fixtures/userStates'; +import { Admin } from './page-objects'; import { test, expect } from './utils/test'; test.use({ storageState: Users.admin.state }); test.describe.serial('user-invites', () => { + let poAdmin: Admin; + test.beforeEach(async ({ page }) => { + poAdmin = new Admin(page); await page.goto('/admin/users/invite'); - await expect(page.locator('//div[contains(text(), "Invite Members")]')).toBeVisible(); + await expect(poAdmin.tabs.users.inviteUsersTitle).toBeVisible(); }); test('expect SMTP setup warning and routing to email settings', async ({ page }) => { - await expect(page.locator('role=link[name="Set up SMTP"]')).toBeVisible(); + await expect(poAdmin.tabs.users.setupSmtpLink).toBeVisible(); - await page.locator('role=link[name="Set up SMTP"]').click(); + await poAdmin.tabs.users.setupSmtpLink.click(); await expect(page).toHaveURL('/admin/settings/Email'); }); From 97c8040b446c0610055431043e41d00733d64b7d Mon Sep 17 00:00:00 2001 From: "lingohub[bot]" <69908207+lingohub[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 15:58:40 +0000 Subject: [PATCH 08/66] =?UTF-8?q?i18n:=20Language=20update=20from=20LingoH?= =?UTF-8?q?ub=20=F0=9F=A4=96=20on=202023-08-31Z=20(#30243)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com> --- .../rocketchat-i18n/i18n/af.i18n.json | 2 ++ .../rocketchat-i18n/i18n/ar.i18n.json | 3 ++- .../rocketchat-i18n/i18n/az.i18n.json | 2 ++ .../rocketchat-i18n/i18n/be-BY.i18n.json | 2 ++ .../rocketchat-i18n/i18n/bg.i18n.json | 2 ++ .../rocketchat-i18n/i18n/bs.i18n.json | 2 ++ .../rocketchat-i18n/i18n/ca.i18n.json | 3 ++- .../rocketchat-i18n/i18n/cs.i18n.json | 3 ++- .../rocketchat-i18n/i18n/cy.i18n.json | 2 ++ .../rocketchat-i18n/i18n/da.i18n.json | 3 ++- .../rocketchat-i18n/i18n/de-AT.i18n.json | 2 ++ .../rocketchat-i18n/i18n/de.i18n.json | 6 ++---- .../rocketchat-i18n/i18n/el.i18n.json | 2 ++ .../rocketchat-i18n/i18n/en.i18n.json | 3 +-- .../rocketchat-i18n/i18n/eo.i18n.json | 2 ++ .../rocketchat-i18n/i18n/es.i18n.json | 3 ++- .../rocketchat-i18n/i18n/fa.i18n.json | 2 ++ .../rocketchat-i18n/i18n/fi.i18n.json | 7 ++----- .../rocketchat-i18n/i18n/fr.i18n.json | 3 ++- .../rocketchat-i18n/i18n/gl.i18n.json | 1 + .../rocketchat-i18n/i18n/he.i18n.json | 2 ++ .../rocketchat-i18n/i18n/hr.i18n.json | 2 ++ .../rocketchat-i18n/i18n/hu.i18n.json | 4 ++-- .../rocketchat-i18n/i18n/id.i18n.json | 2 ++ .../rocketchat-i18n/i18n/it.i18n.json | 3 ++- .../rocketchat-i18n/i18n/ja.i18n.json | 3 ++- .../rocketchat-i18n/i18n/ka-GE.i18n.json | 3 ++- .../rocketchat-i18n/i18n/km.i18n.json | 2 ++ .../rocketchat-i18n/i18n/ko.i18n.json | 3 ++- .../rocketchat-i18n/i18n/ku.i18n.json | 2 ++ .../rocketchat-i18n/i18n/lo.i18n.json | 2 ++ .../rocketchat-i18n/i18n/lt.i18n.json | 2 ++ .../rocketchat-i18n/i18n/lv.i18n.json | 2 ++ .../rocketchat-i18n/i18n/mn.i18n.json | 2 ++ .../rocketchat-i18n/i18n/ms-MY.i18n.json | 2 ++ .../rocketchat-i18n/i18n/nl.i18n.json | 3 ++- .../rocketchat-i18n/i18n/no.i18n.json | 2 ++ .../rocketchat-i18n/i18n/pl.i18n.json | 4 ++-- .../rocketchat-i18n/i18n/pt-BR.i18n.json | 19 +++++++++---------- .../rocketchat-i18n/i18n/pt.i18n.json | 3 ++- .../rocketchat-i18n/i18n/ro.i18n.json | 2 ++ .../rocketchat-i18n/i18n/ru.i18n.json | 3 ++- .../rocketchat-i18n/i18n/sk-SK.i18n.json | 2 ++ .../rocketchat-i18n/i18n/sl-SI.i18n.json | 2 ++ .../rocketchat-i18n/i18n/sq.i18n.json | 2 ++ .../rocketchat-i18n/i18n/sr.i18n.json | 2 ++ .../rocketchat-i18n/i18n/sv.i18n.json | 7 ++----- .../rocketchat-i18n/i18n/ta-IN.i18n.json | 2 ++ .../rocketchat-i18n/i18n/th-TH.i18n.json | 2 ++ .../rocketchat-i18n/i18n/tr.i18n.json | 3 ++- .../rocketchat-i18n/i18n/ug.i18n.json | 2 ++ .../rocketchat-i18n/i18n/uk.i18n.json | 3 ++- .../rocketchat-i18n/i18n/vi-VN.i18n.json | 2 ++ .../rocketchat-i18n/i18n/zh-HK.i18n.json | 2 ++ .../rocketchat-i18n/i18n/zh-TW.i18n.json | 3 ++- .../rocketchat-i18n/i18n/zh.i18n.json | 3 ++- 56 files changed, 117 insertions(+), 47 deletions(-) diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/af.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/af.i18n.json index 1f8dc09c9585..c1322ebab0af 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/af.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/af.i18n.json @@ -1831,6 +1831,8 @@ "Offline_success_message": "Vanlyn Sukses Boodskap", "Offline_unavailable": "Vanlyn is nie beskikbaar nie", "Older_than": "Ouer as", + "Omnichannel_Reports_Status_Open": "oop", + "Omnichannel_Reports_Status_Closed": "gesluit", "On": "op", "online": "aanlyn", "Online": "Online", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ar.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ar.i18n.json index 3b61c7d46ef5..d6b7e5a0739b 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ar.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ar.i18n.json @@ -2019,7 +2019,6 @@ "Generate_new_key": "إنشاء مفتاح جديد", "Generate_New_Link": "إنشاء رابط جديد", "Generating_key": "يتم إنشاء مفتاح", - "Get_link": "الحصول على رابط", "get-password-policy-forbidRepeatingCharacters": "يجب ألا تحتوي كلمة المرور على رموز متكررة", "get-password-policy-forbidRepeatingCharactersCount": "يجب ألا تحتوي كلمة المرور على أكثر من {{forbidRepeatingCharactersCount}} من الرموز المتكررة", "get-password-policy-maxLength": "يجب أن يزيد طول كلمة المرور على {{maxLength}} من الرموز", @@ -3181,6 +3180,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "مفتاح التشفير (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "إذا تم توفيره، فسيقوم بتشفير الرمز المميز للمستخدم مع المفتاح المقدم وسيحتاج النظام الخارجي إلى فك تشفير البيانات للوصول إلى الرمز المميز", "Omnichannel_External_Frame_URL": "عنوان URL للإطار الخارجي", + "Omnichannel_Reports_Status_Open": "فتح", + "Omnichannel_Reports_Status_Closed": "تم الإغلاق", "On": "مُفعّل", "On_Hold": "قيد الانتظار", "On_Hold_Chats": "قيد الانتظار", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/az.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/az.i18n.json index 6eb91c5e0f93..d63adf27a952 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/az.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/az.i18n.json @@ -1831,6 +1831,8 @@ "Offline_success_message": "Offline Uğur Mesajı", "Offline_unavailable": "Offline mövcud deyil", "Older_than": "Daha yaşlı", + "Omnichannel_Reports_Status_Open": "Açıq", + "Omnichannel_Reports_Status_Closed": "Bağlı", "On": "On", "online": "onlayn", "Online": "Onlayn", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/be-BY.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/be-BY.i18n.json index 195ae7976527..f46d3ea22b1d 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/be-BY.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/be-BY.i18n.json @@ -1847,6 +1847,8 @@ "Offline_success_message": "Offline Поспех паведамлення", "Offline_unavailable": "Offline недаступны", "Older_than": "Старэй", + "Omnichannel_Reports_Status_Open": "адкрыты", + "Omnichannel_Reports_Status_Closed": "закрыта", "On": "на", "online": "онлайн", "Online": "інтэрнэт", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/bg.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/bg.i18n.json index 344c2a75a499..b4bd9d07a849 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/bg.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/bg.i18n.json @@ -1828,6 +1828,8 @@ "Offline_success_message": "Съобщение за успешно офлайн", "Offline_unavailable": "Офлайн не е налице", "Older_than": "По-стари от", + "Omnichannel_Reports_Status_Open": "Отвори", + "Omnichannel_Reports_Status_Closed": "Затворен", "On": "На", "online": "на линия", "Online": "На линия", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/bs.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/bs.i18n.json index c58116b0c42e..81135ed5fa0d 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/bs.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/bs.i18n.json @@ -1824,6 +1824,8 @@ "Offline_success_message": "Izvanmrežna poruka uspjeha", "Offline_unavailable": "Nedostupnost izvanmrežnosti", "Older_than": "Stariji od", + "Omnichannel_Reports_Status_Open": "Otvori", + "Omnichannel_Reports_Status_Closed": "Zatvoreno", "On": "Uključeno", "online": "na liniji", "Online": "Online", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ca.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ca.i18n.json index c243fc4a5585..b6e15bbf6f66 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ca.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ca.i18n.json @@ -1997,7 +1997,6 @@ "Generate_new_key": "Generar una nova clau", "Generate_New_Link": "Generar un nou enllaç", "Generating_key": "Generant clau", - "Get_link": "Obtenir l'enllaç", "get-password-policy-forbidRepeatingCharacters": "La contrasenya no ha de contenir caràcters repetits", "get-password-policy-forbidRepeatingCharactersCount": "La contrasenya no ha de contenir més que {{forbidRepeatingCharactersCount}} caràcters repetits", "get-password-policy-maxLength": "La contrasenya ha de tenir un màxim de {{maxLength}} caràcters", @@ -3146,6 +3145,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "Clau de xifrat (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "Si es proporciona, xifrarà el token de l'usuari amb la clau proporcionada i el sistema extern haurà de desxifrar les dades per accedir a el token.", "Omnichannel_External_Frame_URL": "URL de marc extern", + "Omnichannel_Reports_Status_Open": "Obre", + "Omnichannel_Reports_Status_Closed": "Tancat", "On": "Activa", "On_Hold_Chats": "En espera", "On_Hold_conversations": "Converses en espera", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/cs.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/cs.i18n.json index cac3e0a65941..ff081e3a5eeb 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/cs.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/cs.i18n.json @@ -1705,7 +1705,6 @@ "Generate_new_key": "Vygenerovat nový klíč", "Generate_New_Link": "Vytvořit nový odkaz", "Generating_key": "Generování klíče", - "Get_link": "Získat odkaz", "get-password-policy-forbidRepeatingCharacters": "Heslo nesmí obsahovat opakující se znaky", "get-password-policy-forbidRepeatingCharactersCount": "Heslo nesmí obsahovat více než {{forbidRepeatingCharactersCount}} opakujících se znaků", "get-password-policy-maxLength": "Heslo nesmí být delší než {{maxLength}} znaků", @@ -2662,6 +2661,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "JWK klíč šifrování", "Omnichannel_External_Frame_Encryption_JWK_Description": "Pokud je povoleno zašifruje uživatelský data poskytnutým klíčem a externí systém je musí rozšifrovat.", "Omnichannel_External_Frame_URL": "URL externího rámce", + "Omnichannel_Reports_Status_Open": "Otevřít", + "Omnichannel_Reports_Status_Closed": "Zavřeno", "On": "Zapnuto", "online": "online", "Online": "Online", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/cy.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/cy.i18n.json index 793b1691b7e9..0f939e6b345e 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/cy.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/cy.i18n.json @@ -1826,6 +1826,8 @@ "Offline_success_message": "Neges Llwyddiant All-lein", "Offline_unavailable": "All-lein ddim ar gael", "Older_than": "Yn hŷn na", + "Omnichannel_Reports_Status_Open": "Agor", + "Omnichannel_Reports_Status_Closed": "Ar gau", "On": "Ar", "online": "ar-lein", "Online": "Ar-lein", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/da.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/da.i18n.json index ea4c9264efe9..317faac59164 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/da.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/da.i18n.json @@ -1716,7 +1716,6 @@ "Generate_new_key": "Generér en ny nøgle", "Generate_New_Link": "Generér nyt link", "Generating_key": "Genererer nøgle", - "Get_link": "Få link", "get-password-policy-forbidRepeatingCharacters": "Adgangskoden bør ikke indeholde gentagne tegn", "get-password-policy-forbidRepeatingCharactersCount": "Adgangskoden bør ikke indeholde mere end {{forbidRepeatingCharactersCount}} gentagne tegn", "get-password-policy-maxLength": "Adgangskoden skal maksimalt være {{maxLength}} tegn lang", @@ -2675,6 +2674,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "Krypteringsnøgle (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "Hvis en nøgle forefindes, vil brugerens token krypteres og eksterne systemer skal dekryptere data'en for at tilgå token", "Omnichannel_External_Frame_URL": "Ekstern frame-URL", + "Omnichannel_Reports_Status_Open": "Åbent", + "Omnichannel_Reports_Status_Closed": "Lukket", "On": "På", "online": "online", "Online": "Online", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/de-AT.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/de-AT.i18n.json index 78e458b50bbb..68b45bb97714 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/de-AT.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/de-AT.i18n.json @@ -1834,6 +1834,8 @@ "Offline_success_message": "Nachricht, dass Offline Nachricht erfolgreich", "Offline_unavailable": "offline - nicht verfügbar", "Older_than": "Älter als", + "Omnichannel_Reports_Status_Open": "Öffnen", + "Omnichannel_Reports_Status_Closed": "Geschlossen", "On": "Ein", "online": "online", "Online": "Online", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/de.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/de.i18n.json index e5d66cd9accc..47649dd17b2d 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/de.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/de.i18n.json @@ -2257,7 +2257,6 @@ "Generate_new_key": "Neuen Schlüssel erzeugen", "Generate_New_Link": "Neuen Link erstellen", "Generating_key": "Schlüssel generieren", - "Get_link": "Link abrufen", "get-password-policy-forbidRepeatingCharacters": "Das Passwort sollte keine sich wiederholenden Zeichen enthalten", "get-password-policy-forbidRepeatingCharactersCount": "Das Passwort darf nicht mehr als {{forbidRepeatingCharactersCount}} Zeichen enthalten, die sich wiederholen", "get-password-policy-maxLength": "Das Passwort sollte maximal {{maxLength}} Zeichen lang sein", @@ -2538,7 +2537,6 @@ "Invalid_setting_s": "Ungültige Einstellung: %s", "Invalid_two_factor_code": "Fehlerhafter Zwei-Faktor-Code", "Invalid_username": "Der eingegebene Benutzername ist ungültig", - "Invalid_JSON": "Ungültiges JSON", "invisible": "unsichtbar", "Invisible": "Unsichtbar", "Invitation": "Einladung", @@ -3216,7 +3214,6 @@ "Message_has_been_edited_by": "Die Nachricht wurde editiert von {{username}}", "Message_has_been_edited_by_at": "Die Nachricht wurde bearbeitet von __Benutzername__ am __datum__", "Message_has_been_pinned": "Nachricht wurde angeheftet", - "Message_has_been_shared": "Nachricht wurde geteilt", "Message_has_been_starred": "Nachricht wurde als Favorit gekennzeichnet", "Message_has_been_unpinned": "Nachricht wurde entpinnt", "Message_has_been_unstarred": "Nachricht nicht mehr favorisiert", @@ -3572,6 +3569,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "Verschlüsselungsschlüssel (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "Wenn angegeben, wird das Token des Benutzers mit dem angegebenen Schlüssel verschlüsselt und das externe System muss die Daten entschlüsseln, um auf das Token zuzugreifen", "Omnichannel_External_Frame_URL": "URL des externen Frames", + "Omnichannel_Reports_Status_Open": "Öffnen", + "Omnichannel_Reports_Status_Closed": "Geschlossen", "On": "Ein", "On_Hold": "In der Warteschleife", "On_Hold_Chats": "Angehalten", @@ -4254,7 +4253,6 @@ "Select_an_option": "Eine Option auswählen", "Select_at_least_one_user": "Mindestens einen Benutzer auswählen", "Select_at_least_two_users": "Mindestens zwei Benutzer auswählen", - "Share_Message": "Nachricht teilen", "Select_department": "Eine Abteilung auswählen", "Select_file": "Datei auswählen", "Select_role": "Eine Rolle auswählen", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/el.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/el.i18n.json index d36aee78cff4..b51fa54a97af 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/el.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/el.i18n.json @@ -1839,6 +1839,8 @@ "Offline_success_message": "Offline μήνυμα επιτυχίας", "Offline_unavailable": "offline διαθέσιμη", "Older_than": "Μεγαλύτερος από", + "Omnichannel_Reports_Status_Open": "Ανοιχτό", + "Omnichannel_Reports_Status_Closed": "Έκλεισε", "On": "Επί", "online": "σε απευθείας σύνδεση", "Online": "Συνδεδεμένος", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index 4dfd49cabd30..3522dc59e8cb 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -639,7 +639,6 @@ "Apps_Manual_Update_Modal_Title": "This app is already installed", "Apps_Manual_Update_Modal_Body": "Do you want to update it?", "Apps_User_Already_Exists": "The username \"{{username}}\" is already being used. Rename or remove the user using it to install this App", - "AutoLinker": "AutoLinker", "Apps_WhatIsIt": "Apps: What Are They?", "Apps_WhatIsIt_paragraph1": "A new icon in the administration area! What does this mean and what are Apps?", @@ -6034,4 +6033,4 @@ "Filter_by_room": "Filter by room type", "Filter_by_visibility": "Filter by visibility", "Theme_Appearence": "Theme Appearence" -} +} \ No newline at end of file diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/eo.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/eo.i18n.json index 8066b28297fa..9c9501c8a174 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/eo.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/eo.i18n.json @@ -1831,6 +1831,8 @@ "Offline_success_message": "Senkonekta Sukcesa Mesaĝo", "Offline_unavailable": "Senkonekta ne disponebla", "Older_than": "Pli maljuna ol", + "Omnichannel_Reports_Status_Open": "Malfermita", + "Omnichannel_Reports_Status_Closed": "Fermita", "On": "Sur", "online": "enreta", "Online": "Enreta", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/es.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/es.i18n.json index cb9e83821017..50a7b8d63873 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/es.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/es.i18n.json @@ -1995,7 +1995,6 @@ "Generate_new_key": "Generar una nueva clave", "Generate_New_Link": "Generar un nuevo enlace", "Generating_key": "Generando clave", - "Get_link": "Obtener enlace", "get-password-policy-forbidRepeatingCharacters": "La contraseña no debe contener caracteres repetidos", "get-password-policy-forbidRepeatingCharactersCount": "La contraseña solo puede contener {{forbidRepeatingCharactersCount}} caracteres repetidos", "get-password-policy-maxLength": "La contraseña debe tener un máximo de {{maxLength}} caracteres", @@ -3156,6 +3155,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "Clave de cifrado (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "Si se proporciona, cifrará el token del usuario con la clave proporcionada y el sistema externo deberá descifrar los datos para acceder al token.", "Omnichannel_External_Frame_URL": "URL de marco externo", + "Omnichannel_Reports_Status_Open": "Abiertas", + "Omnichannel_Reports_Status_Closed": "Cerrado", "On": "Activar", "On_Hold": "En espera", "On_Hold_Chats": "En espera", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/fa.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/fa.i18n.json index ea451b6ad4d5..dba68fa6b255 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/fa.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/fa.i18n.json @@ -2132,6 +2132,8 @@ "Omnichannel_Directory": "راهنمای ارتباط کانال همه‌کاره", "Omnichannel_appearance": "ظاهر کانال همه‌کاره", "Omnichannel_Contact_Center": "مرکز مخاطبان کانال همه‌کاره", + "Omnichannel_Reports_Status_Open": "باز کن", + "Omnichannel_Reports_Status_Closed": "بسته", "On": "روشن", "online": "برخط", "Online": "برخط", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/fi.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/fi.i18n.json index 0fc914f509f0..ccdec04a7bec 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/fi.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/fi.i18n.json @@ -2290,7 +2290,6 @@ "Generate_new_key": "Luo uusi avain", "Generate_New_Link": "Luo uusi linkki", "Generating_key": "Luodaan avainta", - "Get_link": "Hae linkki", "get-password-policy-forbidRepeatingCharacters": "Salasana ei saa sisältää toistuvia merkkejä", "get-password-policy-forbidRepeatingCharactersCount": "Salasana ei saa sisältää yli {{forbidRepeatingCharactersCount}} toistuvaa merkkiä", "get-password-policy-maxLength": "Salasanan on oltava enintään {{maxLength}} merkkiä pitkä", @@ -2575,7 +2574,6 @@ "Invalid_setting_s": "Virheellinen asetus: %s", "Invalid_two_factor_code": "Virheellinen kaksivaiheisen tunnistautumisen koodi", "Invalid_username": "Annettu käyttäjätunnus on virheellinen", - "Invalid_JSON": "Virheellinen JSON", "invisible": "näkymätön", "Invisible": "Näkymätön", "Invitation": "Kutsu", @@ -3265,7 +3263,6 @@ "Message_has_been_edited_by": "Viestiä on muokannut {{username}}", "Message_has_been_edited_by_at": "Viestiä on muokannut {{username}} at {{date}}", "Message_has_been_pinned": "Viesti on kiinnitetty", - "Message_has_been_shared": "Viesti on jaettu", "Message_has_been_starred": "Viesti on merkitty tähdellä", "Message_has_been_unpinned": "Viestin kiinnitys poistettu", "Message_has_been_unstarred": "Viestin tähtimerkintä poistettu", @@ -3620,6 +3617,8 @@ "omnichannel_sla_change_history": "Palvelutasosopimusta vaihdettu: {{user}} vaihtoi palvelutasosopimuksen käytännöksi {{sla}}", "Omnichannel_enable_department_removal": "Ota käyttöön osaston poistaminen", "Omnichannel_enable_department_removal_alert": "Poistettuja osastoja ei voi palauttaa, suosittelemme sen sijaan osaston arkistointia.", + "Omnichannel_Reports_Status_Open": "Avaa", + "Omnichannel_Reports_Status_Closed": "Suljettu", "On": "Käytössä", "on-hold-livechat-room": "Omnichannelin pidon huone Room", "on-hold-livechat-room_description": "Lupa asettaa Omnichannel-huone pitoon", @@ -4330,7 +4329,6 @@ "Select_an_option": "Valitse vaihtoehto", "Select_at_least_one_user": "Valitse vähintään yksi käyttäjä", "Select_at_least_two_users": "Valitse vähintään kaksi käyttäjää", - "Share_Message": "Jaa viesti", "Select_department": "Valitse osasto", "Select_file": "Valitse tiedosto", "Select_role": "Valitse rooli", @@ -4338,7 +4336,6 @@ "Select_tag": "Valitse tunniste", "Select_the_channels_you_want_the_user_to_be_removed_from": "Valitse kanavat, joista käyttäjä halutaan poistaa", "Select_the_teams_channels_you_would_like_to_delete": "Valitse Tiimin kanavat Channel jotka haluat poistaa, ne, joita et valitse, siirretään työtilaan.", - "Select_atleast_one_channel_to_share_the_messsage": "Valitse vähintään yksi kanava viestin jakamista varten", "Select_user": "Valitse käyttäjä", "Select_users": "Valitse käyttäjät", "Selected_agents": "Valitut agentit", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/fr.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/fr.i18n.json index 96a4880a3044..08641b831f94 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/fr.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/fr.i18n.json @@ -2010,7 +2010,6 @@ "Generate_new_key": "Générer une nouvelle clé", "Generate_New_Link": "Générer un nouveau lien", "Generating_key": "Génération de la clé", - "Get_link": "Obtenir le lien", "get-password-policy-forbidRepeatingCharacters": "Le mot de passe ne doit pas contenir de caractères répétitifs", "get-password-policy-forbidRepeatingCharactersCount": "Le mot de passe ne doit pas contenir plus de {{forbidRepeatingCharactersCount}} caractères répétitifs", "get-password-policy-maxLength": "Le mot de passe doit comporter au maximum {{maxLength}} caractères", @@ -3174,6 +3173,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "Clé de chiffrement (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "Si cette clé est fournie, elle est utilisée pour chiffrer le jeton de l'utilisateur et le système externe doit déchiffrer les données pour accéder au jeton", "Omnichannel_External_Frame_URL": "URL du cadre externe", + "Omnichannel_Reports_Status_Open": "Ouvert", + "Omnichannel_Reports_Status_Closed": "Fermé", "On": "Activé", "On_Hold": "En attente", "On_Hold_Chats": "En attente", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/gl.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/gl.i18n.json index bac8e5c28aa3..5272cd9e1d3f 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/gl.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/gl.i18n.json @@ -226,6 +226,7 @@ "Offline_message": "Mensaxe fora de liña", "Offline_Message": "Mensaxe fora de liña", "Offline_messages": "Mensaxes fora de liña", + "Omnichannel_Reports_Status_Closed": "Pechado", "online": "en liña", "Online": "En liña", "Only_you_can_see_this_message": "So ti podes ver esta mensaxe", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/he.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/he.i18n.json index beefb3f030db..7f391aa806b4 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/he.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/he.i18n.json @@ -994,6 +994,8 @@ "Offline_message": "הודעה מנותקת", "Offline_success_message": "הודעת הצלחה מנותקת", "Offline_unavailable": "זמין מנותק", + "Omnichannel_Reports_Status_Open": "לִפְתוֹחַ", + "Omnichannel_Reports_Status_Closed": "סגור", "On": "פועל", "online": "זמין", "Online": "זמינים", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/hr.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/hr.i18n.json index 8c11ff0d62b7..bbad485652d1 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/hr.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/hr.i18n.json @@ -1964,6 +1964,8 @@ "Offline_success_message": "Izvanmrežna poruka uspjeha", "Offline_unavailable": "Nedostupnost izvanmrežnosti", "Older_than": "Stariji od", + "Omnichannel_Reports_Status_Open": "Otvori", + "Omnichannel_Reports_Status_Closed": "Zatvoreno", "On": "Uključeno", "online": "na liniji", "Online": "Online", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/hu.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/hu.i18n.json index 3fd57ecb9a7e..d939e8ad16bb 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/hu.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/hu.i18n.json @@ -2213,7 +2213,6 @@ "Generate_new_key": "Új kulcs előállítása", "Generate_New_Link": "Új hivatkozás előállítása", "Generating_key": "Kulcs előállítása", - "Get_link": "Hivatkozás lekérése", "get-password-policy-forbidRepeatingCharacters": "A jelszó nem tartalmazhat ismétlődő karaktereket", "get-password-policy-forbidRepeatingCharactersCount": "A jelszó nem tartalmazhat több mint {{forbidRepeatingCharactersCount}} ismétlődő karaktert", "get-password-policy-maxLength": "A jelszónak legfeljebb {{maxLength}} karakter hosszúságúnak kell lennie", @@ -2489,7 +2488,6 @@ "Invalid_setting_s": "Érvénytelen beállítás: %s", "Invalid_two_factor_code": "Érvénytelen kétfaktoros kód", "Invalid_username": "A megadott felhasználónév érvénytelen", - "Invalid_JSON": "Érvénytelen JSON", "invisible": "láthatatlan", "Invisible": "Láthatatlan", "Invitation": "Meghívás", @@ -3485,6 +3483,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "Titkosítási kulcs (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "Ha meg van adva, akkor a megadott kulccsal titkosítja a felhasználó tokenjét, és a külső rendszernek vissza kell fejtenie az adatokat, hogy hozzáférjen a tokenhez.", "Omnichannel_External_Frame_URL": "Külső keret URL", + "Omnichannel_Reports_Status_Open": "Nyisd ki", + "Omnichannel_Reports_Status_Closed": "Zárva", "On": "Be", "on-hold-livechat-room": "Összcsatornás szoba várakoztatása", "on-hold-livechat-room_description": "Jogosultság az összcsatornás szoba várakoztatásához", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/id.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/id.i18n.json index ff9a52bddb49..4f78b268bcc8 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/id.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/id.i18n.json @@ -1839,6 +1839,8 @@ "Offline_success_message": "pesan sukses Offline", "Offline_unavailable": "Offline tidak tersedia", "Older_than": "Lebih tua dari", + "Omnichannel_Reports_Status_Open": "Buka", + "Omnichannel_Reports_Status_Closed": "Tutup", "On": "Di", "online": "on line", "Online": "Online", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/it.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/it.i18n.json index b2da95a84e62..498c3ea4b5fc 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/it.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/it.i18n.json @@ -1246,7 +1246,6 @@ "Gaming": "Gaming", "General": "Generale", "Generate_New_Link": "Genera nuovo link", - "Get_link": "Ottieni link", "github_no_public_email": "Non hai un email publica sul tuo account GitHub", "Give_a_unique_name_for_the_custom_oauth": "Dai un nome univoco per l'OAuth personalizzato", "strike": "barrato", @@ -1900,6 +1899,8 @@ "Offline_success_message": "Messaggio di successo offline", "Offline_unavailable": "Offline non disponibile", "Older_than": "Più vecchio di", + "Omnichannel_Reports_Status_Open": "Aperto", + "Omnichannel_Reports_Status_Closed": "Chiuso", "On": "Accendi", "online": "in linea", "Online": "Online", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ja.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ja.i18n.json index 689bdf0a8216..0bf0eb5063ae 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ja.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ja.i18n.json @@ -1992,7 +1992,6 @@ "Generate_new_key": "新しいキーを生成", "Generate_New_Link": "新しいリンクの生成", "Generating_key": "キーを生成中", - "Get_link": "リンクの取得", "get-password-policy-forbidRepeatingCharacters": "パスワードに繰り返し文字を含めないでください", "get-password-policy-forbidRepeatingCharactersCount": "パスワードに{{forbidRepeatingCharactersCount}}個を超える繰り返し文字を含めることはできません", "get-password-policy-maxLength": "パスワードは{{maxLength}}文字以内にする必要があります", @@ -3149,6 +3148,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "暗号化キー(JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "指定されている場合、提供されたキーでユーザーのトークンを暗号化します。また外部システムは、トークンにアクセスするためにデータを復号化する必要があります", "Omnichannel_External_Frame_URL": "外部フレームURL", + "Omnichannel_Reports_Status_Open": "開く", + "Omnichannel_Reports_Status_Closed": "閉鎖", "On": "オン", "On_Hold": "保留中", "On_Hold_Chats": "保留中", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ka-GE.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ka-GE.i18n.json index b9ab44fa5495..15514a726e5b 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ka-GE.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ka-GE.i18n.json @@ -1618,7 +1618,6 @@ "Generate_new_key": "შექმენით ახალი გასაღები", "Generate_New_Link": "შექმენით ახალი ბმული", "Generating_key": "გასაღების გენერაცია", - "Get_link": "მიიღეთ ბმული", "github_no_public_email": "თქვენ არ გაქვთ მითითებული საჯარო ელ.ფოსტა GitHub-თვის", "Give_a_unique_name_for_the_custom_oauth": "მიეცით უნიკალური სახელი ინდივიდუალურ oauth-ს ( ღია ავტორიზაცია)", "Give_the_application_a_name_This_will_be_seen_by_your_users": "დაარქვით აპლიკაციას სახელი.ეს ხილული იქნება თქვენთვის", @@ -2506,6 +2505,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "დაშიფვრის გასაღები(JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "გასაღების მოწოდების შემთხვევაში ეს დაშიფრავს მომხმარებლის ტოკენს და გარე სისტემებს მოუწევთ მონაცემების გაშიფვრა ტოკენის მისაღებად.", "Omnichannel_External_Frame_URL": "გარე ჩარჩოს ლინკი", + "Omnichannel_Reports_Status_Open": "გახსნა", + "Omnichannel_Reports_Status_Closed": "დახურულია", "On": "ჩართულია", "online": "ონლაინ", "Online": "ონლაინ", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/km.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/km.i18n.json index bc06b13a5749..376c4f51610a 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/km.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/km.i18n.json @@ -2138,6 +2138,8 @@ "Offline_unavailable": "មិនអាចប្រើបានក្រៅបណ្តាញ", "Old Colors": "ពណ៌ចាស់", "Older_than": "ចាស់​ជាង", + "Omnichannel_Reports_Status_Open": "បើកទូលាយ", + "Omnichannel_Reports_Status_Closed": "បិទ", "On": "បើក", "online": "អនឡាញ", "Online": "លើបណ្តាញ", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ko.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ko.i18n.json index 6cdbbf56113e..34f7608c9bed 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ko.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ko.i18n.json @@ -1763,7 +1763,6 @@ "Generate_new_key": "새 키 생성", "Generate_New_Link": "새 링크 생성", "Generating_key": "키 생성", - "Get_link": "링크 생성", "get-password-policy-forbidRepeatingCharacters": "비밀번호는 반복되는 문자를 포함하지 않아야합니다", "get-password-policy-forbidRepeatingCharactersCount": "비밀번호는 {{forbidRepeatingCharactersCount}} 반복 문자를 초과 할 수 없습니다", "get-password-policy-maxLength": "비밀번호는 최대 {{maxLength}} 자 여야합니다.", @@ -2720,6 +2719,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "암호화 키 (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "제공된 경우 제공된 키로 사용자토큰을 암호화해야하고, 외부 시스템은 토큰에 액세스하기 위해 데이터를 해독해야합니다.", "Omnichannel_External_Frame_URL": "외부 프레임 URL", + "Omnichannel_Reports_Status_Open": "열기", + "Omnichannel_Reports_Status_Closed": "종료", "On": "켜짐", "online": "온라인", "Online": "온라인", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ku.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ku.i18n.json index 4eaeac24e15a..8441a8a2fda8 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ku.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ku.i18n.json @@ -1826,6 +1826,8 @@ "Offline_success_message": "message serkeftina is offline", "Offline_unavailable": "Ne girêdayî ne amade ye", "Older_than": "Mezintirîn", + "Omnichannel_Reports_Status_Open": "Vekirî", + "Omnichannel_Reports_Status_Closed": "Girtî", "On": "Li", "online": "online", "Online": "bike", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/lo.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/lo.i18n.json index a62baae6717a..81c5ababade7 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/lo.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/lo.i18n.json @@ -1868,6 +1868,8 @@ "Offline_success_message": "ຂໍ້ຄວາມສໍາເລັດອອຟໄລ", "Offline_unavailable": "ບໍ່ສາມາດໃຊ້ອອຟໄລ", "Older_than": "ອາ​ຍຸ​ສູງ​ກວ່າ", + "Omnichannel_Reports_Status_Open": "ເປີດ", + "Omnichannel_Reports_Status_Closed": "ປິດ", "On": "ສຸດ", "online": "ອອນໄລນ໌", "Online": "ອອນໄລນ໌", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/lt.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/lt.i18n.json index 1d68a9db90c9..8d3e1c746860 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/lt.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/lt.i18n.json @@ -1886,6 +1886,8 @@ "Offline_success_message": "Sesijos neprisijungus pranešimas", "Offline_unavailable": "Atsijungęs nepasiekiamas", "Older_than": "Vyresni nei", + "Omnichannel_Reports_Status_Open": "Atidaryta", + "Omnichannel_Reports_Status_Closed": "Uždaryta", "On": "apie", "online": "prisijungęs", "Online": "Prisijungęs", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/lv.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/lv.i18n.json index de9ed7f71f81..e658e85d3b05 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/lv.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/lv.i18n.json @@ -1844,6 +1844,8 @@ "Offline_success_message": "Bezsaistes vēstule veiksmīga", "Offline_unavailable": "Bezsaiste nav pieejama", "Older_than": "Vecāki par", + "Omnichannel_Reports_Status_Open": "Atvērt", + "Omnichannel_Reports_Status_Closed": "Aizvērts", "On": "Ieslēgts", "online": "tiešsaistē", "Online": "Tiešsaistē", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/mn.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/mn.i18n.json index 75c1882c0313..c7959fc2a85c 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/mn.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/mn.i18n.json @@ -1826,6 +1826,8 @@ "Offline_success_message": "Оффлайн амжилттай зурвас", "Offline_unavailable": "Офлайн боломжгүй байна", "Older_than": "Аас дээш насны", + "Omnichannel_Reports_Status_Open": "Нээлттэй байна", + "Omnichannel_Reports_Status_Closed": "Хаалттай байна", "On": "Дээр", "online": "онлайн байна", "Online": "Онлайн", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ms-MY.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ms-MY.i18n.json index ae8be0bd18e1..dea066ead6fd 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ms-MY.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ms-MY.i18n.json @@ -1838,6 +1838,8 @@ "Offline_success_message": "mesej kejayaan Offline", "Offline_unavailable": "luar talian tidak tersedia", "Older_than": "Lebih tua daripada", + "Omnichannel_Reports_Status_Open": "Dibuka", + "Omnichannel_Reports_Status_Closed": "ditutup", "On": "Pada", "online": "dalam talian", "Online": "Dalam talian", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/nl.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/nl.i18n.json index 5a4891a48f02..f611b39aebd4 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/nl.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/nl.i18n.json @@ -2005,7 +2005,6 @@ "Generate_new_key": "Genereer een nieuwe sleutel", "Generate_New_Link": "Genereer een nieuwe link", "Generating_key": "Sleutel genereren", - "Get_link": "Link krijgen", "get-password-policy-forbidRepeatingCharacters": "Het wachtwoord mag geen herhalende tekens bevatten", "get-password-policy-forbidRepeatingCharactersCount": "Het wachtwoord mag niet meer dan {{forbidRepeatingCharactersCount}} herhalende tekens bevatten", "get-password-policy-maxLength": "Het wachtwoord mag maximaal {{maxLength}} tekens lang zijn", @@ -3167,6 +3166,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "Versleutelingssleuten (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "Indien verstrekt, versleutelt het het token van de gebruiker met de meegeleverde sleutel en moet het externe systeem de gegevens ontsleutelen om toegang te krijgen tot het token", "Omnichannel_External_Frame_URL": "URL van externe frame", + "Omnichannel_Reports_Status_Open": "Open", + "Omnichannel_Reports_Status_Closed": "Gesloten", "On": "Aan", "On_Hold": "In de wacht", "On_Hold_Chats": "On-hold", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/no.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/no.i18n.json index 4d148f582c36..1eb6c8ceb8bd 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/no.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/no.i18n.json @@ -1917,6 +1917,8 @@ "Offline_success_message": "Frakoblet suksessmelding", "Offline_unavailable": "Frakoblet utilgjengelig", "Older_than": "Eldre enn", + "Omnichannel_Reports_Status_Open": "Åpne", + "Omnichannel_Reports_Status_Closed": "Lukket", "On": "På", "online": "på nett", "Online": "på nett", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/pl.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/pl.i18n.json index e30eaad0bb08..0c4b85e588e0 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/pl.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/pl.i18n.json @@ -2180,7 +2180,6 @@ "Generate_new_key": "Wygeneruj nowy klucz", "Generate_New_Link": "Wygeneruj nowy link", "Generating_key": "Generowanie klucza", - "Get_link": "Skopiuj link", "get-password-policy-forbidRepeatingCharacters": "Hasło nie powinno zawierać powtarzających się znaków", "get-password-policy-forbidRepeatingCharactersCount": "Hasło nie powinno zawierać więcej niż {{forbidRepeatingCharactersCount}} powtarzających się znaków", "get-password-policy-maxLength": "Hasło powinno mieć maksymalną długość {{maxLength}} znaków", @@ -2453,7 +2452,6 @@ "Invalid_setting_s": "Nieprawidłowe ustawienie: %s", "Invalid_two_factor_code": "Nieprawidłowy kod dwuskładnikowy", "Invalid_username": "Wprowadzona nazwa użytkownika jest nieprawidłowa", - "Invalid_JSON": "Nieprawidłowy JSON", "invisible": "niewidoczny", "Invisible": "Niewidoczny", "Invitation": "Zaproszenie", @@ -3425,6 +3423,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "Klucz szyfrujący (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "Jeśli podane, szyfruje on token użytkownika dostarczonym kluczem, a zewnętrzny system będzie musiał odszyfrować dane, aby uzyskać dostęp do tokena", "Omnichannel_External_Frame_URL": "Adres URL zewnętrznej ramki", + "Omnichannel_Reports_Status_Open": "Otwarty", + "Omnichannel_Reports_Status_Closed": "Zamknięty", "On": "Na", "on-hold-livechat-room": "Wstrzymaj Omnichannel RoomRoom", "on-hold-livechat-room_description": "Pozwolenie na wstrzymanie omnichannel roomu", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index 931bb7bda467..de5c2356a6b9 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -5,13 +5,13 @@ "__count__empty_rooms_will_be_removed_automatically__rooms__": "{{count}} salas vazias serão removidas automaticamente:
{{rooms}}.", "__count__message_pruned": "{{count}} mensagem apagada", "__count__message_pruned_plural": "{{count}} mensagens apagadas", + "__count__conversations__period__": "{{count}} conversas, {{period}}", + "__count__tags__and__count__conversations__period__": "{{count}} tags e {{conversations}} conversas, {{period}}", + "__departments__departments_and__count__conversations__period__": "{{departments}} departmentos e {{count}} conversas, {{period}}", "__usersCount__member_joined_plural": "+ {{usersCount}} membros entraram", "__usersCount__people_will_be_invited": "{{usersCount}} usuários vão ser convidados", "__username__is_no_longer__role__defined_by__user_by_": "{{username}} não pertence mais a {{role}}, por {{user_by}}", "__username__was_set__role__by__user_by_": "{{username}} foi definido como {{role}} por {{user_by}}", - "__count__conversations__period__": "{{count}} conversas, {{period}}", - "__count__tags__and__count__conversations__period__": "{{count}} tags e {{conversations}} conversas, {{period}}", - "__departments__departments_and__count__conversations__period__": "{{departments}} departmentos e {{count}} conversas, {{period}}", "__count__without__department__": "{{count}} sem departamento", "__count__without__tags__": "{{count}} sem tags", "__count__without__assignee__": "{{count}} sem responsável", @@ -993,11 +993,6 @@ "conversation_with_s": "a conversa com %s", "Conversations": "Conversas", "Conversations_per_day": "Conversas por dia", - "Conversations_by_agents": "Conversas por agente", - "Conversations_by_channel": "Conversar por canal", - "Conversations_by_department": "Conversas por departamento", - "Conversations_by_status": "Conversas por status", - "Conversations_by_tag": "Conversas por tag", "Convert": "Converter", "Convert_Ascii_Emojis": "Converter ASCII em emoji", "Convert_to_channel": "Converter em canal", @@ -2053,7 +2048,6 @@ "Generate_new_key": "Gerar uma nova chave", "Generate_New_Link": "Gerar novo link", "Generating_key": "Gerando chave", - "Get_link": "Obter link", "get-password-policy-forbidRepeatingCharacters": "A senha não deve conter caracteres repetidos", "get-password-policy-forbidRepeatingCharactersCount": "A senha não deve conter mais de {{forbidRepeatingCharactersCount}} caracteres repetidos", "get-password-policy-maxLength": "A senha deve ter no máximo {{maxLength}} caracteres", @@ -4965,10 +4959,15 @@ "onboarding.form.standaloneServerForm.servicesUnavailable": "Alguns dos serviços estarão indisponíveis ou precisarão de configuração manual", "onboarding.form.standaloneServerForm.publishOwnApp": "Para enviar notificações de push, você precisará compilar e publicar seu próprio aplicativo no Google Play e App Store", "onboarding.form.standaloneServerForm.manuallyIntegrate": "É necessário integrar manualmente com serviços externos", + "Conversations_by_agents": "Conversas por agente", + "Conversations_by_channel": "Conversar por canal", + "Conversations_by_department": "Conversas por departamento", + "Conversations_by_status": "Conversas por status", + "Conversations_by_tag": "Conversas por tag", "Awaiting_confirmation": "Aguardando confirmação", "RegisterWorkspace_Features_MobileNotifications_Title": "Notificações push móveis", "RegisterWorkspace_Features_Marketplace_Title": "Marketplace", "RegisterWorkspace_Features_Omnichannel_Title": "Omnichannel", "RegisterWorkspace_Setup_Label": "E-mail da conta da nuvem", "cloud.RegisterWorkspace_Setup_Terms_Privacy": "Eu concordo com os <1>Termos e condições e a <3>Política de privacidade" -} +} \ No newline at end of file diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/pt.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/pt.i18n.json index 0d87a6512f51..e31b0d86bb0f 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/pt.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/pt.i18n.json @@ -1429,7 +1429,6 @@ "Full_Screen": "Tela cheia", "Gaming": "Jogos", "General": "Geral", - "Get_link": "Obter Ligação", "github_no_public_email": "Não possui um e-mail público na sua conta GitHub", "Give_a_unique_name_for_the_custom_oauth": "Dê um nome exclusivo para o oauth customizado", "strike": "tachado", @@ -2134,6 +2133,8 @@ "Old Colors": "Cores antigas", "Old Colors (minor)": "Cores antigas (menores)", "Older_than": "Mais velho que", + "Omnichannel_Reports_Status_Open": "Aberto", + "Omnichannel_Reports_Status_Closed": "Encerrado", "On": "Ligar", "online": "ligado", "Online": "Ligado", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ro.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ro.i18n.json index d7a84c0d5367..9f1326ebca11 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ro.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ro.i18n.json @@ -1830,6 +1830,8 @@ "Offline_success_message": "Mesajul de succes offline", "Offline_unavailable": "offline nu sunt disponibile", "Older_than": "Mai vechi de", + "Omnichannel_Reports_Status_Open": "Deschis", + "Omnichannel_Reports_Status_Closed": "Închis", "On": "Pe", "online": "pe net", "Online": "Activ", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ru.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ru.i18n.json index bf4713cf7bb5..8f71b6f49ab2 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ru.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ru.i18n.json @@ -2147,7 +2147,6 @@ "Generate_new_key": "Сгенерировать новый ключ", "Generate_New_Link": "Сгенерировать новую ссылку", "Generating_key": "Генерация ключа", - "Get_link": "Получить ссылку", "get-password-policy-forbidRepeatingCharacters": "Пароль не может содержать повторяющихся символов подряд", "get-password-policy-forbidRepeatingCharactersCount": "Пароль не должен содержать более {{forbidRepeatingCharactersCount}} повторяющихся символов в пароле", "get-password-policy-maxLength": "Пароль должен быть максимум {{maxLength}} символов длиной", @@ -3324,6 +3323,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "Ключ шифрования (JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "Если это предусмотрено, то токен пользователя будет зашифрован с помощью предоставленного ключа, и внешняя система должна будет расшифровать данные, чтобы получить доступ к токену", "Omnichannel_External_Frame_URL": "URL-адрес внешнего фрейма", + "Omnichannel_Reports_Status_Open": "Открыть", + "Omnichannel_Reports_Status_Closed": "Закрыто", "On": "Включено", "On_Hold": "На удержании", "On_Hold_Chats": "На удержании", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/sk-SK.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/sk-SK.i18n.json index 881d6dfc7016..dd4830288374 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/sk-SK.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/sk-SK.i18n.json @@ -1840,6 +1840,8 @@ "Offline_success_message": "Správa o úspechu offline", "Offline_unavailable": "Offline nie je k dispozícii", "Older_than": "Starší než", + "Omnichannel_Reports_Status_Open": "OTVORENÉ", + "Omnichannel_Reports_Status_Closed": "ZATVORENÉ", "On": "na", "online": "on-line", "Online": "online", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/sl-SI.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/sl-SI.i18n.json index 4655855136ae..fb52e11295fe 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/sl-SI.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/sl-SI.i18n.json @@ -1820,6 +1820,8 @@ "Offline_success_message": "Sporočilo o uspehu ob nedosegljivosti", "Offline_unavailable": "Nedosegljivo stanje ni na voljo", "Older_than": "Starejša od", + "Omnichannel_Reports_Status_Open": "Odpri", + "Omnichannel_Reports_Status_Closed": "Zaprto", "On": "Vklop", "online": "na spletu", "Online": "Dosegljiv", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/sq.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/sq.i18n.json index 9e95d7d2e600..fdb85c4fe51b 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/sq.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/sq.i18n.json @@ -1830,6 +1830,8 @@ "Offline_success_message": "Mesazhi Offline sukses", "Offline_unavailable": "Offline padisponueshëm", "Older_than": "Më të vjetër se", + "Omnichannel_Reports_Status_Open": "hapur", + "Omnichannel_Reports_Status_Closed": "Mbyllur", "On": "në", "online": "Online", "Online": "Në linjë", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/sr.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/sr.i18n.json index e86375f295fd..73a4e9f57c4e 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/sr.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/sr.i18n.json @@ -1669,6 +1669,8 @@ "Offline_success_message": "Оффлине успех порука", "Offline_unavailable": "оффлине недоступан", "Older_than": "Старији од", + "Omnichannel_Reports_Status_Open": "Отвори", + "Omnichannel_Reports_Status_Closed": "Затворено", "On": "на", "online": "на мрежи", "Online": "На мрежи", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/sv.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/sv.i18n.json index e111ab9c3e42..35792cce086a 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/sv.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/sv.i18n.json @@ -2292,7 +2292,6 @@ "Generate_new_key": "Generera en ny nyckel", "Generate_New_Link": "Generera en ny länk", "Generating_key": "Genererar nyckel", - "Get_link": "Kopiera länk", "get-password-policy-forbidRepeatingCharacters": "Lösenordet får inte innehålla samma tecken fler än en gång", "get-password-policy-forbidRepeatingCharactersCount": "Lösenordet får inte innehålla fler än {{forbidRepeatingCharactersCount}} upprepade tecken", "get-password-policy-maxLength": "Lösenordet får bestå av högst {{maxLength}} tecken", @@ -2579,7 +2578,6 @@ "Invalid_setting_s": "Ogiltig inställning: %s", "Invalid_two_factor_code": "Ogiltig tvåfaktorkod", "Invalid_username": "Inloggningsnamnet är ogiltigt", - "Invalid_JSON": "Ogiltig JSON", "invisible": "osynlig", "Invisible": "Osynlig", "Invitation": "Inbjudan", @@ -3270,7 +3268,6 @@ "Message_has_been_edited_by": "Meddelandet har redigerats av {{username}}", "Message_has_been_edited_by_at": "Meddelandet redigerades av {{username}} den {{date}}", "Message_has_been_pinned": "Meddelandet har fästs", - "Message_has_been_shared": "Meddelandet har delats", "Message_has_been_starred": "Meddelandet har stjärnmarkerats", "Message_has_been_unpinned": "Meddelandet har lossats", "Message_has_been_unstarred": "Meddelandets stjärnmarkeringar har tagits bort", @@ -3625,6 +3622,8 @@ "omnichannel_sla_change_history": "SLA-policyn har ändrats: {{user}} har ändrat SLA-policy till {{sla}}", "Omnichannel_enable_department_removal": "Aktivera borttagning av avdelningar", "Omnichannel_enable_department_removal_alert": "Avdelningar som tagits bort kan inte återställas, vi rekommenderar att du istället arkiverar avdelningen.", + "Omnichannel_Reports_Status_Open": "Öppna", + "Omnichannel_Reports_Status_Closed": "Stängd", "On": "På", "on-hold-livechat-room": "Parkera Omnichannel-rum", "on-hold-livechat-room_description": "Behörighet att parkera Omnichannel-rum", @@ -4335,7 +4334,6 @@ "Select_an_option": "Välj ett alternativ", "Select_at_least_one_user": "Välj åtminstone en användare", "Select_at_least_two_users": "Välj åtminstone två användare", - "Share_Message": "Dela meddelande", "Select_department": "Välj en avdelning", "Select_file": "Välj fil", "Select_role": "Välj en roll", @@ -4343,7 +4341,6 @@ "Select_tag": "Välj en tagg", "Select_the_channels_you_want_the_user_to_be_removed_from": "Välj de kanaler du vill ta bort användaren från", "Select_the_teams_channels_you_would_like_to_delete": "Välj de teamkanaler du vill ta bort. De du inte väljer flyttas till arbetsytan.", - "Select_atleast_one_channel_to_share_the_messsage": "Välj minst en kanal för att dela meddelandet", "Select_user": "Välj användare", "Select_users": "Välj användare", "Selected_agents": "Utvalda agenter", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ta-IN.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ta-IN.i18n.json index 87ea611e9dc8..b1d003f0f85c 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ta-IN.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ta-IN.i18n.json @@ -1831,6 +1831,8 @@ "Offline_success_message": "ஆஃப்லைன் வெற்றி செய்தியை", "Offline_unavailable": "ஆஃப்லைனில் கிடையாது", "Older_than": "விட பழைய", + "Omnichannel_Reports_Status_Open": "திறந்த", + "Omnichannel_Reports_Status_Closed": "மூடப்பட்ட", "On": "மீது", "online": "ஆன்லைன்", "Online": "ஆன்லைன்", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/th-TH.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/th-TH.i18n.json index a57b7da81f20..21b9d0e62439 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/th-TH.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/th-TH.i18n.json @@ -1824,6 +1824,8 @@ "Offline_success_message": "ข้อความความสำเร็จออฟไลน์", "Offline_unavailable": "ไม่มีออฟไลน์", "Older_than": "เก่ากว่า", + "Omnichannel_Reports_Status_Open": "เปิด", + "Omnichannel_Reports_Status_Closed": "ปิด", "On": "บน", "online": "ออนไลน์", "Online": "ออนไลน์", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/tr.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/tr.i18n.json index 24b5ef7f7b00..77bad5262630 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/tr.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/tr.i18n.json @@ -1451,7 +1451,6 @@ "Gaming": "Oyun", "General": "Genel", "Generate_New_Link": "Yeni Bağlantı Oluştur", - "Get_link": "Bağlantıyı Al", "github_no_public_email": "Sen GitHub hesabınızda kamu e-posta olarak herhangi bir e-posta yok", "Give_a_unique_name_for_the_custom_oauth": "Özel OAuth için benzersiz bir ad verin", "strike": "üstü çizili", @@ -2191,6 +2190,8 @@ "Old Colors (minor)": "Eski Renkler (küçük)", "Older_than": "Daha eski", "Omnichannel": "Çoklu Kanal", + "Omnichannel_Reports_Status_Open": "Aç", + "Omnichannel_Reports_Status_Closed": "Kapalı", "On": "Açık", "online": "çevrimiçi", "Online": "Çevrimiçi", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/ug.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/ug.i18n.json index 4c8759aad52c..e8838c82a80e 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/ug.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/ug.i18n.json @@ -770,6 +770,8 @@ "Offline_message": "تورسىز ئۇچۇر", "Offline_success_message": "ئۇتۇقلۇق تورسىز بولغان ئۇچۇر", "Offline_unavailable": "تورسىز ئىشلەتكىلى بولمايدۇ", + "Omnichannel_Reports_Status_Open": "ئېچىل", + "Omnichannel_Reports_Status_Closed": "ئاخىرلاشتى", "Online": "توردا", "Only_you_can_see_this_message": "پەقەت سىزلا بۇ ئۇچۇرنى كۆرەلەيسىز", "Oops!": "ئاپلا", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/uk.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/uk.i18n.json index 220552fce279..43f5ecab66a4 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/uk.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/uk.i18n.json @@ -1589,7 +1589,6 @@ "Gaming": "Ігри", "General": "Загальні", "Generate_New_Link": "Створити нове посилання", - "Get_link": "Отримати посилання", "github_no_public_email": "У Вашому обліковому записі GitHub, відсутній публічний e-mail", "Give_a_unique_name_for_the_custom_oauth": "Дайте унікальне ім'я для призначеного користувача OAuth", "strike": "страйк", @@ -2349,6 +2348,8 @@ "Offline_success_message": "Немає повідомлення про успішне виконання", "Offline_unavailable": "Offline недоступний", "Older_than": "Старше", + "Omnichannel_Reports_Status_Open": "відкритий", + "Omnichannel_Reports_Status_Closed": "Закрито", "On": "на", "online": "онлайн", "Online": "Онлайн", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/vi-VN.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/vi-VN.i18n.json index 9f4e82a71173..044baaa73720 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/vi-VN.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/vi-VN.i18n.json @@ -1931,6 +1931,8 @@ "Offline_success_message": "Tin nhắn ngoại tuyến thành công", "Offline_unavailable": "Không khả dụng ngoại tuyến", "Older_than": "Lớn tuổi hơn", + "Omnichannel_Reports_Status_Open": "Mở", + "Omnichannel_Reports_Status_Closed": "Đóng", "On": "Trên", "online": "Trực tuyến", "Online": "Trực tuyến", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/zh-HK.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/zh-HK.i18n.json index d2295fedf80d..18c3d1f9548e 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/zh-HK.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/zh-HK.i18n.json @@ -1855,6 +1855,8 @@ "Offline_success_message": "离线成功消息", "Offline_unavailable": "离线不可用", "Older_than": "年长过", + "Omnichannel_Reports_Status_Open": "开放", + "Omnichannel_Reports_Status_Closed": "关闭", "On": "上", "online": "在线", "Online": "在线", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/zh-TW.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/zh-TW.i18n.json index fef07d94e499..5ad5c0eb1d2b 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/zh-TW.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/zh-TW.i18n.json @@ -1971,7 +1971,6 @@ "Generate_new_key": "產生新的金鑰", "Generate_New_Link": "產生新的連接", "Generating_key": "產生金鑰中", - "Get_link": "取得連結", "get-password-policy-forbidRepeatingCharacters": "密碼不應包含重複字元", "get-password-policy-forbidRepeatingCharactersCount": "密碼中不得包含 {{forbidRepeatingCharactersCount}} 個重複字元", "get-password-policy-maxLength": "密碼長度不得超過 {{maxLength}} 個字元", @@ -3088,6 +3087,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "加密金鑰(JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "如果提供,它將使用提供的金鑰加密使用者的token,並且外部系統將需要解密資料以存取token", "Omnichannel_External_Frame_URL": "外部框架網址", + "Omnichannel_Reports_Status_Open": "打開", + "Omnichannel_Reports_Status_Closed": "已關閉", "On": "在", "On_Hold": "保留", "On_Hold_conversations": "保持對話", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/zh.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/zh.i18n.json index 8b08aa0c1489..df4642f4b0df 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/zh.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/zh.i18n.json @@ -1795,7 +1795,6 @@ "Generate_new_key": "生成新钥", "Generate_New_Link": "产生新链接", "Generating_key": "生成钥", - "Get_link": "获取链接", "get-password-policy-forbidRepeatingCharacters": "密码不应包含重复的字符", "get-password-policy-forbidRepeatingCharactersCount": "密码不应包含多于 {{forbidRepeatingCharactersCount}} 个重复的字符", "get-password-policy-maxLength": "密码长度最大不应超过 {{maxLength}} ", @@ -2779,6 +2778,8 @@ "Omnichannel_External_Frame_Encryption_JWK": "加密密钥(JWK)", "Omnichannel_External_Frame_Encryption_JWK_Description": "如提供则会使用提供的密钥加密用户的令牌,外部系统需要对数据进行解密才能使用令牌", "Omnichannel_External_Frame_URL": "外部框架 URL", + "Omnichannel_Reports_Status_Open": "打开", + "Omnichannel_Reports_Status_Closed": "已关闭", "On": "打开", "online": "在线", "Online": "在线", From 212ad923ffe1cff57343e1f039c78d89b3d22483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?= <60678893+juliajforesti@users.noreply.github.com> Date: Tue, 5 Sep 2023 16:52:48 -0300 Subject: [PATCH 09/66] regression: Thread badge click-animation (#30275) --- apps/meteor/tests/e2e/administration.spec.ts | 6 ++ .../fragments/admin-flextab-users.ts | 8 +- .../meteor/tests/e2e/user-invitations.spec.ts | 24 ------ .../HeaderToolboxActionBadge.tsx | 2 + yarn.lock | 86 +++++++++---------- 5 files changed, 55 insertions(+), 71 deletions(-) delete mode 100644 apps/meteor/tests/e2e/user-invitations.spec.ts diff --git a/apps/meteor/tests/e2e/administration.spec.ts b/apps/meteor/tests/e2e/administration.spec.ts index 91130728e20c..5a47a77bba99 100644 --- a/apps/meteor/tests/e2e/administration.spec.ts +++ b/apps/meteor/tests/e2e/administration.spec.ts @@ -47,6 +47,12 @@ test.describe.parallel('administration', () => { await expect(poAdmin.tabs.users.userRole).toBeVisible(); await poAdmin.tabs.users.btnSave.click(); }); + + test('expect SMTP setup warning and routing to email settings', async ({ page }) => { + await poAdmin.tabs.users.btnInvite.click(); + await poAdmin.tabs.users.setupSmtpLink.click(); + await expect(page).toHaveURL('/admin/settings/Email'); + }); }); test.describe('Rooms', () => { diff --git a/apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-users.ts b/apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-users.ts index f4b5104a9a84..bd46de6ea00f 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-users.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-users.ts @@ -15,6 +15,10 @@ export class AdminFlextabUsers { return this.page.locator('role=button[name="Save"]'); } + get btnInvite(): Locator { + return this.page.locator('role=button[name="Invite"]'); + } + get inputName(): Locator { return this.page.locator('//label[text()="Name"]/following-sibling::span//input'); } @@ -44,10 +48,6 @@ export class AdminFlextabUsers { await this.page.locator(`li[value=${role}]`).click(); } - get inviteUsersTitle(): Locator { - return this.page.locator('aside >> text="Invite Members"'); - } - get setupSmtpLink(): Locator { return this.page.locator('role=link[name="Set up SMTP"]') } diff --git a/apps/meteor/tests/e2e/user-invitations.spec.ts b/apps/meteor/tests/e2e/user-invitations.spec.ts deleted file mode 100644 index 4bcdf82d6f43..000000000000 --- a/apps/meteor/tests/e2e/user-invitations.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Users } from './fixtures/userStates'; -import { Admin } from './page-objects'; -import { test, expect } from './utils/test'; - -test.use({ storageState: Users.admin.state }); - -test.describe.serial('user-invites', () => { - let poAdmin: Admin; - - test.beforeEach(async ({ page }) => { - poAdmin = new Admin(page); - await page.goto('/admin/users/invite'); - - await expect(poAdmin.tabs.users.inviteUsersTitle).toBeVisible(); - }); - - test('expect SMTP setup warning and routing to email settings', async ({ page }) => { - await expect(poAdmin.tabs.users.setupSmtpLink).toBeVisible(); - - await poAdmin.tabs.users.setupSmtpLink.click(); - - await expect(page).toHaveURL('/admin/settings/Email'); - }); -}); diff --git a/packages/ui-client/src/components/Header/HeaderToolbox/HeaderToolboxActionBadge.tsx b/packages/ui-client/src/components/Header/HeaderToolbox/HeaderToolboxActionBadge.tsx index c05cc3341816..d8da9762de9c 100644 --- a/packages/ui-client/src/components/Header/HeaderToolbox/HeaderToolboxActionBadge.tsx +++ b/packages/ui-client/src/components/Header/HeaderToolbox/HeaderToolboxActionBadge.tsx @@ -5,10 +5,12 @@ import type { ComponentProps, FC } from 'react'; const HeaderToolboxActionBadge: FC> = (props) => ( diff --git a/yarn.lock b/yarn.lock index d14adeed87af..68ef61bc51eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7917,16 +7917,16 @@ __metadata: languageName: node linkType: hard -"@rocket.chat/css-in-js@npm:~0.31.26-dev.18": - version: 0.31.26-dev.18 - resolution: "@rocket.chat/css-in-js@npm:0.31.26-dev.18" +"@rocket.chat/css-in-js@npm:~0.31.26-dev.20": + version: 0.31.26-dev.20 + resolution: "@rocket.chat/css-in-js@npm:0.31.26-dev.20" dependencies: "@emotion/hash": ^0.9.0 - "@rocket.chat/css-supports": ~0.31.26-dev.18 - "@rocket.chat/memo": ~0.31.26-dev.18 - "@rocket.chat/stylis-logical-props-middleware": ~0.31.26-dev.18 + "@rocket.chat/css-supports": ~0.31.26-dev.20 + "@rocket.chat/memo": ~0.31.26-dev.20 + "@rocket.chat/stylis-logical-props-middleware": ~0.31.26-dev.20 stylis: ~4.1.3 - checksum: 1b4190a2463a0fb9e60c588383951d10aa0d7b501855dd6340ffcc6f1af116c93b3370e9acf03724151a59a53c6f5a111678a3454b23e8fed04a1843ebb31331 + checksum: 0898cc5e6493c67db0623d73896f07e035639d1714942fb7cd28ccf2f050f5e0f6742d75e91ab746b8745524bac86e367e3bec08baf815515a0759673e4d270d languageName: node linkType: hard @@ -7943,12 +7943,12 @@ __metadata: languageName: node linkType: hard -"@rocket.chat/css-supports@npm:~0.31.26-dev.18": - version: 0.31.26-dev.18 - resolution: "@rocket.chat/css-supports@npm:0.31.26-dev.18" +"@rocket.chat/css-supports@npm:~0.31.26-dev.20": + version: 0.31.26-dev.20 + resolution: "@rocket.chat/css-supports@npm:0.31.26-dev.20" dependencies: - "@rocket.chat/memo": ~0.31.26-dev.18 - checksum: 08fe45007b8edaa7a0baedfec0434dab51aa240e20c01f6762906b0841d7871aa5b9a1d91abb0dd0fcf7779b93067d6e6a67f31a59759bf178067c1d660670a2 + "@rocket.chat/memo": ~0.31.26-dev.20 + checksum: 6e123c782288e3dbf18e7c54aabac254d8d041d1592dc08e758519ae1bf54ed33f92ce9b08a47e31b0d5315df7a260cba78fca02ed6c3fd0992405559821bc6a languageName: node linkType: hard @@ -8173,10 +8173,10 @@ __metadata: languageName: node linkType: hard -"@rocket.chat/fuselage-tokens@npm:~0.32.0-dev.378": - version: 0.32.0-dev.378 - resolution: "@rocket.chat/fuselage-tokens@npm:0.32.0-dev.378" - checksum: 2db23b7c013c3a1c290f0a663305dd9d3db4a8bd49b22fde8d17abf411c673f22147599d427595731380021649e125d410dc15e9b6e384530238688240630a64 +"@rocket.chat/fuselage-tokens@npm:~0.32.0-dev.380": + version: 0.32.0-dev.380 + resolution: "@rocket.chat/fuselage-tokens@npm:0.32.0-dev.380" + checksum: b1300376eafba878a07e7c3ae2d434f38b7388bc5fe2d1fa3d87d3e9513f426b1734ec0d4aaa05cfa70c01a1d6ca3bb06119145f812a00b64d1da9ca5bf17845 languageName: node linkType: hard @@ -8236,14 +8236,14 @@ __metadata: linkType: soft "@rocket.chat/fuselage@npm:next": - version: 0.32.0-dev.428 - resolution: "@rocket.chat/fuselage@npm:0.32.0-dev.428" - dependencies: - "@rocket.chat/css-in-js": ~0.31.26-dev.18 - "@rocket.chat/css-supports": ~0.31.26-dev.18 - "@rocket.chat/fuselage-tokens": ~0.32.0-dev.378 - "@rocket.chat/memo": ~0.31.26-dev.18 - "@rocket.chat/styled": ~0.31.26-dev.18 + version: 0.32.0-dev.430 + resolution: "@rocket.chat/fuselage@npm:0.32.0-dev.430" + dependencies: + "@rocket.chat/css-in-js": ~0.31.26-dev.20 + "@rocket.chat/css-supports": ~0.31.26-dev.20 + "@rocket.chat/fuselage-tokens": ~0.32.0-dev.380 + "@rocket.chat/memo": ~0.31.26-dev.20 + "@rocket.chat/styled": ~0.31.26-dev.20 invariant: ^2.2.4 react-aria: ~3.23.1 react-keyed-flatten-children: ^1.3.0 @@ -8255,7 +8255,7 @@ __metadata: react: ^17.0.2 react-dom: ^17.0.2 react-virtuoso: 1.2.4 - checksum: 7f39b64138d77fb9956f821f0a3c638fee38d1f66f1cf243983eed7683ca442096b76ec09bf282fe6f9caf4c6fbab0b38b3fe6310f0fcbc9afd1f09d39f95cf3 + checksum: 5b09c6d0fac32e7b353891c898e1e3ba929af9b8fd9b2d41de9d0e1e1d17cc04101b713934dd59a58a09a301673a1299a688d017e9c86db28a65aeb6d1b1e32e languageName: node linkType: hard @@ -8513,10 +8513,10 @@ __metadata: languageName: node linkType: hard -"@rocket.chat/memo@npm:~0.31.26-dev.18": - version: 0.31.26-dev.18 - resolution: "@rocket.chat/memo@npm:0.31.26-dev.18" - checksum: c3006dc08e1f3e5e1ac95cc23f52a4d5445971c5dbb985023128a7e4f8e929913a5103d4c4b7fdbd2848b1982a32440dc64f3894caaa293c774232160fbe4b71 +"@rocket.chat/memo@npm:~0.31.26-dev.20": + version: 0.31.26-dev.20 + resolution: "@rocket.chat/memo@npm:0.31.26-dev.20" + checksum: 72db6d791028eaff24533c29f633f5abcaa33b78d335c3a04af6baef4b102c912b7176a43ab8a8886c2b49513a892d7da0c4b28620dfd43e867c0c5e06730897 languageName: node linkType: hard @@ -9358,15 +9358,6 @@ __metadata: languageName: node linkType: hard -"@rocket.chat/styled@npm:~0.31.26-dev.18": - version: 0.31.26-dev.18 - resolution: "@rocket.chat/styled@npm:0.31.26-dev.18" - dependencies: - "@rocket.chat/css-in-js": ~0.31.26-dev.18 - checksum: 54ede68d3ab24aa0a685bc55148e52a7e17e394d5f16f7114df64633733ca3c9fd39ba30036065ca16636cff6ef9c045a2a82024c0597d9864e77d49e1e56636 - languageName: node - linkType: hard - "@rocket.chat/styled@npm:~0.31.26-dev.2": version: 0.31.26-dev.7 resolution: "@rocket.chat/styled@npm:0.31.26-dev.7" @@ -9376,14 +9367,23 @@ __metadata: languageName: node linkType: hard -"@rocket.chat/stylis-logical-props-middleware@npm:~0.31.26-dev.18": - version: 0.31.26-dev.18 - resolution: "@rocket.chat/stylis-logical-props-middleware@npm:0.31.26-dev.18" +"@rocket.chat/styled@npm:~0.31.26-dev.20": + version: 0.31.26-dev.20 + resolution: "@rocket.chat/styled@npm:0.31.26-dev.20" + dependencies: + "@rocket.chat/css-in-js": ~0.31.26-dev.20 + checksum: 6e068f46b81681ecca4c0d4ca9f1d207948d1f50cc49edc059573d66093aa1bab303d720d04dc59f48fa6044ed4bf71e336b0ef261d84b84e28b85f4596a3508 + languageName: node + linkType: hard + +"@rocket.chat/stylis-logical-props-middleware@npm:~0.31.26-dev.20": + version: 0.31.26-dev.20 + resolution: "@rocket.chat/stylis-logical-props-middleware@npm:0.31.26-dev.20" dependencies: - "@rocket.chat/css-supports": ~0.31.26-dev.18 + "@rocket.chat/css-supports": ~0.31.26-dev.20 peerDependencies: stylis: 4.0.10 - checksum: 5dd4b4d242d568549c6f2dfd8c0ef85d605176b05214d85f3bbd48f648836a287a404d8e44647e383400232f599e80ba34da377af9d960f452f8716489f862f6 + checksum: 917b96f677478bf9b6e0b553b59019f28bdbedcb18e5e61fffc73631c003ecadc4ac81c370d4205c6553638e88f6dfff49f70e6bf3e192283e8b5e10e912b54c languageName: node linkType: hard From db919f9b23b81c13b653303faab5500cc8a2564e Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 5 Sep 2023 20:13:30 +0000 Subject: [PATCH 10/66] 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 11/66] 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 f800e43110c9746df86c3feaddd07980bc0e29e9 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 5 Sep 2023 23:49:41 -0300 Subject: [PATCH 12/66] test: enable http cache for tests (#30278) --- .github/workflows/ci-test-e2e.yml | 5 +- apps/meteor/package.json | 1 + apps/meteor/playwright.config.ts | 3 + apps/meteor/playwright.prepare.mjs | 9 ++ .../tests/e2e/channel-management.spec.ts | 20 ++--- apps/meteor/tests/e2e/homepage.spec.ts | 82 ++++++++++--------- .../omnichannel/omnichannel-livechat.spec.ts | 1 + .../omnichannel-priorities-sidebar.spec.ts | 1 + .../page-objects/fragments/home-sidenav.ts | 3 + .../tests/e2e/page-objects/home-channel.ts | 9 ++ .../e2e/page-objects/omnichannel-livechat.ts | 2 +- 11 files changed, 84 insertions(+), 52 deletions(-) create mode 100644 apps/meteor/playwright.prepare.mjs diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index e22b293d444b..9a05543605db 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -209,8 +209,11 @@ jobs: REPORTER_ROCKETCHAT_DRAFT: ${{ github.event.pull_request.draft }} QASE_API_TOKEN: ${{ secrets.QASE_API_TOKEN }} QASE_REPORT: ${{ github.ref == 'refs/heads/develop' && 'true' || '' }} + CI: true working-directory: ./apps/meteor - run: yarn test:e2e --shard=${{ matrix.shard }}/${{ inputs.total-shard }} + run: | + yarn prepare + yarn test:e2e --shard=${{ matrix.shard }}/${{ inputs.total-shard }} - name: Store playwright test trace if: inputs.type == 'ui' && always() diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 427ad86ddca3..c2e17b3e82c3 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -50,6 +50,7 @@ "set-version": "node .scripts/set-version.js", "release": "meteor npm run set-version --silent", "storybook": "cross-env NODE_OPTIONS=--max-old-space-size=8192 start-storybook -p 6006 --no-version-updates", + "prepare": "node playwright.prepare.mjs", "docker:start": "docker-compose up" }, "license": "MIT", diff --git a/apps/meteor/playwright.config.ts b/apps/meteor/playwright.config.ts index d94efbf60399..329d4daa1947 100644 --- a/apps/meteor/playwright.config.ts +++ b/apps/meteor/playwright.config.ts @@ -5,6 +5,7 @@ import * as constants from './tests/e2e/config/constants'; export default { globalSetup: require.resolve('./tests/e2e/config/global-setup.ts'), use: { + channel: 'chromium', headless: true, ignoreHTTPSErrors: true, trace: 'retain-on-failure', @@ -51,4 +52,6 @@ export default { timeout: 60 * 1000, globalTimeout: (process.env.IS_EE === 'true' ? 50 : 40) * 60 * 1000, maxFailures: process.env.CI ? 5 : undefined, + // Retry on CI only. + retries: process.env.CI ? 2 : 0, } as PlaywrightTestConfig; diff --git a/apps/meteor/playwright.prepare.mjs b/apps/meteor/playwright.prepare.mjs new file mode 100644 index 000000000000..5f3a20f21623 --- /dev/null +++ b/apps/meteor/playwright.prepare.mjs @@ -0,0 +1,9 @@ +// prepare.js + +import { readFileSync, writeFileSync } from 'fs'; +import path from 'path'; + +const modules = path.resolve(`node_modules`); +const destination = path.join(modules, 'playwright-core', 'lib', 'server', 'chromium', 'crNetworkManager.js'); +const buffer = readFileSync(destination); +writeFileSync(destination, buffer.toString().replace('cacheDisabled: true', 'cacheDisabled: false')); diff --git a/apps/meteor/tests/e2e/channel-management.spec.ts b/apps/meteor/tests/e2e/channel-management.spec.ts index 7c1533282519..7cad1be43cbf 100644 --- a/apps/meteor/tests/e2e/channel-management.spec.ts +++ b/apps/meteor/tests/e2e/channel-management.spec.ts @@ -11,13 +11,9 @@ test.use({ storageState: Users.admin.state }); test.describe.serial('channel-management', () => { let poHomeChannel: HomeChannel; let targetChannel: string; - let regularUserPage: Page; - test.beforeAll(async ({ api, browser }) => { + test.beforeAll(async ({ api }) => { targetChannel = await createTargetChannel(api); - regularUserPage = await browser.newPage({ storageState: Users.user2.state }); - await regularUserPage.goto('/home'); - await regularUserPage.waitForSelector('[data-qa-id="home-header"]'); }); test.beforeEach(async ({ page }) => { @@ -26,10 +22,6 @@ test.describe.serial('channel-management', () => { await page.goto('/home'); }); - test.afterAll(async () => { - await regularUserPage.close(); - }); - test('expect add "user1" to "targetChannel"', async () => { await poHomeChannel.sidenav.openChat(targetChannel); await poHomeChannel.tabs.btnTabMembers.click(); @@ -113,7 +105,8 @@ test.describe.serial('channel-management', () => { await expect(poHomeChannel.toastSuccess).toBeVisible(); }); - test('expect "readOnlyChannel" to show join button', async () => { + let regularUserPage: Page; + test('expect "readOnlyChannel" to show join button', async ({ browser }) => { const channelName = faker.string.uuid(); await poHomeChannel.sidenav.openNewByLabel('Channel'); @@ -122,8 +115,15 @@ test.describe.serial('channel-management', () => { await poHomeChannel.sidenav.checkboxReadOnly.click(); await poHomeChannel.sidenav.btnCreate.click(); + regularUserPage = await browser.newPage({ storageState: Users.user2.state }); + + const channel = new HomeChannel(regularUserPage); + await regularUserPage.goto(`/channel/${channelName}`); + await channel.waitForChannel(); await expect(regularUserPage.locator('button >> text="Join"')).toBeVisible(); + + await regularUserPage.close(); }); test.skip('expect all notification preferences of "targetChannel" to be "Mentions"', async () => { diff --git a/apps/meteor/tests/e2e/homepage.spec.ts b/apps/meteor/tests/e2e/homepage.spec.ts index 465ecea03cbf..380fa54d2af3 100644 --- a/apps/meteor/tests/e2e/homepage.spec.ts +++ b/apps/meteor/tests/e2e/homepage.spec.ts @@ -26,16 +26,21 @@ test.describe.serial('homepage', () => { await adminPage.waitForSelector('[data-qa-id="home-header"]'); }); + test.afterAll(async ({ api }) => { + expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: false })).status()).toBe(200); + expect((await api.post('/settings/Layout_Custom_Body_Only', { value: false })).status()).toBe(200); + await adminPage.close(); + }); + test('layout', async () => { await test.step('expect show customize button', async () => { await expect(adminPage.locator('role=button[name="Customize"]')).toBeVisible(); }); - + await test.step('expect all cards to be visible', async () => { await Promise.all(Object.values(CardIds).map((id) => expect(adminPage.locator(`[data-qa-id="${id}"]`)).toBeVisible())); }); - }) - + }); test.describe('custom body with empty custom content', async () => { test.beforeAll(async ({ api }) => { @@ -48,17 +53,16 @@ test.describe.serial('homepage', () => { adminPage.locator('role=status[name="Admins may insert content html to be rendered in this white space."]'), ).toBeVisible(); }); - + await test.step('expect both change visibility and show only custom content buttons to be disabled', async () => { await expect(adminPage.locator('role=button[name="Show to workspace"]')).toBeDisabled(); await expect(adminPage.locator('role=button[name="Show only this content"]')).toBeDisabled(); }); - + await test.step('expect visibility tag to show "not visible"', async () => { await expect(adminPage.locator('role=status[name="Not visible to workspace"]')).toBeVisible(); }); - }) - + }); }); test.describe('custom body with custom content', () => { @@ -66,17 +70,16 @@ test.describe.serial('homepage', () => { await expect((await api.post('/settings/Layout_Home_Body', { value: 'Hello admin' })).status()).toBe(200); }); - test('layout', async() => { + test('layout', async () => { await test.step('expect custom body to be visible', async () => { await expect(adminPage.locator('role=status[name="Hello admin"]')).toBeVisible(); }); - + await test.step('expect correct state for card buttons', async () => { await expect(adminPage.locator('role=button[name="Show to workspace"]')).not.toBeDisabled(); await expect(adminPage.locator('role=button[name="Show only this content"]')).toBeDisabled(); }); - }) - + }); test.describe('enterprise edition', () => { test.skip(!IS_EE, 'Enterprise Only'); @@ -103,12 +106,6 @@ test.describe.serial('homepage', () => { }); }); }); - - test.afterAll(async ({ api }) => { - expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: false })).status()).toBe(200); - expect((await api.post('/settings/Layout_Custom_Body_Only', { value: false })).status()).toBe(200); - await adminPage.close(); - }); }); test.describe('for regular users', () => { @@ -121,23 +118,31 @@ test.describe.serial('homepage', () => { await regularUserPage.waitForSelector('[data-qa-id="home-header"]'); }); + test.afterAll(async () => { + await regularUserPage.close(); + }); + test('layout', async () => { await test.step('expect to not show customize button', async () => { await expect(regularUserPage.locator('role=button[name="Customize"]')).not.toBeVisible(); }); - + await test.step(`expect ${notVisibleCards.join(' and ')} cards to not be visible`, async () => { await Promise.all(notVisibleCards.map((id) => expect(regularUserPage.locator(`[data-qa-id="${id}"]`)).not.toBeVisible())); }); - + await test.step('expect all other cards to be visible', async () => { - await Promise.all(Object.values(CardIds).filter((id) => !notVisibleCards.includes(id)).map((id) => expect(regularUserPage.locator(`[data-qa-id="${id}"]`)).toBeVisible())); + await Promise.all( + Object.values(CardIds) + .filter((id) => !notVisibleCards.includes(id)) + .map((id) => expect(regularUserPage.locator(`[data-qa-id="${id}"]`)).toBeVisible()), + ); }); - + await test.step('expect welcome text to use Site_Name default setting', async () => { await expect(regularUserPage.locator('role=heading[name="Welcome to Rocket.Chat"]')).toBeVisible(); }); - + await test.step('expect header text to use Layout_Home_Title default setting', async () => { await expect(regularUserPage.locator('[data-qa-type="PageHeader-title"]')).toContainText('Home'); }); @@ -152,20 +157,19 @@ test.describe.serial('homepage', () => { await regularUserPage.waitForSelector('[data-qa-id="home-header"]'); }); + test.afterAll(async ({ api }) => { + expect((await api.post('/settings/Site_Name', { value: 'Rocket.Chat' })).status()).toBe(200); + expect((await api.post('/settings/Layout_Home_Title', { value: 'Home' })).status()).toBe(200); + }); + test('layout', async () => { await test.step('expect welcome text to be NewSiteName', async () => { await expect(regularUserPage.locator('role=heading[name="Welcome to NewSiteName"]')).toBeVisible(); }); - + await test.step('expect header text to be Layout_Home_Title setting', async () => { await expect(regularUserPage.locator('[data-qa-type="PageHeader-title"]')).toContainText('NewTitle'); }); - }) - - - test.afterAll(async ({ api }) => { - expect((await api.post('/settings/Site_Name', { value: 'Rocket.Chat' })).status()).toBe(200); - expect((await api.post('/settings/Layout_Home_Title', { value: 'Home' })).status()).toBe(200); }); }); @@ -178,6 +182,10 @@ test.describe.serial('homepage', () => { await regularUserPage.waitForSelector('[data-qa-id="home-header"]'); }); + test.afterAll(async ({ api }) => { + expect((await api.post('/settings/Layout_Home_Body', { value: '' })).status()).toBe(200); + expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: false })).status()).toBe(200); + }); test('expect custom body to be visible', async () => { await expect(regularUserPage.locator('role=status[name="Hello"]')).toBeVisible(); @@ -190,26 +198,20 @@ test.describe.serial('homepage', () => { expect((await api.post('/settings/Layout_Custom_Body_Only', { value: true })).status()).toBe(200); }); + test.afterAll(async ({ api }) => { + expect((await api.post('/settings/Layout_Custom_Body_Only', { value: false })).status()).toBe(200); + }); + test('layout', async () => { await test.step('expect default layout to not be visible', async () => { await expect(regularUserPage.locator('[data-qa-id="homepage-welcome-text"]')).not.toBeVisible(); }); - + await test.step('expect custom body to be visible', async () => { await expect(regularUserPage.locator('role=status[name="Hello"]')).toBeVisible(); }); - }) - - - test.afterAll(async ({ api }) => { - expect((await api.post('/settings/Layout_Custom_Body_Only', { value: false })).status()).toBe(200); }); }); - - test.afterAll(async ({ api }) => { - expect((await api.post('/settings/Layout_Home_Body', { value: '' })).status()).toBe(200); - expect((await api.post('/settings/Layout_Home_Custom_Block_Visible', { value: false })).status()).toBe(200); - }); }); }); }); diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat.spec.ts index c5250b1d1150..8d8bf3eed191 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat.spec.ts @@ -32,6 +32,7 @@ test.describe('Livechat', () => { test.afterAll(async ({ api }) => { await api.delete('/livechat/users/agent/user1'); await poAuxContext.page.close(); + await page.close(); }); test('Send message to online agent', async () => { diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-priorities-sidebar.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-priorities-sidebar.spec.ts index b521090e7097..559d24889633 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-priorities-sidebar.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-priorities-sidebar.spec.ts @@ -65,6 +65,7 @@ test.describe.serial('Omnichannel Priorities [Sidebar]', () => { await poLivechat.onlineAgentMessage.type('this_a_test_message_from_visitor'); await poLivechat.btnSendMessageToOnlineAgent.click(); await poHomeChannel.sidenav.getSidebarItemByName(NEW_USER.name).click(); + await poLivechat.page.close(); }); await test.step('Queue: Sidebar priority change', async () => { diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts index 5e5e3f93bfb6..4f3d7b4886eb 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts @@ -75,7 +75,10 @@ export class HomeSidenav { await this.page.locator('role=navigation >> role=button[name=Search]').click(); await this.page.locator('role=search >> role=searchbox').type(name); await this.page.locator(`role=search >> role=listbox >> role=link >> text="${name}"`).click(); + await this.waitForChannel(); + } + async waitForChannel(): Promise { await this.page.locator('role=main').waitFor(); await this.page.locator('role=main >> role=heading[level=1]').waitFor(); diff --git a/apps/meteor/tests/e2e/page-objects/home-channel.ts b/apps/meteor/tests/e2e/page-objects/home-channel.ts index 1d6e450d9764..d2f43c5cfec5 100644 --- a/apps/meteor/tests/e2e/page-objects/home-channel.ts +++ b/apps/meteor/tests/e2e/page-objects/home-channel.ts @@ -1,5 +1,6 @@ import type { Locator, Page } from '@playwright/test'; +import { expect } from '../utils/test'; import { HomeContent, HomeSidenav, HomeFlextab } from './fragments'; export class HomeChannel { @@ -25,4 +26,12 @@ export class HomeChannel { get btnContextualbarClose(): Locator { return this.page.locator('[data-qa="ContextualbarActionClose"]'); } + + async waitForChannel(): Promise { + await this.page.locator('role=main').waitFor(); + await this.page.locator('role=main >> role=heading[level=1]').waitFor(); + + await expect(this.page.locator('role=main >> .rcx-skeleton')).toHaveCount(0); + await expect(this.page.locator('role=main >> role=list')).not.toHaveAttribute('aria-busy', 'true'); + } } diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts index 754ab9c01d7a..b4a7c9b92345 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts @@ -1,7 +1,7 @@ import type { Page, Locator, APIResponse } from '@playwright/test'; export class OmnichannelLiveChat { - private readonly page: Page; + readonly page: Page; constructor(page: Page, private readonly api: { get(url: string): Promise }) { this.page = page; From 3dfede27033722775c7ee972304ab0630a3ccac1 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Tue, 5 Sep 2023 23:51:18 -0300 Subject: [PATCH 13/66] chore: Move a11y violation tests to Playwright (#30293) --- .../AccountFeaturePreviewPage.spec.tsx | 30 ---- .../OmnichannelPreferencesPage.spec.tsx | 19 --- .../views/admin/mailer/MailerPage.spec.tsx | 17 --- .../currentChats/CurrentChatsPage.spec.tsx | 17 --- apps/meteor/package.json | 3 +- apps/meteor/tests/e2e/account-profile.spec.ts | 132 ++++++++++++++++++ apps/meteor/tests/e2e/administration.spec.ts | 11 ++ .../omnichannel-current-chats.spec.ts | 15 ++ .../e2e/settings-account-profile.spec.ts | 101 -------------- apps/meteor/tests/e2e/utils/test.ts | 8 ++ yarn.lock | 85 ++++------- 11 files changed, 194 insertions(+), 244 deletions(-) delete mode 100644 apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.spec.tsx delete mode 100644 apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.spec.tsx delete mode 100644 apps/meteor/client/views/admin/mailer/MailerPage.spec.tsx delete mode 100644 apps/meteor/client/views/omnichannel/currentChats/CurrentChatsPage.spec.tsx create mode 100644 apps/meteor/tests/e2e/account-profile.spec.ts create mode 100644 apps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts delete mode 100644 apps/meteor/tests/e2e/settings-account-profile.spec.ts diff --git a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.spec.tsx b/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.spec.tsx deleted file mode 100644 index 157fa9b7acdf..000000000000 --- a/apps/meteor/client/views/account/featurePreview/AccountFeaturePreviewPage.spec.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { defaultFeaturesPreview } from '@rocket.chat/ui-client'; -import { render } from '@testing-library/react'; -import { axe, toHaveNoViolations } from 'jest-axe'; -import React from 'react'; - -import AccountFeaturePreviewPage from './AccountFeaturePreviewPage'; - -expect.extend(toHaveNoViolations); - -it('should have no a11y violations', async () => { - const { container } = render(, { - wrapper: mockAppRoot() - .withSetting('Accounts_AllowFeaturePreview', true) - .withUserPreference('featurePreview', defaultFeaturesPreview) - .withEndpoint('POST', '/v1/users.setPreferences', () => ({ - user: { - _id: 'userId', - settings: { - profile: {}, - preferences: {}, - }, - }, - })) - .build(), - }); - - const results = await axe(container); - expect(results).toHaveNoViolations(); -}); diff --git a/apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.spec.tsx b/apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.spec.tsx deleted file mode 100644 index 263d29c2ebdf..000000000000 --- a/apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.spec.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { render } from '@testing-library/react'; -import { axe, toHaveNoViolations } from 'jest-axe'; -import React from 'react'; - -import OmnichannelPreferencesPage from './OmnichannelPreferencesPage'; - -expect.extend(toHaveNoViolations); - -it('should have no a11y violations', async () => { - const { container } = render(, { - wrapper: mockAppRoot() - .withMethod('license:getModules', () => ['livechat-enterprise']) - .build(), - }); - - const results = await axe(container); - expect(results).toHaveNoViolations(); -}); diff --git a/apps/meteor/client/views/admin/mailer/MailerPage.spec.tsx b/apps/meteor/client/views/admin/mailer/MailerPage.spec.tsx deleted file mode 100644 index f5e23e35c3d2..000000000000 --- a/apps/meteor/client/views/admin/mailer/MailerPage.spec.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { render } from '@testing-library/react'; -import { axe, toHaveNoViolations } from 'jest-axe'; -import React from 'react'; - -import MailerPage from './MailerPage'; - -expect.extend(toHaveNoViolations); - -it('should have no a11y violations', async () => { - const { container } = render(, { - wrapper: mockAppRoot().build(), - }); - - const results = await axe(container); - expect(results).toHaveNoViolations(); -}); diff --git a/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsPage.spec.tsx b/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsPage.spec.tsx deleted file mode 100644 index b95af28fe6a6..000000000000 --- a/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsPage.spec.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { render } from '@testing-library/react'; -import { axe, toHaveNoViolations } from 'jest-axe'; -import React from 'react'; - -import CurrentChatsPage from './CurrentChatsPage'; - -expect.extend(toHaveNoViolations); - -it('should have no a11y violations', async () => { - const { container } = render( undefined} />, { - wrapper: mockAppRoot().build(), - }); - - const results = await axe(container); - expect(results).toHaveNoViolations(); -}); diff --git a/apps/meteor/package.json b/apps/meteor/package.json index c2e17b3e82c3..7b0ea3b73cc7 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -63,6 +63,7 @@ "email": "support@rocket.chat" }, "devDependencies": { + "@axe-core/playwright": "^4.7.3", "@babel/core": "~7.22.9", "@babel/eslint-parser": "~7.22.9", "@babel/plugin-proposal-nullish-coalescing-operator": "~7.18.6", @@ -115,7 +116,6 @@ "@types/he": "^1.1.2", "@types/i18next-sprintf-postprocessor": "^0.2.0", "@types/imap": "^0.8.37", - "@types/jest-axe": "^3.5.5", "@types/jsdom": "^16.2.15", "@types/jsdom-global": "^3.0.4", "@types/jsrsasign": "^10.5.8", @@ -183,7 +183,6 @@ "fast-glob": "^3.2.12", "i18next": "~23.4.5", "jest": "~29.6.1", - "jest-axe": "^8.0.0", "jsdom-global": "^3.0.2", "mocha": "^9.2.2", "nyc": "^15.1.0", diff --git a/apps/meteor/tests/e2e/account-profile.spec.ts b/apps/meteor/tests/e2e/account-profile.spec.ts new file mode 100644 index 000000000000..b850b7855c6f --- /dev/null +++ b/apps/meteor/tests/e2e/account-profile.spec.ts @@ -0,0 +1,132 @@ +import { faker } from '@faker-js/faker'; + +import { Users } from './fixtures/userStates'; +import { HomeChannel, AccountProfile } from './page-objects'; +import { test, expect } from './utils/test'; + +test.use({ storageState: Users.user3.state }); + +test.describe.serial('settings-account-profile', () => { + let poHomeChannel: HomeChannel; + let poAccountProfile: AccountProfile; + + const token = faker.string.alpha(10); + + test.beforeEach(async ({ page }) => { + poHomeChannel = new HomeChannel(page); + poAccountProfile = new AccountProfile(page); + }); + + // FIXME: solve test intermitencies + test.describe('Profile', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/account/profile'); + }) + + test.skip('expect update profile with new name/username', async () => { + const newName = faker.person.fullName(); + const newUsername = faker.internet.userName({ firstName: newName }); + + await poAccountProfile.inputName.fill(newName); + await poAccountProfile.inputUsername.fill(newUsername); + await poAccountProfile.btnSubmit.click(); + await poAccountProfile.btnClose.click(); + await poHomeChannel.sidenav.openChat('general'); + await poHomeChannel.content.sendMessage('any_message'); + + await expect(poHomeChannel.content.lastUserMessageNotSequential).toContainText(newUsername); + + await poHomeChannel.content.lastUserMessageNotSequential.locator('figure').click(); + await poHomeChannel.content.linkUserCard.click(); + + await expect(poHomeChannel.tabs.userInfoUsername).toHaveText(newUsername); + }) + + test('change avatar', async ({ page }) => { + await test.step('expect change avatar image by upload', async () => { + await poAccountProfile.inputImageFile.setInputFiles('./tests/e2e/fixtures/files/test-image.jpeg'); + + await poAccountProfile.btnSubmit.click(); + await expect(page.locator('.rcx-toastbar.rcx-toastbar--success').first()).toBeVisible(); + }); + + await test.step('expect to close toastbar', async () => { + await page.locator('.rcx-toastbar.rcx-toastbar--success').first().click(); + }); + + await test.step('expect set image from url', async () => { + await poAccountProfile.inputAvatarLink.fill('https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50'); + await poAccountProfile.btnSetAvatarLink.click(); + + await poAccountProfile.btnSubmit.click(); + await expect(page.locator('.rcx-toastbar.rcx-toastbar--success').first()).toBeVisible(); + }); + }); + }); + + test('Personal Access Tokens', async ({ page }) => { + const response = page.waitForResponse('**/api/v1/users.getPersonalAccessTokens'); + await page.goto('/account/tokens'); + await response; + + await test.step('expect show empty personal access tokens table', async () => { + await expect(poAccountProfile.tokensTableEmpty).toBeVisible(); + await expect(poAccountProfile.inputToken).toBeVisible(); + }); + + await test.step('expect show new personal token', async () => { + await poAccountProfile.inputToken.type(token); + await poAccountProfile.btnTokensAdd.click(); + await expect(poAccountProfile.tokenAddedModal).toBeVisible(); + await page.locator('role=button[name=Ok]').click(); + }); + + await test.step('expect not allow add new personal token with same name', async () => { + await poAccountProfile.inputToken.type(token); + await poAccountProfile.btnTokensAdd.click(); + await expect(page.locator('.rcx-toastbar.rcx-toastbar--error')).toBeVisible(); + }); + + await test.step('expect regenerate personal token', async () => { + await poAccountProfile.tokenInTable(token).locator('button >> nth=0').click(); + await poAccountProfile.btnRegenerateTokenModal.click(); + await expect(poAccountProfile.tokenAddedModal).toBeVisible(); + await page.locator('role=button[name=Ok]').click(); + }); + + await test.step('expect delete personal token', async () => { + await poAccountProfile.tokenInTable(token).locator('button >> nth=1').click(); + await poAccountProfile.btnRemoveTokenModal.click(); + await expect(page.locator('.rcx-toastbar.rcx-toastbar--success')).toBeVisible(); + }); + }); + + test.describe('Omnichannel', () => { + test('should not have any accessibility violations', async ({ page, makeAxeBuilder }) => { + await page.goto('/account/omnichannel'); + + const results = await makeAxeBuilder().analyze(); + expect(results.violations).toEqual([]); + }) + }) + + test.describe('Feature Preview', () => { + test('should not have any accessibility violations', async ({ page, makeAxeBuilder }) => { + await page.goto('/account/feature-preview'); + + const results = await makeAxeBuilder().analyze(); + expect(results.violations).toEqual([]); + }) + }) + + test.describe('Accessibility & Appearance', () => { + test('should not have any accessibility violations', async ({ page, makeAxeBuilder }) => { + await page.goto('/account/accessibility-and-appearance'); + + const results = await makeAxeBuilder().analyze(); + expect(results.violations).toEqual([]); + }) + }) +}); + + diff --git a/apps/meteor/tests/e2e/administration.spec.ts b/apps/meteor/tests/e2e/administration.spec.ts index 5a47a77bba99..b439258429f8 100644 --- a/apps/meteor/tests/e2e/administration.spec.ts +++ b/apps/meteor/tests/e2e/administration.spec.ts @@ -78,6 +78,17 @@ test.describe.parallel('administration', () => { }); }); + test.describe('Mailer', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/admin/mailer'); + }) + + test('should not have any accessibility violations', async ({ makeAxeBuilder }) => { + const results = await makeAxeBuilder().analyze(); + expect(results.violations).toEqual([]); + }) + }) + test.describe('Settings', () => { test.describe('General', () => { test.beforeEach(async ({ page }) => { diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts new file mode 100644 index 000000000000..8138ab839b75 --- /dev/null +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-current-chats.spec.ts @@ -0,0 +1,15 @@ +import { Users } from '../fixtures/userStates'; +import { test, expect } from '../utils/test'; + +test.use({ storageState: Users.admin.state }); + +test.describe.parallel('Omnichannel current chats', () => { + test.beforeEach(async ({ page }) =>{ + await page.goto('/omnichannel/current') + }) + + test.skip('should not have any accessibility violations', async ({ makeAxeBuilder }) => { + const results = await makeAxeBuilder().analyze(); + expect(results.violations).toEqual([]); + }) +}) diff --git a/apps/meteor/tests/e2e/settings-account-profile.spec.ts b/apps/meteor/tests/e2e/settings-account-profile.spec.ts deleted file mode 100644 index 7d33d71cfae6..000000000000 --- a/apps/meteor/tests/e2e/settings-account-profile.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { faker } from '@faker-js/faker'; - -import { Users } from './fixtures/userStates'; -import { HomeChannel, AccountProfile } from './page-objects'; -import { test, expect } from './utils/test'; - -test.use({ storageState: Users.user3.state }); - -test.describe.serial('settings-account-profile', () => { - let poHomeChannel: HomeChannel; - let poAccountProfile: AccountProfile; - - const token = faker.string.alpha(10); - - test.beforeEach(async ({ page }) => { - poHomeChannel = new HomeChannel(page); - poAccountProfile = new AccountProfile(page); - - await page.goto('/account/profile'); - }); - - // FIXME: solve test intermitencies - test.skip('expect update profile with new name/username', async () => { - const newName = faker.person.fullName(); - const newUsername = faker.internet.userName(newName); - - await poAccountProfile.inputName.fill(newName); - await poAccountProfile.inputUsername.fill(newUsername); - await poAccountProfile.btnSubmit.click(); - await poAccountProfile.btnClose.click(); - await poHomeChannel.sidenav.openChat('general'); - await poHomeChannel.content.sendMessage('any_message'); - - await expect(poHomeChannel.content.lastUserMessageNotSequential).toContainText(newUsername); - - await poHomeChannel.content.lastUserMessageNotSequential.locator('figure').click(); - await poHomeChannel.content.linkUserCard.click(); - - await expect(poHomeChannel.tabs.userInfoUsername).toHaveText(newUsername); - }); - - test('Personal Access Tokens', async ({ page }) => { - const response = page.waitForResponse('**/api/v1/users.getPersonalAccessTokens'); - await page.goto('/account/tokens'); - await response; - - await test.step('expect show empty personal access tokens table', async () => { - await expect(poAccountProfile.tokensTableEmpty).toBeVisible(); - await expect(poAccountProfile.inputToken).toBeVisible(); - }); - - await test.step('expect show new personal token', async () => { - await poAccountProfile.inputToken.type(token); - await poAccountProfile.btnTokensAdd.click(); - await expect(poAccountProfile.tokenAddedModal).toBeVisible(); - await page.locator('role=button[name=Ok]').click(); - }); - - await test.step('expect not allow add new personal token with same name', async () => { - await poAccountProfile.inputToken.type(token); - await poAccountProfile.btnTokensAdd.click(); - await expect(page.locator('.rcx-toastbar.rcx-toastbar--error')).toBeVisible(); - }); - - await test.step('expect regenerate personal token', async () => { - await poAccountProfile.tokenInTable(token).locator('button >> nth=0').click(); - await poAccountProfile.btnRegenerateTokenModal.click(); - await expect(poAccountProfile.tokenAddedModal).toBeVisible(); - await page.locator('role=button[name=Ok]').click(); - }); - - await test.step('expect delete personal token', async () => { - await poAccountProfile.tokenInTable(token).locator('button >> nth=1').click(); - await poAccountProfile.btnRemoveTokenModal.click(); - await expect(page.locator('.rcx-toastbar.rcx-toastbar--success')).toBeVisible(); - }); - }); - - test('change avatar', async ({ page }) => { - await page.goto('/account/profile'); - - await test.step('expect change avatar image by upload', async () => { - await poAccountProfile.inputImageFile.setInputFiles('./tests/e2e/fixtures/files/test-image.jpeg'); - - await poAccountProfile.btnSubmit.click(); - await expect(page.locator('.rcx-toastbar.rcx-toastbar--success').first()).toBeVisible(); - }); - - await test.step('expect to close toastbar', async () => { - await page.locator('.rcx-toastbar.rcx-toastbar--success').first().click(); - }); - - await test.step('expect set image from url', async () => { - await poAccountProfile.inputAvatarLink.fill('https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50'); - await poAccountProfile.btnSetAvatarLink.click(); - - await poAccountProfile.btnSubmit.click(); - await expect(page.locator('.rcx-toastbar.rcx-toastbar--success').first()).toBeVisible(); - }); - }); -}); diff --git a/apps/meteor/tests/e2e/utils/test.ts b/apps/meteor/tests/e2e/utils/test.ts index 7418307a647d..5ccea233d88a 100644 --- a/apps/meteor/tests/e2e/utils/test.ts +++ b/apps/meteor/tests/e2e/utils/test.ts @@ -1,6 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; +import AxeBuilder from '@axe-core/playwright'; import type { Locator, APIResponse, APIRequestContext } from '@playwright/test'; import { test as baseTest, request as baseRequest } from '@playwright/test'; import { v4 as uuid } from 'uuid'; @@ -21,6 +22,7 @@ export type BaseTest = { put(uri: string, data: AnyObj, prefix?: string): Promise; delete(uri: string, params?: AnyObj, prefix?: string): Promise; }; + makeAxeBuilder: () => AxeBuilder; }; declare global { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -112,6 +114,12 @@ 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]); + await use(makeAxeBuilder); + } }); export const { expect } = test; diff --git a/yarn.lock b/yarn.lock index 68ef61bc51eb..061b01927896 100644 --- a/yarn.lock +++ b/yarn.lock @@ -955,6 +955,17 @@ __metadata: languageName: node linkType: hard +"@axe-core/playwright@npm:^4.7.3": + version: 4.7.3 + resolution: "@axe-core/playwright@npm:4.7.3" + dependencies: + axe-core: ^4.7.0 + peerDependencies: + playwright-core: ">= 1.0.0" + checksum: c913cf6a816af283fc733411013460656213cf6c0efffcc36db1fd2984ffac3d780efd0a9aabd3b41ce78e2a536fee9ba5436d19311f660067e4c3560677b115 + languageName: node + linkType: hard + "@babel/code-frame@npm:7.12.11": version: 7.12.11 resolution: "@babel/code-frame@npm:7.12.11" @@ -8540,6 +8551,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/meteor@workspace:apps/meteor" dependencies: + "@axe-core/playwright": ^4.7.3 "@babel/core": ~7.22.9 "@babel/eslint-parser": ~7.22.9 "@babel/plugin-proposal-nullish-coalescing-operator": ~7.18.6 @@ -8658,7 +8670,6 @@ __metadata: "@types/he": ^1.1.2 "@types/i18next-sprintf-postprocessor": ^0.2.0 "@types/imap": ^0.8.37 - "@types/jest-axe": ^3.5.5 "@types/jsdom": ^16.2.15 "@types/jsdom-global": ^3.0.4 "@types/jsrsasign": ^10.5.8 @@ -8796,7 +8807,6 @@ __metadata: ip-range-check: ^0.2.0 is-svg: ^4.3.2 jest: ~29.6.1 - jest-axe: ^8.0.0 jquery: ^3.6.0 jschardet: ^3.0.0 jsdom: ^16.7.0 @@ -12338,16 +12348,6 @@ __metadata: languageName: node linkType: hard -"@types/jest-axe@npm:^3.5.5": - version: 3.5.5 - resolution: "@types/jest-axe@npm:3.5.5" - dependencies: - "@types/jest": "*" - axe-core: ^3.5.5 - checksum: 535038968034fe80fb466dcd5939ea5d9e9adb3ef00852ded3e41c62536c05137eb30bcbfd608142d2bc571d65c20b8e3563181674fb48594c2662d340bb4da5 - languageName: node - linkType: hard - "@types/jest@npm:*, @types/jest@npm:~29.5.3": version: 29.5.3 resolution: "@types/jest@npm:29.5.3" @@ -15075,20 +15075,13 @@ __metadata: languageName: node linkType: hard -"axe-core@npm:4.7.2, axe-core@npm:^4.2.0": +"axe-core@npm:^4.2.0, axe-core@npm:^4.7.0": version: 4.7.2 resolution: "axe-core@npm:4.7.2" checksum: 5d86fa0f45213b0e54cbb5d713ce885c4a8fe3a72b92dd915a47aa396d6fd149c4a87fec53aa978511f6d941402256cfeb26f2db35129e370f25a453c688655a languageName: node linkType: hard -"axe-core@npm:^3.5.5": - version: 3.5.6 - resolution: "axe-core@npm:3.5.6" - checksum: 000777d2b6bf1f390beb1fb4b8714ed9127797c021c345b032db0c144e07320dbbe8cb0bcb7688b90b79cfbd3cdc1f27a4dc857804e3c61d7e0defb34deeb830 - languageName: node - linkType: hard - "axios@npm:^0.21.0, axios@npm:^0.21.1": version: 0.21.4 resolution: "axios@npm:0.21.4" @@ -16707,16 +16700,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:4.1.2, chalk@npm:^4, chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.2": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc - languageName: node - linkType: hard - "chalk@npm:^1.0.0": version: 1.1.3 resolution: "chalk@npm:1.1.3" @@ -16730,6 +16713,16 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^4, chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.2": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc + languageName: node + linkType: hard + "change-case@npm:^4.1.2": version: 4.1.2 resolution: "change-case@npm:4.1.2" @@ -25496,18 +25489,6 @@ __metadata: languageName: node linkType: hard -"jest-axe@npm:^8.0.0": - version: 8.0.0 - resolution: "jest-axe@npm:8.0.0" - dependencies: - axe-core: 4.7.2 - chalk: 4.1.2 - jest-matcher-utils: 29.2.2 - lodash.merge: 4.6.2 - checksum: 895501afa6ac6c49e5e45ee1cd4a8e923589f220f6f950a8f5366cc3f3636aaee9c9d501a469f9658185e7a5928b59a337d4b4f1c7bb3f4b3b5ba8b3811c9f15 - languageName: node - linkType: hard - "jest-changed-files@npm:^29.5.0": version: 29.5.0 resolution: "jest-changed-files@npm:29.5.0" @@ -25623,7 +25604,7 @@ __metadata: languageName: node linkType: hard -"jest-diff@npm:^29.2.1, jest-diff@npm:^29.6.1": +"jest-diff@npm:^29.6.1": version: 29.6.2 resolution: "jest-diff@npm:29.6.2" dependencies: @@ -25709,7 +25690,7 @@ __metadata: languageName: node linkType: hard -"jest-get-type@npm:^29.2.0, jest-get-type@npm:^29.4.3": +"jest-get-type@npm:^29.4.3": version: 29.4.3 resolution: "jest-get-type@npm:29.4.3" checksum: 6ac7f2dde1c65e292e4355b6c63b3a4897d7e92cb4c8afcf6d397f2682f8080e094c8b0b68205a74d269882ec06bf696a9de6cd3e1b7333531e5ed7b112605ce @@ -25774,18 +25755,6 @@ __metadata: languageName: node linkType: hard -"jest-matcher-utils@npm:29.2.2": - version: 29.2.2 - resolution: "jest-matcher-utils@npm:29.2.2" - dependencies: - chalk: ^4.0.0 - jest-diff: ^29.2.1 - jest-get-type: ^29.2.0 - pretty-format: ^29.2.1 - checksum: 97ef2638ab826c25f84bfedea231cef091820ae0876ba316922da81145e950d2b9d2057d3645813b5ee880bb975ed4f22e228dda5d0d26a20715e575b675357d - languageName: node - linkType: hard - "jest-matcher-utils@npm:^29.6.1": version: 29.6.1 resolution: "jest-matcher-utils@npm:29.6.1" @@ -27144,7 +27113,7 @@ __metadata: languageName: node linkType: hard -"lodash.merge@npm:4.6.2, lodash.merge@npm:^4.6.2": +"lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005 @@ -32083,7 +32052,7 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.2.1, pretty-format@npm:^29.6.1, pretty-format@npm:^29.6.2": +"pretty-format@npm:^29.0.0, pretty-format@npm:^29.6.1, pretty-format@npm:^29.6.2": version: 29.6.2 resolution: "pretty-format@npm:29.6.2" dependencies: From 3245a0a3184f3adcab7ad239135457f0c0f29659 Mon Sep 17 00:00:00 2001 From: Rafael Tapia Date: Wed, 6 Sep 2023 09:05:57 -0300 Subject: [PATCH 14/66] fix: linkedin oauth broken (#30252) --- .changeset/odd-elephants-promise.md | 5 + .../lib/server/startup/oAuthServicesUpdate.js | 2 +- .../linkedin-oauth/linkedin-client.js | 2 +- .../linkedin-oauth/linkedin-server.js | 120 +++++++----------- 4 files changed, 51 insertions(+), 78 deletions(-) create mode 100644 .changeset/odd-elephants-promise.md diff --git a/.changeset/odd-elephants-promise.md b/.changeset/odd-elephants-promise.md new file mode 100644 index 000000000000..a12817ed175b --- /dev/null +++ b/.changeset/odd-elephants-promise.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fix LinkedIn OAuth broken diff --git a/apps/meteor/app/lib/server/startup/oAuthServicesUpdate.js b/apps/meteor/app/lib/server/startup/oAuthServicesUpdate.js index 397c3a491c5d..b01ef2f9fb0c 100644 --- a/apps/meteor/app/lib/server/startup/oAuthServicesUpdate.js +++ b/apps/meteor/app/lib/server/startup/oAuthServicesUpdate.js @@ -97,7 +97,7 @@ async function _OAuthServicesUpdate() { if (serviceName === 'Linkedin') { data.clientConfig = { - requestPermissions: ['r_liteprofile', 'r_emailaddress'], + requestPermissions: ['openid', 'email', 'profile'], }; } diff --git a/apps/meteor/packages/linkedin-oauth/linkedin-client.js b/apps/meteor/packages/linkedin-oauth/linkedin-client.js index 4c2ae09d1cae..29be9dd1af22 100644 --- a/apps/meteor/packages/linkedin-oauth/linkedin-client.js +++ b/apps/meteor/packages/linkedin-oauth/linkedin-client.js @@ -29,7 +29,7 @@ Linkedin.requestCredential = async function (options, credentialRequestCompleteC scope = requestPermissions.join('+'); } else { // If extra permissions not passed, we need to request basic, available to all - scope = 'r_emailaddress+r_liteprofile'; + scope = 'openid+email+profile'; } const loginStyle = OAuth._loginStyle('linkedin', config, options); if (!otherOptionsToPassThrough.popupOptions) { diff --git a/apps/meteor/packages/linkedin-oauth/linkedin-server.js b/apps/meteor/packages/linkedin-oauth/linkedin-server.js index fe67fe11b028..62e4dad143ce 100644 --- a/apps/meteor/packages/linkedin-oauth/linkedin-server.js +++ b/apps/meteor/packages/linkedin-oauth/linkedin-server.js @@ -4,45 +4,6 @@ import { ServiceConfiguration } from 'meteor/service-configuration'; export const Linkedin = {}; -const getImage = (profilePicture) => { - const image = []; - if (profilePicture !== undefined) { - for (const element of profilePicture['displayImage~'].elements) { - for (const identifier of element.identifiers) { - image.push(identifier.identifier); - } - } - } - return { - displayImage: profilePicture ? profilePicture.displayImage : null, - identifiersUrl: image, - }; -}; - -// Request for email, returns array -const getEmails = async function (accessToken) { - const url = encodeURI( - `https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))&oauth2_access_token=${accessToken}`, - ); - const data = await fetch(url); - const response = await data.json(); - const emails = []; - for (const element of response.elements) { - emails.push(element['handle~'].emailAddress); - } - return emails; -}; - -// checks whether a string parses as JSON -const isJSON = function (str) { - try { - JSON.parse(str); - return true; - } catch (e) { - return false; - } -}; - // returns an object containing: // - accessToken // - expiresIn: lifetime of token in seconds @@ -53,33 +14,37 @@ const getTokenResponse = async function (query) { let responseContent; try { // Request an access token - const request = await fetch('https://api.linkedin.com/uas/oauth2/accessToken', { + const body = new URLSearchParams({ + grant_type: 'authorization_code', + client_id: config.clientId, + client_secret: OAuth.openSecret(config.secret), + code: query.code, + redirect_uri: OAuth._redirectUri('linkedin', config), + }); + + const response = await fetch('https://api.linkedin.com/uas/oauth2/accessToken', { method: 'POST', - body: JSON.stringify({ - grant_type: 'authorization_code', - client_id: config.clientId, - client_secret: OAuth.openSecret(config.secret), - code: query.code, - redirect_uri: OAuth._redirectUri('linkedin', config), - }), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body, }); - responseContent = await request.text(); + + if (!response.ok) { + throw new Error(responseContent.error_description); + } + + responseContent = await response.json(); } catch (err) { throw new Error(`Failed to complete OAuth handshake with Linkedin. ${err.message}`); } - // If 'responseContent' does not parse as JSON, it is an error. - if (!isJSON(responseContent)) { - throw new Error(`Failed to complete OAuth handshake with Linkedin. ${responseContent}`); - } - // Success! Extract access token and expiration - const parsedResponse = JSON.parse(responseContent); - const accessToken = parsedResponse.access_token; - const expiresIn = parsedResponse.expires_in; + const accessToken = responseContent.access_token; + const expiresIn = responseContent.expires_in; if (!accessToken) { - throw new Error(`Failed to complete OAuth handshake with Linkedin -- can't find access token in HTTP response. ${responseContent}`); + throw new Error(`Failed to complete OAuth handshake with Linkedin -- can't find access token in HTTP response. ${JSON.stringify(responseContent)}`); } return { @@ -88,13 +53,23 @@ const getTokenResponse = async function (query) { }; }; -// Request available fields from r_liteprofile +// Request available fields from profile const getIdentity = async function (accessToken) { try { const url = encodeURI( - `https://api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))&oauth2_access_token=${accessToken}`, + `https://api.linkedin.com/v2/userinfo`, ); - const request = await fetch(url); + const request = await fetch(url, { + method: 'GET', + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + + if (!request.ok) { + throw new Error(await request.text()); + } + return request.json(); } catch (err) { throw new Error(`Failed to fetch identity from Linkedin. ${err.message}`); @@ -106,30 +81,23 @@ OAuth.registerService('linkedin', 2, null, async (query) => { const { accessToken } = response; const identity = await getIdentity(accessToken); - const { id, firstName, lastName, profilePicture } = identity; + const { sub, given_name, family_name, picture, email } = identity; - if (!id) { + if (!sub) { throw new Error('Linkedin did not provide an id'); } - const emails = await getEmails(accessToken); - const fields = { - linkedinId: id, - firstName, - lastName, - profilePicture: getImage(profilePicture), - emails, + linkedinId: sub, + firstName: given_name, + lastName: family_name, + profilePicture: picture, + emailAddress: email, + email }; - if (emails.length) { - const primaryEmail = emails[0]; - fields.emailAddress = primaryEmail; // for backward compatibility with previous versions of this package - fields.email = primaryEmail; - } - const serviceData = { - id, + id: sub, accessToken, expiresAt: +new Date() + 1000 * response.expiresIn, ...fields, From e6d92ff1323537ba6cc653049e5d24ea4a17b12a Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 6 Sep 2023 11:11:01 -0300 Subject: [PATCH 15/66] chore: Registration form a11y improvements (#30280) --- apps/meteor/tests/e2e/register.spec.ts | 9 ++ .../src/components/CustomFieldsForm.tsx | 21 +++- .../web-ui-registration/src/RegisterForm.tsx | 119 +++++++++++------- 3 files changed, 102 insertions(+), 47 deletions(-) diff --git a/apps/meteor/tests/e2e/register.spec.ts b/apps/meteor/tests/e2e/register.spec.ts index 37d4c9b2c696..f99f212ff718 100644 --- a/apps/meteor/tests/e2e/register.spec.ts +++ b/apps/meteor/tests/e2e/register.spec.ts @@ -123,6 +123,15 @@ test.describe.serial('register', () => { await expect(poRegistration.registrationDisabledCallout).toBeVisible(); }); }); + + test('should not have any accessibility violations', async ({ page, makeAxeBuilder }) => { + await page.goto('/home'); + await poRegistration.goToRegister.click(); + + const results = await makeAxeBuilder().disableRules(['landmark-one-main', 'region']).analyze(); + + expect(results.violations).toEqual([]); + }); }); test.describe('Registration for secret password', async () => { diff --git a/packages/ui-client/src/components/CustomFieldsForm.tsx b/packages/ui-client/src/components/CustomFieldsForm.tsx index 49d4a120e47d..9423456ebe8e 100644 --- a/packages/ui-client/src/components/CustomFieldsForm.tsx +++ b/packages/ui-client/src/components/CustomFieldsForm.tsx @@ -1,6 +1,7 @@ import type { CustomFieldMetadata } from '@rocket.chat/core-typings'; import type { SelectOption } from '@rocket.chat/fuselage'; import { Field, Select, TextInput } from '@rocket.chat/fuselage'; +import { useUniqueId } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useTranslation } from '@rocket.chat/ui-contexts'; import { useCallback, useMemo } from 'react'; @@ -35,6 +36,7 @@ const CustomField = ({ }: CustomFieldProps) => { const t = useTranslation(); const { errors } = useFormState({ control }); + const fieldId = useUniqueId(); const Component = FIELD_TYPES[type] ?? null; @@ -47,7 +49,7 @@ const CustomField = ({ const validateRequired = useCallback((value) => (required ? typeof value === 'string' && !!value.trim() : true), [required]); const getErrorMessage = useCallback( - (error: any) => { + (error) => { switch (error?.type) { case 'required': return t('The_field_is_required', label || name); @@ -71,14 +73,23 @@ const CustomField = ({ rules={{ minLength: props.minLength, maxLength: props.maxLength, validate: { required: validateRequired } }} render={({ field }) => ( - + {label || t(name as TranslationKey)} - {required && '*'} - + - {errorMessage} + + {errorMessage} + )} /> diff --git a/packages/web-ui-registration/src/RegisterForm.tsx b/packages/web-ui-registration/src/RegisterForm.tsx index db3879d6e027..32ba9238766d 100644 --- a/packages/web-ui-registration/src/RegisterForm.tsx +++ b/packages/web-ui-registration/src/RegisterForm.tsx @@ -34,8 +34,14 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo const passwordConfirmationPlaceholder = String(useSetting('Accounts_ConfirmPasswordPlaceholder')); const formLabelId = useUniqueId(); - const passwordId = useUniqueId(); const passwordVerifierId = useUniqueId(); + const nameId = useUniqueId(); + const emailId = useUniqueId(); + const usernameId = useUniqueId(); + const passwordId = useUniqueId(); + const passwordConfirmationId = useUniqueId(); + const reasonId = useUniqueId(); + const registerUser = useRegisterMethod(); const customFields = useAccountsCustomFields(); @@ -54,7 +60,7 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo formState: { errors }, } = useForm({ mode: 'onBlur' }); - const password = watch('password'); + const { password } = watch(); const passwordIsValid = useValidatePassword(password); const handleRegister = async ({ password, passwordConfirmation: _, ...formData }: LoginRegisterPayload) => { @@ -103,8 +109,8 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo - - {requireNameForRegister ? `${t('registration.component.form.name')}*` : t('registration.component.form.nameOptional')} + + {t('registration.component.form.name')} - {errors.name && {t('registration.component.form.requiredField')}} + {errors.name && ( + + {t('registration.component.form.requiredField')} + + )} - {t('registration.component.form.email')}* + + {t('registration.component.form.email')} + - {errors.email && {errors.email.message || t('registration.component.form.requiredField')}} + {errors.email && ( + + {errors.email.message} + + )} - {t('registration.component.form.username')}* + + {t('registration.component.form.username')} + - {errors.username?.message && {errors.username.message}} - {errors.username?.type === 'required' && {t('registration.component.form.requiredField')}} + {errors.username && ( + + {errors.username.message} + + )} - {t('registration.component.form.password')}* + + {t('registration.component.form.password')} + {errors?.password && ( @@ -176,43 +201,53 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo )} - {requiresPasswordConfirmation && ( + + {requiresPasswordConfirmation && ( + + {t('registration.component.form.confirmPassword')} watch('password') === val, + validate: (val: string) => (watch('password') === val ? true : t('registration.component.form.invalidConfirmPass')), })} - error={errors.passwordConfirmation?.type === 'validate' ? t('registration.component.form.invalidConfirmPass') : undefined} - aria-invalid={errors.passwordConfirmation ? 'true' : false} - id='passwordConfirmation' + error={errors.passwordConfirmation?.message} + aria-invalid={errors.passwordConfirmation ? 'true' : 'false'} + id={passwordConfirmationId} + aria-describedby={`${passwordConfirmationId}-error`} placeholder={passwordConfirmationPlaceholder || t('Confirm_password')} disabled={!passwordIsValid} /> - )} - {errors.passwordConfirmation?.type === 'validate' && requiresPasswordConfirmation && ( - {t('registration.component.form.invalidConfirmPass')} - )} - {errors.passwordConfirmation?.type === 'required' && requiresPasswordConfirmation && ( - {t('registration.component.form.requiredField')} - )} - + {errors.passwordConfirmation && ( + + {errors.passwordConfirmation.message} + + )} + + )} {manuallyApproveNewUsersRequired && ( - {t('registration.component.form.reasonToJoin')}* + + {t('registration.component.form.reasonToJoin')} + - {errors.reason && {t('registration.component.form.requiredField')}} + {errors.reason && ( + + {t('registration.component.form.requiredField')} + + )} )} 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 16/66] 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 17/66] 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 18/66] 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 19/66] 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 20/66] 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 21/66] 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 22/66] 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 23/66] 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 24/66] 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')} - - ( - - {children} - - ); -} diff --git a/packages/livechat/src/components/FilesDropTarget/index.tsx b/packages/livechat/src/components/FilesDropTarget/index.tsx new file mode 100644 index 000000000000..3e9935c37565 --- /dev/null +++ b/packages/livechat/src/components/FilesDropTarget/index.tsx @@ -0,0 +1,122 @@ +import type { ComponentChildren, Ref } from 'preact'; +import type { TargetedEvent } from 'preact/compat'; +import { useState } from 'preact/hooks'; +import type { JSXInternal } from 'preact/src/jsx'; + +import { createClassName } from '../../helpers/createClassName'; +import styles from './styles.scss'; + +const escapeForRegExp = (string: string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + +type FilesDropTargetProps = { + overlayed?: boolean; + overlayText?: string; + accept?: string; + multiple?: boolean; + className?: string; + style?: JSXInternal.CSSProperties; + children?: ComponentChildren; + inputRef?: Ref; + onUpload?: (files: File[]) => void; +}; + +export const FilesDropTarget = ({ + overlayed, + overlayText, + accept, + multiple, + className, + style = {}, + children, + inputRef, + onUpload, +}: FilesDropTargetProps) => { + const [dragLevel, setDragLevel] = useState(0); + + const handleDragOver = (event: DragEvent) => { + event.preventDefault(); + }; + + const handleDragEnter = (event: DragEvent) => { + event.preventDefault(); + setDragLevel(dragLevel + 1); + }; + + const handleDragLeave = (event: DragEvent) => { + event.preventDefault(); + setDragLevel(dragLevel - 1); + }; + + const handleDrop = (event: DragEvent) => { + event.preventDefault(); + + if (dragLevel === 0 || !event?.dataTransfer?.files?.length) { + return; + } + + setDragLevel(0); + + handleUpload(event?.dataTransfer?.files); + }; + + const handleInputChange = (event: TargetedEvent) => { + if (!event?.currentTarget?.files?.length) { + return; + } + + handleUpload(event.currentTarget.files); + }; + + const handleUpload = (files: FileList) => { + if (!onUpload) { + return; + } + + let filteredFiles = Array.from(files); + + if (accept) { + const acceptMatchers = accept.split(',').map((acceptString) => { + if (acceptString.charAt(0) === '.') { + return ({ name }: { name: string }) => new RegExp(`${escapeForRegExp(acceptString)}$`, 'i').test(name); + } + + const matchTypeOnly = /^(.+)\/\*$/i.exec(acceptString); + if (matchTypeOnly) { + return ({ type }: { type: string }) => new RegExp(`^${escapeForRegExp(matchTypeOnly[1])}/.*$`, 'i').test(type); + } + + return ({ type }: { type: string }) => new RegExp(`^s${escapeForRegExp(acceptString)}$`, 'i').test(type); + }); + + filteredFiles = filteredFiles.filter((file) => acceptMatchers.some((acceptMatcher) => acceptMatcher(file))); + } + + if (!multiple) { + filteredFiles = filteredFiles.slice(0, 1); + } + + filteredFiles.length && onUpload(filteredFiles); + }; + + return ( +
0 }, [className])} + style={style} + > + + {children} +
+ ); +}; diff --git a/packages/livechat/src/components/FilesDropTarget/stories.tsx b/packages/livechat/src/components/FilesDropTarget/stories.tsx index e1a01cbaea09..d687fbaad492 100644 --- a/packages/livechat/src/components/FilesDropTarget/stories.tsx +++ b/packages/livechat/src/components/FilesDropTarget/stories.tsx @@ -71,7 +71,7 @@ AcceptingMultipleFiles.args = { export const TriggeringBrowseAction = Template.bind({}); TriggeringBrowseAction.storyName = 'triggering browse action'; -const ref = createRef(); +const inputRef = createRef(); TriggeringBrowseAction.args = { children: (
- +
), - ref, + inputRef, }; diff --git a/packages/livechat/src/routes/Chat/component.js b/packages/livechat/src/routes/Chat/component.js index 98991ab72b53..8bd9ac468c6e 100644 --- a/packages/livechat/src/routes/Chat/component.js +++ b/packages/livechat/src/routes/Chat/component.js @@ -1,4 +1,4 @@ -import { Component } from 'preact'; +import { Component, createRef } from 'preact'; import { Suspense, lazy } from 'preact/compat'; import { withTranslation } from 'react-i18next'; @@ -35,6 +35,8 @@ class Chat extends Component { emojiPickerActive: false, }; + inputRef = createRef(null); + handleFilesDropTargetRef = (ref) => { this.filesDropTarget = ref; }; @@ -61,7 +63,7 @@ class Chat extends Component { handleUploadClick = (event) => { event.preventDefault(); - this.filesDropTarget.browse(); + this.inputRef?.current?.click(); }; handleSendClick = (event) => { @@ -151,7 +153,7 @@ class Chat extends Component { handleEmojiClick={this.handleEmojiClick} {...props} > - + {incomingCallAlert && !!incomingCallAlert.show && } {incomingCallAlert?.show && ongoingCall && ongoingCall.callStatus === CallStatus.IN_PROGRESS_SAME_TAB ? ( From 781bdfe9055ce1178629d5e6d0c147c2071356c0 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 14 Sep 2023 14:47:15 -0300 Subject: [PATCH 66/66] regression: commit subject alignment --- apps/meteor/client/views/admin/info/DeploymentCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/client/views/admin/info/DeploymentCard.tsx b/apps/meteor/client/views/admin/info/DeploymentCard.tsx index 6bc9ece2b850..7a95e7aae018 100644 --- a/apps/meteor/client/views/admin/info/DeploymentCard.tsx +++ b/apps/meteor/client/views/admin/info/DeploymentCard.tsx @@ -65,7 +65,7 @@ const DeploymentCard = ({ info, statistics, instances }: DeploymentCardProps): R {t('Commit_details')} {t('github_HEAD')}: ({commit.hash ? commit.hash.slice(0, 9) : ''})
- {t('Branch')}: {commit.branch} + {t('Branch')}: {commit.branch}
{commit.subject}