summaryrefslogtreecommitdiffstats
path: root/webapp/actions
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/actions')
-rw-r--r--webapp/actions/file_actions.jsx29
-rw-r--r--webapp/actions/global_actions.jsx54
-rw-r--r--webapp/actions/post_actions.jsx394
-rw-r--r--webapp/actions/websocket_actions.jsx27
4 files changed, 157 insertions, 347 deletions
diff --git a/webapp/actions/file_actions.jsx b/webapp/actions/file_actions.jsx
index 204f452d8..628144676 100644
--- a/webapp/actions/file_actions.jsx
+++ b/webapp/actions/file_actions.jsx
@@ -1,25 +1,24 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import * as AsyncClient from 'utils/async_client.jsx';
-import Client from 'client/web_client.jsx';
+import store from 'stores/redux_store.jsx';
+const dispatch = store.dispatch;
+const getState = store.getState;
+import {uploadFile as uploadFileRedux} from 'mattermost-redux/actions/files';
export function uploadFile(file, name, channelId, clientId, success, error) {
- Client.uploadFile(
- file,
- name,
- channelId,
- clientId,
+ const fileFormData = new FormData();
+ fileFormData.append('files', file, name);
+ fileFormData.append('channel_id', channelId);
+ fileFormData.append('client_ids', clientId);
+
+ uploadFileRedux(channelId, null, [clientId], fileFormData)(dispatch, getState).then(
(data) => {
- if (success) {
+ if (data && success) {
success(data);
- }
- },
- (err) => {
- AsyncClient.dispatchError(err, 'uploadFile');
-
- if (error) {
- error(err);
+ } else if (data == null && error) {
+ const serverError = getState().requests.files.uploadFiles.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx
index a1b178d67..13d74c845 100644
--- a/webapp/actions/global_actions.jsx
+++ b/webapp/actions/global_actions.jsx
@@ -4,14 +4,13 @@
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
import ChannelStore from 'stores/channel_store.jsx';
-import PostStore from 'stores/post_store.jsx';
import UserStore from 'stores/user_store.jsx';
import BrowserStore from 'stores/browser_store.jsx';
import ErrorStore from 'stores/error_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import SearchStore from 'stores/search_store.jsx';
-import {handleNewPost, loadPosts, loadPostsBefore, loadPostsAfter} from 'actions/post_actions.jsx';
+import {handleNewPost} from 'actions/post_actions.jsx';
import {loadProfilesForSidebar} from 'actions/user_actions.jsx';
import {loadChannelsForCurrentUser} from 'actions/channel_actions.jsx';
import {stopPeriodicStatusUpdates} from 'actions/status_actions.jsx';
@@ -59,7 +58,6 @@ export function emitChannelClickEvent(channel) {
getMyChannelMemberPromise.then(() => {
getChannelStats(chan.id)(dispatch, getState);
viewChannel(chan.id, oldChannelId)(dispatch, getState);
- loadPosts(chan.id);
// Mark previous and next channel as read
ChannelStore.resetCounts([chan.id, oldChannelId]);
@@ -106,10 +104,15 @@ export function doFocusPost(channelId, postId, data) {
channelId,
post_list: data
});
+
+ dispatch({
+ type: ActionTypes.RECEIVED_FOCUSED_POST,
+ data: postId,
+ channelId
+ });
+
loadChannelsForCurrentUser();
getChannelStats(channelId)(dispatch, getState);
- loadPostsBefore(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
- loadPostsAfter(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
}
export function emitPostFocusEvent(postId, onSuccess) {
@@ -148,8 +151,10 @@ export function emitCloseRightHandSide() {
SearchStore.storeSearchResults(null, false, false);
SearchStore.emitSearchChange();
- PostStore.storeSelectedPostId(null);
- PostStore.emitSelectedPostChange(false, false);
+ dispatch({
+ type: ActionTypes.SELECT_POST,
+ postId: ''
+ });
}
export function emitPostFocusRightHandSideFromSearch(post, isMentionSearch) {
@@ -188,29 +193,6 @@ export function emitLeaveTeam() {
removeUserFromTeam(TeamStore.getCurrentId(), UserStore.getCurrentId())(dispatch, getState);
}
-export function emitLoadMorePostsEvent() {
- const id = ChannelStore.getCurrentId();
- loadMorePostsTop(id, false);
-}
-
-export function emitLoadMorePostsFocusedTopEvent() {
- const id = PostStore.getFocusedPostId();
- loadMorePostsTop(id, true);
-}
-
-export function loadMorePostsTop(id, isFocusPost) {
- const earliestPostId = PostStore.getEarliestPostFromPage(id).id;
- if (PostStore.requestVisibilityIncrease(id, Constants.POST_CHUNK_SIZE)) {
- loadPostsBefore(earliestPostId, 0, Constants.POST_CHUNK_SIZE, isFocusPost);
- }
-}
-
-export function emitLoadMorePostsFocusedBottomEvent() {
- const id = PostStore.getFocusedPostId();
- const latestPostId = PostStore.getLatestPost(id).id;
- loadPostsAfter(latestPostId, 0, Constants.POST_CHUNK_SIZE, Boolean(id));
-}
-
export function emitUserPostedEvent(post) {
AppDispatcher.handleServerAction({
type: ActionTypes.CREATE_POST,
@@ -225,13 +207,6 @@ export function emitUserCommentedEvent(post) {
});
}
-export function emitPostDeletedEvent(post) {
- AppDispatcher.handleServerAction({
- type: ActionTypes.POST_DELETED,
- post
- });
-}
-
export function showDeletePostModal(post, commentCount = 0) {
AppDispatcher.handleViewAction({
type: ActionTypes.TOGGLE_DELETE_POST_MODAL,
@@ -421,11 +396,6 @@ export function loadDefaultLocale() {
return newLocalizationSelected(locale);
}
-export function viewLoggedIn() {
- // Clear pending posts (shouldn't have pending posts if we are loading)
- PostStore.clearPendingPosts();
-}
-
let lastTimeTypingSent = 0;
export function emitLocalUserTypingEvent(channelId, parentId) {
const t = Date.now();
diff --git a/webapp/actions/post_actions.jsx b/webapp/actions/post_actions.jsx
index d55a0d578..1eb1f4feb 100644
--- a/webapp/actions/post_actions.jsx
+++ b/webapp/actions/post_actions.jsx
@@ -4,14 +4,12 @@
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
import ChannelStore from 'stores/channel_store.jsx';
-import PostStore from 'stores/post_store.jsx';
import UserStore from 'stores/user_store.jsx';
+import PostStore from 'stores/post_store.jsx';
-import {loadStatusesForChannel} from 'actions/status_actions.jsx';
import {loadNewDMIfNeeded, loadNewGMIfNeeded} from 'actions/user_actions.jsx';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import {sendDesktopNotification} from 'actions/notification_actions.jsx';
-import * as GlobalActions from 'actions/global_actions.jsx';
import Client from 'client/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
@@ -25,7 +23,20 @@ import store from 'stores/redux_store.jsx';
const dispatch = store.dispatch;
const getState = store.getState;
import {getProfilesByIds} from 'mattermost-redux/actions/users';
+import {
+ createPost as createPostRedux,
+ getPostThread,
+ editPost,
+ deletePost as deletePostRedux,
+ getPosts,
+ getPostsBefore,
+ addReaction as addReactionRedux,
+ removeReaction as removeReactionRedux
+} from 'mattermost-redux/actions/posts';
import {getMyChannelMember} from 'mattermost-redux/actions/channels';
+import {PostTypes} from 'mattermost-redux/action_types';
+import * as Selectors from 'mattermost-redux/selectors/entities/posts';
+import {batchActions} from 'redux-batched-actions';
export function handleNewPost(post, msg) {
let websocketMessageProps = {};
@@ -54,19 +65,22 @@ export function handleNewPost(post, msg) {
}
function completePostReceive(post, websocketMessageProps) {
- if (post.root_id && PostStore.getPost(post.channel_id, post.root_id) == null) {
- Client.getPost(
- post.channel_id,
- post.root_id,
+ if (post.root_id && Selectors.getPost(getState(), post.root_id) != null) {
+ getPostThread(post.root_id)(dispatch, getState).then(
(data) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POSTS,
- id: post.channel_id,
- numRequested: 0,
- post_list: data
+ // Need manual dispatch to remove pending post
+ dispatch({
+ type: PostTypes.RECEIVED_POSTS,
+ data: {
+ order: [],
+ posts: {
+ [post.id]: post
+ }
+ },
+ channelId: post.channel_id
});
- // Required to update order
+ // Still needed to update unreads
AppDispatcher.handleServerAction({
type: ActionTypes.RECEIVED_POST,
post,
@@ -74,17 +88,25 @@ function completePostReceive(post, websocketMessageProps) {
});
sendDesktopNotification(post, websocketMessageProps);
-
loadProfilesForPosts(data.posts);
- },
- (err) => {
- AsyncClient.dispatchError(err, 'getPost');
}
);
return;
}
+ dispatch({
+ type: PostTypes.RECEIVED_POSTS,
+ data: {
+ order: [],
+ posts: {
+ [post.id]: post
+ }
+ },
+ channelId: post.channel_id
+ });
+
+ // Still needed to update unreads
AppDispatcher.handleServerAction({
type: ActionTypes.RECEIVED_POST,
post,
@@ -167,138 +189,6 @@ export function getPinnedPosts(channelId = ChannelStore.getCurrentId()) {
);
}
-export function loadPosts(channelId = ChannelStore.getCurrentId(), isPost = false) {
- const postList = PostStore.getAllPosts(channelId);
- const latestPostTime = PostStore.getLatestPostFromPageTime(channelId);
-
- if (
- !postList || Object.keys(postList).length === 0 ||
- (!isPost && postList.order.length < Constants.POST_CHUNK_SIZE) ||
- latestPostTime === 0
- ) {
- loadPostsPage(channelId, Constants.POST_CHUNK_SIZE, isPost);
- return;
- }
-
- Client.getPosts(
- channelId,
- latestPostTime,
- (data) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POSTS,
- id: channelId,
- before: true,
- numRequested: 0,
- post_list: data,
- isPost
- });
-
- loadProfilesForPosts(data.posts);
- loadStatusesForChannel(channelId);
- },
- (err) => {
- AsyncClient.dispatchError(err, 'loadPosts');
- }
- );
-}
-
-export function loadPostsPage(channelId = ChannelStore.getCurrentId(), max = Constants.POST_CHUNK_SIZE, isPost = false) {
- const postList = PostStore.getAllPosts(channelId);
-
- // if we already have more than POST_CHUNK_SIZE posts,
- // let's get the amount we have but rounded up to next multiple of POST_CHUNK_SIZE,
- // with a max
- let numPosts = Math.min(max, Constants.POST_CHUNK_SIZE);
- if (postList && postList.order.length > 0) {
- numPosts = Math.min(max, Constants.POST_CHUNK_SIZE * Math.ceil(postList.order.length / Constants.POST_CHUNK_SIZE));
- }
-
- Client.getPostsPage(
- channelId,
- 0,
- numPosts,
- (data) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POSTS,
- id: channelId,
- before: true,
- numRequested: numPosts,
- checkLatest: true,
- checkEarliest: true,
- post_list: data,
- isPost
- });
-
- loadProfilesForPosts(data.posts);
- loadStatusesForChannel(channelId);
- },
- (err) => {
- AsyncClient.dispatchError(err, 'loadPostsPage');
- }
- );
-}
-
-export function loadPostsBefore(postId, offset, numPost, isPost) {
- const channelId = ChannelStore.getCurrentId();
- if (channelId == null) {
- return;
- }
-
- Client.getPostsBefore(
- channelId,
- postId,
- offset,
- numPost,
- (data) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POSTS,
- id: channelId,
- before: true,
- checkEarliest: true,
- numRequested: numPost,
- post_list: data,
- isPost
- });
-
- loadProfilesForPosts(data.posts);
- loadStatusesForChannel(channelId);
- },
- (err) => {
- AsyncClient.dispatchError(err, 'loadPostsBefore');
- }
- );
-}
-
-export function loadPostsAfter(postId, offset, numPost, isPost) {
- const channelId = ChannelStore.getCurrentId();
- if (channelId == null) {
- return;
- }
-
- Client.getPostsAfter(
- channelId,
- postId,
- offset,
- numPost,
- (data) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POSTS,
- id: channelId,
- before: false,
- numRequested: numPost,
- post_list: data,
- isPost
- });
-
- loadProfilesForPosts(data.posts);
- loadStatusesForChannel(channelId);
- },
- (err) => {
- AsyncClient.dispatchError(err, 'loadPostsAfter');
- }
- );
-}
-
export function loadProfilesForPosts(posts) {
const profilesToLoad = {};
for (const pid in posts) {
@@ -321,124 +211,37 @@ export function loadProfilesForPosts(posts) {
}
export function addReaction(channelId, postId, emojiName) {
- const reaction = {
- post_id: postId,
- user_id: UserStore.getCurrentId(),
- emoji_name: emojiName
- };
- emitEmojiPosted(emojiName);
-
- AsyncClient.saveReaction(channelId, reaction);
+ addReactionRedux(postId, emojiName)(dispatch, getState);
}
export function removeReaction(channelId, postId, emojiName) {
- const reaction = {
- post_id: postId,
- user_id: UserStore.getCurrentId(),
- emoji_name: emojiName
- };
-
- AsyncClient.deleteReaction(channelId, reaction);
+ removeReactionRedux(postId, emojiName)(dispatch, getState);
}
-const postQueue = [];
-
-export function queuePost(post, doLoadPost, success, error) {
- postQueue.push(
- createPost.bind(
- this,
- post,
- doLoadPost,
- (data) => {
- if (success) {
- success(data);
- }
-
- postSendComplete();
- },
- (err) => {
- if (error) {
- error(err);
- }
-
- postSendComplete();
- }
- )
- );
-
- sendFirstPostInQueue();
-}
-
-// Remove the completed post from the queue and send the next one
-function postSendComplete() {
- postQueue.shift();
- sendNextPostInQueue();
-}
-
-// Start sending posts if a new queue has started
-function sendFirstPostInQueue() {
- if (postQueue.length === 1) {
- sendNextPostInQueue();
- }
-}
+export function createPost(post, files, success) {
+ createPostRedux(post, files)(dispatch, getState).then(() => {
+ if (post.root_id) {
+ PostStore.storeCommentDraft(post.root_id, null);
+ } else {
+ PostStore.storeDraft(post.channel_id, null);
+ }
-// Send the next post in the queue if there is one
-function sendNextPostInQueue() {
- const nextPostAction = postQueue[0];
- if (nextPostAction) {
- nextPostAction();
- }
+ if (success) {
+ success();
+ }
+ });
}
-export function createPost(post, doLoadPost, success, error) {
- Client.createPost(post,
+export function updatePost(post, success) {
+ editPost(post)(dispatch, getState).then(
(data) => {
- if (doLoadPost) {
- loadPosts(post.channel_id);
- } else {
- PostStore.removePendingPost(post.pending_post_id);
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POST,
- post: data
- });
-
- if (success) {
- success(data);
- }
- },
-
- (err) => {
- if (err.id === 'api.post.create_post.root_id.app_error') {
- PostStore.removePendingPost(post.pending_post_id);
- } else {
- post.state = Constants.POST_FAILED;
- PostStore.updatePendingPost(post);
- }
-
- if (error) {
- error(err);
+ if (data && success) {
+ success();
}
}
);
}
-export function updatePost(post, success, isPost) {
- Client.updatePost(
- post,
- () => {
- loadPosts(post.channel_id, isPost);
-
- if (success) {
- success();
- }
- },
- (err) => {
- AsyncClient.dispatchError(err, 'updatePost');
- });
-}
-
export function emitEmojiPosted(emoji) {
AppDispatcher.handleServerAction({
type: ActionTypes.EMOJI_POSTED,
@@ -446,29 +249,31 @@ export function emitEmojiPosted(emoji) {
});
}
-export function deletePost(channelId, post, success, error) {
- Client.deletePost(
- channelId,
- post.id,
+export function deletePost(channelId, post, success) {
+ const {currentUserId} = getState().entities.users;
+
+ let hardDelete = false;
+ if (post.user_id === currentUserId) {
+ hardDelete = true;
+ }
+
+ deletePostRedux(post, hardDelete)(dispatch, getState).then(
() => {
- GlobalActions.emitRemovePost(post);
- if (post.id === PostStore.getSelectedPostId()) {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POST_SELECTED,
- postId: null
+ if (post.id === getState().views.rhs.selectedPostId) {
+ dispatch({
+ type: ActionTypes.SELECT_POST,
+ postId: ''
});
}
+ dispatch({
+ type: PostTypes.REMOVE_POST,
+ data: post
+ });
+
if (success) {
success();
}
- },
- (err) => {
- AsyncClient.dispatchError(err, 'deletePost');
-
- if (error) {
- error(err);
- }
}
);
}
@@ -500,10 +305,49 @@ export function performSearch(terms, isMentionSearch, success, error) {
);
}
-export function storePostDraft(channelId, draft) {
- AppDispatcher.handleViewAction({
- type: ActionTypes.POST_DRAFT_CHANGED,
- channelId,
- draft
- });
+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 (doDispatch, doGetState) => {
+ if (doGetState().views.channel.loadingPosts[channelId]) {
+ return true;
+ }
+
+ const currentPostVisibility = doGetState().views.channel.postVisibility[channelId];
+
+ if (currentPostVisibility >= Constants.MAX_POST_VISIBILITY) {
+ return true;
+ }
+
+ doDispatch(batchActions([
+ {
+ type: ActionTypes.LOADING_POSTS,
+ data: true,
+ channelId
+ },
+ {
+ type: ActionTypes.INCREASE_POST_VISIBILITY,
+ data: channelId,
+ amount: POST_INCREASE_AMOUNT
+ }
+ ]));
+
+ const page = Math.floor(currentPostVisibility / POST_INCREASE_AMOUNT);
+
+ let posts;
+ if (focusedPostId) {
+ posts = await getPostsBefore(channelId, focusedPostId, page, POST_INCREASE_AMOUNT)(dispatch, getState);
+ } else {
+ posts = await getPosts(channelId, page, POST_INCREASE_AMOUNT)(doDispatch, doGetState);
+ }
+
+ doDispatch({
+ type: ActionTypes.LOADING_POSTS,
+ data: false,
+ channelId
+ });
+
+ return posts.order.length >= POST_INCREASE_AMOUNT;
+ };
}
diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx
index b7a0b12a8..1aaecfb71 100644
--- a/webapp/actions/websocket_actions.jsx
+++ b/webapp/actions/websocket_actions.jsx
@@ -5,7 +5,6 @@ import $ from 'jquery';
import UserStore from 'stores/user_store.jsx';
import TeamStore from 'stores/team_store.jsx';
-import PostStore from 'stores/post_store.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import BrowserStore from 'stores/browser_store.jsx';
@@ -21,7 +20,7 @@ import * as AsyncClient from 'utils/async_client.jsx';
import {getSiteURL} from 'utils/url.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
-import {handleNewPost, loadPosts, loadProfilesForPosts} from 'actions/post_actions.jsx';
+import {handleNewPost, loadProfilesForPosts} from 'actions/post_actions.jsx';
import {loadProfilesForSidebar} from 'actions/user_actions.jsx';
import {loadChannelsForCurrentUser} from 'actions/channel_actions.jsx';
import * as StatusActions from 'actions/status_actions.jsx';
@@ -36,8 +35,9 @@ const dispatch = store.dispatch;
const getState = store.getState;
import {batchActions} from 'redux-batched-actions';
import {viewChannel, getChannelAndMyMember, getChannelStats} from 'mattermost-redux/actions/channels';
+import {getPosts} from 'mattermost-redux/actions/posts';
import {setServerVersion} from 'mattermost-redux/actions/general';
-import {ChannelTypes, TeamTypes, UserTypes} from 'mattermost-redux/action_types';
+import {ChannelTypes, TeamTypes, UserTypes, PostTypes} from 'mattermost-redux/action_types';
const MAX_WEBSOCKET_FAILS = 7;
@@ -97,7 +97,7 @@ export function reconnect(includeWebSocket = true) {
if (Client.teamId) {
loadChannelsForCurrentUser();
- loadPosts(ChannelStore.getCurrentId());
+ getPosts(ChannelStore.getCurrentId())(dispatch, getState);
StatusActions.loadStatusesForChannelAndSidebar();
}
@@ -246,8 +246,7 @@ function handleNewPostEvent(msg) {
function handlePostEditEvent(msg) {
// Store post
const post = JSON.parse(msg.data.post);
- PostStore.storePost(post, false);
- PostStore.emitChange();
+ dispatch({type: PostTypes.RECEIVED_POST, data: post});
// Update channel state
if (ChannelStore.getCurrentId() === msg.broadcast.channel_id) {
@@ -259,7 +258,7 @@ function handlePostEditEvent(msg) {
function handlePostDeleteEvent(msg) {
const post = JSON.parse(msg.data.post);
- GlobalActions.emitPostDeletedEvent(post);
+ dispatch({type: PostTypes.POST_DELETED, data: post});
}
function handleTeamAddedEvent(msg) {
@@ -424,19 +423,17 @@ function handleWebrtc(msg) {
function handleReactionAddedEvent(msg) {
const reaction = JSON.parse(msg.data.reaction);
- AppDispatcher.handleServerAction({
- type: ActionTypes.ADDED_REACTION,
- postId: reaction.post_id,
- reaction
+ dispatch({
+ type: PostTypes.RECEIVED_REACTION,
+ data: reaction
});
}
function handleReactionRemovedEvent(msg) {
const reaction = JSON.parse(msg.data.reaction);
- AppDispatcher.handleServerAction({
- type: ActionTypes.REMOVED_REACTION,
- postId: reaction.post_id,
- reaction
+ dispatch({
+ type: PostTypes.REACTION_DELETED,
+ data: reaction
});
}