Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/olive-pens-think.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixes incorrect URL generation in Global Search "Jump to message" feature, resolving navigation issues when jumping to messages across different channels.
10 changes: 5 additions & 5 deletions apps/meteor/client/lib/rooms/roomCoordinator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,18 @@ class RoomCoordinatorClient extends RoomCoordinator {
roomType: RoomType,
subData: RoomIdentification,
queryParams?: Record<string, string>,
options: { replace?: boolean } = {},
options: { replace?: boolean; routeParamsOverrides?: Record<string, string> } = {},
): void {
const config = this.getRoomTypeConfig(roomType);
if (!config?.route) {
return;
}

let routeData = {};
let _routeData = {};
if (config.route.link) {
routeData = config.route.link(subData);
_routeData = config.route.link(subData);
} else if (subData?.name) {
routeData = {
_routeData = {
name: subData.name,
};
} else {
Expand All @@ -88,7 +88,7 @@ class RoomCoordinatorClient extends RoomCoordinator {
router.navigate(
{
pattern: config.route.path ?? '/home',
params: routeData,
params: { ..._routeData, ...options.routeParamsOverrides },
search: queryParams,
},
options,
Expand Down
11 changes: 8 additions & 3 deletions apps/meteor/client/lib/utils/goToRoomById.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@ import { roomCoordinator } from '../rooms/roomCoordinator';

const getRoomById = memoize((rid: IRoom['_id']) => callWithErrorHandling('getRoomById', rid));

export const goToRoomById = async (rid: IRoom['_id']): Promise<void> => {
export type GoToRoomByIdOptions = {
replace?: boolean;
routeParamsOverrides?: Record<string, string>;
};

export const goToRoomById = async (rid: IRoom['_id'], options: GoToRoomByIdOptions = {}): Promise<void> => {
if (!rid) {
return;
}

const subscription = Subscriptions.state.find((record) => record.rid === rid);

if (subscription) {
roomCoordinator.openRouteLink(subscription.t, subscription, router.getSearchParameters());
roomCoordinator.openRouteLink(subscription.t, subscription, router.getSearchParameters(), options);
return;
}

const room = await getRoomById(rid);
roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }, router.getSearchParameters());
roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }, router.getSearchParameters(), options);
};
23 changes: 5 additions & 18 deletions apps/meteor/client/lib/utils/legacyJumpToMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { isThreadMessage } from '@rocket.chat/core-typings';
import { goToRoomById } from './goToRoomById';
import { RoomHistoryManager } from '../../../app/ui-utils/client';
import { router } from '../../providers/RouterProvider';
import { Rooms } from '../../stores';
import { RoomManager } from '../RoomManager';

/** @deprecated */
Expand All @@ -15,24 +14,12 @@ export const legacyJumpToMessage = async (message: IMessage) => {
if (tab === 'thread' && (context === message.tmid || context === message._id)) {
return;
}
router.navigate(
{
name: router.getRouteName()!,
params: {
tab: 'thread',
context: message.tmid || message._id,
rid: message.rid,
name: Rooms.state.get(message.rid)?.name ?? '',
},
search: {
...router.getSearchParameters(),
msg: message._id,
},
},
{ replace: false },
);
await RoomHistoryManager.getSurroundingMessages(message);

await goToRoomById(message.rid, {
routeParamsOverrides: { tab: 'thread', context: message.tmid || message._id },
replace: RoomManager.opened === message.rid,
});
await RoomHistoryManager.getSurroundingMessages(message);
return;
}

Expand Down
78 changes: 78 additions & 0 deletions apps/meteor/tests/e2e/global-search.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { IMessage } from '@rocket.chat/core-typings';
import { Random } from '@rocket.chat/random';

import { Users } from './fixtures/userStates';
import { HomeChannel } from './page-objects';
import { setSettingValueById } from './utils';
import type { BaseTest } from './utils/test';
import { expect, test } from './utils/test';

test.use({ storageState: Users.admin.state });

test.describe.serial('Global Search', () => {
let targetChannel: { name: string; _id: string };
let targetGroup: { name: string; _id: string };
let threadMessage: IMessage;
let poHomeChannel: HomeChannel;

const fillMessages = async (api: BaseTest['api']) => {
const { message: parentMessage } = await (
await api.post('/chat.postMessage', { roomId: targetChannel._id, text: 'This is main message in channel' })
).json();

const { message: childMessage } = await (
await api.post('/chat.postMessage', { roomId: targetChannel._id, text: `This is thread message in channel`, tmid: parentMessage._id })
).json();
threadMessage = childMessage;
};

test.beforeAll(async ({ api }) => {
await Promise.all([
api
.post('/channels.create', { name: Random.id() })
.then((res) => res.json())
.then((data) => {
targetChannel = data.channel;
}),
api
.post('/groups.create', {
name: Random.id(),
extraData: { encrypted: false },
})
.then((res) => res.json())
.then((data) => {
targetGroup = data.group;
}),
setSettingValueById(api, 'Search.defaultProvider.GlobalSearchEnabled', true),
]);
await fillMessages(api);
});

test.afterAll(({ api }) =>
Promise.all([
api.post('/channels.delete', { roomId: targetChannel._id }),
api.post('/groups.delete', { roomId: targetGroup._id }),
setSettingValueById(api, 'Search.defaultProvider.GlobalSearchEnabled', false),
]),
);

test.beforeEach(async ({ page }) => {
poHomeChannel = new HomeChannel(page);
await page.goto('/home');
});

test('should open the correct message when jumping from global search in group to channel thread', async ({ page }) => {
await poHomeChannel.sidenav.openChat(targetGroup.name);
await poHomeChannel.roomToolbar.btnSearchMessages.click();

await poHomeChannel.tabs.searchMessages.search(threadMessage.msg.slice(10), { global: true }); // fill partial text to match search

const message = await poHomeChannel.tabs.searchMessages.getResultItem(threadMessage.msg);
await message.hover();
const jumpToMessageButton = message.getByRole('button', { name: 'Jump to message' });
await jumpToMessageButton.click();

await expect(page.locator('header').getByRole('button').filter({ hasText: targetChannel.name })).toBeVisible(); // match channel name in room header
await expect(page.getByText(threadMessage.msg)).toBeVisible();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { HomeFlextabNotificationPreferences } from './home-flextab-notificationP
import { HomeFlextabOtr } from './home-flextab-otr';
import { HomeFlextabPruneMessages } from './home-flextab-pruneMessages';
import { HomeFlextabRoom } from './home-flextab-room';
import { SearchMessagesFlexTab } from './searchMessages-flextab';

export class HomeFlextab {
private readonly page: Page;
Expand All @@ -25,6 +26,8 @@ export class HomeFlextab {

readonly pruneMessages: HomeFlextabPruneMessages;

readonly searchMessages: SearchMessagesFlexTab;

constructor(page: Page) {
this.page = page;
this.members = new HomeFlextabMembers(page);
Expand All @@ -34,6 +37,7 @@ export class HomeFlextab {
this.otr = new HomeFlextabOtr(page);
this.exportMessages = new ExportMessagesTab(page);
this.pruneMessages = new HomeFlextabPruneMessages(page);
this.searchMessages = new SearchMessagesFlexTab(page);
}

get toolbarPrimaryActions(): Locator {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Page } from '@playwright/test';

import { FlexTab } from './flextab';

export class SearchMessagesFlexTab extends FlexTab {
constructor(page: Page) {
super(page.getByRole('dialog', { name: 'Search Messages' }));
}

async search(text: string, { global = false }: { global?: boolean } = {}) {
if (global) {
await this.root.getByText('Global search').click();
}
await this.root.getByPlaceholder('Search Messages').fill(text);
}

async getResultItem(messageText: string) {
return this.root.getByRole('listitem', { name: messageText });
}
}
4 changes: 4 additions & 0 deletions apps/meteor/tests/e2e/page-objects/fragments/toolbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export class RoomToolbar extends Toolbar {
return this.root.getByRole('button', { name: 'Options' });
}

get btnSearchMessages(): Locator {
return this.root.getByRole('button', { name: 'Search Messages' });
}

get btnDisableE2EEncryption(): Locator {
return this.root.getByRole('button', { name: 'Disable E2E encryption' });
}
Expand Down
Loading