Skip to content

Commit

Permalink
Reorganize post state and make postsInChannel into a sparse array (ma…
Browse files Browse the repository at this point in the history
…ttermost#2609)

* MM-13957 Reorganize post actions (mattermost#2343)

* MM-13957 Reorganize post actions

* Use postDeleted action creator

* Show join/leave messages since combined systed messages have been temporarily removed

* Re-add tests for showFlaggedPosts and showPinnedPosts

* Add temporary fix for permalink view

* Update mattermost-redux

* MM-13958/MM-13959 Make postsInChannel into a sparse array (mattermost#2411)

* MM-13958/MM-13959 Make postsInChannel into a sparse array

* Fix unit tests

* Fix being unable to load channels with between 30 and 60 posts

* Fix unit tests

* MM-13960 Re-add support for combined user activity posts  (mattermost#2465)

* Add unit tests for PostList

* Remove unnecessary null check

* MM-13960 Re-add support for combined user activity posts

* Fix being deleted combined posts not disappearing for the user who deletes the post

* Fix PostList unit tests

* Fix New Messages Below indicator when PostList takes post IDs

* Update mattermost-redux

* Update mattermost-redux
  • Loading branch information
hmhealey committed Apr 15, 2019
1 parent efe092a commit da3ac93
Show file tree
Hide file tree
Showing 41 changed files with 1,321 additions and 831 deletions.
2 changes: 1 addition & 1 deletion actions/integration_actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,4 @@ describe('actions/integration_actions', () => {
expect(getProfilesByIds).not.toHaveBeenCalled();
});
});
});
});
72 changes: 3 additions & 69 deletions actions/post_actions.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {batchActions} from 'redux-batched-actions';

import {PostTypes, SearchTypes} from 'mattermost-redux/action_types';
import {SearchTypes} from 'mattermost-redux/action_types';
import {getMyChannelMember} from 'mattermost-redux/actions/channels';
import {getChannel, getMyChannelMember as getMyChannelMemberSelector} from 'mattermost-redux/selectors/entities/channels';
import * as PostActions from 'mattermost-redux/actions/posts';
Expand Down Expand Up @@ -129,60 +127,6 @@ export function addReaction(postId, emojiName) {
};
}

const POST_INCREASE_AMOUNT = Constants.POST_CHUNK_SIZE / 2;

// Returns true if there are more posts to load
export function increasePostVisibility(channelId, focusedPostId) {
return async (dispatch, getState) => {
const state = getState();
if (state.views.channel.loadingPosts[channelId]) {
return true;
}

const currentPostVisibility = state.views.channel.postVisibility[channelId];

if (currentPostVisibility >= Constants.MAX_POST_VISIBILITY) {
return true;
}

dispatch({
type: ActionTypes.LOADING_POSTS,
data: true,
channelId,
});

const page = Math.floor(currentPostVisibility / POST_INCREASE_AMOUNT);

let result;
if (focusedPostId) {
result = await dispatch(PostActions.getPostsBefore(channelId, focusedPostId, page, POST_INCREASE_AMOUNT));
} else {
result = await dispatch(PostActions.getPosts(channelId, page, POST_INCREASE_AMOUNT));
}
const posts = result.data;

const actions = [{
type: ActionTypes.LOADING_POSTS,
data: false,
channelId,
}];

if (posts) {
actions.push({
type: ActionTypes.INCREASE_POST_VISIBILITY,
data: channelId,
amount: posts.order.length,
});
}

dispatch(batchActions(actions));
return {
moreToLoad: posts ? posts.order.length >= POST_INCREASE_AMOUNT : false,
error: result.error,
};
};
}

export function searchForTerm(term) {
return (dispatch) => {
dispatch(RhsActions.updateSearchTerms(term));
Expand Down Expand Up @@ -289,14 +233,7 @@ export function hideEditPostModal() {

export function deleteAndRemovePost(post) {
return async (dispatch, getState) => {
const {currentUserId} = getState().entities.users;

let hardDelete = false;
if (post.user_id === currentUserId) {
hardDelete = true;
}

const {error} = await dispatch(PostActions.deletePost(post, hardDelete));
const {error} = await dispatch(PostActions.deletePost(post));
if (error) {
return {error};
}
Expand All @@ -309,10 +246,7 @@ export function deleteAndRemovePost(post) {
});
}

dispatch({
type: PostTypes.REMOVE_POST,
data: post,
});
dispatch(PostActions.removePost(post));

return {data: true};
};
Expand Down
67 changes: 8 additions & 59 deletions actions/post_actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import thunk from 'redux-thunk';
import configureStore from 'redux-mock-store';

import {Posts} from 'mattermost-redux/constants';
import {SearchTypes} from 'mattermost-redux/action_types';
import * as PostActions from 'mattermost-redux/actions/posts';
import {Posts} from 'mattermost-redux/constants';

import * as Actions from 'actions/post_actions';
import {Constants, ActionTypes, RHSStates} from 'utils/constants';
Expand All @@ -16,12 +17,11 @@ jest.mock('mattermost-redux/actions/posts', () => ({
addReaction: (...args) => ({type: 'MOCK_ADD_REACTION', args}),
createPost: (...args) => ({type: 'MOCK_CREATE_POST', args}),
createPostImmediately: (...args) => ({type: 'MOCK_CREATE_POST_IMMEDIATELY', args}),
getPosts: (...args) => ({type: 'MOCK_GET_POSTS', args}),
getPostsBefore: (...args) => ({type: 'MOCK_GET_POSTS_BEFORE', args}),
flagPost: (...args) => ({type: 'MOCK_FLAG_POST', args}),
unflagPost: (...args) => ({type: 'MOCK_UNFLAG_POST', args}),
pinPost: (...args) => ({type: 'MOCK_PIN_POST', args}),
unpinPost: (...args) => ({type: 'MOCK_UNPIN_POST', args}),
receivedNewPost: (...args) => ({type: 'MOCK_RECEIVED_NEW_POST', args}),
}));

jest.mock('actions/emoji_actions', () => ({
Expand All @@ -44,17 +44,10 @@ const POST_CREATED_TIME = Date.now();

// This mocks the Date.now() function so it returns a constant value
global.Date.now = jest.fn(() => POST_CREATED_TIME);

const INCREASED_POST_VISIBILITY = {amount: 1, data: 'current_channel_id', type: 'INCREASE_POST_VISIBILITY'};
const STOP_TYPING = {type: 'stop_typing', data: {id: 'current_channel_idundefined', now: POST_CREATED_TIME, userId: 'some_user_id'}};

function getReceivedPosts(post) {
return {
type: 'RECEIVED_NEW_POST',
data: {...post},
channelId: post.channel_id,
};
}

describe('Actions.Posts', () => {
const latestPost = {
id: 'latest_post_id',
Expand All @@ -70,7 +63,9 @@ describe('Actions.Posts', () => {
[latestPost.id]: latestPost,
},
postsInChannel: {
current_channel_id: [latestPost.id],
current_channel_id: [
{order: [latestPost.id], recent: true},
],
},
postsInThread: {},
messagesHistory: {
Expand Down Expand Up @@ -154,10 +149,6 @@ describe('Actions.Posts', () => {
posts: {
editingPost: {},
},
channel: {
loadingPosts: {},
postVisibility: {current_channel_id: 60},
},
rhs: {searchTerms: ''},
},
};
Expand All @@ -172,7 +163,7 @@ describe('Actions.Posts', () => {
INCREASED_POST_VISIBILITY,
{
meta: {batch: true},
payload: [getReceivedPosts(newPost), STOP_TYPING],
payload: [PostActions.receivedNewPost(newPost), STOP_TYPING],
type: 'BATCHING_REDUCER.BATCH',
},
]);
Expand Down Expand Up @@ -223,48 +214,6 @@ describe('Actions.Posts', () => {
expect(testStore.getActions()).toEqual([{type: ActionTypes.HIDE_EDIT_POST_MODAL}]);
});

test('increasePostVisibility', async () => {
const testStore = await mockStore(initialState);

await testStore.dispatch(Actions.increasePostVisibility('current_channel_id'));
expect(testStore.getActions()).toEqual([
{channelId: 'current_channel_id', data: true, type: 'LOADING_POSTS'},
{args: ['current_channel_id', 2, 30], type: 'MOCK_GET_POSTS'},
{
meta: {batch: true},
payload: [
{channelId: 'current_channel_id', data: false, type: 'LOADING_POSTS'},
],
type: 'BATCHING_REDUCER.BATCH',
},
]);

await testStore.dispatch(Actions.increasePostVisibility('current_channel_id', 'latest_post_id'));
expect(testStore.getActions()).toEqual([
{channelId: 'current_channel_id', data: true, type: 'LOADING_POSTS'},
{args: ['current_channel_id', 2, 30], type: 'MOCK_GET_POSTS'},
{
meta: {batch: true},
payload: [
{channelId: 'current_channel_id', data: false, type: 'LOADING_POSTS'},
],
type: 'BATCHING_REDUCER.BATCH',
},
{channelId: 'current_channel_id', data: true, type: 'LOADING_POSTS'},
{
args: ['current_channel_id', 'latest_post_id', 2, 30],
type: 'MOCK_GET_POSTS_BEFORE',
},
{
meta: {batch: true},
payload: [
{channelId: 'current_channel_id', data: false, type: 'LOADING_POSTS'},
],
type: 'BATCHING_REDUCER.BATCH',
},
]);
});

test('searchForTerm', async () => {
const testStore = await mockStore(initialState);

Expand Down
27 changes: 11 additions & 16 deletions actions/post_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// See LICENSE.txt for license information.

import {batchActions} from 'redux-batched-actions';
import {PostTypes} from 'mattermost-redux/action_types';
import {
markChannelAsRead,
markChannelAsUnread,
Expand All @@ -28,8 +27,7 @@ export function completePostReceive(post, websocketMessageProps) {
const state = getState();

const rootPost = PostSelectors.getPost(state, post.root_id);
const postsInChannel = PostSelectors.getPostIdsInChannel(getState(), post.channel_id);
if (post.root_id && !rootPost && postsInChannel && postsInChannel.length !== 0) {
if (post.root_id && !rootPost) {
const {data: posts} = await dispatch(PostActions.getPostThread(post.root_id));
if (posts) {
dispatch(lastPostActions(post, websocketMessageProps));
Expand All @@ -56,20 +54,17 @@ export function lastPostActions(post, websocketMessageProps) {

// Need manual dispatch to remove pending post

const actions = [{
type: PostTypes.RECEIVED_NEW_POST,
data: {
...post,
const actions = [
PostActions.receivedNewPost(post),
{
type: WebsocketEvents.STOP_TYPING,
data: {
id: post.channel_id + post.root_id,
userId: post.user_id,
now: Date.now(),
},
},
channelId: post.channel_id,
}, {
type: WebsocketEvents.STOP_TYPING,
data: {
id: post.channel_id + post.root_id,
userId: post.user_id,
now: Date.now(),
},
}];
];

dispatch(batchActions(actions));

Expand Down
18 changes: 7 additions & 11 deletions actions/post_utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import thunk from 'redux-thunk';
import configureStore from 'redux-mock-store';

import {receivedNewPost} from 'mattermost-redux/actions/posts';
import {Posts} from 'mattermost-redux/constants';

import * as PostActionsUtils from 'actions/post_utils';
Expand Down Expand Up @@ -34,17 +35,10 @@ const POST_CREATED_TIME = Date.now();

// This mocks the Date.now() function so it returns a constant value
global.Date.now = jest.fn(() => POST_CREATED_TIME);

const INCREASED_POST_VISIBILITY = {amount: 1, data: 'current_channel_id', type: 'INCREASE_POST_VISIBILITY'};
const STOP_TYPING = {type: 'stop_typing', data: {id: 'current_channel_idundefined', now: POST_CREATED_TIME, userId: 'some_user_id'}};

function getReceivedPosts(post) {
return {
type: 'RECEIVED_NEW_POST',
data: {...post},
channelId: post.channel_id,
};
}

describe('actions/post_utils', () => {
const latestPost = {
id: 'latest_post_id',
Expand All @@ -59,7 +53,9 @@ describe('actions/post_utils', () => {
[latestPost.id]: latestPost,
},
postsInChannel: {
current_channel_id: [latestPost.id],
current_channel_id: [
{order: [latestPost.id], recent: true},
],
},
postsInThread: {},
messagesHistory: {
Expand Down Expand Up @@ -105,7 +101,7 @@ describe('actions/post_utils', () => {
INCREASED_POST_VISIBILITY,
{
meta: {batch: true},
payload: [getReceivedPosts(newPost), STOP_TYPING],
payload: [receivedNewPost(newPost), STOP_TYPING],
type: 'BATCHING_REDUCER.BATCH',
},
]);
Expand All @@ -121,7 +117,7 @@ describe('actions/post_utils', () => {
INCREASED_POST_VISIBILITY,
{
meta: {batch: true},
payload: [getReceivedPosts(newPost), STOP_TYPING],
payload: [receivedNewPost(newPost), STOP_TYPING],
type: 'BATCHING_REDUCER.BATCH',
},
]);
Expand Down
11 changes: 7 additions & 4 deletions actions/status_actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ export function loadStatusesForChannelAndSidebar() {

const channelId = getCurrentChannelId(state);
const postsInChannel = getPostsInCurrentChannel(state);
const posts = postsInChannel.slice(0, state.views.channel.postVisibility[channelId] || 0);
for (const post of posts) {
if (post.user_id) {
statusesToLoad[post.user_id] = true;

if (postsInChannel) {
const posts = postsInChannel.slice(0, state.views.channel.postVisibility[channelId] || 0);
for (const post of posts) {
if (post.user_id) {
statusesToLoad[post.user_id] = true;
}
}
}

Expand Down
9 changes: 7 additions & 2 deletions actions/status_actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ describe('actions/status_actions', () => {
},
posts: {
posts: {post_id1: {id: 'post_id1', user_id: 'current_user_id'}, post_id2: {id: 'post_id2', user_id: 'user_id2'}},
postsInChannel: {channel_id1: ['post_id1', 'post_id2'], channel_id2: []},
postsInChannel: {
channel_id1: [
{order: ['post_id1', 'post_id2'], recent: true},
],
channel_id2: [],
},
},
preferences: {
myPreferences: {
Expand Down Expand Up @@ -128,4 +133,4 @@ describe('actions/status_actions', () => {
expect(getStatusesByIds).not.toHaveBeenCalled();
});
});
});
});
Loading

0 comments on commit da3ac93

Please sign in to comment.