diff --git a/.changeset/weak-books-tell.md b/.changeset/weak-books-tell.md new file mode 100644 index 000000000000..675901263f31 --- /dev/null +++ b/.changeset/weak-books-tell.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Forces the highlight code language registration, preventing it to not being available when trying to use on the UI diff --git a/apps/meteor/client/hooks/useHighlightedCode.ts b/apps/meteor/client/hooks/useHighlightedCode.ts index 43c4a5e6ea58..4e3405ca3034 100644 --- a/apps/meteor/client/hooks/useHighlightedCode.ts +++ b/apps/meteor/client/hooks/useHighlightedCode.ts @@ -1,7 +1,19 @@ +import { useTranslation } from '@rocket.chat/ui-contexts'; +import { useQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; -import hljs from '../../app/markdown/lib/hljs'; +import hljs, { register } from '../../app/markdown/lib/hljs'; export function useHighlightedCode(language: string, text: string): string { - return useMemo(() => hljs.highlight(language, text).value, [language, text]); + const t = useTranslation(); + const { isLoading } = useQuery(['register-highlight-language', language], async () => { + try { + await register(language); + return true; + } catch (error) { + console.error('Not possible to register the provided language'); + } + }); + + return useMemo(() => (isLoading ? t('Loading') : hljs.highlight(language, text).value), [isLoading, language, text, t]); } diff --git a/apps/meteor/client/views/admin/integrations/IntegrationsTable.tsx b/apps/meteor/client/views/admin/integrations/IntegrationsTable.tsx index 206458e09c9b..e2942f384c9d 100644 --- a/apps/meteor/client/views/admin/integrations/IntegrationsTable.tsx +++ b/apps/meteor/client/views/admin/integrations/IntegrationsTable.tsx @@ -107,7 +107,7 @@ const IntegrationsTable = ({ type }: { type?: string }) => { )} {isSuccess && data && data.integrations.length > 0 && ( <> - + {headers} {isSuccess && diff --git a/apps/meteor/tests/e2e/administration.spec.ts b/apps/meteor/tests/e2e/administration.spec.ts index 902d4f09b12c..e4af3c26c106 100644 --- a/apps/meteor/tests/e2e/administration.spec.ts +++ b/apps/meteor/tests/e2e/administration.spec.ts @@ -3,8 +3,7 @@ import { faker } from '@faker-js/faker'; import { IS_EE } from './config/constants'; import { Users } from './fixtures/userStates'; import { Admin, Utils } from './page-objects'; -import { createTargetChannel } from './utils'; -import { setSettingValueById } from './utils/setSettingValueById'; +import { createTargetChannel, setSettingValueById } from './utils'; import { test, expect } from './utils/test'; test.use({ storageState: Users.admin.state }); @@ -275,6 +274,52 @@ test.describe.parallel('administration', () => { }); }); + test.describe('Integrations', () => { + const messageCodeHighlightDefault = + 'javascript,css,markdown,dockerfile,json,go,rust,clean,bash,plaintext,powershell,scss,shell,yaml,vim'; + const incomingIntegrationName = faker.string.uuid(); + + test.beforeAll(async ({ api }) => { + await setSettingValueById(api, 'Message_Code_highlight', ''); + }); + + test.beforeEach(async ({ page }) => { + await page.goto('/admin/integrations'); + }); + + test.afterAll(async ({ api }) => { + await setSettingValueById(api, 'Message_Code_highlight', messageCodeHighlightDefault); + }); + + test('should display the example payload correctly', async () => { + await poAdmin.btnNew.click(); + await poAdmin.btnInstructions.click(); + + await expect(poAdmin.codeExamplePayload('Loading')).not.toBeVisible(); + }); + + test('should be able to create new incoming integration', async () => { + await poAdmin.btnNew.click(); + await poAdmin.inputName.fill(incomingIntegrationName); + await poAdmin.inputPostToChannel.fill('#general'); + await poAdmin.inputPostAs.fill(Users.admin.data.username); + await poAdmin.btnSave.click(); + + await expect(poAdmin.inputWebhookUrl).not.toHaveValue('Will be available here after saving.'); + + await poAdmin.btnBack.click(); + await expect(poAdmin.getIntegrationByName(incomingIntegrationName)).toBeVisible(); + }); + + test('should be able to delete an incoming integration', async () => { + await poAdmin.getIntegrationByName(incomingIntegrationName).click(); + await poAdmin.btnDelete.click(); + await poUtils.btnModalConfirmDelete.click(); + + await expect(poAdmin.getIntegrationByName(incomingIntegrationName)).not.toBeVisible(); + }); + }); + test.describe('Settings', () => { test.describe('General', () => { test.beforeEach(async ({ page }) => { diff --git a/apps/meteor/tests/e2e/page-objects/admin.ts b/apps/meteor/tests/e2e/page-objects/admin.ts index f3567652fe6e..210dbc95f326 100644 --- a/apps/meteor/tests/e2e/page-objects/admin.ts +++ b/apps/meteor/tests/e2e/page-objects/admin.ts @@ -213,11 +213,47 @@ export class Admin { return this.page.getByRole('button', { name: 'Add' }); } + getUserRowByUsername(username: string): Locator { + return this.page.locator('tr', { hasText: username }); + } + get btnBack(): Locator { return this.page.getByRole('button', { name: 'Back' }); } - getUserRowByUsername(username: string): Locator { - return this.page.locator('tr', { hasText: username }); + get btnNew(): Locator { + return this.page.getByRole('button', { name: 'New' }); + } + + get btnDelete(): Locator { + return this.page.getByRole('button', { name: 'Delete' }); + } + + get btnInstructions(): Locator { + return this.page.getByRole('button', { name: 'Instructions' }); + } + + get inputName(): Locator { + return this.page.getByRole('textbox', { name: 'Name' }); + } + + get inputPostToChannel(): Locator { + return this.page.getByRole('textbox', { name: 'Post to Channel' }); + } + + get inputPostAs(): Locator { + return this.page.getByRole('textbox', { name: 'Post as' }); + } + + codeExamplePayload(text: string): Locator { + return this.page.locator('code', { hasText: text }); + } + + getIntegrationByName(name: string): Locator { + return this.page.getByRole('table', { name: 'Integrations table' }).locator('tr', { hasText: name }); + } + + get inputWebhookUrl(): Locator { + return this.page.getByRole('textbox', { name: 'Webhook URL' }); } } diff --git a/apps/meteor/tests/e2e/utils/index.ts b/apps/meteor/tests/e2e/utils/index.ts index 9f83fc0ae246..e1daf601f648 100644 --- a/apps/meteor/tests/e2e/utils/index.ts +++ b/apps/meteor/tests/e2e/utils/index.ts @@ -1,2 +1,3 @@ export * from './create-target-channel'; export * from './setSettingValueById'; +export * from './getSettingValueById'; diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index e9d1894ef74e..779c71c9d755 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -2763,6 +2763,7 @@ "Integrations_Outgoing_Type_RoomLeft": "User Left Room", "Integrations_Outgoing_Type_SendMessage": "Message Sent", "Integrations_Outgoing_Type_UserCreated": "User Created", + "Integrations_table": "Integrations table", "InternalHubot": "Internal Hubot", "InternalHubot_EnableForChannels": "Enable for Public Channels", "InternalHubot_EnableForDirectMessages": "Enable for Direct Messages",