[NEW] Direct link to a threaded conversation (#3406)

* [FIX] deeplinking to thread

* fix how to find threadId

* tmid as route params jumpToThreaId

* minor tweak

* minor tweak on logic

* E2E Test

* minor tweak

* wait for the return of the thread

* Minor refactor

* Fix e2e tests for docker

* popToRoot when focused and there is a jumpToThread

Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
Reinaldo Neto 2021-10-26 13:11:50 -03:00 committed by GitHub
parent 72d50887a4
commit 2ab1bacdb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 8 deletions

View File

@ -45,8 +45,10 @@ const navigate = function* navigate({ params }) {
if (params.path || params.rid) {
let type;
let name;
let jumpToThreadId;
if (params.path) {
[type, name] = params.path.split('/');
// Following this pattern: {channelType}/{channelName}/thread/{threadId}
[type, name, , jumpToThreadId] = params.path.split('/');
}
if (type !== 'invite' || params.rid) {
const room = yield RocketChat.canOpenRoom(params);
@ -65,14 +67,19 @@ const navigate = function* navigate({ params }) {
if (focusedRooms.includes(room.rid)) {
// if there's one room on the list or last room is the one
if (focusedRooms.length === 1 || focusedRooms[0] === room.rid) {
yield goRoom({ item, isMasterDetail, jumpToMessageId });
if (jumpToThreadId) {
// With this conditional when there is a jumpToThreadId we can avoid the thread open again
// above other thread and the room could call again the thread
popToRoot({ isMasterDetail });
}
yield goRoom({ item, isMasterDetail, jumpToMessageId, jumpToThreadId });
} else {
popToRoot({ isMasterDetail });
yield goRoom({ item, isMasterDetail, jumpToMessageId });
yield goRoom({ item, isMasterDetail, jumpToMessageId, jumpToThreadId });
}
} else {
popToRoot({ isMasterDetail });
yield goRoom({ item, isMasterDetail, jumpToMessageId });
yield goRoom({ item, isMasterDetail, jumpToMessageId, jumpToThreadId });
}
if (params.isCall) {

View File

@ -149,6 +149,7 @@ class RoomView extends React.Component {
prid
};
this.jumpToMessageId = props.route.params?.jumpToMessageId;
this.jumpToThreadId = props.route.params?.jumpToThreadId;
const roomUserId = props.route.params?.roomUserId ?? RocketChat.getUidDirectMessage(room);
this.state = {
joined: true,
@ -209,6 +210,9 @@ class RoomView extends React.Component {
if (this.jumpToMessageId) {
this.jumpToMessage(this.jumpToMessageId);
}
if (this.jumpToThreadId && !this.jumpToMessageId) {
this.navToThread({ tmid: this.jumpToThreadId });
}
if (isIOS && this.rid) {
this.updateUnreadCount();
}
@ -254,6 +258,10 @@ class RoomView extends React.Component {
this.jumpToMessage(route?.params?.jumpToMessageId);
}
if (route?.params?.jumpToThreadId !== prevProps.route?.params?.jumpToThreadId) {
this.navToThread({ tmid: route?.params?.jumpToThreadId });
}
if (appState === 'foreground' && appState !== prevProps.appState && this.rid) {
// Fire List.query() just to keep observables working
if (this.list && this.list.current) {
@ -872,7 +880,12 @@ class RoomView extends React.Component {
if (item.tmid) {
let name = item.tmsg;
if (!name) {
name = await this.getThreadName(item.tmid, item.id);
const result = await this.getThreadName(item.tmid, item.id);
// test if there isn't a thread
if (!result) {
return;
}
name = result;
}
if (item.t === E2E_MESSAGE_TYPE && item.e2e !== E2E_STATUS.DONE) {
name = I18n.t('Encrypted_message');

View File

@ -44,6 +44,9 @@ const data = {
},
alternate: {
name: `detox-alternate-${value}`
},
alternate2: {
name: `detox-alternate2-${value}`
}
},
teams: {

View File

@ -45,6 +45,9 @@ const data = {
},
alternate: {
name: `detox-alternate-${value}`
},
alternate2: {
name: `detox-alternate2-${value}`
}
},
teams: {

View File

@ -116,11 +116,12 @@ const changeChannelJoinCode = async (roomId, joinCode) => {
}
};
const sendMessage = async (user, channel, msg) => {
const sendMessage = async (user, channel, msg, tmid) => {
console.log(`Sending message to ${channel}`);
try {
await login(user.username, user.password);
await rocketchat.post('chat.postMessage', { channel, msg });
const response = await rocketchat.post('chat.postMessage', { channel, msg, tmid });
return response.data;
} catch (infoError) {
console.log(JSON.stringify(infoError));
throw new Error('Failed to find or create private group');

View File

@ -1,6 +1,6 @@
const data = require('../../data');
const { tapBack, checkServer, navigateToRegister } = require('../../helpers/app');
const { get, login } = require('../../helpers/data_setup');
const { get, login, sendMessage } = require('../../helpers/data_setup');
const DEEPLINK_METHODS = { AUTH: 'auth', ROOM: 'room' };
const getDeepLink = (method, server, params) => {
@ -12,9 +12,15 @@ const getDeepLink = (method, server, params) => {
describe('Deep linking', () => {
let userId;
let authToken;
let threadId;
const threadMessage = `to-thread-${data.random}`;
before(async () => {
const loginResult = await login(data.users.regular.username, data.users.regular.password);
({ userId, authToken } = loginResult);
// create a thread with api
const result = await sendMessage(data.users.regular, data.groups.alternate2.name, threadMessage);
threadId = result.message._id;
await sendMessage(data.users.regular, result.message.rid, data.random, threadId);
});
describe('Authentication', () => {
@ -87,6 +93,18 @@ describe('Deep linking', () => {
.withTimeout(10000);
});
it('should navigate to the thread using path', async () => {
await device.launchApp({
permissions: { notifications: 'YES' },
newInstance: true,
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `path=group/${data.groups.alternate2.name}/thread/${threadId}`),
sourceApp: 'com.apple.mobilesafari'
});
await waitFor(element(by.id(`room-view-title-${threadMessage}`)))
.toExist()
.withTimeout(10000);
});
it('should navigate to the room using rid', async () => {
const roomResult = await get(`groups.info?roomName=${data.groups.private.name}`);
await device.launchApp({