[MM-54879] Goodbye, GraphQL -- Regards Webapp (#24850)

Этот коммит содержится в:
M-ZubairAhmed
2023-10-12 17:03:13 +05:30
коммит произвёл GitHub
родитель cd4d220a21
Коммит 760dfe41f9
28 изменённых файлов: 89 добавлений и 889 удалений

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

@@ -694,7 +694,6 @@ const defaultServerConfig: AdminConfig = {
PermalinkPreviews: false,
CallsEnabled: true,
NormalizeLdapDNs: false,
GraphQL: false,
PostPriority: false,
WysiwygEditor: false,
OnboardingTourTips: true,

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

@@ -1,27 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import nock from 'nock';
import type {Channel} from '@mattermost/types/channels';
import type {Role} from '@mattermost/types/roles';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {Client4} from 'mattermost-redux/client';
import {
searchMoreChannels,
addUsersToChannel,
openDirectChannelToUserId,
openGroupChannelToUserIds,
loadChannelsForCurrentUser, fetchChannelsAndMembers,
loadChannelsForCurrentUser,
} from 'actions/channel_actions';
import {CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE} from 'actions/channel_queries';
import {loadProfilesForSidebar} from 'actions/user_actions';
import configureStore from 'store';
import TestHelper from 'packages/mattermost-redux/test/test_helper';
import mockStore from 'tests/test_store';
const initialState = {
@@ -116,7 +104,7 @@ const initialState = {
const realDateNow = Date.now;
jest.mock('mattermost-redux/actions/channels', () => ({
fetchMyChannelsAndMembersREST: (...args: any) => ({type: 'MOCK_FETCH_CHANNELS_AND_MEMBERS', args}),
fetchChannelsAndMembers: (...args: any) => ({type: 'MOCK_FETCH_CHANNELS_AND_MEMBERS', args}),
searchChannels: () => {
return {
type: 'MOCK_SEARCH_CHANNELS',
@@ -281,217 +269,5 @@ describe('Actions.Channel', () => {
await testStore.dispatch(openGroupChannelToUserIds(fakeData.userIds));
expect(testStore.getActions()).toEqual(expectedActions);
});
describe('fetchChannelsAndMembers', () => {
let role1: Role;
let role2: Role;
beforeAll(() => {
TestHelper.initBasic(Client4);
role1 = TestHelper.basicRoles?.system_admin as Role;
role2 = TestHelper.basicRoles?.system_user as Role;
});
afterEach(() => {
nock.cleanAll();
});
afterAll(() => {
TestHelper.tearDown();
});
test('should throws error when response errors out', async () => {
const store = configureStore();
nock(Client4.getGraphQLUrl()).
post('').reply(200, {
errors: [{message: 'some error'}],
});
const result = await store.dispatch(fetchChannelsAndMembers());
expect(Object.keys(result)).toEqual(['error']);
});
test('should throws error when response is not correct', async () => {
[null, undefined, {}].
forEach(async (dataResponse) => {
const store = configureStore();
nock(Client4.getGraphQLUrl()).
post('').reply(200, {
data: dataResponse,
});
const result = await store.dispatch(fetchChannelsAndMembers());
expect(Object.keys(result)).toEqual(['error']);
});
});
test('should throws not throw error when responses are empty', async () => {
[[[], []], [[fakeGQLChannelWithId('team1')], []], [[], [fakeGQLChannelMember('user1', 'channel2', [role1])]]].
forEach(async ([channelResponse, channelMemberResponse]) => {
const store = configureStore();
nock(Client4.getGraphQLUrl()).
post('').
reply(200, {
data: {
channels: [...channelResponse],
channelMembers: [...channelMemberResponse],
},
});
const result = await store.dispatch(fetchChannelsAndMembers());
expect(Object.keys(result)).not.toEqual(['error']);
});
});
test('should return correct channels, channel members and roles when under max limit', async () => {
const store = configureStore();
const perPage = Math.floor(CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE / 2);
const channels = [];
for (let i = 1; i <= perPage; i++) {
channels.push(fakeGQLChannelWithId(`team${i}`));
}
const channelMembers = [];
for (let i = 1; i <= perPage; i++) {
channelMembers.push(fakeGQLChannelMember('user1', `channel${i}`, [role1]));
}
nock(Client4.getGraphQLUrl()).
post('').
reply(200, {
data: {
channels: [...channels],
channelMembers: [...channelMembers],
},
});
const result = await store.dispatch(fetchChannelsAndMembers());
expect(result.data.channels.length).toEqual(perPage);
expect(result.data.channelMembers.length).toEqual(perPage);
// Since we added a single role to each channel member, we should have as many roles as channel members
expect(result.data.roles.length).toEqual(perPage);
});
test('should return correct channels, channel members, roles when responses span across multiple pages', async () => {
const store = configureStore();
const p1Page = CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE;
const p2Page = CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE;
const p3Page = Math.floor(CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE / 2);
const responsesPerPage = [p1Page, p2Page, p3Page];
const totalNumOfResponses = p1Page + p2Page + p3Page;
const channelsResponsePages: any[][] = [];
const channelMembersResponsePages: any[][] = [];
responsesPerPage.forEach((responsePerPage, i) => {
const channelResponsePerPage = [];
const channelMemberResponsePerPage = [];
for (let j = 1; j <= responsePerPage; j++) {
const channel = fakeGQLChannelWithId(`team${i}_${j}`);
channelResponsePerPage.push(channel);
const random0or1 = Math.round(Math.random());
channelMemberResponsePerPage.push(fakeGQLChannelMember('user1', `channel${i}_${j}`, random0or1 === 0 ? [role1, role2] : [role2]));
}
channelsResponsePages.push(channelResponsePerPage);
channelMembersResponsePages.push(channelMemberResponsePerPage);
});
responsesPerPage.forEach((_, i) => {
nock(Client4.getGraphQLUrl()).
post('').
reply(200, {
data: {
channels: [...channelsResponsePages[i]],
channelMembers: [...channelMembersResponsePages[i]],
},
});
});
const result = await store.dispatch(fetchChannelsAndMembers());
expect(result.data.channels.length).toEqual(totalNumOfResponses);
expect(result.data.channelMembers.length).toEqual(totalNumOfResponses);
});
test('should error out when pagination throws errors', async () => {
const store = configureStore();
const p1Page = CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE;
const p2Page = CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE; // so that page 3 will throw an error
const responsesPerPage = [p1Page, p2Page];
const channelsResponsePages: any[][] = [];
const channelMembersResponsePages: any[][] = [];
responsesPerPage.forEach((responsePerPage, i) => {
const channelResponsePerPage = [];
const channelMemberResponsePerPage = [];
for (let j = 1; j <= responsePerPage; j++) {
const channel = fakeGQLChannelWithId(`team${i}_${j}`);
channelResponsePerPage.push(channel);
const random0or1 = Math.round(Math.random());
channelMemberResponsePerPage.push(fakeGQLChannelMember('user1', `channel${i}_${j}`, random0or1 === 0 ? [role1, role2] : [role2]));
}
channelsResponsePages.push(channelResponsePerPage);
channelMembersResponsePages.push(channelMemberResponsePerPage);
});
responsesPerPage.forEach((_, i) => {
nock(Client4.getGraphQLUrl()).
post('').
reply(200, {
data: {
channels: [...channelsResponsePages[i]],
channelMembers: [...channelMembersResponsePages[i]],
},
});
});
// Last page will throw an error
nock(Client4.getGraphQLUrl()).
post('').
reply(200, {
data: {},
errors: [{message: 'some error'}],
});
const result = await store.dispatch(fetchChannelsAndMembers());
expect(Object.keys(result)).toEqual(['error']);
});
function fakeGQLChannelWithId(teamId: Team['id']) {
return Object.assign(TestHelper.fakeChannelWithId(teamId), {
team: {id: teamId},
});
}
function fakeGQLChannelMember(userId: UserProfile['id'], channelId: Channel['id'], roles: Role[] = []) {
return Object.assign(TestHelper.fakeChannelMember(userId, channelId), {
channel: {
id: channelId,
},
user: {
id: userId,
},
roles: [...roles],
});
}
});
});

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

@@ -3,33 +3,19 @@
import {batchActions} from 'redux-batched-actions';
import type {Channel, ChannelMembership, ServerChannel} from '@mattermost/types/channels';
import type {Channel} from '@mattermost/types/channels';
import type {ServerError} from '@mattermost/types/errors';
import type {Role} from '@mattermost/types/roles';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {ChannelTypes, PreferenceTypes, RoleTypes} from 'mattermost-redux/action_types';
import {PreferenceTypes} from 'mattermost-redux/action_types';
import * as ChannelActions from 'mattermost-redux/actions/channels';
import {logError} from 'mattermost-redux/actions/errors';
import {savePreferences} from 'mattermost-redux/actions/preferences';
import {Client4} from 'mattermost-redux/client';
import {getChannelByName, getUnreadChannelIds, getChannel} from 'mattermost-redux/selectors/entities/channels';
import {getMyChannelMemberships} from 'mattermost-redux/selectors/entities/common';
import {getCurrentTeamUrl, getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import type {ActionFunc} from 'mattermost-redux/types/actions';
import {
getChannelsAndChannelMembersQueryString,
transformToReceivedChannelsReducerPayload,
transformToReceivedChannelMembersReducerPayload,
CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE,
} from 'actions/channel_queries';
import type {
ChannelsAndChannelMembersQueryResponseType,
GraphQLChannel,
GraphQLChannelMember} from 'actions/channel_queries';
import {trackEvent} from 'actions/telemetry_actions.jsx';
import {loadNewDMIfNeeded, loadNewGMIfNeeded, loadProfilesForSidebar} from 'actions/user_actions';
@@ -95,7 +81,7 @@ export function loadChannelsForCurrentUser(): ActionFunc {
const state = getState();
const unreads = getUnreadChannelIds(state);
await dispatch(ChannelActions.fetchMyChannelsAndMembersREST(getCurrentTeamId(state)));
await dispatch(ChannelActions.fetchChannelsAndMembers(getCurrentTeamId(state)));
for (const id of unreads) {
const channel = getChannel(state, id);
if (channel && channel.type === Constants.DM_CHANNEL) {
@@ -191,89 +177,3 @@ export function muteChannel(userId: UserProfile['id'], channelId: Channel['id'])
mark_unread: NotificationLevels.MENTION,
});
}
/**
* Fetches channels and channel members with graphql and then dispatches the result to redux store.
* @param teamId If team id is provided, only channels and channel members in that team will be fetched. Otherwise, all channels and all channel members will be fetched.
*/
export function fetchChannelsAndMembers(teamId: Team['id'] = ''): ActionFunc<{channels: ServerChannel[]; channelMembers: ChannelMembership[]}> {
return async (dispatch, getState) => {
const state = getState();
const currentUserId = getCurrentUserId(state);
let channelsResponse: GraphQLChannel[] = [];
let channelMembersResponse: GraphQLChannelMember[] = [];
try {
let channelsCursor = '';
let channelMembersCursor = '';
let page = 1;
let responsesPerPage: number;
do {
// eslint-disable-next-line no-await-in-loop
const {data, errors} = await Client4.fetchWithGraphQL<ChannelsAndChannelMembersQueryResponseType>(getChannelsAndChannelMembersQueryString(teamId, channelsCursor, channelMembersCursor));
if (errors || !data) {
throw new Error(`Failed to fetch channels and channel members at page ${page}`);
} else if (data.channels.length === 0 || data.channelMembers.length === 0) {
break;
}
// Based on the fact that the number of channels and channel members returned by the server is the same
responsesPerPage = data.channels.length;
channelsCursor = data.channels[responsesPerPage - 1].cursor;
channelMembersCursor = data.channelMembers[responsesPerPage - 1].cursor;
page += 1;
channelsResponse = [...channelsResponse, ...data.channels];
channelMembersResponse = [...channelMembersResponse, ...data.channelMembers];
} while (responsesPerPage === CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE);
} catch (error) {
dispatch(logError(error as ServerError));
return {error: error as ServerError};
}
let roles: Role[] = [];
channelMembersResponse.forEach((channelMembers) => {
if (channelMembers?.roles?.length) {
channelMembers.roles.forEach((role) => {
roles = [...roles, role];
});
}
});
const channels = transformToReceivedChannelsReducerPayload(channelsResponse);
const channelMembers = transformToReceivedChannelMembersReducerPayload(channelMembersResponse, currentUserId);
const actions = [];
if (teamId) {
actions.push({
type: ChannelTypes.RECEIVED_CHANNELS,
teamId,
data: channels,
});
actions.push({
type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS,
data: channelMembers,
});
actions.push({
type: RoleTypes.RECEIVED_ROLES,
data: roles,
});
} else {
actions.push({
type: ChannelTypes.RECEIVED_ALL_CHANNELS,
data: channels,
});
actions.push({
type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS,
data: channelMembers,
});
}
await dispatch(batchActions(actions));
return {data: {channels, channelMembers, roles}};
};
}

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

@@ -1,159 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {ChannelMembership, ServerChannel, ChannelType} from '@mattermost/types/channels';
import type {Role} from '@mattermost/types/roles';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {convertRolesNamesArrayToString} from 'mattermost-redux/actions/roles';
export const CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE = 200;
type Cursor = {
cursor: string;
}
export type GraphQLChannel = Omit<ServerChannel, 'team_id'> & Cursor & {
team: Team;
};
export type GraphQLChannelMember = Omit<ChannelMembership, 'channel_id | user_id | roles | post_root_id'> & Cursor & {
channel: ServerChannel;
roles: Role[];
};
export type ChannelsAndChannelMembersQueryResponseType = {
data?: {
channels: GraphQLChannel[];
channelMembers: GraphQLChannelMember[];
};
errors?: unknown;
}
const channelsFragment = `
fragment channelsFragment on Channel {
cursor
id
create_at: createAt
update_at: updateAt
delete_at: deleteAt
team {
id
}
type
display_name: displayName
name
header
purpose
last_post_at: lastPostAt
last_root_post_at: lastRootPostAt
total_msg_count: totalMsgCount
total_msg_count_root: totalMsgCountRoot
creator_id: creatorId
scheme_id: schemeId
group_constrained: groupConstrained
shared
props
policy_id: policyId
}
`;
const channelMembersFragment = `
fragment channelMembersFragment on ChannelMember {
cursor
channel {
id
}
roles {
id
name
permissions
}
last_viewed_at: lastViewedAt
msg_count: msgCount
msg_count_root: msgCountRoot
mention_count: mentionCount
mention_count_root: mentionCountRoot
urgent_mention_count: urgentMentionCount
notify_props: notifyProps
last_update_at: lastUpdateAt
scheme_admin: schemeAdmin
scheme_user: schemeUser
}
`;
const channelsAndChannelMembersQueryString = `
query gqlWebChannelsAndChannelMembers($teamId: String, $perPage: Int!, $channelsCursor: String, $channelMembersCursor: String) {
channels(userId: "me", teamId: $teamId, first: $perPage, after: $channelsCursor) {
...channelsFragment
}
channelMembers(userId: "me", teamId: $teamId, first: $perPage, after: $channelMembersCursor) {
...channelMembersFragment
}
}
${channelsFragment}
${channelMembersFragment}
`;
export function getChannelsAndChannelMembersQueryString(teamId: Team['id'] = '', channelsCursor: Cursor['cursor'] = '', channelMembersCursor: Cursor['cursor'] = '') {
return JSON.stringify({
query: channelsAndChannelMembersQueryString,
operationName: 'gqlWebChannelsAndChannelMembers',
variables: {
teamId,
perPage: CHANNELS_AND_CHANNEL_MEMBERS_PER_PAGE,
channelsCursor,
channelMembersCursor,
},
});
}
export function transformToReceivedChannelsReducerPayload(
channels: Partial<GraphQLChannel[]>,
): ServerChannel[] {
return channels.map((channel) => ({
id: channel?.id ?? '',
create_at: channel?.create_at ?? 0,
update_at: channel?.update_at ?? 0,
delete_at: channel?.delete_at ?? 0,
team_id: channel?.team?.id ?? '',
type: channel?.type ?? '' as ChannelType,
display_name: channel?.display_name ?? '',
name: channel?.name ?? '',
header: channel?.header ?? '',
purpose: channel?.purpose ?? '',
last_post_at: channel?.last_post_at ?? 0,
last_root_post_at: channel?.last_root_post_at ?? 0,
total_msg_count: channel?.total_msg_count ?? 0,
total_msg_count_root: channel?.total_msg_count_root ?? 0,
creator_id: channel?.creator_id ?? '',
scheme_id: channel?.scheme_id ?? '',
group_constrained: channel?.group_constrained ?? false,
shared: channel?.shared ?? undefined,
props: channel && channel.props ? {...channel.props} : undefined,
policy_id: channel?.policy_id ?? null,
}));
}
export function transformToReceivedChannelMembersReducerPayload(
channelMembers: Partial<GraphQLChannelMember[]>,
userId: UserProfile['id'],
): ChannelMembership[] {
return channelMembers.map((channelMember) => ({
channel_id: channelMember?.channel?.id ?? '',
user_id: userId,
roles: convertRolesNamesArrayToString(channelMember?.roles ?? []),
last_viewed_at: channelMember?.last_viewed_at ?? 0,
msg_count: channelMember?.msg_count ?? 0,
msg_count_root: channelMember?.msg_count_root ?? 0,
mention_count: channelMember?.mention_count ?? 0,
mention_count_root: channelMember?.mention_count_root ?? 0,
urgent_mention_count: channelMember?.urgent_mention_count ?? 0,
notify_props: channelMember && channelMember.notify_props ? {...channelMember.notify_props} : {},
last_update_at: channelMember?.last_update_at ?? 0,
scheme_admin: channelMember?.scheme_admin ?? false,
scheme_user: channelMember?.scheme_user ?? false,
}));
}

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

@@ -23,7 +23,7 @@ jest.mock('actions/views/lhs', () => ({
}));
jest.mock('mattermost-redux/actions/users', () => ({
loadMeREST: () => ({type: 'MOCK_RECEIVED_ME'}),
loadMe: () => ({type: 'MOCK_RECEIVED_ME'}),
}));
jest.mock('stores/redux_store', () => {

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

@@ -11,17 +11,17 @@ import type {UserProfile} from '@mattermost/types/users';
import {ChannelTypes} from 'mattermost-redux/action_types';
import {fetchAppBindings} from 'mattermost-redux/actions/apps';
import {
fetchMyChannelsAndMembersREST,
fetchChannelsAndMembers,
getChannelByNameAndTeamName,
getChannelStats,
selectChannel,
} from 'mattermost-redux/actions/channels';
import {logout, loadMe, loadMeREST} from 'mattermost-redux/actions/users';
import {logout, loadMe} from 'mattermost-redux/actions/users';
import {Preferences} from 'mattermost-redux/constants';
import {appsEnabled} from 'mattermost-redux/selectors/entities/apps';
import {getCurrentChannelStats, getCurrentChannelId, getMyChannelMember, getRedirectChannelNameForTeam, getChannelsNameMapInTeam, getAllDirectChannels, getChannelMessageCount} from 'mattermost-redux/selectors/entities/channels';
import {getConfig, isPerformanceDebuggingEnabled} from 'mattermost-redux/selectors/entities/general';
import {getBool, getIsOnboardingFlowEnabled, isCollapsedThreadsEnabled, isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getBool, getIsOnboardingFlowEnabled, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamId, getMyTeams, getTeam, getMyTeamMember, getTeamMemberships, getActiveTeamsList} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser, getCurrentUserId, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
import type {ActionFunc, DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
@@ -309,7 +309,7 @@ export async function getTeamRedirectChannelIfIsAccesible(user: UserProfile, tea
let teamChannels = getChannelsNameMapInTeam(state, team.id);
if (!teamChannels || Object.keys(teamChannels).length === 0) {
// This should be executed in pretty limited scenarios (empty teams)
await dispatch(fetchMyChannelsAndMembersREST(team.id)); // eslint-disable-line no-await-in-loop
await dispatch(fetchChannelsAndMembers(team.id)); // eslint-disable-line no-await-in-loop
state = getState();
teamChannels = getChannelsNameMapInTeam(state, team.id);
}
@@ -356,11 +356,7 @@ export async function redirectUserToDefaultTeam() {
const shouldLoadUser = Utils.isEmptyObject(getTeamMemberships(state)) || !user;
const onboardingFlowEnabled = getIsOnboardingFlowEnabled(state);
if (shouldLoadUser) {
if (isGraphQLEnabled(state)) {
await dispatch(loadMe());
} else {
await dispatch(loadMeREST());
}
await dispatch(loadMe());
state = getState();
user = getCurrentUser(state);
}

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

@@ -238,7 +238,7 @@ function initRequestCountingIfNecessary() {
for (const entry of entries.getEntries()) {
const url = entry.name;
if (!url.includes('/api/v4/') && !url.includes('/api/v5/')) {
if (!url.includes('/api/v4/')) {
// Don't count requests made outside of the MM server's API
continue;
}

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

@@ -20,7 +20,7 @@ jest.mock('mattermost-redux/actions/users', () => {
const original = jest.requireActual('mattermost-redux/actions/users');
return {
...original,
loadMeREST: () => ({type: 'MOCK_LOAD_ME'}),
loadMe: () => ({type: 'MOCK_LOAD_ME'}),
};
});

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

@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {getClientConfig, getLicenseConfig} from 'mattermost-redux/actions/general';
import {loadMe, loadMeREST} from 'mattermost-redux/actions/users';
import {loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
@@ -20,22 +20,15 @@ export type TranslationPluginFunction = (locale: string) => Translations
export function loadConfigAndMe() {
return async (dispatch: DispatchFunc) => {
const [{data: clientConfig}] = await Promise.all([
await Promise.all([
dispatch(getClientConfig()),
dispatch(getLicenseConfig()),
]);
const isGraphQLEnabled = clientConfig && clientConfig.FeatureFlagGraphQL === 'true';
let isMeLoaded = false;
if (document.cookie.includes('MMUSERID=')) {
if (isGraphQLEnabled) {
const dataFromLoadMe = await dispatch(loadMe());
isMeLoaded = dataFromLoadMe?.data ?? false;
} else {
const dataFromLoadMeREST = await dispatch(loadMeREST());
isMeLoaded = dataFromLoadMeREST?.data ?? false;
}
const dataFromLoadMe = await dispatch(loadMe());
isMeLoaded = dataFromLoadMe?.data ?? false;
}
return {data: isMeLoaded};

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

@@ -6,7 +6,7 @@ import type {History} from 'history';
import type {Channel} from '@mattermost/types/channels';
import type {GlobalState} from '@mattermost/types/store';
import {joinChannel, getChannelByNameAndTeamName, getChannelMember, markGroupChannelOpen, fetchMyChannelsAndMembersREST} from 'mattermost-redux/actions/channels';
import {joinChannel, getChannelByNameAndTeamName, getChannelMember, markGroupChannelOpen, fetchChannelsAndMembers} from 'mattermost-redux/actions/channels';
import {getUser, getUserByUsername, getUserByEmail} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import {getChannelByName, getOtherChannels, getChannel, getChannelsNameMapInTeam, getRedirectChannelNameForTeam} from 'mattermost-redux/selectors/entities/channels';
@@ -68,7 +68,7 @@ export function onChannelByIdentifierEnter({match, history}: MatchAndHistory): A
dispatch(goToDirectChannelByUserId(match, history, identifier));
break;
case 'error':
await dispatch(fetchMyChannelsAndMembersREST(teamObj!.id));
await dispatch(fetchChannelsAndMembers(teamObj!.id));
handleError(match, history, getRedirectChannelNameForTeam(state, teamObj!.id));
break;
}
@@ -136,7 +136,7 @@ export function goToChannelByChannelId(match: Match, history: History): ActionFu
if (!channel || !member) {
const dispatchResult = await dispatch(joinChannel(getCurrentUserId(state), teamObj!.id, channelId, ''));
if ('error' in dispatchResult) {
await dispatch(fetchMyChannelsAndMembersREST(teamObj!.id));
await dispatch(fetchChannelsAndMembers(teamObj!.id));
handleChannelJoinError(match, history, getRedirectChannelNameForTeam(state, teamObj!.id));
return {data: undefined};
}
@@ -202,7 +202,7 @@ export function goToChannelByChannelName(match: Match, history: History): Action
if (!channel) {
const getChannelDispatchResult = await dispatch(getChannelByNameAndTeamName(team, channelName, true));
if ('error' in getChannelDispatchResult || getChannelDispatchResult.data.delete_at === 0) {
await dispatch(fetchMyChannelsAndMembersREST(teamObj!.id));
await dispatch(fetchChannelsAndMembers(teamObj!.id));
handleChannelJoinError(match, history, getRedirectChannelNameForTeam(state, teamObj!.id));
return {data: undefined};
}
@@ -235,7 +235,7 @@ function goToDirectChannelByUsername(match: Match, history: History): ActionFunc
if (!user) {
const dispatchResult = await dispatch(getUserByUsername(username));
if ('error' in dispatchResult) {
await dispatch(fetchMyChannelsAndMembersREST(teamObj!.id));
await dispatch(fetchChannelsAndMembers(teamObj!.id));
handleError(match, history, getRedirectChannelNameForTeam(state, teamObj!.id));
return {data: undefined};
}
@@ -244,7 +244,7 @@ function goToDirectChannelByUsername(match: Match, history: History): ActionFunc
const directChannelDispatchRes = await dispatch(openDirectChannelToUserId(user.id));
if ('error' in directChannelDispatchRes) {
await dispatch(fetchMyChannelsAndMembersREST(teamObj!.id));
await dispatch(fetchChannelsAndMembers(teamObj!.id));
handleError(match, history, getRedirectChannelNameForTeam(state, teamObj!.id));
return {data: undefined};
}
@@ -264,7 +264,7 @@ export function goToDirectChannelByUserId(match: Match, history: History, userId
if (!user) {
const dispatchResult = await dispatch(getUser(userId));
if ('error' in dispatchResult) {
await dispatch(fetchMyChannelsAndMembersREST(teamObj!.id));
await dispatch(fetchChannelsAndMembers(teamObj!.id));
handleError(match, history, getRedirectChannelNameForTeam(state, teamObj!.id));
return {data: undefined};
}
@@ -287,7 +287,7 @@ export function goToDirectChannelByUserIds(match: Match, history: History): Acti
if (!user) {
const dispatchResult = await dispatch(getUser(userId));
if ('error' in dispatchResult) {
await dispatch(fetchMyChannelsAndMembersREST(teamObj!.id));
await dispatch(fetchChannelsAndMembers(teamObj!.id));
handleError(match, history, getRedirectChannelNameForTeam(state, teamObj!.id));
return {data: undefined};
}
@@ -310,7 +310,7 @@ export function goToDirectChannelByEmail(match: Match, history: History): Action
if (!user) {
const dispatchResult = await dispatch(getUserByEmail(email));
if ('error' in dispatchResult) {
await dispatch(fetchMyChannelsAndMembersREST(teamObj!.id));
await dispatch(fetchChannelsAndMembers(teamObj!.id));
handleError(match, history, getRedirectChannelNameForTeam(state, teamObj!.id));
return {data: undefined};
}
@@ -335,7 +335,7 @@ function goToGroupChannelByGroupId(match: Match, history: History): ActionFunc {
if (!channel) {
const dispatchResult = await dispatch(joinChannel(getCurrentUserId(state), teamObj!.id, '', groupId));
if ('error' in dispatchResult) {
await dispatch(fetchMyChannelsAndMembersREST(teamObj!.id));
await dispatch(fetchChannelsAndMembers(teamObj!.id));
handleError(match, history, getRedirectChannelNameForTeam(state, teamObj!.id));
return {data: undefined};
}

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

@@ -12,12 +12,12 @@ import {Link, useLocation, useHistory, Route} from 'react-router-dom';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {loadMe, loadMeREST} from 'mattermost-redux/actions/users';
import {loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import {RequestStatus} from 'mattermost-redux/constants';
import {isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud';
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {getIsOnboardingFlowEnabled, isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getTeamByName, getMyTeamMember} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
@@ -112,7 +112,6 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
const experimentalPrimaryTeamMember = useSelector((state: GlobalState) => getMyTeamMember(state, experimentalPrimaryTeam?.id ?? ''));
const onboardingFlowEnabled = useSelector(getIsOnboardingFlowEnabled);
const isCloud = useSelector(isCurrentLicenseCloud);
const graphQLEnabled = useSelector(isGraphQLEnabled);
const loginIdInput = useRef<HTMLInputElement>(null);
const passwordInput = useRef<HTMLInputElement>(null);
@@ -629,11 +628,7 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
};
const postSubmit = async (userProfile: UserProfile) => {
if (graphQLEnabled) {
await dispatch(loadMe());
} else {
await dispatch(loadMeREST());
}
await dispatch(loadMe());
// check for query params brought over from signup_user_complete
const params = new URLSearchParams(search);

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

@@ -13,10 +13,10 @@ import type {ServerError} from '@mattermost/types/errors';
import type {UserProfile} from '@mattermost/types/users';
import {getTeamInviteInfo} from 'mattermost-redux/actions/teams';
import {createUser, loadMe, loadMeREST} from 'mattermost-redux/actions/users';
import {createUser, loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {getIsOnboardingFlowEnabled, isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {isEmail} from 'mattermost-redux/utils/helpers';
@@ -110,7 +110,6 @@ const Signup = ({onCustomizeHeader}: SignupProps) => {
const loggedIn = Boolean(useSelector(getCurrentUserId));
const onboardingFlowEnabled = useSelector(getIsOnboardingFlowEnabled);
const usedBefore = useSelector((state: GlobalState) => (!inviteId && !loggedIn && token ? getGlobalItem(state, token, null) : undefined));
const graphQLEnabled = useSelector(isGraphQLEnabled);
const emailInput = useRef<HTMLInputElement>(null);
const nameInput = useRef<HTMLInputElement>(null);
@@ -482,11 +481,7 @@ const Signup = ({onCustomizeHeader}: SignupProps) => {
const postSignupSuccess = async () => {
const redirectTo = (new URLSearchParams(search)).get('redirect_to');
if (graphQLEnabled) {
await dispatch(loadMe());
} else {
await dispatch(loadMeREST());
}
await dispatch(loadMe());
if (token) {
setGlobalItem(token, JSON.stringify({usedBefore: true}));

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

@@ -5,17 +5,16 @@ import type {ServerError} from '@mattermost/types/errors';
import type {GetGroupsForUserParams, GetGroupsParams} from '@mattermost/types/groups';
import type {Team} from '@mattermost/types/teams';
import {fetchMyChannelsAndMembersREST} from 'mattermost-redux/actions/channels';
import {fetchChannelsAndMembers} from 'mattermost-redux/actions/channels';
import {logError} from 'mattermost-redux/actions/errors';
import {getGroups, getAllGroupsAssociatedToChannelsInTeam, getAllGroupsAssociatedToTeam, getGroupsByUserIdPaginated} from 'mattermost-redux/actions/groups';
import {forceLogoutIfNecessary} from 'mattermost-redux/actions/helpers';
import {getTeamByName, selectTeam} from 'mattermost-redux/actions/teams';
import {getLicense} from 'mattermost-redux/selectors/entities/general';
import {isCustomGroupsEnabled, isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {isCustomGroupsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import type {ActionFunc} from 'mattermost-redux/types/actions';
import {fetchChannelsAndMembers} from 'actions/channel_actions';
import {loadStatusesForChannelAndSidebar} from 'actions/status_actions';
import {addUserToTeam} from 'actions/team_actions';
import LocalStorageStore from 'stores/local_storage_store';
@@ -30,13 +29,8 @@ export function initializeTeam(team: Team): ActionFunc<Team, ServerError> {
const currentUser = getCurrentUser(state);
LocalStorageStore.setPreviousTeamId(currentUser.id, team.id);
const graphQLEnabled = isGraphQLEnabled(state);
try {
if (graphQLEnabled) {
await dispatch(fetchChannelsAndMembers(team.id));
} else {
await dispatch(fetchMyChannelsAndMembersREST(team.id));
}
await dispatch(fetchChannelsAndMembers(team.id));
} catch (error) {
forceLogoutIfNecessary(error as ServerError, dispatch, getState);
dispatch(logError(error as ServerError));

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

@@ -5,14 +5,12 @@ import {connect} from 'react-redux';
import type {ConnectedProps} from 'react-redux';
import type {RouteComponentProps} from 'react-router-dom';
import {fetchAllMyTeamsChannelsAndChannelMembersREST, fetchMyChannelsAndMembersREST} from 'mattermost-redux/actions/channels';
import {fetchAllMyTeamsChannelsAndChannelMembersREST, fetchChannelsAndMembers} from 'mattermost-redux/actions/channels';
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
import {getLicense, getConfig} from 'mattermost-redux/selectors/entities/general';
import {isGraphQLEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamId, getMyTeams} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import {fetchChannelsAndMembers} from 'actions/channel_actions';
import {markChannelAsReadOnFocus} from 'actions/views/channel';
import {getSelectedThreadIdInCurrentTeam} from 'selectors/views/threads';
@@ -36,7 +34,6 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
const config = getConfig(state);
const currentUser = getCurrentUser(state);
const plugins = state.plugins.components.NeedsTeamComponent;
const graphQLEnabled = isGraphQLEnabled(state);
const disableRefetchingOnBrowserFocus = config.DisableRefetchingOnBrowserFocus === 'true';
return {
@@ -46,14 +43,12 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
plugins,
selectedThreadId: getSelectedThreadIdInCurrentTeam(state),
mfaRequired: checkIfMFARequired(currentUser, license, config, ownProps.match.url),
graphQLEnabled,
disableRefetchingOnBrowserFocus,
};
}
const mapDispatchToProps = {
fetchChannelsAndMembers,
fetchMyChannelsAndMembersREST,
fetchAllMyTeamsChannelsAndChannelMembersREST,
markChannelAsReadOnFocus,
initializeTeam,

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

@@ -53,17 +53,13 @@ function TeamController(props: Props) {
useEffect(() => {
async function fetchInitialChannels() {
if (props.graphQLEnabled) {
await props.fetchChannelsAndMembers();
} else {
await props.fetchAllMyTeamsChannelsAndChannelMembersREST();
}
await props.fetchAllMyTeamsChannelsAndChannelMembersREST();
setInitialChannelsLoaded(true);
}
fetchInitialChannels();
}, [props.graphQLEnabled]);
}, []);
useEffect(() => {
const wakeUpIntervalId = setInterval(() => {
@@ -95,11 +91,7 @@ function TeamController(props: Props) {
if (!props.disableRefetchingOnBrowserFocus) {
const currentTime = Date.now();
if ((currentTime - blurTime.current) > UNREAD_CHECK_TIME_MILLISECONDS && props.currentTeamId) {
if (props.graphQLEnabled) {
props.fetchChannelsAndMembers(props.currentTeamId);
} else {
props.fetchMyChannelsAndMembersREST(props.currentTeamId);
}
props.fetchChannelsAndMembers(props.currentTeamId);
}
}
}
@@ -132,7 +124,7 @@ function TeamController(props: Props) {
window.removeEventListener('blur', handleBlur);
window.removeEventListener('keydown', handleKeydown);
};
}, [props.selectedThreadId, props.graphQLEnabled, props.currentChannelId, props.currentTeamId]);
}, [props.selectedThreadId, props.currentChannelId, props.currentTeamId]);
// Effect runs on mount, adds active state to window
useEffect(() => {

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

@@ -9,7 +9,7 @@ import {UserTypes} from 'mattermost-redux/action_types';
import * as Actions from 'mattermost-redux/actions/channels';
import {createIncomingHook, createOutgoingHook} from 'mattermost-redux/actions/integrations';
import {addUserToTeam} from 'mattermost-redux/actions/teams';
import {getProfilesByIds, loadMeREST} from 'mattermost-redux/actions/users';
import {getProfilesByIds, loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import type {ActionResult} from 'mattermost-redux/types/actions';
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
@@ -185,7 +185,7 @@ describe('Actions.Channels', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/users/ids').
@@ -358,7 +358,7 @@ describe('Actions.Channels', () => {
expect(myMembers[TestHelper.basicChannel!.id]).toBeTruthy();
});
it('fetchMyChannelsAndMembersREST', async () => {
it('fetchChannelsAndMembers', async () => {
nock(Client4.getBaseRoute()).
post('/users').
query(true).
@@ -386,7 +386,7 @@ describe('Actions.Channels', () => {
get(`/users/me/teams/${TestHelper.basicTeam!.id}/channels/members`).
reply(200, [{user_id: TestHelper.basicUser!.id, roles: 'channel_user', channel_id: directChannel.id}, TestHelper.basicChannelMember]);
await store.dispatch(Actions.fetchMyChannelsAndMembersREST(TestHelper.basicTeam!.id));
await store.dispatch(Actions.fetchChannelsAndMembers(TestHelper.basicTeam!.id));
const {channels, channelsInTeam, myMembers} = store.getState().entities.channels;
expect(channels).toBeTruthy();
@@ -412,7 +412,7 @@ describe('Actions.Channels', () => {
get(`/users/me/teams/${TestHelper.basicTeam!.id}/channels/members`).
reply(200, [TestHelper.basicChannelMember]);
await store.dispatch(Actions.fetchMyChannelsAndMembersREST(TestHelper.basicTeam!.id));
await store.dispatch(Actions.fetchChannelsAndMembers(TestHelper.basicTeam!.id));
nock(Client4.getBaseRoute()).
put(`/channels/${TestHelper.basicChannel!.id}/members/${TestHelper.basicUser!.id}/notify_props`).
@@ -475,7 +475,7 @@ describe('Actions.Channels', () => {
get(`/users/me/teams/${TestHelper.basicTeam!.id}/channels/members`).
reply(200, [{user_id: TestHelper.basicUser!.id, roles: 'channel_user', channel_id: secondChannel.id}, TestHelper.basicChannelMember]);
await store.dispatch(Actions.fetchMyChannelsAndMembersREST(TestHelper.basicTeam!.id));
await store.dispatch(Actions.fetchChannelsAndMembers(TestHelper.basicTeam!.id));
nock(Client4.getBaseRoute()).
post('/hooks/incoming').
@@ -579,7 +579,7 @@ describe('Actions.Channels', () => {
get(`/users/me/teams/${TestHelper.basicTeam!.id}/channels/members`).
reply(200, [{user_id: TestHelper.basicUser!.id, roles: 'channel_user', channel_id: secondChannel.id}, TestHelper.basicChannelMember]);
await store.dispatch(Actions.fetchMyChannelsAndMembersREST(TestHelper.basicTeam!.id));
await store.dispatch(Actions.fetchChannelsAndMembers(TestHelper.basicTeam!.id));
nock(Client4.getBaseRoute()).
post('/hooks/incoming').
@@ -1900,7 +1900,7 @@ describe('Actions.Channels', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/channels').
@@ -1933,7 +1933,7 @@ describe('Actions.Channels', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/channels').

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

@@ -497,7 +497,7 @@ export function getChannelTimezones(channelId: string): ActionFunc {
};
}
export function fetchMyChannelsAndMembersREST(teamId: string): ActionFunc<{channels: ServerChannel[]; channelMembers: ChannelMembership[]}> {
export function fetchChannelsAndMembers(teamId: string): ActionFunc<{channels: ServerChannel[]; channelMembers: ChannelMembership[]}> {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
let channels;
let channelMembers;
@@ -1503,7 +1503,7 @@ export default {
patchChannel,
updateChannelNotifyProps,
getChannel,
fetchMyChannelsAndMembersREST,
fetchChannelsAndMembers,
getChannelTimezones,
getChannelMembersByIds,
leaveChannel,

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

@@ -12,7 +12,7 @@ import {PostTypes, UserTypes} from 'mattermost-redux/action_types';
import {getChannelStats} from 'mattermost-redux/actions/channels';
import {createCustomEmoji} from 'mattermost-redux/actions/emojis';
import * as Actions from 'mattermost-redux/actions/posts';
import {loadMeREST} from 'mattermost-redux/actions/users';
import {loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import type {ActionResult, GetStateFunc} from 'mattermost-redux/types/actions';
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
@@ -274,7 +274,7 @@ describe('Actions.Posts', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/posts').
@@ -368,7 +368,7 @@ describe('Actions.Posts', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/posts').
@@ -1015,7 +1015,7 @@ describe('Actions.Posts', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/posts').
@@ -1048,7 +1048,7 @@ describe('Actions.Posts', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/posts').
@@ -1221,7 +1221,7 @@ describe('Actions.Posts', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/posts').
@@ -1250,7 +1250,7 @@ describe('Actions.Posts', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/posts').
@@ -1284,7 +1284,7 @@ describe('Actions.Posts', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMeREST());
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/posts').

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

@@ -5,7 +5,7 @@ import nock from 'nock';
import {UserTypes} from 'mattermost-redux/action_types';
import * as Actions from 'mattermost-redux/actions/preferences';
import {loadMeREST} from 'mattermost-redux/actions/users';
import {loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
@@ -203,7 +203,7 @@ describe('Actions.Preferences', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await loadMeREST()(store.dispatch, store.getState);
await loadMe()(store.dispatch, store.getState);
// Test that a new preference is created if none exists
nock(Client4.getUsersRoute()).
@@ -303,7 +303,7 @@ describe('Actions.Preferences', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await loadMeREST()(store.dispatch, store.getState);
await loadMe()(store.dispatch, store.getState);
const theme = {
type: 'Mattermost Dark',

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

@@ -104,7 +104,3 @@ export function loadRolesIfNeeded(roles: Iterable<string>): ActionFunc {
return {data: state.entities.roles.roles};
};
}
export function convertRolesNamesArrayToString(roles: Role[]): string {
return roles.map((role) => role.name!).join(' ') ?? '';
}

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

@@ -9,7 +9,7 @@ import type {Team} from '@mattermost/types/teams';
import {GeneralTypes, UserTypes} from 'mattermost-redux/action_types';
import * as Actions from 'mattermost-redux/actions/teams';
import {loadMeREST} from 'mattermost-redux/actions/users';
import {loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import {General, RequestStatus} from 'mattermost-redux/constants';
import type {ActionResult} from 'mattermost-redux/types/actions';
@@ -55,7 +55,7 @@ describe('Actions.Teams', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await loadMeREST()(store.dispatch, store.getState);
await loadMe()(store.dispatch, store.getState);
nock(Client4.getBaseRoute()).
get('/users/me/teams').
@@ -741,7 +741,7 @@ describe('Actions.Teams', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await loadMeREST()(store.dispatch, store.getState);
await loadMe()(store.dispatch, store.getState);
const team = TestHelper.basicTeam;
const imageData = fs.createReadStream('src/packages/mattermost-redux/test/assets/images/test.png');
@@ -759,7 +759,7 @@ describe('Actions.Teams', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await loadMeREST()(store.dispatch, store.getState);
await loadMe()(store.dispatch, store.getState);
const team = TestHelper.basicTeam;
@@ -776,7 +776,7 @@ describe('Actions.Teams', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await loadMeREST()(store.dispatch, store.getState);
await loadMe()(store.dispatch, store.getState);
const schemeId = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
const {id} = TestHelper.basicTeam!;

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

@@ -89,7 +89,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
nock(Client4.getBaseRoute()).
post('/users/me/terms_of_service').
@@ -115,7 +115,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
nock(Client4.getBaseRoute()).
post('/users/me/terms_of_service').
@@ -661,7 +661,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
nock(Client4.getBaseRoute()).
post('/users/login').
@@ -717,7 +717,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
nock(Client4.getBaseRoute()).
post('/users/login').
@@ -854,7 +854,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const state = store.getState();
const currentUser = state.entities.users.profiles[state.entities.users.currentUserId];
@@ -905,7 +905,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const state = store.getState();
const currentUserId = state.entities.users.currentUserId;
@@ -953,7 +953,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -974,7 +974,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -995,7 +995,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const beforeTime = new Date().getTime();
const currentUserId = store.getState().entities.users.currentUserId;
@@ -1090,7 +1090,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const testImageData = fs.createReadStream('src/packages/mattermost-redux/test/assets/images/test.png');
@@ -1115,7 +1115,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -1182,7 +1182,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -1213,7 +1213,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -1249,7 +1249,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -1286,7 +1286,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -1323,7 +1323,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -1371,7 +1371,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -1426,7 +1426,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;
@@ -1481,7 +1481,7 @@ describe('Actions.Users', () => {
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await Actions.loadMeREST()(store.dispatch, store.getState);
await Actions.loadMe()(store.dispatch, store.getState);
const currentUserId = store.getState().entities.users.currentUserId;

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

@@ -4,29 +4,16 @@
import type {AnyAction} from 'redux';
import {batchActions} from 'redux-batched-actions';
import type {ClientConfig, ClientLicense} from '@mattermost/types/config';
import type {ServerError} from '@mattermost/types/errors';
import type {PreferenceType} from '@mattermost/types/preferences';
import type {Role} from '@mattermost/types/roles';
import type {Team, TeamMembership} from '@mattermost/types/teams';
import type {UserProfile, UserStatus, GetFilteredUsersStatsOpts, UsersStats, UserCustomStatus} from '@mattermost/types/users';
import {UserTypes, AdminTypes, GeneralTypes, PreferenceTypes, TeamTypes, RoleTypes} from 'mattermost-redux/action_types';
import {UserTypes, AdminTypes} from 'mattermost-redux/action_types';
import {logError} from 'mattermost-redux/actions/errors';
import {setServerVersion, getClientConfig, getLicenseConfig} from 'mattermost-redux/actions/general';
import {bindClientFunc, forceLogoutIfNecessary, debounce} from 'mattermost-redux/actions/helpers';
import {getMyPreferences} from 'mattermost-redux/actions/preferences';
import {loadRolesIfNeeded} from 'mattermost-redux/actions/roles';
import {getMyTeams, getMyTeamMembers, getMyTeamUnreads} from 'mattermost-redux/actions/teams';
import {
currentUserInfoQuery,
transformToRecievedMeReducerPayload,
transformToRecievedTeamsListReducerPayload,
transformToReceivedUserAndTeamRolesReducerPayload,
transformToRecievedMyTeamMembersReducerPayload,
} from 'mattermost-redux/actions/users_queries';
import type {
CurrentUserInfoQueryResponseType} from 'mattermost-redux/actions/users_queries';
import {Client4} from 'mattermost-redux/client';
import {General} from 'mattermost-redux/constants';
import {getServerVersion} from 'mattermost-redux/selectors/entities/general';
@@ -67,7 +54,7 @@ export function createUser(user: UserProfile, token: string, inviteId: string, r
};
}
export function loadMeREST(): ActionFunc {
export function loadMe(): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
// Sometimes the server version is set in one or the other
const serverVersion = getState().entities.general.serverVersion || Client4.getServerVersion();
@@ -94,76 +81,6 @@ export function loadMeREST(): ActionFunc {
};
}
export function loadMe(): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
// Sometimes the server version is set in one or the other
const serverVersion = getState().entities.general.serverVersion || Client4.getServerVersion();
dispatch(setServerVersion(serverVersion));
let clientLicense: ClientLicense;
let clientConfig: ClientConfig;
let userProfile: UserProfile;
let roles: Role[];
let preferences: PreferenceType[];
let teams: Team[];
let teamMemberships: TeamMembership[];
try {
const {data, errors} = await Client4.fetchWithGraphQL<CurrentUserInfoQueryResponseType>(currentUserInfoQuery);
if (errors || !data) {
throw new Error('Error returned in fetching current user info with graphQL');
}
clientLicense = Object.assign({}, data.license);
clientConfig = Object.assign({}, data.config);
userProfile = transformToRecievedMeReducerPayload(data.user);
roles = transformToReceivedUserAndTeamRolesReducerPayload(data.user.roles, data.teamMembers);
preferences = [...data.user.preferences];
teams = transformToRecievedTeamsListReducerPayload(data.teamMembers);
teamMemberships = transformToRecievedMyTeamMembersReducerPayload(data.teamMembers, data.user.id);
} catch (error) {
dispatch(logError(error as ServerError));
return {error: error as ServerError};
}
dispatch(
batchActions([
{
type: GeneralTypes.CLIENT_LICENSE_RECEIVED,
data: clientLicense,
},
{
type: GeneralTypes.CLIENT_CONFIG_RECEIVED,
data: clientConfig,
},
{
type: UserTypes.RECEIVED_ME,
data: userProfile,
},
{
type: RoleTypes.RECEIVED_ROLES,
data: roles,
},
{
type: PreferenceTypes.RECEIVED_ALL_PREFERENCES,
data: preferences,
},
{
type: TeamTypes.RECEIVED_TEAMS_LIST,
data: teams,
},
{
type: TeamTypes.RECEIVED_MY_TEAM_MEMBERS,
data: teamMemberships,
},
]),
);
return {data: true};
};
}
export function logout(): ActionFunc {
return async (dispatch: DispatchFunc) => {
dispatch({type: UserTypes.LOGOUT_REQUEST, data: null});

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

@@ -1,160 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {ClientConfig, ClientLicense} from '@mattermost/types/config';
import type {PreferenceType} from '@mattermost/types/preferences';
import type {Role} from '@mattermost/types/roles';
import type {Team, TeamMembership} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {convertRolesNamesArrayToString} from 'mattermost-redux/actions/roles';
const currentUserInfoQueryString = `
query gqlWebCurrentUserInfo {
config
license
user(id: "me") {
id
create_at: createAt
delete_at: deleteAt
update_at: updateAt
username
auth_service: authService
email
nickname
first_name: firstName
last_name: lastName
position
roles {
id
name
permissions
}
props
notify_props: notifyProps
last_picture_update: lastPictureUpdate
last_password_update: lastPasswordUpdate
terms_of_service_id: termsOfServiceId
terms_of_service_create_at: termsOfServiceCreateAt
locale
timezone
remote_id: remoteId
preferences {
name
user_id: userId
category
value
}
is_bot: isBot
bot_description: botDescription
mfa_active: mfaActive
}
teamMembers(userId: "me") {
team {
id
display_name: displayName
name
create_at: createAt
update_at: updateAt
delete_at: deleteAt
description
email
type
company_name: companyName
allowed_domains: allowedDomains
invite_id: inviteId
last_team_icon_update: lastTeamIconUpdate
group_constrained: groupConstrained
allow_open_invite: allowOpenInvite
scheme_id: schemeId
policy_id: policyId
}
roles {
id
name
permissions
}
delete_at: deleteAt
scheme_guest: schemeGuest
scheme_user: schemeUser
scheme_admin: schemeAdmin
}
}
`;
export const currentUserInfoQuery = JSON.stringify({query: currentUserInfoQueryString, operationName: 'gqlWebCurrentUserInfo'});
type GraphQLUser = UserProfile & {
roles: Role[];
preferences: PreferenceType[];
};
type GraphQLTeamMember = {
team: Team;
user: UserProfile;
roles: Role[];
delete_at: number;
scheme_guest: boolean;
scheme_user: boolean;
scheme_admin: boolean;
}
export type CurrentUserInfoQueryResponseType = {
data?: {
user: GraphQLUser;
config: ClientConfig;
license: ClientLicense;
teamMembers: GraphQLTeamMember[];
};
errors?: unknown;
};
export function transformToReceivedUserAndTeamRolesReducerPayload(
userRoles: GraphQLUser['roles'],
teamMembers: GraphQLTeamMember[]): Role[] {
let roles: Role[] = [...userRoles];
teamMembers.forEach((teamMember) => {
if (teamMember.roles) {
roles = [...roles, ...teamMember.roles];
}
});
return roles;
}
export function transformToRecievedMeReducerPayload(user: GraphQLUser): UserProfile {
return {
...user,
position: user?.position ?? '',
roles: convertRolesNamesArrayToString(user?.roles ?? []),
};
}
export function transformToRecievedTeamsListReducerPayload(teamsMembers: GraphQLTeamMember[]): Team[] {
return teamsMembers.map((teamMember) => ({...teamMember.team}));
}
export function transformToRecievedMyTeamMembersReducerPayload(
teamsMembers: Partial<GraphQLTeamMember[]>,
userId: UserProfile['id'],
): TeamMembership[] {
return teamsMembers.map((teamMember) => ({
team_id: teamMember?.team?.id ?? '',
user_id: userId || '',
delete_at: teamMember?.delete_at ?? 0,
roles: convertRolesNamesArrayToString(teamMember?.roles ?? []),
scheme_admin: teamMember?.scheme_admin ?? false,
scheme_guest: teamMember?.scheme_guest ?? false,
scheme_user: teamMember?.scheme_user ?? false,
// Remove these fields once webapp deprecates getting unread counts from teams
// below fields arent included in the response but were inside of TeamMembership api types
mention_count: 0,
mention_count_root: 0,
msg_count: 0,
msg_count_root: 0,
thread_count: 0,
thread_mention_count: 0,
}));
}

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

@@ -244,10 +244,6 @@ export function getIsOnboardingFlowEnabled(state: GlobalState): boolean {
return getConfig(state).EnableOnboardingFlow === 'true';
}
export function isGraphQLEnabled(state: GlobalState): boolean {
return getFeatureFlagValue(state, 'GraphQL') === 'true';
}
export function getHasDismissedSystemConsoleLimitReached(state: GlobalState): boolean {
return getBool(state, Preferences.CATEGORY_UPGRADE_CLOUD, Preferences.SYSTEM_CONSOLE_LIMIT_REACHED, false);
}

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

@@ -41,15 +41,6 @@ describe('Client4', () => {
expect(client.serverVersion).toEqual('5.3.0.5.3.0.abc123');
});
});
describe('fetchWithGraphQL', () => {
test('Should have correct graphql url', async () => {
const client = new Client4();
client.setUrl('http://mattermost.example.com');
expect(client.getGraphQLUrl()).toEqual('http://mattermost.example.com/api/v5/graphql');
});
});
});
describe('ClientError', () => {

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

@@ -159,8 +159,6 @@ const PER_PAGE_DEFAULT = 60;
export const DEFAULT_LIMIT_BEFORE = 30;
export const DEFAULT_LIMIT_AFTER = 30;
const GRAPHQL_ENDPOINT = '/api/v5/graphql';
export default class Client4 {
logToConsole = false;
serverVersion = '';
@@ -194,10 +192,6 @@ export default class Client4 {
return this.getUrl() + baseUrl;
}
getGraphQLUrl() {
return `${this.url}${GRAPHQL_ENDPOINT}`;
}
setUrl(url: string) {
this.url = url;
}
@@ -4049,15 +4043,6 @@ export default class Client4 {
);
}
/**
* @param query string query of graphQL, pass the json stringified version of the query
* eg. const query = JSON.stringify({query: `{license, config}`, operationName: 'queryForLicenseAndConfig'});
* client4.fetchWithGraphQL(query);
*/
fetchWithGraphQL = async <DataResponse>(query: string) => {
return this.doFetch<DataResponse>(this.getGraphQLUrl(), {method: 'post', body: query});
}
getCallsChannelState = (channelId: string) => {
return this.doFetch<{enabled: boolean; id: string}>(
`${this.url}/plugins/${'com.mattermost.calls'}/${channelId}`,

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

@@ -120,7 +120,6 @@ export type ClientConfig = {
FileLevel: string;
FeatureFlagAppsEnabled: string;
FeatureFlagCallsEnabled: string;
FeatureFlagGraphQL: string;
ForgotPasswordLink: string;
GiphySdkKey: string;
GoogleDeveloperKey: string;