Improve Redux types part 7/Remove unused actions (#26006)

* Remove unused setFirstChannelName action

* Remove makeOnMoveHistoryIndex

* Remove selectPostFromRightHandSideSearchByPostId

* Remove selectPostAndParentChannel

* Remove searchMoreChannels

* Remove fetchRemoteListing

* Remove sendGenericPostMessage

* Remove unused version of periodic status update code

* Remove unused code around non-global items in storage

Either pre-Redux or early in our usage of Redux, I think this code was
meant to let us store things in localStorage on a per-user basis. If we
ever used it, it hasn't been for a while now.

* Remove unused loadProfilesAndStatusesInChannel action

* Remove collapseCategory and expandCategory

* Removed unused actions from mattermost-redux/actions/channels

* Remove unused getDataRetentionPolicy action and state

* Remove unused getWarnMetricsStatus action

* Remove unused getFirstAdminVisitMarketplaceStatus action

* Remove unused getReactionsForPost action

* Remove now-unused state.entities.posts.selectedPostId

* asdf marketplace stuff in general

* Remove unused makeDirectChannelVisibleIfNecessary and makeGroupMessageVisibleIfNecessary

* Remove old searchFiles action

* Remove unused search actions

* Remove non-graceful addUsersToTeam action

* Remove unused version of joinTeam action

* Remove unused updateTeamMemberRoles action

* Remove another unused verison of the periodic status update code

* Remove unused getUserAccessTokens action

* Fix linting

* Remove unit tests involving recent search results

* Fix another test
This commit is contained in:
Harrison Healey 2024-02-02 15:59:00 -05:00 committed by GitHub
parent 45633198ca
commit 25073a99e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
61 changed files with 35 additions and 1803 deletions

View File

@ -2,7 +2,6 @@
// See LICENSE.txt for license information.
import {
searchMoreChannels,
addUsersToChannel,
openDirectChannelToUserId,
openGroupChannelToUserIds,
@ -142,24 +141,6 @@ describe('Actions.Channel', () => {
expect(loadProfilesForSidebar).toHaveBeenCalledTimes(1);
});
test('searchMoreChannels', async () => {
const testStore = await mockStore(initialState);
const expectedActions = [{
type: 'MOCK_SEARCH_CHANNELS',
data: [{
id: 'channel-id',
name: 'channel-name',
display_name: 'Channel',
delete_at: 0,
type: 'O',
}],
}];
await testStore.dispatch(searchMoreChannels('', false, true));
expect(testStore.getActions()).toEqual(expectedActions);
});
test('addUsersToChannel', async () => {
const testStore = await mockStore(initialState);

View File

@ -11,7 +11,6 @@ import {PreferenceTypes} from 'mattermost-redux/action_types';
import * as ChannelActions from 'mattermost-redux/actions/channels';
import {savePreferences} from 'mattermost-redux/actions/preferences';
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 {NewActionFuncAsync} from 'mattermost-redux/types/actions';
@ -96,26 +95,6 @@ export function loadChannelsForCurrentUser(): NewActionFuncAsync {
};
}
export function searchMoreChannels(term: string, showArchivedChannels: boolean, hideJoinedChannels: boolean): NewActionFuncAsync<Channel[]> { // HARRISONTODO unused
return async (dispatch, getState) => {
const state = getState();
const teamId = getCurrentTeamId(state);
if (!teamId) {
throw new Error('No team id');
}
const {data, error} = await dispatch(ChannelActions.searchChannels(teamId, term, showArchivedChannels));
if (data) {
const myMembers = getMyChannelMemberships(state);
const channels = hideJoinedChannels ? (data as Channel[]).filter((channel) => !myMembers[channel.id]) : data;
return {data: channels};
}
return {error};
};
}
export function autocompleteChannels(term: string, success: (channels: Channel[]) => void, error?: (err: ServerError) => void): NewActionFuncAsync<boolean> {
return async (dispatch, getState) => {
const state = getState();

View File

@ -28,7 +28,6 @@ import type {NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/a
import {calculateUnreadCount} from 'mattermost-redux/utils/channel_utils';
import {handleNewPost} from 'actions/post_actions';
import {stopPeriodicStatusUpdates} from 'actions/status_actions';
import {loadProfilesForSidebar} from 'actions/user_actions';
import {clearUserCookie} from 'actions/views/cookie';
import {close as closeLhs} from 'actions/views/lhs';
@ -188,25 +187,6 @@ export function sendEphemeralPost(message: string, channelId?: string, parentId?
};
}
export function sendGenericPostMessage(message: string, channelId?: string, parentId?: string, userId?: string): NewActionFuncAsync<boolean, GlobalState> { // HARRISONTODO unused
return (doDispatch, doGetState) => {
const timestamp = Utils.getTimestamp();
const post = {
id: Utils.generateId(),
user_id: userId || '0',
channel_id: channelId || getCurrentChannelId(doGetState()),
message,
type: PostTypes.SYSTEM_GENERIC,
create_at: timestamp,
update_at: timestamp,
root_id: parentId || '',
props: {},
} as Post;
return doDispatch(handleNewPost(post));
};
}
export function sendAddToChannelEphemeralPost(user: UserProfile, addedUsername: string, addedUserId: string, channelId: string, postRootId = '', timestamp: number) {
const post = {
id: Utils.generateId(),
@ -271,7 +251,6 @@ export function emitUserLoggedOutEvent(redirectTo = '/', shouldSignalLogout = tr
BrowserStore.signalLogout();
}
stopPeriodicStatusUpdates();
WebsocketActions.close();
clearUserCookie();

View File

@ -23,24 +23,6 @@ import type {GlobalState} from 'types/store';
import {doAppSubmit, openAppsModal, postEphemeralCallResponseForContext} from './apps';
export function fetchRemoteListing(): NewActionFuncAsync<MarketplacePlugin[], GlobalState> { // HARRISONTODO unused
return async (dispatch, getState) => {
const state = getState();
const filter = getFilter(state);
try {
const plugins = await Client4.getRemoteMarketplacePlugins(filter);
dispatch({
type: ActionTypes.RECEIVED_MARKETPLACE_PLUGINS,
plugins,
});
return {data: plugins};
} catch (error: any) {
return {error};
}
};
}
// fetchPlugins fetches the latest marketplace plugins and apps, subject to any existing search filter.
export function fetchListing(localOnly = false): NewActionFuncAsync<Array<MarketplacePlugin | MarketplaceApp>, GlobalState> {
return async (dispatch, getState) => {

View File

@ -8,12 +8,10 @@ import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels'
import {getPostsInCurrentChannel} from 'mattermost-redux/selectors/entities/posts';
import {getDirectShowPreferences} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import type {NewActionFunc, ThunkActionFunc} from 'mattermost-redux/types/actions';
import type {NewActionFunc} from 'mattermost-redux/types/actions';
import {loadCustomEmojisForCustomStatusesByUserIds} from 'actions/emoji_actions';
import {Constants} from 'utils/constants';
import type {GlobalState} from 'types/store';
export function loadStatusesForChannelAndSidebar(): NewActionFunc<boolean, GlobalState> {
@ -115,22 +113,3 @@ export function loadProfilesMissingStatus(users: UserProfile[]): NewActionFunc {
return {data: true};
};
}
let intervalId: NodeJS.Timeout;
export function startPeriodicStatusUpdates(): ThunkActionFunc<void, GlobalState> { // HARRISONTODO unused
return (dispatch) => {
clearInterval(intervalId);
intervalId = setInterval(
() => {
dispatch(loadStatusesForChannelAndSidebar());
},
Constants.STATUS_INTERVAL,
);
};
}
export function stopPeriodicStatusUpdates() { // HARRISONTODO used but does nothing
clearInterval(intervalId);
}

View File

@ -10,26 +10,6 @@ describe('Actions.Storage', () => {
store = await configureStore();
});
it('setItem', async () => {
store.dispatch(Actions.setItem('test', 'value'));
expect(store.getState().storage.storage.unknown_test.value).toBe('value');
expect(typeof store.getState().storage.storage.unknown_test.timestamp).not.toBe('undefined');
});
it('removeItem', async () => {
store.dispatch(Actions.setItem('test1', 'value1'));
store.dispatch(Actions.setItem('test2', 'value2'));
expect(store.getState().storage.storage.unknown_test1.value).toBe('value1');
expect(store.getState().storage.storage.unknown_test2.value).toBe('value2');
store.dispatch(Actions.removeItem('test1'));
expect(typeof store.getState().storage.storage.unknown_test1).toBe('undefined');
expect(store.getState().storage.storage.unknown_test2.value).toBe('value2');
});
it('setGlobalItem', async () => {
store.dispatch(Actions.setGlobalItem('test', 'value'));

View File

@ -1,34 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {NewActionFunc} from 'mattermost-redux/types/actions';
import {StorageTypes} from 'utils/constants';
import {getPrefix} from 'utils/storage_utils';
export function setItem(name: string, value: string): NewActionFunc {
return (dispatch, getState) => {
const state = getState();
const prefix = getPrefix(state);
dispatch({
type: StorageTypes.SET_ITEM,
data: {prefix, name, value, timestamp: new Date()},
});
return {data: true};
};
}
export function removeItem(name: string): NewActionFunc { // HARRISONTODO unused
return (dispatch, getState) => {
const state = getState();
const prefix = getPrefix(state);
dispatch({
type: StorageTypes.REMOVE_ITEM,
data: {prefix, name},
});
return {data: true};
};
}
export function setGlobalItem(name: string, value: any) {
return {

View File

@ -174,16 +174,6 @@ describe('Actions.User', () => {
} as GlobalState['views'],
} as GlobalState;
test('loadProfilesAndStatusesInChannel', async () => {
const testStore = mockStore(initialState);
await testStore.dispatch(UserActions.loadProfilesAndStatusesInChannel('channel_1', 0, 60, 'status', {}));
const actualActions = testStore.getActions();
expect(actualActions[0].args).toEqual(['channel_1', 0, 60, 'status', {}]);
expect(actualActions[0].type).toEqual('MOCK_GET_PROFILES_IN_CHANNEL');
expect(actualActions[1].args).toEqual([['user_1']]);
expect(actualActions[1].type).toEqual('MOCK_GET_STATUSES_BY_ID');
});
test('loadProfilesAndTeamMembers', async () => {
const expectedActions = [{type: 'MOCK_GET_PROFILES_IN_TEAM', args: ['team_1', 0, 60, '', {}]}];

View File

@ -40,16 +40,6 @@ export const queue = new PQueue({concurrency: 4});
const dispatch = store.dispatch;
const getState = store.getState;
export function loadProfilesAndStatusesInChannel(channelId: string, page = 0, perPage: number = General.PROFILE_CHUNK_SIZE, sort = '', options = {}): NewActionFuncAsync { // HARRISONTODO unused
return async (doDispatch) => {
const {data} = await doDispatch(UserActions.getProfilesInChannel(channelId, page, perPage, sort, options));
if (data) {
doDispatch(loadStatusesForProfilesList(data));
}
return {data: true};
};
}
export function loadProfilesAndReloadTeamMembers(page: number, perPage: number, teamId: string, options = {}): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const newTeamId = teamId || getCurrentTeamId(doGetState());

View File

@ -175,13 +175,6 @@ export function multiSelectChannelAdd(channelId: string): NewActionFunc<unknown,
};
}
export function setFirstChannelName(channelName: string) { // HARRISONTODO unused
return {
type: ActionTypes.FIRST_CHANNEL_NAME,
data: channelName,
};
}
// Much of this logic was pulled from the react-beautiful-dnd sample multiselect implementation
// Found here: https://github.com/atlassian/react-beautiful-dnd/tree/master/stories/src/multi-drag
export function multiSelectChannelTo(channelId: string): NewActionFunc<unknown, GlobalState> {

View File

@ -3,7 +3,6 @@
import {
addMessageIntoHistory,
moveHistoryIndexBack,
} from 'mattermost-redux/actions/posts';
import {Posts} from 'mattermost-redux/constants';
@ -14,7 +13,6 @@ import {setGlobalItem, actionOnGlobalItemsWithPrefix} from 'actions/storage';
import {
clearCommentDraftUploads,
updateCommentDraft,
makeOnMoveHistoryIndex,
submitPost,
submitCommand,
makeOnSubmit,
@ -217,47 +215,6 @@ describe('rhs view actions', () => {
});
});
describe('makeOnMoveHistoryIndex', () => {
beforeAll(() => {
jest.useFakeTimers();
jest.setSystemTime(42);
});
afterAll(() => {
jest.useRealTimers();
});
test('it moves comment history index back', () => {
const onMoveHistoryIndex = makeOnMoveHistoryIndex(rootId, -1);
store.dispatch(onMoveHistoryIndex());
const testStore = mockStore(initialState);
testStore.dispatch(moveHistoryIndexBack(Posts.MESSAGE_TYPES.COMMENT));
expect(store.getActions()).toEqual(
expect.arrayContaining(testStore.getActions()),
);
});
test('it stores history message in draft', (done) => {
const onMoveHistoryIndex = makeOnMoveHistoryIndex(rootId, -1);
store.dispatch(onMoveHistoryIndex());
const testStore = mockStore(initialState);
testStore.dispatch(updateCommentDraft(rootId, {message: 'test message', channelId, rootId, fileInfos: [], uploadsInProgress: []}));
expect(store.getActions()).toEqual(
expect.arrayContaining(testStore.getActions()),
);
done();
});
});
describe('submitPost', () => {
const draft = {message: '', channelId, rootId, fileInfos: []};

View File

@ -5,14 +5,10 @@ import type {Post} from '@mattermost/types/posts';
import {
addMessageIntoHistory,
moveHistoryIndexBack,
moveHistoryIndexForward,
} from 'mattermost-redux/actions/posts';
import {Posts} from 'mattermost-redux/constants';
import {createSelector} from 'mattermost-redux/selectors/create_selector';
import {getCustomEmojisByName} from 'mattermost-redux/selectors/entities/emojis';
import {
makeGetMessageInHistoryItem,
getPost,
makeGetPostIdsForThread,
} from 'mattermost-redux/selectors/entities/posts';
@ -26,7 +22,6 @@ import {runMessageWillBePostedHooks, runSlashCommandWillBePostedHooks} from 'act
import * as PostActions from 'actions/post_actions';
import {actionOnGlobalItemsWithPrefix} from 'actions/storage';
import {updateDraft, removeDraft} from 'actions/views/drafts';
import {getPostDraft} from 'selectors/rhs';
import {Constants, StoragePrefixes} from 'utils/constants';
import EmojiMap from 'utils/emoji_map';
@ -52,28 +47,6 @@ export function updateCommentDraft(rootId: string, draft?: PostDraft, save = fal
return updateDraft(key, draft ?? null, rootId, save);
}
export function makeOnMoveHistoryIndex(rootId: string, direction: number): () => NewActionFunc<boolean, GlobalState> { // HARRISONTODO unused
const getMessageInHistory = makeGetMessageInHistoryItem(Posts.MESSAGE_TYPES.COMMENT as 'comment');
return () => (dispatch, getState) => {
const draft = getPostDraft(getState(), StoragePrefixes.COMMENT_DRAFT, rootId);
if (draft.message !== '' && draft.message !== getMessageInHistory(getState())) {
return {data: true};
}
if (direction === -1) {
dispatch(moveHistoryIndexBack(Posts.MESSAGE_TYPES.COMMENT as 'comment'));
} else if (direction === 1) {
dispatch(moveHistoryIndexForward(Posts.MESSAGE_TYPES.COMMENT as 'comment'));
}
const nextMessageInHistory = getMessageInHistory(getState());
dispatch(updateCommentDraft(rootId, {...draft, message: nextMessageInHistory}));
return {data: true};
};
}
export function submitPost(channelId: string, rootId: string, draft: PostDraft): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();

View File

@ -123,10 +123,6 @@ export function selectPostFromRightHandSideSearch(post: Post) {
return selectPostFromRightHandSideSearchWithPreviousState(post);
}
export function selectPostCardFromRightHandSideSearch(post: Post) { // HARRISONTODO unused
return selectPostCardFromRightHandSideSearchWithPreviousState(post);
}
export function selectPostFromRightHandSideSearchByPostId(postId: string): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
const post = getPost(getState(), postId);
@ -526,17 +522,6 @@ export function toggleRhsExpanded() {
};
}
export function selectPostAndParentChannel(post: Post): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
const channel = getChannelSelector(getState(), post.channel_id);
if (!channel) {
await dispatch(getChannel(post.channel_id));
}
dispatch(selectPost(post));
return {data: true};
};
}
export function selectPost(post: Post) {
return {
type: ActionTypes.SELECT_POST,

View File

@ -31,7 +31,6 @@ export default keyMirror({
RECEIVED_SYSTEM_ANALYTICS: null,
RECEIVED_TEAM_ANALYTICS: null,
RECEIVED_USER_ACCESS_TOKEN: null,
RECEIVED_USER_ACCESS_TOKENS: null,
RECEIVED_USER_ACCESS_TOKENS_FOR_USER: null,
RECEIVED_PLUGINS: null,
RECEIVED_PLUGIN_STATUSES: null,

View File

@ -16,10 +16,6 @@ export default keyMirror({
CREATE_CHANNEL_SUCCESS: null,
CREATE_CHANNEL_FAILURE: null,
UPDATE_CHANNEL_REQUEST: null,
UPDATE_CHANNEL_SUCCESS: null,
UPDATE_CHANNEL_FAILURE: null,
DELETE_CHANNEL_SUCCESS: null,
UNARCHIVED_CHANNEL_SUCCESS: null,
@ -61,8 +57,6 @@ export default keyMirror({
RECEIVED_CHANNEL_DELETED: null,
RECEIVED_CHANNEL_UNARCHIVED: null,
RECEIVED_LAST_VIEWED_AT: null,
UPDATE_CHANNEL_HEADER: null,
UPDATE_CHANNEL_PURPOSE: null,
CHANNEL_MEMBER_ADDED: null,
CHANNEL_MEMBER_REMOVED: null,

View File

@ -12,8 +12,6 @@ export default keyMirror({
CLIENT_LICENSE_RECEIVED: null,
CLIENT_LICENSE_RESET: null,
RECEIVED_DATA_RETENTION_POLICY: null,
LOG_CLIENT_ERROR_REQUEST: null,
LOG_CLIENT_ERROR_SUCCESS: null,
LOG_CLIENT_ERROR_FAILURE: null,
@ -26,7 +24,6 @@ export default keyMirror({
SET_CONFIG_AND_LICENSE: null,
WARN_METRICS_STATUS_RECEIVED: null,
WARN_METRIC_STATUS_RECEIVED: null,
WARN_METRIC_STATUS_REMOVED: null,

View File

@ -42,10 +42,8 @@ export default keyMirror({
POST_REMOVED: null,
RECEIVED_FOCUSED_POST: null,
RECEIVED_POST_SELECTED: null,
RECEIVED_EDIT_POST: null,
RECEIVED_REACTION: null,
RECEIVED_REACTIONS: null,
REACTION_DELETED: null,
ADD_MESSAGE_INTO_HISTORY: null,

View File

@ -17,7 +17,6 @@ export default keyMirror({
SEARCH_PINNED_POSTS_REQUEST: null,
SEARCH_PINNED_POSTS_SUCCESS: null,
SEARCH_PINNED_POSTS_FAILURE: null,
REMOVE_SEARCH_PINNED_POSTS: null,
RECEIVED_SEARCH_POSTS: null,
RECEIVED_SEARCH_FILES: null,
RECEIVED_SEARCH_FLAGGED_POSTS: null,
@ -25,5 +24,4 @@ export default keyMirror({
RECEIVED_SEARCH_TERM: null,
REMOVE_SEARCH_POSTS: null,
REMOVE_SEARCH_FILES: null,
REMOVE_SEARCH_TERM: null,
});

View File

@ -20,10 +20,6 @@ export default keyMirror({
GET_TEAM_MEMBERS_SUCCESS: null,
GET_TEAM_MEMBERS_FAILURE: null,
JOIN_TEAM_REQUEST: null,
JOIN_TEAM_SUCCESS: null,
JOIN_TEAM_FAILURE: null,
TEAM_INVITE_INFO_REQUEST: null,
TEAM_INVITE_INFO_SUCCESS: null,
TEAM_INVITE_INFO_FAILURE: null,

View File

@ -28,14 +28,6 @@ import {insertMultipleWithoutDuplicates, insertWithoutDuplicates, removeItem} fr
import {General} from '../constants';
export function expandCategory(categoryId: string) { // HARRISONTODO unused
return setCategoryCollapsed(categoryId, false);
}
export function collapseCategory(categoryId: string) { // HARRISONTODO unused
return setCategoryCollapsed(categoryId, true);
}
export function setCategoryCollapsed(categoryId: string, collapsed: boolean) {
return patchCategory(categoryId, {
collapsed,

View File

@ -8,7 +8,6 @@ import type {IncomingWebhook, OutgoingWebhook} from '@mattermost/types/integrati
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, loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
@ -249,31 +248,6 @@ describe('Actions.Channels', () => {
expect(profilesInChannel[created.id].has(user2.id)).toBeTruthy();
});
it('updateChannel', async () => {
const channel = {
...TestHelper.basicChannel!,
purpose: 'This is to test redux',
header: 'MM with Redux',
};
nock(Client4.getBaseRoute()).
put(`/channels/${channel.id}`).
reply(200, channel);
await store.dispatch(Actions.updateChannel(channel));
const updateRequest = store.getState().requests.channels.updateChannel;
if (updateRequest.status === RequestStatus.FAILURE) {
throw new Error(JSON.stringify(updateRequest.error));
}
const {channels} = store.getState().entities.channels;
const channelId = Object.keys(channels)[0];
expect(channelId).toBeTruthy();
expect(channels[channelId]).toBeTruthy();
expect(channels[channelId].header).toEqual('MM with Redux');
});
it('patchChannel', async () => {
const channel = {
header: 'MM with Redux2',
@ -285,11 +259,6 @@ describe('Actions.Channels', () => {
await store.dispatch(Actions.patchChannel(TestHelper.basicChannel!.id, channel));
const updateRequest = store.getState().requests.channels.updateChannel;
if (updateRequest.status === RequestStatus.FAILURE) {
throw new Error(JSON.stringify(updateRequest.error));
}
const {channels} = store.getState().entities.channels;
const channelId = Object.keys(channels)[0];
expect(channelId).toBeTruthy();
@ -307,11 +276,6 @@ describe('Actions.Channels', () => {
await store.dispatch(Actions.updateChannelPrivacy(publicChannel.id, General.PRIVATE_CHANNEL));
const updateRequest = store.getState().requests.channels.updateChannel;
if (updateRequest.status === RequestStatus.FAILURE) {
throw new Error(JSON.stringify(updateRequest.error));
}
const {channels} = store.getState().entities.channels;
const channelId = Object.keys(channels)[0];
expect(channelId).toBeTruthy();
@ -1460,70 +1424,6 @@ describe('Actions.Channels', () => {
expect(stats[channelId].member_count >= 1).toBeTruthy();
});
it('updateChannelMemberRoles', async () => {
nock(Client4.getBaseRoute()).
post('/users').
reply(201, TestHelper.fakeUserWithId());
const user = await TestHelper.basicClient4!.createUser(TestHelper.fakeUser(), '', '');
nock(Client4.getTeamsRoute()).
post(`/${TestHelper.basicChannel!.id}/members`).
reply(201, {team_id: TestHelper.basicTeam!.id, roles: 'channel_user', user_id: user.id});
await store.dispatch(addUserToTeam(TestHelper.basicTeam!.id, user.id));
nock(Client4.getBaseRoute()).
post(`/channels/${TestHelper.basicChannel!.id}/members`).
reply(201, {channel_id: TestHelper.basicChannel!.id, roles: 'channel_user', user_id: user.id});
await store.dispatch(Actions.addChannelMember(TestHelper.basicChannel!.id, user.id));
const roles = General.CHANNEL_USER_ROLE + ' ' + General.CHANNEL_ADMIN_ROLE;
nock(Client4.getBaseRoute()).
put(`/channels/${TestHelper.basicChannel!.id}/members/${user.id}/roles`).
reply(200, {roles});
await store.dispatch(Actions.updateChannelMemberRoles(TestHelper.basicChannel!.id, user.id, roles));
const members = store.getState().entities.channels.membersInChannel;
expect(members[TestHelper.basicChannel!.id]).toBeTruthy();
expect(members[TestHelper.basicChannel!.id][user.id]).toBeTruthy();
expect(members[TestHelper.basicChannel!.id][user.id].roles === roles).toBeTruthy();
});
it('updateChannelHeader', async () => {
nock(Client4.getBaseRoute()).
get(`/channels/${TestHelper.basicChannel!.id}`).
reply(200, TestHelper.basicChannel!);
await store.dispatch(Actions.getChannel(TestHelper.basicChannel!.id));
const header = 'this is an updated test header';
await store.dispatch(Actions.updateChannelHeader(TestHelper.basicChannel!.id, header));
const {channels} = store.getState().entities.channels;
const channel = channels[TestHelper.basicChannel!.id];
expect(channel).toBeTruthy();
expect(channel.header).toEqual(header);
});
it('updateChannelPurpose', async () => {
nock(Client4.getBaseRoute()).
get(`/channels/${TestHelper.basicChannel!.id}`).
reply(200, TestHelper.basicChannel!);
await store.dispatch(Actions.getChannel(TestHelper.basicChannel!.id));
const purpose = 'this is an updated test purpose';
await store.dispatch(Actions.updateChannelPurpose(TestHelper.basicChannel!.id, purpose));
const {channels} = store.getState().entities.channels;
const channel = channels[TestHelper.basicChannel!.id];
expect(channel).toBeTruthy();
expect(channel.purpose).toEqual(purpose);
});
describe('leaveChannel', () => {
const team = TestHelper.fakeTeam();
const user = TestHelper.fakeUserWithId();

View File

@ -256,114 +256,36 @@ export function createGroupChannel(userIds: string[]): NewActionFuncAsync<Channe
}
export function patchChannel(channelId: string, patch: Partial<Channel>): NewActionFuncAsync<Channel> {
return async (dispatch, getState) => {
dispatch({type: ChannelTypes.UPDATE_CHANNEL_REQUEST, data: null});
let updated;
try {
updated = await Client4.patchChannel(channelId, patch);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch({type: ChannelTypes.UPDATE_CHANNEL_FAILURE, error});
dispatch(logError(error));
return {error};
}
dispatch(batchActions([
{
type: ChannelTypes.RECEIVED_CHANNEL,
data: updated,
},
{
type: ChannelTypes.UPDATE_CHANNEL_SUCCESS,
},
]));
return {data: updated};
};
}
export function updateChannel(channel: Channel): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
dispatch({type: ChannelTypes.UPDATE_CHANNEL_REQUEST, data: null});
let updated;
try {
updated = await Client4.updateChannel(channel);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch({type: ChannelTypes.UPDATE_CHANNEL_FAILURE, error});
dispatch(logError(error));
return {error};
}
dispatch(batchActions([
{
type: ChannelTypes.RECEIVED_CHANNEL,
data: updated,
},
{
type: ChannelTypes.UPDATE_CHANNEL_SUCCESS,
},
]));
return {data: updated};
};
return bindClientFunc({
clientFunc: Client4.patchChannel,
onSuccess: [ChannelTypes.RECEIVED_CHANNEL],
params: [channelId, patch],
});
}
export function updateChannelPrivacy(channelId: string, privacy: string): NewActionFuncAsync<Channel> {
return async (dispatch, getState) => {
dispatch({type: ChannelTypes.UPDATE_CHANNEL_REQUEST, data: null});
let updatedChannel;
try {
updatedChannel = await Client4.updateChannelPrivacy(channelId, privacy);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch({type: ChannelTypes.UPDATE_CHANNEL_FAILURE, error});
dispatch(logError(error));
return {error};
}
dispatch(batchActions([
{
type: ChannelTypes.RECEIVED_CHANNEL,
data: updatedChannel,
},
{
type: ChannelTypes.UPDATE_CHANNEL_SUCCESS,
},
]));
return {data: updatedChannel};
};
return bindClientFunc({
clientFunc: Client4.updateChannelPrivacy,
onSuccess: [ChannelTypes.RECEIVED_CHANNEL],
params: [channelId, privacy],
});
}
export function convertGroupMessageToPrivateChannel(channelID: string, teamID: string, displayName: string, name: string): NewActionFuncAsync {
return async (dispatch, getState) => {
dispatch({type: ChannelTypes.UPDATE_CHANNEL_REQUEST, data: null});
let updatedChannel;
try {
updatedChannel = await Client4.convertGroupMessageToPrivateChannel(channelID, teamID, displayName, name);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch({type: ChannelTypes.UPDATE_CHANNEL_FAILURE, error});
dispatch(logError(error));
return {error};
}
dispatch(batchActions([
{
type: ChannelTypes.RECEIVED_CHANNEL,
data: updatedChannel,
},
{
type: ChannelTypes.UPDATE_CHANNEL_SUCCESS,
},
]));
dispatch({
type: ChannelTypes.RECEIVED_CHANNEL,
data: updatedChannel,
});
// move the channel from direct message category to the default "channels" category
const channelsCategory = getCategoryInTeamByType(getState(), teamID, CategoryTypes.CHANNELS);
@ -1136,60 +1058,6 @@ export function removeChannelMember(channelId: string, userId: string): NewActio
};
}
export function updateChannelMemberRoles(channelId: string, userId: string, roles: string): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
try {
await Client4.updateChannelMemberRoles(channelId, userId, roles);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error));
return {error};
}
const membersInChannel = getState().entities.channels.membersInChannel[channelId];
if (membersInChannel && membersInChannel[userId]) {
dispatch({
type: ChannelTypes.RECEIVED_CHANNEL_MEMBER,
data: {...membersInChannel[userId], roles},
});
}
return {data: true};
};
}
export function updateChannelHeader(channelId: string, header: string): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch) => {
Client4.trackEvent('action', 'action_channels_update_header', {channel_id: channelId});
dispatch({
type: ChannelTypes.UPDATE_CHANNEL_HEADER,
data: {
channelId,
header,
},
});
return {data: true};
};
}
export function updateChannelPurpose(channelId: string, purpose: string): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch) => {
Client4.trackEvent('action', 'action_channels_update_purpose', {channel_id: channelId});
dispatch({
type: ChannelTypes.UPDATE_CHANNEL_PURPOSE,
data: {
channelId,
purpose,
},
});
return {data: true};
};
}
export function markChannelAsRead(channelId: string, skipUpdateViewTime = false): NewActionFunc {
return (dispatch, getState) => {
if (skipUpdateViewTime) {
@ -1494,7 +1362,6 @@ export default {
selectChannel,
createChannel,
createDirectChannel,
updateChannel,
patchChannel,
updateChannelNotifyProps,
getChannel,
@ -1513,8 +1380,6 @@ export default {
getChannelStats,
addChannelMember,
removeChannelMember,
updateChannelHeader,
updateChannelPurpose,
markChannelAsRead,
favoriteChannel,
unfavoriteChannel,

View File

@ -64,58 +64,6 @@ describe('Actions.General', () => {
expect(serverVersion).toEqual(version);
});
it('getDataRetentionPolicy', async () => {
const responseData = {
message_deletion_enabled: true,
file_deletion_enabled: false,
message_retention_cutoff: Date.now(),
file_retention_cutoff: 0,
};
nock(Client4.getBaseRoute()).
get('/data_retention/policy').
query(true).
reply(200, responseData);
await store.dispatch(Actions.getDataRetentionPolicy());
await TestHelper.wait(100);
const {dataRetentionPolicy} = store.getState().entities.general;
expect(dataRetentionPolicy).toEqual(responseData);
});
it('getWarnMetricsStatus', async () => {
const responseData = {
metric1: true,
metric2: false,
};
nock(Client4.getBaseRoute()).
get('/warn_metrics/status').
query(true).
reply(200, responseData);
await store.dispatch(Actions.getWarnMetricsStatus());
const {warnMetricsStatus} = store.getState().entities.general;
expect(warnMetricsStatus.metric1).toEqual(true);
expect(warnMetricsStatus.metric2).toEqual(false);
});
it('getFirstAdminVisitMarketplaceStatus', async () => {
const responseData = {
name: 'FirstAdminVisitMarketplace',
value: 'false',
};
nock(Client4.getPluginsRoute()).
get('/marketplace/first_admin_visit').
query(true).
reply(200, responseData);
await store.dispatch(Actions.getFirstAdminVisitMarketplaceStatus());
const {firstAdminVisitMarketplaceStatus} = store.getState().entities.general;
expect(firstAdminVisitMarketplaceStatus).toEqual(false);
});
it('setFirstAdminVisitMarketplaceStatus', async () => {
nock(Client4.getPluginsRoute()).
post('/marketplace/first_admin_visit').

View File

@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {batchActions} from 'redux-batched-actions';
import {LogLevel} from '@mattermost/types/client4';
import type {SystemSetting} from '@mattermost/types/general';
@ -33,29 +31,6 @@ export function getClientConfig(): NewActionFuncAsync {
};
}
export function getDataRetentionPolicy(): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
let data;
try {
data = await Client4.getDataRetentionPolicy();
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch({
type: GeneralTypes.RECEIVED_DATA_RETENTION_POLICY,
error,
});
dispatch(logError(error));
return {error};
}
dispatch(batchActions([
{type: GeneralTypes.RECEIVED_DATA_RETENTION_POLICY, data},
]));
return {data};
};
}
export function getLicenseConfig() {
return bindClientFunc({
clientFunc: Client4.getClientLicenseOld,
@ -90,21 +65,6 @@ export function setUrl(url: string) {
return true;
}
export function getWarnMetricsStatus(): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
let data;
try {
data = await Client4.getWarnMetricsStatus();
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
return {error};
}
dispatch({type: GeneralTypes.WARN_METRICS_STATUS_RECEIVED, data});
return {data};
};
}
export function setFirstAdminVisitMarketplaceStatus(): NewActionFuncAsync {
return async (dispatch) => {
try {
@ -118,22 +78,6 @@ export function setFirstAdminVisitMarketplaceStatus(): NewActionFuncAsync {
};
}
export function getFirstAdminVisitMarketplaceStatus(): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
let data;
try {
data = await Client4.getFirstAdminVisitMarketplaceStatus();
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
return {error};
}
data = JSON.parse(data.value);
dispatch({type: GeneralTypes.FIRST_ADMIN_VISIT_MARKETPLACE_STATUS_RECEIVED, data});
return {data};
};
}
// accompanying "set" happens as part of Client4.completeSetup
export function getFirstAdminSetupComplete(): NewActionFuncAsync<SystemSetting> {
return async (dispatch, getState) => {
@ -153,11 +97,8 @@ export function getFirstAdminSetupComplete(): NewActionFuncAsync<SystemSetting>
export default {
getClientConfig,
getDataRetentionPolicy,
getLicenseConfig,
logClientError,
setServerVersion,
setUrl,
getWarnMetricsStatus,
getFirstAdminVisitMarketplaceStatus,
};

View File

@ -1277,46 +1277,6 @@ describe('Actions.Posts', () => {
expect(!reactions[TestHelper.basicUser!.id + '-' + emojiName]).toBeTruthy();
});
it('getReactionsForPost', async () => {
const {dispatch, getState} = store;
TestHelper.mockLogin();
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMe());
nock(Client4.getBaseRoute()).
post('/posts').
reply(201, TestHelper.fakePostWithId(TestHelper.basicChannel!.id));
const post1 = await Client4.createPost(
TestHelper.fakePost(TestHelper.basicChannel!.id),
);
const emojiName = '+1';
nock(Client4.getBaseRoute()).
post('/reactions').
reply(201, {user_id: TestHelper.basicUser!.id, post_id: post1.id, emoji_name: emojiName, create_at: 1508168444721});
await dispatch(Actions.addReaction(post1.id, emojiName));
dispatch({
type: PostTypes.REACTION_DELETED,
data: {user_id: TestHelper.basicUser!.id, post_id: post1.id, emoji_name: emojiName},
});
nock(Client4.getBaseRoute()).
get(`/posts/${post1.id}/reactions`).
reply(200, [{user_id: TestHelper.basicUser!.id, post_id: post1.id, emoji_name: emojiName, create_at: 1508168444721}]);
await dispatch(Actions.getReactionsForPost(post1.id));
const state = getState();
const reactions = state.entities.posts.reactions[post1.id];
expect(reactions).toBeTruthy();
expect(reactions[TestHelper.basicUser!.id + '-' + emojiName]).toBeTruthy();
});
it('getCustomEmojiForReaction', async () => {
const testImageData = fs.createReadStream('src/packages/mattermost-redux/test/assets/images/test.png');
const {dispatch, getState} = store;

View File

@ -6,16 +6,14 @@ import {batchActions} from 'redux-batched-actions';
import type {Channel, ChannelUnread} from '@mattermost/types/channels';
import type {FetchPaginatedThreadOptions} from '@mattermost/types/client4';
import type {ServerError} from '@mattermost/types/errors';
import type {Group} from '@mattermost/types/groups';
import type {Post, PostList, PostAcknowledgement} from '@mattermost/types/posts';
import type {Reaction} from '@mattermost/types/reactions';
import type {GlobalState} from '@mattermost/types/store';
import type {UserProfile} from '@mattermost/types/users';
import {PostTypes, ChannelTypes, FileTypes, IntegrationTypes} from 'mattermost-redux/action_types';
import {selectChannel} from 'mattermost-redux/actions/channels';
import {systemEmojis, getCustomEmojiByName, getCustomEmojisByName} from 'mattermost-redux/actions/emojis';
import {systemEmojis, getCustomEmojiByName} from 'mattermost-redux/actions/emojis';
import {searchGroups} from 'mattermost-redux/actions/groups';
import {bindClientFunc, forceLogoutIfNecessary} from 'mattermost-redux/actions/helpers';
import {
@ -657,58 +655,6 @@ export function getCustomEmojiForReaction(name: string): NewActionFuncAsync {
};
}
export function getReactionsForPost(postId: string): ThunkActionFunc<Promise<Reaction[] | {error: ServerError}>> { // HARRISONTODO unused
return async (dispatch, getState) => {
let reactions;
try {
reactions = await Client4.getReactionsForPost(postId);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error));
return {error};
}
if (reactions && reactions.length > 0) {
const nonExistentEmoji = getState().entities.emojis.nonExistentEmoji;
const customEmojisByName = selectCustomEmojisByName(getState());
const emojisToLoad = new Set<string>();
reactions.forEach((r: Reaction) => {
const name = r.emoji_name;
if (systemEmojis.has(name)) {
// It's a system emoji, go the next match
return;
}
if (nonExistentEmoji.has(name)) {
// We've previously confirmed this is not a custom emoji
return;
}
if (customEmojisByName.has(name)) {
// We have the emoji, go to the next match
return;
}
emojisToLoad.add(name);
});
dispatch(getCustomEmojisByName(Array.from(emojisToLoad)));
}
dispatch(batchActions([
{
type: PostTypes.RECEIVED_REACTIONS,
data: reactions,
postId,
},
]));
return reactions;
};
}
export function flagPost(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const {currentUserId} = getState().entities.users;
@ -1251,13 +1197,6 @@ export function removePost(post: ExtendedPost): NewActionFunc<boolean> {
};
}
export function selectPost(postId: string) { // HARRISONTODO unused
return {
type: PostTypes.RECEIVED_POST_SELECTED,
data: postId,
};
}
export function moveThread(postId: string, channelId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
try {

View File

@ -11,7 +11,6 @@ import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
import TestHelper from '../../test/test_helper';
import configureStore from '../../test/test_store';
import {Preferences} from '../constants';
const OK_RESPONSE = {status: 'OK'};
@ -191,72 +190,6 @@ describe('Actions.Preferences', () => {
expect(!myPreferences['test--test3']).toBeTruthy();
});
it('makeDirectChannelVisibleIfNecessary', async () => {
const user = TestHelper.basicUser!;
nock(Client4.getBaseRoute()).
post('/users').
reply(201, TestHelper.fakeUserWithId());
const user2 = await TestHelper.createClient4().createUser(TestHelper.fakeUser(), '', '');
TestHelper.mockLogin();
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(loadMe());
// Test that a new preference is created if none exists
nock(Client4.getUsersRoute()).
put(`/${TestHelper.basicUser!.id}/preferences`).
reply(200, OK_RESPONSE);
await store.dispatch(Actions.makeDirectChannelVisibleIfNecessary(user2.id));
let state = store.getState();
let myPreferences = state.entities.preferences.myPreferences;
let preference = myPreferences[`${Preferences.CATEGORY_DIRECT_CHANNEL_SHOW}--${user2.id}`];
// preference for showing direct channel doesn't exist
expect(preference).toBeTruthy();
// preference for showing direct channel is not true
expect(preference.value).toBe('true');
// Test that nothing changes if the preference already exists and is true
nock(Client4.getUsersRoute()).
put(`/${TestHelper.basicUser!.id}/preferences`).
reply(200, OK_RESPONSE);
await store.dispatch(Actions.makeDirectChannelVisibleIfNecessary(user2.id));
const state2 = store.getState();
// store should not change since direct channel is already visible
expect(state).toEqual(state2);
// Test that the preference is updated if it already exists and is false
nock(Client4.getUsersRoute()).
put(`/${TestHelper.basicUser!.id}/preferences`).
reply(200, OK_RESPONSE);
store.dispatch(Actions.savePreferences(user.id, [{
...preference,
value: 'false',
}]));
nock(Client4.getUsersRoute()).
put(`/${TestHelper.basicUser!.id}/preferences`).
reply(200, OK_RESPONSE);
await store.dispatch(Actions.makeDirectChannelVisibleIfNecessary(user2.id));
state = store.getState();
myPreferences = state.entities.preferences.myPreferences;
preference = myPreferences[`${Preferences.CATEGORY_DIRECT_CHANNEL_SHOW}--${user2.id}`];
// preference for showing direct channel doesn't exist
expect(preference).toBeTruthy();
// preference for showing direct channel is not true
expect(preference.value).toEqual('true');
});
it('saveTheme', async () => {
const user = TestHelper.basicUser!;
const team = TestHelper.basicTeam!;

View File

@ -11,9 +11,7 @@ import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import type {NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
import {getChannelAndMyMember, getMyChannelMember} from './channels';
import {bindClientFunc} from './helpers';
import {getProfilesByIds, getProfilesInChannel} from './users';
import {Preferences} from '../constants';
@ -50,60 +48,6 @@ export function getMyPreferences() {
});
}
export function makeDirectChannelVisibleIfNecessary(otherUserId: string): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
const state = getState();
const myPreferences = getMyPreferencesSelector(state);
const currentUserId = getCurrentUserId(state);
let preference = myPreferences[getPreferenceKey(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, otherUserId)];
if (!preference || preference.value === 'false') {
preference = {
user_id: currentUserId,
category: Preferences.CATEGORY_DIRECT_CHANNEL_SHOW,
name: otherUserId,
value: 'true',
};
dispatch(getProfilesByIds([otherUserId]));
dispatch(savePreferences(currentUserId, [preference]));
}
return {data: true};
};
}
export function makeGroupMessageVisibleIfNecessary(channelId: string): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
const state = getState();
const myPreferences = getMyPreferencesSelector(state);
const currentUserId = getCurrentUserId(state);
const {channels} = state.entities.channels;
let preference = myPreferences[getPreferenceKey(Preferences.CATEGORY_GROUP_CHANNEL_SHOW, channelId)];
if (!preference || preference.value === 'false') {
preference = {
user_id: currentUserId,
category: Preferences.CATEGORY_GROUP_CHANNEL_SHOW,
name: channelId,
value: 'true',
};
if (channels[channelId]) {
dispatch(getMyChannelMember(channelId));
} else {
dispatch(getChannelAndMyMember(channelId));
}
dispatch(getProfilesInChannel(channelId, 0));
dispatch(savePreferences(currentUserId, [preference]));
}
return {data: true};
};
}
export function setActionsMenuInitialisationState(initializationState: Record<string, boolean>): ThunkActionFunc<void> {
return async (dispatch, getState) => {
const state = getState();

View File

@ -61,13 +61,9 @@ describe('Actions.Search', () => {
await dispatch(Actions.searchPosts(TestHelper.basicTeam!.id, search1, false, false));
let state = getState();
let {recent, results} = state.entities.search;
let {results} = state.entities.search;
const {posts} = state.entities.posts;
let current = state.entities.search.current[TestHelper.basicTeam!.id];
expect(recent[TestHelper.basicTeam!.id]).toBeTruthy();
let searchIsPresent = recent[TestHelper.basicTeam!.id].findIndex((r: {terms: string}) => r.terms === search1);
expect(searchIsPresent !== -1).toBeTruthy();
expect(Object.keys(recent[TestHelper.basicTeam!.id]).length).toEqual(1);
expect(results.length).toEqual(1);
expect(posts[results[0]]).toBeTruthy();
expect(!current.isEnd).toBeTruthy();
@ -80,60 +76,9 @@ describe('Actions.Search', () => {
await dispatch(Actions.searchPostsWithParams(TestHelper.basicTeam!.id, {terms: search1, page: 1} as SearchParameter));
state = getState();
current = state.entities.search.current[TestHelper.basicTeam!.id];
recent = state.entities.search.recent;
results = state.entities.search.results;
expect(recent[TestHelper.basicTeam!.id]).toBeTruthy();
searchIsPresent = recent[TestHelper.basicTeam!.id].findIndex((r: {terms: string}) => r.terms === search1);
expect(searchIsPresent !== -1).toBeTruthy();
expect(Object.keys(recent[TestHelper.basicTeam!.id]).length).toEqual(1);
expect(results.length).toEqual(1);
expect(current.isEnd).toBeTruthy();
// DISABLED
// Test for posts from a user in a channel
//const search2 = `from: ${TestHelper.basicUser.username} in: ${TestHelper.basicChannel.name}`;
//nock(Client4.getTeamsRoute(), `/${TestHelper.basicTeam.id}/posts/search`).
//post(`/${TestHelper.basicTeam.id}/posts/search`).
//reply(200, {order: [post1.id, post2.id, TestHelper.basicPost.id], posts: {[post1.id]: post1, [TestHelper.basicPost.id]: TestHelper.basicPost, [post2.id]: post2}});
//nock(Client4.getChannelsRoute()).
//get(`/${TestHelper.basicChannel.id}/members/me`).
//reply(201, {user_id: TestHelper.basicUser.id, channel_id: TestHelper.basicChannel.id});
//
//await dispatch(Actions.searchPosts(
//TestHelper.basicTeam.id,
//search2
//));
//
//state = getState();
//recent = state.entities.search.recent;
//results = state.entities.search.results;
//searchIsPresent = recent[TestHelper.basicTeam.id].findIndex((r) => r.terms === search1);
//expect(searchIsPresent !== -1).toBeTruthy();
//expect(Object.keys(recent[TestHelper.basicTeam.id]).length).toEqual(2);
//expect(results.length).toEqual(3);
// Clear posts from the search store
//await dispatch(Actions.clearSearch());
//state = getState();
//recent = state.entities.search.recent;
//results = state.entities.search.results;
//searchIsPresent = recent[TestHelper.basicTeam.id].findIndex((r) => r.terms === search1);
//expect(searchIsPresent !== -1).toBeTruthy();
//expect(Object.keys(recent[TestHelper.basicTeam.id]).length).toEqual(2);
//expect(results.length).toEqual(0);
// Clear a recent term
//await dispatch(Actions.removeSearchTerms(TestHelper.basicTeam.id, search2));
//state = getState();
//recent = state.entities.search.recent;
//results = state.entities.search.results;
//searchIsPresent = recent[TestHelper.basicTeam.id].findIndex((r) => r.terms === search1);
//expect(searchIsPresent !== -1).toBeTruthy();
//searchIsPresent = recent[TestHelper.basicTeam.id].findIndex((r) => r.terms === search2);
//expect(searchIsPresent === -1).toBeTruthy();
//expect(Object.keys(recent[TestHelper.basicTeam.id]).length).toEqual(1);
//expect(results.length).toEqual(0);
});
it('Perform Files Search', async () => {
@ -153,16 +98,12 @@ describe('Actions.Search', () => {
get(`/${TestHelper.basicChannel!.id}/members/me`).
reply(201, {user_id: TestHelper.basicUser!.id, channel_id: TestHelper.basicChannel!.id});
await dispatch(Actions.searchFiles(TestHelper.basicTeam!.id, search1, false, false));
await dispatch(Actions.searchFilesWithParams(TestHelper.basicTeam!.id, {terms: search1, is_or_search: false, include_deleted_channels: false, page: 0, per_page: Actions.WEBAPP_SEARCH_PER_PAGE}));
let state = getState();
let {recent, fileResults} = state.entities.search;
let {fileResults} = state.entities.search;
const {filesFromSearch} = state.entities.files;
let current = state.entities.search.current[TestHelper.basicTeam!.id];
expect(recent[TestHelper.basicTeam!.id]).toBeTruthy();
let searchIsPresent = recent[TestHelper.basicTeam!.id].findIndex((r: {terms: string}) => r.terms === search1);
expect(searchIsPresent !== -1).toBeTruthy();
expect(Object.keys(recent[TestHelper.basicTeam!.id]).length).toEqual(1);
expect(fileResults.length).toEqual(1);
expect(filesFromSearch[fileResults[0]]).toBeTruthy();
expect(!current.isFilesEnd).toBeTruthy();
@ -175,12 +116,7 @@ describe('Actions.Search', () => {
await dispatch(Actions.searchFilesWithParams(TestHelper.basicTeam!.id, {terms: search1, page: 1} as SearchParameter));
state = getState();
current = state.entities.search.current[TestHelper.basicTeam!.id];
recent = state.entities.search.recent;
fileResults = state.entities.search.fileResults;
expect(recent[TestHelper.basicTeam!.id]).toBeTruthy();
searchIsPresent = recent[TestHelper.basicTeam!.id].findIndex((r: {terms: string}) => r.terms === search1);
expect(searchIsPresent !== -1).toBeTruthy();
expect(Object.keys(recent[TestHelper.basicTeam!.id]).length).toEqual(1);
expect(fileResults.length).toEqual(1);
expect(current.isFilesEnd).toBeTruthy();
});

View File

@ -19,7 +19,7 @@ import {receivedFiles} from './files';
import {forceLogoutIfNecessary} from './helpers';
import {getMentionsAndStatusesForPosts, receivedPosts} from './posts';
const WEBAPP_SEARCH_PER_PAGE = 20;
export const WEBAPP_SEARCH_PER_PAGE = 20;
export function getMissingChannelsFromPosts(posts: PostList['posts']): ThunkActionFunc<unknown> {
return async (dispatch, getState) => {
@ -182,10 +182,6 @@ export function searchFilesWithParams(teamId: string, params: SearchParameter):
};
}
export function searchFiles(teamId: string, terms: string, isOrSearch: boolean, includeDeletedChannels: boolean) { // HARRISONTODO unused
return searchFilesWithParams(teamId, {terms, is_or_search: isOrSearch, include_deleted_channels: includeDeletedChannels, page: 0, per_page: WEBAPP_SEARCH_PER_PAGE});
}
export function getMoreFilesForSearch(): NewActionFuncAsync {
return async (dispatch, getState) => {
const teamId = getCurrentTeamId(getState());
@ -269,35 +265,7 @@ export function getPinnedPosts(channelId: string): NewActionFuncAsync {
};
}
export function clearPinnedPosts(channelId: string): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch) => {
dispatch({
type: SearchTypes.REMOVE_SEARCH_PINNED_POSTS,
data: {
channelId,
},
});
return {data: true};
};
}
export function removeSearchTerms(teamId: string, terms: string): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch) => {
dispatch({
type: SearchTypes.REMOVE_SEARCH_TERM,
data: {
teamId,
terms,
},
});
return {data: true};
};
}
export default {
clearSearch,
removeSearchTerms,
searchPosts,
};

View File

@ -7,11 +7,11 @@ import nock from 'nock';
import type {Team} from '@mattermost/types/teams';
import {GeneralTypes, UserTypes} from 'mattermost-redux/action_types';
import {UserTypes} from 'mattermost-redux/action_types';
import * as Actions from 'mattermost-redux/actions/teams';
import {loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import {General, RequestStatus} from 'mattermost-redux/constants';
import {RequestStatus} from 'mattermost-redux/constants';
import TestHelper from '../../test/test_helper';
import configureStore from '../../test/test_store';
@ -344,65 +344,6 @@ describe('Actions.Teams', () => {
expect(patched.invite_id).toEqual(patchedInviteId);
});
it('Join Open Team', async () => {
const client = TestHelper.createClient4();
nock(Client4.getBaseRoute()).
post('/users').
query(true).
reply(201, TestHelper.fakeUserWithId());
const user = await client.createUser(
TestHelper.fakeUser(),
'',
'',
TestHelper.basicTeam!.invite_id,
);
nock(Client4.getBaseRoute()).
post('/users/login').
reply(200, user);
await client.login(user.email, 'password1');
nock(Client4.getBaseRoute()).
post('/teams').
reply(201, {...TestHelper.fakeTeamWithId(), allow_open_invite: true});
const team = await client.createTeam({...TestHelper.fakeTeam(), allow_open_invite: true});
store.dispatch({type: GeneralTypes.RECEIVED_SERVER_VERSION, data: '4.0.0'});
nock(Client4.getBaseRoute()).
post('/teams/members/invite').
query(true).
reply(201, {user_id: TestHelper.basicUser!.id, team_id: team.id});
nock(Client4.getBaseRoute()).
get(`/teams/${team.id}`).
reply(200, team);
nock(Client4.getUserRoute('me')).
get('/teams/members').
reply(200, [{user_id: TestHelper.basicUser!.id, roles: 'team_user', team_id: team.id}]);
nock(Client4.getUserRoute('me')).
get('/teams/unread').
query({params: {include_collapsed_threads: true}}).
reply(200, [{team_id: team.id, msg_count: 0, mention_count: 0}]);
await store.dispatch(Actions.joinTeam(team.invite_id, team.id));
const state = store.getState();
const request = state.requests.teams.joinTeam;
if (request.status !== RequestStatus.SUCCESS) {
throw new Error(JSON.stringify(request.error));
}
const {teams, myMembers} = state.entities.teams;
expect(teams[team.id]).toBeTruthy();
expect(myMembers[team.id]).toBeTruthy();
});
it('getMyTeamMembers and getMyTeamUnreads', async () => {
nock(Client4.getUserRoute('me')).
get('/teams/members').
@ -561,33 +502,6 @@ describe('Actions.Teams', () => {
expect(members[TestHelper.basicTeam!.id][user.id]).toBeTruthy();
});
it('addUsersToTeam', async () => {
nock(Client4.getBaseRoute()).
post('/users').
reply(201, TestHelper.fakeUserWithId());
const user = await TestHelper.basicClient4!.createUser(TestHelper.fakeUser(), '', '');
nock(Client4.getBaseRoute()).
post('/users').
reply(201, TestHelper.fakeUserWithId());
const user2 = await TestHelper.basicClient4!.createUser(TestHelper.fakeUser(), '', '');
nock(Client4.getTeamRoute(TestHelper.basicTeam!.id)).
post('/members/batch').
reply(201, [{user_id: user.id, team_id: TestHelper.basicTeam!.id}, {user_id: user2.id, team_id: TestHelper.basicTeam!.id}]);
await store.dispatch(Actions.addUsersToTeam(TestHelper.basicTeam!.id, [user.id, user2.id]));
const members = store.getState().entities.teams.membersInTeam;
const profilesInTeam = store.getState().entities.users.profilesInTeam;
expect(members[TestHelper.basicTeam!.id]).toBeTruthy();
expect(members[TestHelper.basicTeam!.id][user.id]).toBeTruthy();
expect(members[TestHelper.basicTeam!.id][user2.id]).toBeTruthy();
expect(profilesInTeam[TestHelper.basicTeam!.id]).toBeTruthy();
expect(profilesInTeam[TestHelper.basicTeam!.id].has(user.id)).toBeTruthy();
expect(profilesInTeam[TestHelper.basicTeam!.id].has(user2.id)).toBeTruthy();
});
describe('removeUserFromTeam', () => {
const team = {id: 'team'};
const user = {id: 'user'};
@ -684,31 +598,6 @@ describe('Actions.Teams', () => {
});
});
it('updateTeamMemberRoles', async () => {
nock(Client4.getBaseRoute()).
post('/users').
reply(201, TestHelper.fakeUserWithId());
const user = await TestHelper.basicClient4!.createUser(TestHelper.fakeUser(), '', '');
nock(Client4.getTeamRoute(TestHelper.basicTeam!.id)).
post('/members').
reply(201, {user_id: user.id, team_id: TestHelper.basicTeam!.id});
await store.dispatch(Actions.addUserToTeam(TestHelper.basicTeam!.id, user.id));
const roles = General.TEAM_USER_ROLE + ' ' + General.TEAM_ADMIN_ROLE;
nock(Client4.getBaseRoute()).
put(`/teams/${TestHelper.basicTeam!.id}/members/${user.id}/roles`).
reply(200, {user_id: user.id, team_id: TestHelper.basicTeam!.id, roles});
await store.dispatch(Actions.updateTeamMemberRoles(TestHelper.basicTeam!.id, user.id, roles.split(' ')));
const members = store.getState().entities.teams.membersInTeam;
expect(members[TestHelper.basicTeam!.id]).toBeTruthy();
expect(members[TestHelper.basicTeam!.id][user.id]).toBeTruthy();
expect(members[TestHelper.basicTeam!.id][user.id].roles).toEqual(roles.split(' '));
});
it('sendEmailInvitesToTeam', async () => {
nock(Client4.getTeamRoute(TestHelper.basicTeam!.id)).
post('/invite/email').

View File

@ -16,8 +16,6 @@ import {loadRolesIfNeeded} from 'mattermost-redux/actions/roles';
import {getProfilesByIds, getStatusesByIds} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import {General} from 'mattermost-redux/constants';
import {isCompatibleWithJoinViewTeamPermissions} from 'mattermost-redux/selectors/entities/general';
import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import type {ActionResult, DispatchFunc, GetStateFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
@ -484,36 +482,6 @@ export function addUserToTeam(teamId: string, userId: string): NewActionFuncAsyn
};
}
export function addUsersToTeam(teamId: string, userIds: string[]): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
let members;
try {
members = await Client4.addUsersToTeam(teamId, userIds);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error));
return {error};
}
const profiles: Array<Partial<UserProfile>> = [];
members.forEach((m: TeamMembership) => profiles.push({id: m.user_id}));
dispatch(batchActions([
{
type: UserTypes.RECEIVED_PROFILES_LIST_IN_TEAM,
data: profiles,
id: teamId,
},
{
type: TeamTypes.RECEIVED_MEMBERS_IN_TEAM,
data: members,
},
]));
return {data: members};
};
}
export function addUsersToTeamGracefully(teamId: string, userIds: string[]): NewActionFuncAsync<TeamMemberWithError[]> {
return async (dispatch, getState) => {
let result: TeamMemberWithError[];
@ -598,28 +566,6 @@ export function removeUserFromTeam(teamId: string, userId: string): NewActionFun
};
}
export function updateTeamMemberRoles(teamId: string, userId: string, roles: string[]): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
try {
await Client4.updateTeamMemberRoles(teamId, userId, roles);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error));
return {error};
}
const membersInTeam = getState().entities.teams.membersInTeam[teamId];
if (membersInTeam && membersInTeam[userId]) {
dispatch({
type: TeamTypes.RECEIVED_MEMBER_IN_TEAM,
data: {...membersInTeam[userId], roles},
});
}
return {data: true};
};
}
export function sendEmailInvitesToTeam(teamId: string, emails: string[]) {
return bindClientFunc({
clientFunc: Client4.sendEmailInvitesToTeam,
@ -707,37 +653,6 @@ export function checkIfTeamExists(teamName: string): NewActionFuncAsync<boolean>
};
}
export function joinTeam(inviteId: string, teamId: string): NewActionFuncAsync { // HARRISONTODO
return async (dispatch, getState) => {
dispatch({type: TeamTypes.JOIN_TEAM_REQUEST, data: null});
const state = getState();
try {
if (isCompatibleWithJoinViewTeamPermissions(state)) {
const currentUserId = state.entities.users.currentUserId;
await Client4.addToTeam(teamId, currentUserId);
} else {
await Client4.joinTeam(inviteId);
}
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch({type: TeamTypes.JOIN_TEAM_FAILURE, error});
dispatch(logError(error));
return {error};
}
dispatch(getMyTeamUnreads(isCollapsedThreadsEnabled(state)));
await Promise.all([
dispatch(getTeam(teamId)),
dispatch(getMyTeamMembers()),
]);
dispatch({type: TeamTypes.JOIN_TEAM_SUCCESS, data: null});
return {data: true};
};
}
export function setTeamIcon(teamId: string, imageData: File): NewActionFuncAsync {
return async (dispatch) => {
await Client4.setTeamIcon(teamId, imageData);

View File

@ -208,9 +208,6 @@ describe('Actions.Users', () => {
// channel stats is not empty
expect(channels.stats).toEqual({});
// selected post id is not empty
expect(posts.selectedPostId).toEqual('');
// current focused post id is not empty
expect(posts.currentFocusedPostId).toEqual('');
@ -1243,43 +1240,6 @@ describe('Actions.Users', () => {
expect(!userAccessTokens[data.id].token).toBeTruthy();
});
it('getUserAccessTokens', async () => {
TestHelper.mockLogin();
store.dispatch({
type: UserTypes.LOGIN_SUCCESS,
});
await store.dispatch(Actions.loadMe());
const currentUserId = store.getState().entities.users.currentUserId;
nock(Client4.getBaseRoute()).
post(`/users/${currentUserId}/tokens`).
reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId});
const {data} = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
nock(Client4.getBaseRoute()).
get('/users/tokens').
query(true).
reply(200, [{id: data.id, description: 'test token', user_id: currentUserId}]);
await store.dispatch(Actions.getUserAccessTokens());
const {myUserAccessTokens} = store.getState().entities.users;
const {userAccessTokensByUser, userAccessTokens} = store.getState().entities.admin;
expect(myUserAccessTokens).toBeTruthy();
expect(myUserAccessTokens[data.id]).toBeTruthy();
expect(!myUserAccessTokens[data.id].token).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][data.id]).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][data.id].token).toBeTruthy();
expect(userAccessTokens).toBeTruthy();
expect(userAccessTokens[data.id]).toBeTruthy();
expect(!userAccessTokens[data.id].token).toBeTruthy();
});
it('getUserAccessTokensForUser', async () => {
TestHelper.mockLogin();
store.dispatch({

View File

@ -872,45 +872,6 @@ export function searchProfiles(term: string, options: any = {}): NewActionFuncAs
};
}
let statusIntervalId: NodeJS.Timeout|null;
export function startPeriodicStatusUpdates(): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
if (statusIntervalId) {
clearInterval(statusIntervalId);
}
statusIntervalId = setInterval(
() => {
const {statuses} = getState().entities.users;
if (!statuses) {
return;
}
const userIds = Object.keys(statuses);
if (!userIds.length) {
return;
}
dispatch(getStatusesByIds(userIds));
},
General.STATUS_INTERVAL,
);
return {data: true};
};
}
export function stopPeriodicStatusUpdates(): NewActionFuncAsync { // HARRISONTODO unused
return async () => {
if (statusIntervalId) {
clearInterval(statusIntervalId);
}
return {data: true};
};
}
export function updateMe(user: Partial<UserProfile>): NewActionFuncAsync<UserProfile> {
return async (dispatch) => {
dispatch({type: UserTypes.UPDATE_ME_REQUEST, data: null});
@ -1209,27 +1170,6 @@ export function getUserAccessToken(tokenId: string): NewActionFuncAsync<UserAcce
};
}
export function getUserAccessTokens(page = 0, perPage: number = General.PROFILE_CHUNK_SIZE): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
let data;
try {
data = await Client4.getUserAccessTokens(page, perPage);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error));
return {error};
}
dispatch({
type: AdminTypes.RECEIVED_USER_ACCESS_TOKENS,
data,
});
return {data};
};
}
export function getUserAccessTokensForUser(userId: string, page = 0, perPage: number = General.PROFILE_CHUNK_SIZE): NewActionFuncAsync<UserAccessToken[]> {
return async (dispatch, getState) => {
let data;
@ -1369,8 +1309,6 @@ export default {
revokeSessionsForAllUsers,
getUserAudits,
searchProfiles,
startPeriodicStatusUpdates,
stopPeriodicStatusUpdates,
updateMe,
updateUserRoles,
updateUserMfa,

View File

@ -13,7 +13,6 @@ export default {
TEAMS_CHUNK_SIZE: 50,
JOBS_CHUNK_SIZE: 50,
SEARCH_TIMEOUT_MILLISECONDS: 100,
STATUS_INTERVAL: 60000,
AUTOCOMPLETE_SPLIT_CHARACTERS: ['.', '-', '_'],
OUT_OF_OFFICE: 'ooo',
OFFLINE: 'offline',

View File

@ -295,15 +295,6 @@ function userAccessTokens(state: Record<string, UserAccessToken> = {}, action: A
return {...state, ...nextState};
}
case AdminTypes.RECEIVED_USER_ACCESS_TOKENS: {
const nextState: any = {};
for (const uat of action.data) {
nextState[uat.id] = uat;
}
return {...state, ...nextState};
}
case UserTypes.REVOKED_USER_ACCESS_TOKEN: {
const nextState = {...state};
Reflect.deleteProperty(nextState, action.data);
@ -341,16 +332,6 @@ function userAccessTokensByUser(state: RelationOneToOne<UserProfile, Record<stri
return {...state, [action.userId]: nextUserState};
}
case AdminTypes.RECEIVED_USER_ACCESS_TOKENS: { // UserAccessToken[]
const nextUserState: any = {};
for (const uat of action.data) {
nextUserState[uat.user_id] = nextUserState[uat.user_id] || {};
nextUserState[uat.user_id][uat.id] = uat;
}
return {...state, ...nextUserState};
}
case UserTypes.REVOKED_USER_ACCESS_TOKEN: {
const userIds = Object.keys(state);
for (let i = 0; i < userIds.length; i++) {

View File

@ -135,116 +135,6 @@ describe('channels', () => {
});
});
describe('UPDATE_CHANNEL_HEADER', () => {
test('should update channel header', () => {
const state = deepFreeze(channelsReducer({
channels: {
channel1: {
id: 'channel1',
header: 'old',
},
channel2: {
id: 'channel2',
},
},
}, {}));
const nextState = channelsReducer(state, {
type: ChannelTypes.UPDATE_CHANNEL_HEADER,
data: {
channelId: 'channel1',
header: 'new',
},
});
expect(nextState).not.toBe(state);
expect(nextState.channels.channel1).toEqual({
id: 'channel1',
header: 'new',
});
expect(nextState.channels.channel2).toBe(state.channels.channel2);
});
test('should do nothing for a channel that is not loaded', () => {
const state = deepFreeze(channelsReducer({
channels: {
channel1: {
id: 'channel1',
header: 'old',
},
channel2: {
id: 'channel2',
},
},
}, {}));
const nextState = channelsReducer(state, {
type: ChannelTypes.UPDATE_CHANNEL_HEADER,
data: {
channelId: 'channel3',
header: 'new',
},
});
expect(nextState).toBe(state);
});
});
describe('UPDATE_CHANNEL_PURPOSE', () => {
test('should update channel purpose', () => {
const state = deepFreeze(channelsReducer({
channels: {
channel1: {
id: 'channel1',
purpose: 'old',
},
channel2: {
id: 'channel2',
},
},
}, {}));
const nextState = channelsReducer(state, {
type: ChannelTypes.UPDATE_CHANNEL_PURPOSE,
data: {
channelId: 'channel1',
purpose: 'new',
},
});
expect(nextState).not.toBe(state);
expect(nextState.channels.channel1).toEqual({
id: 'channel1',
purpose: 'new',
});
expect(nextState.channels.channel2).toBe(state.channels.channel2);
});
test('should do nothing for a channel that is not loaded', () => {
const state = deepFreeze(channelsReducer({
channels: {
channel1: {
id: 'channel1',
header: 'old',
},
channel2: {
id: 'channel2',
},
},
}, {}));
const nextState = channelsReducer(state, {
type: ChannelTypes.UPDATE_CHANNEL_PURPOSE,
data: {
channelId: 'channel3',
purpose: 'new',
},
});
expect(nextState).toBe(state);
});
});
describe('REMOVE_MEMBER_FROM_CHANNEL', () => {
test('should remove the channel member', () => {
const state = deepFreeze(channelsReducer({

View File

@ -147,36 +147,6 @@ function channels(state: IDMappedObjects<Channel> = {}, action: AnyAction) {
},
};
}
case ChannelTypes.UPDATE_CHANNEL_HEADER: {
const {channelId, header} = action.data;
if (!state[channelId]) {
return state;
}
return {
...state,
[channelId]: {
...state[channelId],
header,
},
};
}
case ChannelTypes.UPDATE_CHANNEL_PURPOSE: {
const {channelId, purpose} = action.data;
if (!state[channelId]) {
return state;
}
return {
...state,
[channelId]: {
...state[channelId],
purpose,
},
};
}
case ChannelTypes.LEAVE_CHANNEL: {
if (action.data) {
const nextState = {...state};

View File

@ -23,17 +23,6 @@ function config(state: Partial<ClientConfig> = {}, action: AnyAction) {
}
}
function dataRetentionPolicy(state: any = {}, action: AnyAction) {
switch (action.type) {
case GeneralTypes.RECEIVED_DATA_RETENTION_POLICY:
return action.data;
case UserTypes.LOGOUT_SUCCESS:
return {};
default:
return state;
}
}
function license(state: ClientLicense = {}, action: AnyAction) {
switch (action.type) {
case GeneralTypes.CLIENT_LICENSE_RECEIVED:
@ -61,8 +50,6 @@ function serverVersion(state = '', action: AnyAction) {
function warnMetricsStatus(state: any = {}, action: AnyAction) {
switch (action.type) {
case GeneralTypes.WARN_METRICS_STATUS_RECEIVED:
return action.data;
case GeneralTypes.WARN_METRIC_STATUS_RECEIVED: {
const nextState = {...state};
nextState[action.data.id] = action.data;
@ -102,7 +89,6 @@ function firstAdminCompleteSetup(state = false, action: AnyAction) {
export default combineReducers({
config,
dataRetentionPolicy,
license,
serverVersion,
warnMetricsStatus,

View File

@ -1136,17 +1136,6 @@ export function postsInThread(state: RelationOneToMany<Post, Post> = {}, action:
}
}
function selectedPostId(state = '', action: AnyAction) {
switch (action.type) {
case PostTypes.RECEIVED_POST_SELECTED:
return action.data;
case UserTypes.LOGOUT_SUCCESS:
return '';
default:
return state;
}
}
export function postEditHistory(state: Post[] = [], action: AnyAction) {
switch (action.type) {
case PostTypes.RECEIVED_POST_HISTORY:
@ -1171,18 +1160,6 @@ function currentFocusedPostId(state = '', action: AnyAction) {
export function reactions(state: RelationOneToOne<Post, Record<string, Reaction>> = {}, action: AnyAction) {
switch (action.type) {
case PostTypes.RECEIVED_REACTIONS: {
const reactionsList = action.data;
const nextReactions: Record<string, Reaction> = {};
reactionsList.forEach((reaction: Reaction) => {
nextReactions[reaction.user_id + '-' + reaction.emoji_name] = reaction;
});
return {
...state,
[action.postId!]: nextReactions,
};
}
case PostTypes.RECEIVED_REACTION: {
const reaction = action.data as Reaction;
const nextReactions = {...(state[reaction.post_id] || {})};
@ -1588,9 +1565,6 @@ export default function reducer(state: Partial<PostsState> = {}, action: AnyActi
// with no guaranteed order
postsInThread: postsInThread(state.postsInThread, action, state.posts!),
// The current selected post
selectedPostId: selectedPostId(state.selectedPostId, action),
// The post history of selected post
postEditHistory: postEditHistory(state.postEditHistory, action),
@ -1616,7 +1590,6 @@ export default function reducer(state: Partial<PostsState> = {}, action: AnyActi
if (state.posts === nextState.posts && state.postsInChannel === nextState.postsInChannel &&
state.postsInThread === nextState.postsInThread &&
state.pendingPostIds === nextState.pendingPostIds &&
state.selectedPostId === nextState.selectedPostId &&
state.postEditHistory === nextState.postEditHistory &&
state.currentFocusedPostId === nextState.currentFocusedPostId &&
state.reactions === nextState.reactions &&

View File

@ -6,7 +6,6 @@ import {combineReducers} from 'redux';
import type {Post} from '@mattermost/types/posts';
import type {PreferenceType} from '@mattermost/types/preferences';
import type {Search} from '@mattermost/types/search';
import {PostTypes, PreferenceTypes, SearchTypes, UserTypes} from 'mattermost-redux/action_types';
import {Preferences} from 'mattermost-redux/constants';
@ -196,61 +195,6 @@ function pinned(state: Record<string, string[]> = {}, action: AnyAction) {
return removePinnedPost(state, action.data);
}
case SearchTypes.REMOVE_SEARCH_PINNED_POSTS: {
const {channelId} = action.data;
const nextState = {...state};
if (nextState[channelId]) {
Reflect.deleteProperty(nextState, channelId);
return nextState;
}
return state;
}
case UserTypes.LOGOUT_SUCCESS:
return {};
default:
return state;
}
}
function recent(state: Record<string, Search[]> = {}, action: AnyAction) {
const {data, type} = action;
switch (type) {
case SearchTypes.RECEIVED_SEARCH_TERM: {
const nextState = {...state};
const {teamId, params} = data;
const {terms, isOrSearch} = params || {};
const team = [...(nextState[teamId] || [])];
const index = team.findIndex((r) => r.terms === terms);
if (index === -1) {
team.push({terms, isOrSearch});
} else {
team[index] = {terms, isOrSearch};
}
return {
...nextState,
[teamId]: team,
};
}
case SearchTypes.REMOVE_SEARCH_TERM: {
const nextState = {...state};
const {teamId, terms} = data;
const team = [...(nextState[teamId] || [])];
const index = team.findIndex((r) => r.terms === terms);
if (index !== -1) {
team.splice(index, 1);
return {
...nextState,
[teamId]: team,
};
}
return nextState;
}
case UserTypes.LOGOUT_SUCCESS:
return {};
@ -341,10 +285,6 @@ export default combineReducers({
// Object where every key is a post id mapping to an array of matched words in that post
matches,
// Object where every key is a team composed with
// an object where the key is the term and the value indicates is "or" search
recent,
// Object holding the current searches for every team
current,

View File

@ -30,16 +30,6 @@ function createChannel(state: RequestStatusType = initialRequestState(), action:
);
}
function updateChannel(state: RequestStatusType = initialRequestState(), action: AnyAction): RequestStatusType {
return handleRequest(
ChannelTypes.UPDATE_CHANNEL_REQUEST,
ChannelTypes.UPDATE_CHANNEL_SUCCESS,
ChannelTypes.UPDATE_CHANNEL_FAILURE,
state,
action,
);
}
function getChannels(state: RequestStatusType = initialRequestState(), action: AnyAction): RequestStatusType {
return handleRequest(
ChannelTypes.GET_CHANNELS_REQUEST,
@ -65,5 +55,4 @@ export default combineReducers({
getAllChannels,
myChannels,
createChannel,
updateChannel,
});

View File

@ -30,18 +30,7 @@ function getTeams(state: RequestStatusType = initialRequestState(), action: AnyA
);
}
function joinTeam(state: RequestStatusType = initialRequestState(), action: AnyAction): RequestStatusType {
return handleRequest(
TeamTypes.JOIN_TEAM_REQUEST,
TeamTypes.JOIN_TEAM_SUCCESS,
TeamTypes.JOIN_TEAM_FAILURE,
state,
action,
);
}
export default combineReducers({
getTeams,
getMyTeams,
joinTeam,
});

View File

@ -107,13 +107,6 @@ describe('Selectors.Teams', () => {
expect(joinableTeams[1]).toBe(openTeams[1]);
});
it('getListableTeams', () => {
const openTeams = [team3, team4];
const listableTeams = Selectors.getListableTeams(testState);
expect(listableTeams[0]).toBe(openTeams[0]);
expect(listableTeams[1]).toBe(openTeams[1]);
});
it('getListedJoinableTeams', () => {
const openTeams = [team4, team3];
const joinableTeams = Selectors.getSortedListableTeams(testState, 'en');
@ -227,82 +220,6 @@ describe('Selectors.Teams', () => {
expect(joinableTeams[3]).toBe(openTeams[1]);
});
it('getListableTeamsUsingPermissions', () => {
const privateTeams = [team1, team2];
const openTeams = [team3, team4];
let modifiedState = {
entities: {
...testState.entities,
teams: {
...testState.entities.teams,
myMembers: {},
},
roles: {
roles: {
system_user: {
...testState.entities.roles.roles.system_user,
permissions: ['list_private_teams'],
},
},
},
general: {
serverVersion: '5.10.0',
},
},
} as GlobalState;
let listableTeams = Selectors.getListableTeams(modifiedState);
expect(listableTeams[0]).toBe(privateTeams[0]);
expect(listableTeams[1]).toBe(privateTeams[1]);
modifiedState = {
entities: {
...testState.entities,
teams: {
...testState.entities.teams,
myMembers: {},
},
roles: {
roles: {
system_user: {
permissions: ['list_public_teams'],
},
},
},
general: {
serverVersion: '5.10.0',
},
},
} as GlobalState;
listableTeams = Selectors.getListableTeams(modifiedState);
expect(listableTeams[0]).toBe(openTeams[0]);
expect(listableTeams[1]).toBe(openTeams[1]);
modifiedState = {
entities: {
...testState.entities,
teams: {
...testState.entities.teams,
myMembers: {},
},
roles: {
roles: {
system_user: {
permissions: ['list_public_teams', 'list_private_teams'],
},
},
},
general: {
serverVersion: '5.10.0',
},
},
} as GlobalState;
listableTeams = Selectors.getListableTeams(modifiedState);
expect(listableTeams[0]).toBe(privateTeams[0]);
expect(listableTeams[1]).toBe(privateTeams[1]);
expect(listableTeams[2]).toBe(openTeams[0]);
expect(listableTeams[3]).toBe(openTeams[1]);
});
it('getSortedListableTeamsUsingPermissions', () => {
const privateTeams = [team2, team1];
const openTeams = [team4, team3];

View File

@ -226,15 +226,6 @@ export const getListableTeamIds: (state: GlobalState) => Array<Team['id']> = cre
},
);
export const getListableTeams: (state: GlobalState) => Team[] = createSelector(
'getListableTeams',
getTeams,
getListableTeamIds,
(teams, listableTeamIds) => {
return listableTeamIds.map((id) => teams[id]);
},
);
export const getSortedListableTeams: (state: GlobalState, locale: string) => Team[] = createSelector(
'getSortedListableTeams',
getTeams,

View File

@ -10,7 +10,6 @@ const state: GlobalState = {
entities: {
general: {
config: {},
dataRetentionPolicy: {},
license: {},
serverVersion: '',
warnMetricsStatus: {},
@ -75,7 +74,6 @@ const state: GlobalState = {
postEditHistory: [],
reactions: {},
openGraph: {},
selectedPostId: '',
currentFocusedPostId: '',
messagesHistory: {
messages: [],
@ -142,7 +140,6 @@ const state: GlobalState = {
results: [],
fileResults: [],
current: {},
recent: {},
matches: {},
flagged: [],
pinned: {},
@ -245,10 +242,6 @@ const state: GlobalState = {
status: 'not_started',
error: null,
},
updateChannel: {
status: 'not_started',
error: null,
},
},
general: {
websocket: {
@ -279,10 +272,6 @@ const state: GlobalState = {
status: 'not_started',
error: null,
},
joinTeam: {
status: 'not_started',
error: null,
},
},
users: {
login: {

View File

@ -762,7 +762,13 @@ describe('makeCombineUserActivityPosts', () => {
...state.entities,
posts: {
...state.entities.posts,
selectedPostId: 'post2',
messagesHistory: {
messages: [],
index: {
post: 4,
comment: 3,
},
},
},
},
};

View File

@ -58,7 +58,7 @@ export function makeFilterPostsAndAddSeparators() {
(state: GlobalState, {postIds}: PostFilterOptions) => getPostsForIds(state, postIds),
(state: GlobalState, {lastViewedAt}: PostFilterOptions) => lastViewedAt,
(state: GlobalState, {indicateNewMessages}: PostFilterOptions) => indicateNewMessages,
(state) => state.entities.posts.selectedPostId,
() => '', // This previously returned state.entities.posts.selectedPostId which stopped being set at some point
getCurrentUser,
shouldShowJoinLeaveMessages,
(posts, lastViewedAt, indicateNewMessages, selectedPostId, currentUser, showJoinLeave) => {

View File

@ -10,26 +10,6 @@ type ReducerState = ReturnType<typeof storageReducer>;
describe('Reducers.Storage', () => {
const now = new Date();
it('Storage.SET_ITEM', () => {
const nextState = storageReducer(
{
storage: {},
} as ReducerState,
{
type: StorageTypes.SET_ITEM,
data: {
name: 'key',
prefix: 'user_id_',
value: 'value',
timestamp: now,
},
},
);
expect(nextState.storage).toEqual({
user_id_key: {value: 'value', timestamp: now},
});
});
it('Storage.SET_GLOBAL_ITEM', () => {
const nextState = storageReducer(
{
@ -49,37 +29,6 @@ describe('Reducers.Storage', () => {
});
});
it('Storage.REMOVE_ITEM', () => {
let nextState = storageReducer(
{
storage: {
user_id_key: 'value',
},
} as unknown as ReducerState,
{
type: StorageTypes.REMOVE_ITEM,
data: {
name: 'key',
prefix: 'user_id_',
},
},
);
expect(nextState.storage).toEqual({});
nextState = storageReducer(
{
storage: {},
} as ReducerState,
{
type: StorageTypes.REMOVE_ITEM,
data: {
name: 'key',
prefix: 'user_id_',
},
},
);
expect(nextState.storage).toEqual({});
});
it('Storage.REMOVE_GLOBAL_ITEM', () => {
let nextState = storageReducer(
{

View File

@ -38,25 +38,6 @@ function storage(state: Record<string, any> = {}, action: AnyAction) {
return nextState;
}
case StorageTypes.SET_ITEM: {
if (!state[action.data.prefix + action.data.name] ||
!state[action.data.prefix + action.data.name].timestamp ||
state[action.data.prefix + action.data.name].timestamp < action.data.timestamp
) {
const nextState = {...state};
nextState[action.data.prefix + action.data.name] = {
timestamp: action.data.timestamp,
value: action.data.value,
};
return nextState;
}
return state;
}
case StorageTypes.REMOVE_ITEM: {
const nextState = {...state};
Reflect.deleteProperty(nextState, action.data.prefix + action.data.name);
return nextState;
}
case StorageTypes.SET_GLOBAL_ITEM: {
if (!state[action.data.name] ||
!state[action.data.name].timestamp ||

View File

@ -129,23 +129,10 @@ export function lastSelectedChannel(state = '', action: AnyAction): string {
}
}
function firstChannelName(state = '', action: AnyAction) {
switch (action.type) {
case ActionTypes.FIRST_CHANNEL_NAME:
return action.data;
case UserTypes.LOGOUT_SUCCESS:
return '';
default:
return state;
}
}
export default combineReducers({
unreadFilterEnabled,
draggingState,
newCategoryIds,
multiSelectedChannelIds,
lastSelectedChannel,
firstChannelName,
});

View File

@ -26,12 +26,8 @@ const getFirstChannelNamePref = createSelector(
},
);
export function getFirstChannelNameViews(state: GlobalState) {
return state.views.channelSidebar.firstChannelName;
}
export function getFirstChannelName(state: GlobalState) {
return getFirstChannelNameViews(state) || getFirstChannelNamePref(state)?.value || '';
return getFirstChannelNamePref(state)?.value || '';
}
export function getShowLaunchingWorkspace(state: GlobalState) {

View File

@ -3,8 +3,6 @@
import * as Selectors from 'selectors/storage';
import {getPrefix} from 'utils/storage_utils';
import type {GlobalState} from 'types/store';
describe('Selectors.Storage', () => {
@ -27,23 +25,9 @@ describe('Selectors.Storage', () => {
},
} as unknown as GlobalState;
it('getPrefix', () => {
expect(getPrefix({} as GlobalState)).toEqual('unknown_');
expect(getPrefix({entities: {}} as GlobalState)).toEqual('unknown_');
expect(getPrefix({entities: {users: {currentUserId: 'not-exists'}}} as GlobalState)).toEqual('unknown_');
expect(getPrefix({entities: {users: {currentUserId: 'not-exists', profiles: {}}}} as GlobalState)).toEqual('unknown_');
expect(getPrefix({entities: {users: {currentUserId: 'exists', profiles: {exists: {id: 'user_id'}}}}} as unknown as GlobalState)).toEqual('user_id_');
});
it('makeGetGlobalItem', () => {
expect(Selectors.makeGetGlobalItem('not-existing-global-item', undefined)(testState)).toEqual(undefined);
expect(Selectors.makeGetGlobalItem('not-existing-global-item', 'default')(testState)).toEqual('default');
expect(Selectors.makeGetGlobalItem('global-item', undefined)(testState)).toEqual('global-item-value');
});
it('makeGetItem', () => {
expect(Selectors.makeGetItem('not-existing-item', undefined)(testState)).toEqual(undefined);
expect(Selectors.makeGetItem('not-existing-item', 'default')(testState)).toEqual('default');
expect(Selectors.makeGetItem('item', undefined)(testState)).toEqual('item-value');
});
});

View File

@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {getPrefix} from 'utils/storage_utils';
import type {GlobalState} from 'types/store';
export const getGlobalItem = <T = any>(state: GlobalState, name: string, defaultValue: T) => {
@ -11,16 +9,6 @@ export const getGlobalItem = <T = any>(state: GlobalState, name: string, default
return getItemFromStorage(storage, name, defaultValue);
};
export const getItem = <T = any>(state: GlobalState, name: string, defaultValue: T) => {
return getGlobalItem(state, getPrefix(state) + name, defaultValue);
};
export const makeGetItem = <T = any>(name: string, defaultValue: T) => {
return (state: GlobalState) => {
return getItem(state, name, defaultValue);
};
};
export const makeGetGlobalItem = <T = any>(name: string, defaultValue: T) => {
return (state: GlobalState) => {
return getGlobalItem(state, name, defaultValue);

View File

@ -175,7 +175,6 @@ export type ViewsState = {
newCategoryIds: string[];
multiSelectedChannelIds: string[];
lastSelectedChannel: string;
firstChannelName: string;
};
statusDropdown: {

View File

@ -11,6 +11,7 @@ import keyMirror from 'key-mirror';
import {CustomStatusDuration} from '@mattermost/types/users';
import {Preferences as ReduxPreferences} from 'mattermost-redux/constants';
import Permissions from 'mattermost-redux/constants/permissions';
import * as PostListUtils from 'mattermost-redux/utils/post_list';
@ -62,8 +63,8 @@ export const PreviousViewedTypes = {
export const Preferences = {
CATEGORY_CHANNEL_OPEN_TIME: 'channel_open_time',
CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show',
CATEGORY_GROUP_CHANNEL_SHOW: 'group_channel_show',
CATEGORY_DIRECT_CHANNEL_SHOW: ReduxPreferences.CATEGORY_DIRECT_CHANNEL_SHOW,
CATEGORY_GROUP_CHANNEL_SHOW: ReduxPreferences.CATEGORY_GROUP_CHANNEL_SHOW,
CATEGORY_DISPLAY_SETTINGS: 'display_settings',
CATEGORY_SIDEBAR_SETTINGS: 'sidebar_settings',
CATEGORY_ADVANCED_SETTINGS: 'advanced_settings',
@ -315,8 +316,6 @@ export const ActionTypes = keyMirror({
SUPPRESS_RHS: null,
UNSUPPRESS_RHS: null,
FIRST_CHANNEL_NAME: null,
SET_EDIT_CHANNEL_MEMBERS: null,
NEEDS_LOGGED_IN_LIMIT_REACHED_CHECK: null,
@ -883,8 +882,6 @@ export const SearchTypes = keyMirror({
});
export const StorageTypes = keyMirror({
SET_ITEM: null,
REMOVE_ITEM: null,
SET_GLOBAL_ITEM: null,
REMOVE_GLOBAL_ITEM: null,
ACTION_ON_GLOBAL_ITEMS_WITH_PREFIX: null,

View File

@ -1,23 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {GlobalState} from '@mattermost/types/store';
import type {DraftInfo} from 'types/store/draft';
import {StoragePrefixes} from './constants';
export function getPrefix(state: GlobalState) {
if (state && state.entities && state.entities.users && state.entities.users.profiles) {
const user = state.entities.users.profiles[state.entities.users.currentUserId];
if (user) {
return user.id + '_';
}
}
return 'unknown_';
}
export function getDraftInfoFromKey(key: string, prefix: string): DraftInfo | null {
const keyArr = key.split('_');
if (prefix === StoragePrefixes.DRAFT) {

View File

@ -5,7 +5,6 @@ import {ClientConfig, ClientLicense, WarnMetricStatus} from './config';
export type GeneralState = {
config: Partial<ClientConfig>;
dataRetentionPolicy: any;
firstAdminVisitMarketplaceStatus: boolean;
firstAdminCompleteSetup: boolean;
license: ClientLicense;

View File

@ -146,7 +146,6 @@ export type PostsState = {
reactions: RelationOneToOne<Post, Record<string, Reaction>>;
openGraph: RelationOneToOne<Post, Record<string, OpenGraphMetadata>>;
pendingPostIds: string[];
selectedPostId: string;
postEditHistory: Post[];
currentFocusedPostId: string;
messagesHistory: MessageHistory;
@ -221,4 +220,4 @@ export type PostInfo = {
team_type: TeamType;
team_display_name: string;
has_joined_team: boolean;
}
}

View File

@ -12,7 +12,6 @@ export type ChannelsRequestsStatuses = {
getAllChannels: RequestStatusType;
myChannels: RequestStatusType;
createChannel: RequestStatusType;
updateChannel: RequestStatusType;
};
export type GeneralRequestsStatuses = {
@ -32,7 +31,6 @@ export type ThreadsRequestStatuses = {
export type TeamsRequestsStatuses = {
getMyTeams: RequestStatusType;
getTeams: RequestStatusType;
joinTeam: RequestStatusType;
};
export type UsersRequestsStatuses = {

View File

@ -15,9 +15,6 @@ export type SearchState = {
isSearchingTerm: boolean;
isSearchGettingMore: boolean;
isLimitedResults: number;
recent: {
[x: string]: Search[];
};
matches: {
[x: string]: string[];
};