[MM-54021][MM-58736] Remove limit on loading channel members on initial load, reload members on reconnect, separate loading of members from channels on initial load (#28310)

* [MM-54021][MM-58736] Remove limit on loading channel members on initial load, reload members on reconnect, separate loading of members from channels on initial load

* PR feedback

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Devin Binnie
2024-10-07 09:13:31 -04:00
коммит произвёл GitHub
родитель 2b7b4100d2
Коммит ed4cab7aa2
7 изменённых файлов: 71 добавлений и 39 удалений

Просмотреть файл

@@ -31,6 +31,7 @@ import {
getChannelStats,
markMultipleChannelsAsRead,
getChannelMemberCountsByGroup,
fetchAllMyChannelMembers,
} from 'mattermost-redux/actions/channels';
import {getCloudSubscription} from 'mattermost-redux/actions/cloud';
import {clearErrors, logError} from 'mattermost-redux/actions/errors';
@@ -235,6 +236,7 @@ export function reconnect() {
}
dispatch(loadChannelsForCurrentUser());
dispatch(fetchAllMyChannelMembers());
if (mostRecentPost) {
dispatch(syncPostsInChannel(currentChannelId, mostRecentPost.create_at));

Просмотреть файл

@@ -62,6 +62,7 @@ jest.mock('mattermost-redux/actions/users', () => ({
jest.mock('mattermost-redux/actions/channels', () => ({
getChannelStats: jest.fn(() => ({type: 'GET_CHANNEL_STATS'})),
fetchAllMyChannelMembers: jest.fn(() => ({type: 'FETCH_ALL_MY_CHANNEL_MEMBERS'})),
}));
jest.mock('actions/post_actions', () => ({

Просмотреть файл

@@ -13,7 +13,7 @@ import type {UserProfile} from '@mattermost/types/users';
import type {RelationOneToOne} from '@mattermost/types/utilities';
import {UserTypes} from 'mattermost-redux/action_types';
import {fetchAllMyTeamsChannelsAndChannelMembersREST, searchAllChannels} from 'mattermost-redux/actions/channels';
import {fetchAllMyTeamsChannels, searchAllChannels} from 'mattermost-redux/actions/channels';
import {logError} from 'mattermost-redux/actions/errors';
import {Client4} from 'mattermost-redux/client';
import {Preferences} from 'mattermost-redux/constants';
@@ -838,12 +838,12 @@ export default class SwitchChannelProvider extends Provider {
if (!teamId) {
return;
}
const channelsAsync = this.store.dispatch(fetchAllMyTeamsChannelsAndChannelMembersREST());
const channelsAsync = this.store.dispatch(fetchAllMyTeamsChannels());
let channels;
try {
const {data} = await channelsAsync;
channels = data.channels as Channel[];
channels = data as Channel[];
} catch (err) {
this.store.dispatch(logError(err));
return;

Просмотреть файл

@@ -5,7 +5,7 @@ import {connect} from 'react-redux';
import type {ConnectedProps} from 'react-redux';
import type {RouteComponentProps} from 'react-router-dom';
import {fetchAllMyTeamsChannelsAndChannelMembersREST, fetchChannelsAndMembers, unsetActiveChannelOnServer} from 'mattermost-redux/actions/channels';
import {fetchAllMyTeamsChannels, fetchAllMyChannelMembers, fetchChannelsAndMembers, unsetActiveChannelOnServer} from 'mattermost-redux/actions/channels';
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
import {getLicense, getConfig} from 'mattermost-redux/selectors/entities/general';
import {getCurrentTeamId, getMyTeams} from 'mattermost-redux/selectors/entities/teams';
@@ -53,7 +53,8 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
const mapDispatchToProps = {
fetchChannelsAndMembers,
fetchAllMyTeamsChannelsAndChannelMembersREST,
fetchAllMyTeamsChannels,
fetchAllMyChannelMembers,
markAsReadOnFocus,
initializeTeam,
joinTeam,

Просмотреть файл

@@ -55,13 +55,14 @@ function TeamController(props: Props) {
useEffect(() => {
InitialLoadingScreen.stop();
async function fetchInitialChannels() {
await props.fetchAllMyTeamsChannelsAndChannelMembersREST();
async function fetchAllChannels() {
await props.fetchAllMyTeamsChannels();
setInitialChannelsLoaded(true);
}
fetchInitialChannels();
props.fetchAllMyChannelMembers();
fetchAllChannels();
}, []);
useEffect(() => {

Просмотреть файл

@@ -2088,4 +2088,27 @@ describe('Actions.Channels', () => {
expect(channelMemberCounts['group-2'].channel_member_count).toEqual(999);
expect(channelMemberCounts['group-2'].channel_member_timezones_count).toEqual(131);
});
it('fetchAllMyChannelMembers', async () => {
const store = configureStore({
entities: {
users: {
currentUserId: 'some-user-id',
},
},
});
nock(Client4.getBaseRoute()).get(
'/users/some-user-id/channel_members?page=0&per_page=200').
reply(200, [...Array(200).keys()].map((index) => ({channel_id: `channel-${index}`, user_id: 'some-user-id'})));
nock(Client4.getBaseRoute()).get(
'/users/some-user-id/channel_members?page=1&per_page=200').
reply(200, [...Array(200).keys()].map((index) => ({channel_id: `channel-${index + 200}`, user_id: 'some-user-id'})));
nock(Client4.getBaseRoute()).get(
'/users/some-user-id/channel_members?page=2&per_page=200').
reply(200, [...Array(100).keys()].map((index) => ({channel_id: `channel-${index + 400}`, user_id: 'some-user-id'})));
await store.dispatch(Actions.fetchAllMyChannelMembers());
expect(Object.keys(store.getState().entities.channels.myMembers).length).toBe(500);
});
});

Просмотреть файл

@@ -464,32 +464,43 @@ export function fetchChannelsAndMembers(teamId: string): ActionFuncAsync<{channe
};
}
export function fetchAllMyTeamsChannelsAndChannelMembersREST(): ActionFuncAsync {
export function fetchAllMyChannelMembers(): ActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
const {currentUserId} = state.entities.users;
let channels;
let channelsMembers: ChannelMembership[] = [];
let allMembers = true;
let hasMoreMembers = true;
let page = 0;
do {
try {
try {
while (hasMoreMembers) {
// Expected to disable since we don't have number of pages, so we can't use Promise.all
// eslint-disable-next-line no-await-in-loop
await Client4.getAllChannelsMembers(currentUserId, page, 200).then(
// eslint-disable-next-line no-loop-func
(data) => {
channelsMembers = [...channelsMembers, ...data];
page++;
if (data.length < 200) {
allMembers = false;
}
});
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error));
return {error};
const data = await Client4.getAllChannelsMembers(currentUserId, page, 200);
channelsMembers = [...channelsMembers, ...data];
if (data.length < 200) {
hasMoreMembers = false;
}
page++;
}
} while (allMembers && page <= 2);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error));
return {error};
}
dispatch({
type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS,
data: channelsMembers,
currentUserId,
});
return {data: channelsMembers};
};
}
export function fetchAllMyTeamsChannels(): ActionFuncAsync {
return async (dispatch, getState) => {
let channels;
try {
channels = await Client4.getAllTeamsChannels();
} catch (error) {
@@ -498,18 +509,11 @@ export function fetchAllMyTeamsChannelsAndChannelMembersREST(): ActionFuncAsync
return {error};
}
dispatch(batchActions([
{
type: ChannelTypes.RECEIVED_ALL_CHANNELS,
data: channels,
},
{
type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS,
data: channelsMembers,
currentUserId,
},
]));
return {data: {channels, channelsMembers}};
dispatch({
type: ChannelTypes.RECEIVED_ALL_CHANNELS,
data: channels,
});
return {data: channels};
};
}