From 7d7b203567611316edc6418186c8d0530b43c82a Mon Sep 17 00:00:00 2001 From: M-ZubairAhmed Date: Wed, 22 May 2024 14:08:41 +0000 Subject: [PATCH] [MM-58108] Posts missing channel_id in handleThreadReadChanged, handleAllThreadsInChannelMarkedRead, getThreadItemsInChannel (#27006) --- .../src/actions/websocket_actions.jsx | 4 +- .../mattermost-redux/src/actions/threads.ts | 64 ++++++++++--------- .../src/selectors/entities/threads.test.ts | 34 ++++------ .../src/selectors/entities/threads.ts | 29 ++++----- .../mattermost-redux/test/test_helper.ts | 18 ++++++ 5 files changed, 78 insertions(+), 71 deletions(-) diff --git a/webapp/channels/src/actions/websocket_actions.jsx b/webapp/channels/src/actions/websocket_actions.jsx index 8184cf178b..27f779e547 100644 --- a/webapp/channels/src/actions/websocket_actions.jsx +++ b/webapp/channels/src/actions/websocket_actions.jsx @@ -1632,9 +1632,9 @@ function handleThreadReadChanged(msg) { ), ); } else if (msg.broadcast.channel_id) { - handleAllThreadsInChannelMarkedRead(doDispatch, doGetState, msg.broadcast.channel_id, msg.data.timestamp); + doDispatch(handleAllThreadsInChannelMarkedRead(msg.broadcast.channel_id, msg.data.timestamp)); } else { - handleAllMarkedRead(doDispatch, msg.broadcast.team_id); + doDispatch(handleAllMarkedRead(msg.broadcast.team_id)); } }; } diff --git a/webapp/channels/src/packages/mattermost-redux/src/actions/threads.ts b/webapp/channels/src/packages/mattermost-redux/src/actions/threads.ts index 6d3e56bfd7..0ed0020d26 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/actions/threads.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/actions/threads.ts @@ -16,7 +16,7 @@ import {getChannel} from 'mattermost-redux/selectors/entities/channels'; import {makeGetPostsForThread} from 'mattermost-redux/selectors/entities/posts'; import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences'; import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; -import {getThread as getThreadSelector, getThreadItemsInChannel} from 'mattermost-redux/selectors/entities/threads'; +import {getThread as getThreadSelector, getThreadsInChannel} from 'mattermost-redux/selectors/entities/threads'; import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; import type {DispatchFunc, GetStateFunc, ActionFunc, ActionFuncAsync} from 'mattermost-redux/types/actions'; @@ -248,13 +248,13 @@ export function getThread(userId: string, teamId: string, threadId: string, exte }; } -export function handleAllMarkedRead(dispatch: DispatchFunc, teamId: string) { - dispatch({ +export function handleAllMarkedRead(teamId: string) { + return { type: ThreadTypes.ALL_TEAM_THREADS_READ, data: { team_id: teamId, }, - }); + }; } export function markAllThreadsInTeamRead(userId: string, teamId: string): ActionFuncAsync { @@ -267,7 +267,7 @@ export function markAllThreadsInTeamRead(userId: string, teamId: string): Action return {error}; } - handleAllMarkedRead(dispatch, teamId); + dispatch(handleAllMarkedRead(teamId)); return {}; }; @@ -395,32 +395,38 @@ export function setThreadFollow(userId: string, teamId: string, threadId: string }; } -export function handleAllThreadsInChannelMarkedRead(dispatch: DispatchFunc, getState: GetStateFunc, channelId: string, lastViewedAt: number) { - const state = getState(); - const threadsInChannel = getThreadItemsInChannel(state, channelId); - const channel = getChannel(state, channelId); - if (channel == null) { - return; - } - const teamId = channel.team_id; - const actions = []; +export function handleAllThreadsInChannelMarkedRead(channelId: string, lastViewedAt: number): ActionFunc { + return (dispatch, getState) => { + const state = getState(); - for (const thread of threadsInChannel) { - actions.push({ - type: ThreadTypes.READ_CHANGED_THREAD, - data: { - id: thread.id, - channelId, - teamId, - lastViewedAt, - newUnreadMentions: 0, - newUnreadReplies: 0, - isUrgent: thread.is_urgent, - }, - }); - } + const channel = getChannel(state, channelId); + if (channel == null) { + return {data: false}; + } - dispatch(batchActions(actions)); + const teamId = channel.team_id; + const threadsInChannel = getThreadsInChannel(state, channelId); + + const actions = []; + for (const thread of threadsInChannel) { + actions.push({ + type: ThreadTypes.READ_CHANGED_THREAD, + data: { + id: thread.id, + channelId, + teamId, + lastViewedAt, + newUnreadMentions: 0, + newUnreadReplies: 0, + isUrgent: thread.is_urgent, + }, + }); + } + + dispatch(batchActions(actions)); + + return {data: true}; + }; } export function decrementThreadCounts(post: ExtendedPost): ActionFunc { diff --git a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/threads.test.ts b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/threads.test.ts index 705ad349da..27c02f04f3 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/threads.test.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/threads.test.ts @@ -189,6 +189,10 @@ describe('Selectors.Threads.getThreadsInChannel', () => { it('should return threads in channel', () => { const user = TestHelper.fakeUserWithId(); + const thread1 = TestHelper.fakeThread(user.id, channel1.id); + const thread2 = TestHelper.fakeThread(user.id, channel1.id); + const thread3 = TestHelper.fakeThread(user.id, channel2.id); + const thread4 = TestHelper.fakeThread(user.id, channel3.id); const profiles = { [user.id]: user, @@ -205,36 +209,20 @@ describe('Selectors.Threads.getThreadsInChannel', () => { }, threads: { threads: { - a: { - post: { - channel_id: channel1.id, - }, - }, - b: { - post: { - channel_id: channel1.id, - }, - }, - c: { - post: { - channel_id: channel2.id, - }, - }, - d: { - post: { - channel_id: channel3.id, - }, - }, + [thread1.id]: thread1, + [thread2.id]: thread2, + [thread3.id]: thread3, + [thread4.id]: thread4, }, threadsInTeam: { - [team1.id]: ['a', 'b', 'c'], - [team2.id]: ['d'], + [team1.id]: [thread1.id, thread2.id, thread3.id], + [team2.id]: [thread4.id], }, }, }, }); - expect(Selectors.getThreadsInChannel(testState, channel1.id)).toEqual(['a', 'b']); + expect(Selectors.getThreadsInChannel(testState, channel1.id)).toEqual([thread1, thread2]); }); }); diff --git a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/threads.ts b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/threads.ts index beaf0cebd5..518c49c7b6 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/threads.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/threads.ts @@ -176,25 +176,20 @@ function sortByLastReply(ids: Array, threads: ReturnType Array = createSelector( +) => UserThread[] = createSelector( 'getThreadsInChannel', getThreads, - (state: GlobalState, channelID: string) => channelID, - (allThreads: IDMappedObjects, channelID: string) => { - return Object.keys(allThreads).filter((id) => allThreads[id].post.channel_id === channelID); - }, -); + (_: GlobalState, channelID: string) => channelID, + (threads: IDMappedObjects, channelID: Channel['id']) => { + const allThreads = Object.values(threads); -export const getThreadItemsInChannel: ( - state: GlobalState, - channelID: string, -) => UserThread[] = createSelector( - 'getThreadItemsInChannel', - getThreads, - (state: GlobalState, channelID: string) => channelID, - (allThreads: IDMappedObjects, channelID: Channel['id']) => { - return Object.keys(allThreads). - map((id) => allThreads[id]). - filter((item) => item.post.channel_id === channelID); + const threadsInChannel: UserThread[] = []; + for (const thread of allThreads) { + if (thread && thread.post && thread.post.channel_id && thread.post.channel_id === channelID) { + threadsInChannel.push(thread); + } + } + + return threadsInChannel; }, ); diff --git a/webapp/channels/src/packages/mattermost-redux/test/test_helper.ts b/webapp/channels/src/packages/mattermost-redux/test/test_helper.ts index d795fbaa45..53b9866252 100644 --- a/webapp/channels/src/packages/mattermost-redux/test/test_helper.ts +++ b/webapp/channels/src/packages/mattermost-redux/test/test_helper.ts @@ -16,6 +16,7 @@ import type {Reaction} from '@mattermost/types/reactions'; import type {Role} from '@mattermost/types/roles'; import type {Scheme} from '@mattermost/types/schemes'; import type {Team, TeamMembership} from '@mattermost/types/teams'; +import type {UserThread} from '@mattermost/types/threads'; import type {UserProfile, UserNotifyProps} from '@mattermost/types/users'; export const DEFAULT_SERVER = 'http://localhost:8065'; @@ -553,6 +554,23 @@ class TestHelper { }; }; + fakeThread = (userId: string, channelId: string, override?: Partial): UserThread => { + return { + id: this.generateId(), + reply_count: 0, + last_reply_at: 0, + last_viewed_at: 0, + participants: [], + unread_replies: 0, + unread_mentions: 0, + is_following: true, + post: { + channel_id: channelId, + user_id: userId, + }, + ...override, + }; + }; getFileInfoMock = (override: Partial): FileInfo => { return { id: '',