Skip to content

Commit

Permalink
Merge branch 'develop' into fix/katex-overflow
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Jun 17, 2024
2 parents bfdbe4c + 9795e58 commit cef7e25
Show file tree
Hide file tree
Showing 16 changed files with 172 additions and 27 deletions.
6 changes: 6 additions & 0 deletions .changeset/lastmessage-e2ee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/model-typings": patch
---

Fixed last message preview in Sidebar for E2E Ecrypted channels
5 changes: 5 additions & 0 deletions .changeset/weak-books-tell.md
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion apps/meteor/app/lib/server/functions/cleanRoomHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export async function cleanRoomHistory({
}

if (count) {
const lastMessage = await Messages.getLastVisibleMessageSentWithNoTypeByRoomId(rid);
const lastMessage = await Messages.getLastVisibleUserMessageSentByRoomId(rid);

await Rooms.resetLastMessageById(rid, lastMessage, -count);

Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/lib/server/functions/deleteMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export async function deleteMessage(message: IMessage, user: IUser): Promise<voi

// update last message
if (settings.get('Store_Last_Message') && (!room?.lastMessage || room.lastMessage._id === message._id)) {
const lastMessageNotDeleted = await Messages.getLastVisibleMessageSentWithNoTypeByRoomId(message.rid);
const lastMessageNotDeleted = await Messages.getLastVisibleUserMessageSentByRoomId(message.rid);
await Rooms.resetLastMessageById(message.rid, lastMessageNotDeleted, -1);
} else {
// decrease message count
Expand Down
16 changes: 14 additions & 2 deletions apps/meteor/client/hooks/useHighlightedCode.ts
Original file line number Diff line number Diff line change
@@ -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]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const IntegrationsTable = ({ type }: { type?: string }) => {
)}
{isSuccess && data && data.integrations.length > 0 && (
<>
<GenericTable>
<GenericTable aria-label={t('Integrations_table')}>
<GenericTableHeader>{headers}</GenericTableHeader>
<GenericTableBody>
{isSuccess &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,6 @@ const ModerationConsoleTable: FC = () => {
>
{t('User')}
</GenericTableHeaderCell>,

<GenericTableHeaderCell
key='reportedMessage'
direction={sortDirection}
active={sortBy === 'reports.description'}
onClick={setSort}
sort='reports.description'
>
{t('Moderation_Reported_message')}
</GenericTableHeaderCell>,
<GenericTableHeaderCell key='room' direction={sortDirection}>
{t('Room')}
</GenericTableHeaderCell>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type ModerationConsoleRowProps = {
};

const ModerationConsoleTableRow = ({ report, onClick, isDesktopOrLarger }: ModerationConsoleRowProps): JSX.Element => {
const { userId: _id, rooms, name, count, message, username, ts } = report;
const { userId: _id, rooms, name, count, username, ts } = report;

const roomNames = rooms.map((room) => {
if (room.t === 'd') {
Expand All @@ -31,7 +31,6 @@ const ModerationConsoleTableRow = ({ report, onClick, isDesktopOrLarger }: Moder
<GenericTableCell withTruncatedText>
<UserColumn username={username} name={name} fontSize='micro' size={isDesktopOrLarger ? 'x20' : 'x40'} />
</GenericTableCell>
<GenericTableCell withTruncatedText>{message}</GenericTableCell>
<GenericTableCell withTruncatedText>{concatenatedRoomNames}</GenericTableCell>
<GenericTableCell withTruncatedText>{formatDateAndTime(ts)}</GenericTableCell>
<GenericTableCell withTruncatedText>{count}</GenericTableCell>
Expand Down
9 changes: 4 additions & 5 deletions apps/meteor/server/models/raw/Messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1040,12 +1040,11 @@ export class MessagesRaw extends BaseRaw<IMessage> implements IMessagesModel {
return this.findOne(query, options);
}

getLastVisibleMessageSentWithNoTypeByRoomId(rid: string, messageId?: string): Promise<IMessage | null> {
const query = {
getLastVisibleUserMessageSentByRoomId(rid: string, messageId?: string): Promise<IMessage | null> {
const query: Filter<IMessage> = {
rid,
_hidden: { $ne: true },
t: { $exists: false },
$or: [{ tmid: { $exists: false } }, { tshow: true }],
$or: [{ t: 'e2e' }, { t: { $exists: false }, tmid: { $exists: false } }, { t: { $exists: false }, tshow: true }],
...(messageId && { _id: { $ne: messageId } }),
};

Expand All @@ -1055,7 +1054,7 @@ export class MessagesRaw extends BaseRaw<IMessage> implements IMessagesModel {
},
};

return this.findOne(query, options);
return this.findOne<IMessage>(query, options);
}

async cloneAndSaveAsHistoryByRecord(record: IMessage, user: IMessage['u']): Promise<InsertOneResult<IMessage>> {
Expand Down
49 changes: 47 additions & 2 deletions apps/meteor/tests/e2e/administration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down Expand Up @@ -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 }) => {
Expand Down
45 changes: 45 additions & 0 deletions apps/meteor/tests/e2e/e2e-encryption.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,51 @@ test.describe.serial('e2e-encryption', () => {
await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible();
});

test('expect create a private channel, send unecrypted messages, encrypt the channel and delete the last message and check the last message in the sidebar', async ({
page,
}) => {
const channelName = faker.string.uuid();

// Enable Sidebar Extended display mode
await poHomeChannel.sidenav.setDisplayMode('Extended');

// Create private channel
await poHomeChannel.sidenav.openNewByLabel('Channel');
await poHomeChannel.sidenav.inputChannelName.fill(channelName);
await poHomeChannel.sidenav.btnCreate.click();
await expect(page).toHaveURL(`/group/${channelName}`);
await expect(poHomeChannel.toastSuccess).toBeVisible();
await poHomeChannel.dismissToast();

// Send Unencrypted Messages
await poHomeChannel.content.sendMessage('first unencrypted message');
await poHomeChannel.content.sendMessage('second unencrypted message');

// Encrypt channel
await poHomeChannel.tabs.kebab.click({ force: true });
await expect(poHomeChannel.tabs.btnEnableE2E).toBeVisible();
await poHomeChannel.tabs.btnEnableE2E.click({ force: true });
await page.waitForTimeout(1000);
await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible();

// Send Encrypted Messages
const encriptedMessage1 = 'first ENCRYPTED message';
const encriptedMessage2 = 'second ENCRYPTED message';
await poHomeChannel.content.sendMessage(encriptedMessage1);
await poHomeChannel.content.sendMessage(encriptedMessage2);

// Delete last message
await expect(poHomeChannel.content.lastUserMessageBody).toHaveText(encriptedMessage2);
await poHomeChannel.content.openLastMessageMenu();
await page.locator('role=menuitem[name="Delete"]').click();
await page.locator('#modal-root .rcx-button-group--align-end .rcx-button--danger').click();

// Check last message in the sidebar
const sidebarChannel = await poHomeChannel.sidenav.getSidebarItemByName(channelName);
await expect(sidebarChannel).toBeVisible();
await expect(sidebarChannel.locator('span')).toContainText(encriptedMessage1);
});

test.describe('reset keys', () => {
let anotherClientPage: Page;

Expand Down
40 changes: 38 additions & 2 deletions apps/meteor/tests/e2e/page-objects/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' });
}
}
6 changes: 6 additions & 0 deletions apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ export class HomeSidenav {
return this.page.getByRole('toolbar', { name: 'Sidebar actions' });
}

async setDisplayMode(mode: 'Extended' | 'Medium' | 'Condensed'): Promise<void> {
await this.sidebarToolbar.getByRole('button', { name: 'Display' }).click();
await this.sidebarToolbar.getByRole('menuitemcheckbox', { name: mode }).click();
await this.sidebarToolbar.click();
}

// Note: this is different from openChat because queued chats are not searchable
getQueuedChat(name: string): Locator {
return this.page.locator('[data-qa="sidebar-item-title"]', { hasText: name }).first();
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/tests/e2e/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './create-target-channel';
export * from './setSettingValueById';
export * from './getSettingValueById';
1 change: 1 addition & 0 deletions packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/model-typings/src/models/IMessagesModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export interface IMessagesModel extends IBaseModel<IMessage> {
updateAllUsernamesByUserId(userId: string, username: string): Promise<UpdateResult | Document>;

setUrlsById(_id: string, urls: NonNullable<IMessage['urls']>): Promise<UpdateResult>;
getLastVisibleMessageSentWithNoTypeByRoomId(rid: string, messageId?: string): Promise<IMessage | null>;
getLastVisibleUserMessageSentByRoomId(rid: string, messageId?: string): Promise<IMessage | null>;

findOneBySlackTs(slackTs: Date): Promise<IMessage | null>;

Expand Down

0 comments on commit cef7e25

Please sign in to comment.