summaryrefslogtreecommitdiffstats
path: root/webapp/actions
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/actions')
-rw-r--r--webapp/actions/channel_actions.jsx137
-rw-r--r--webapp/actions/emoji_actions.jsx46
-rw-r--r--webapp/actions/global_actions.jsx23
-rw-r--r--webapp/actions/integration_actions.jsx114
-rw-r--r--webapp/actions/post_actions.jsx153
-rw-r--r--webapp/actions/status_actions.jsx133
-rw-r--r--webapp/actions/team_actions.jsx25
-rw-r--r--webapp/actions/user_actions.jsx244
-rw-r--r--webapp/actions/websocket_actions.jsx62
9 files changed, 884 insertions, 53 deletions
diff --git a/webapp/actions/channel_actions.jsx b/webapp/actions/channel_actions.jsx
index ed8e00db6..8364fe9b6 100644
--- a/webapp/actions/channel_actions.jsx
+++ b/webapp/actions/channel_actions.jsx
@@ -1,18 +1,26 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import {browserHistory} from 'react-router/es6';
-import * as Utils from 'utils/utils.jsx';
+import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
+
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
+import PreferenceStore from 'stores/preference_store.jsx';
+
+import {loadProfilesAndTeamMembersForDMSidebar} from 'actions/user_actions.jsx';
+
+import Client from 'client/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as UserAgent from 'utils/user_agent.jsx';
-import Client from 'client/web_client.jsx';
+import * as Utils from 'utils/utils.jsx';
+import {Preferences, ActionTypes} from 'utils/constants.jsx';
+
+import {browserHistory} from 'react-router/es6';
export function goToChannel(channel) {
if (channel.fake) {
- Utils.openDirectChannelToUser(
+ openDirectChannelToUser(
UserStore.getProfileByUsername(channel.display_name),
() => {
browserHistory.push(TeamStore.getCurrentTeamRelativeUrl() + '/channels/' + channel.name);
@@ -53,3 +61,124 @@ export function setChannelAsRead(channelIdParam) {
ChannelStore.emitLastViewed(Number.MAX_VALUE, false);
}
}
+
+export function addUserToChannel(channelId, userId, success, error) {
+ Client.addChannelMember(
+ channelId,
+ userId,
+ (data) => {
+ UserStore.removeProfileNotInChannel(channelId, userId);
+ const profile = UserStore.getProfile(userId);
+ if (profile) {
+ UserStore.saveProfileInChannel(channelId, profile);
+ UserStore.emitInChannelChange();
+ }
+ UserStore.emitNotInChannelChange();
+
+ if (success) {
+ success(data);
+ }
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'addChannelMember');
+
+ if (error) {
+ error(err);
+ }
+ }
+ );
+}
+
+export function removeUserFromChannel(channelId, userId, success, error) {
+ Client.removeChannelMember(
+ channelId,
+ userId,
+ (data) => {
+ UserStore.removeProfileInChannel(channelId, userId);
+ const profile = UserStore.getProfile(userId);
+ if (profile) {
+ UserStore.saveProfileNotInChannel(channelId, profile);
+ UserStore.emitNotInChannelChange();
+ }
+ UserStore.emitInChannelChange();
+
+ if (success) {
+ success(data);
+ }
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'removeChannelMember');
+
+ if (error) {
+ error(err);
+ }
+ }
+ );
+}
+
+export function openDirectChannelToUser(user, success, error) {
+ const channelName = Utils.getDirectChannelName(UserStore.getCurrentId(), user.id);
+ let channel = ChannelStore.getByName(channelName);
+
+ if (channel) {
+ PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, user.id, 'true');
+ loadProfilesAndTeamMembersForDMSidebar();
+
+ AsyncClient.savePreference(
+ Preferences.CATEGORY_DIRECT_CHANNEL_SHOW,
+ user.id,
+ 'true'
+ );
+
+ if (success) {
+ success(channel, true);
+ }
+
+ return;
+ }
+
+ channel = {
+ name: channelName,
+ last_post_at: 0,
+ total_msg_count: 0,
+ type: 'D',
+ display_name: user.username,
+ teammate_id: user.id,
+ status: UserStore.getStatus(user.id)
+ };
+
+ Client.createDirectChannel(
+ user.id,
+ (data) => {
+ Client.getChannel(
+ data.id,
+ (data2) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_CHANNEL,
+ channel: data2.channel,
+ member: data2.member
+ });
+
+ PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, user.id, 'true');
+ loadProfilesAndTeamMembersForDMSidebar();
+
+ AsyncClient.savePreference(
+ Preferences.CATEGORY_DIRECT_CHANNEL_SHOW,
+ user.id,
+ 'true'
+ );
+
+ if (success) {
+ success(data2.channel, false);
+ }
+ }
+ );
+ },
+ () => {
+ browserHistory.push(TeamStore.getCurrentTeamUrl() + '/channels/' + channelName);
+ if (error) {
+ error();
+ }
+ }
+ );
+}
diff --git a/webapp/actions/emoji_actions.jsx b/webapp/actions/emoji_actions.jsx
new file mode 100644
index 000000000..128a9325a
--- /dev/null
+++ b/webapp/actions/emoji_actions.jsx
@@ -0,0 +1,46 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
+
+import UserStore from 'stores/user_store.jsx';
+
+import * as AsyncClient from 'utils/async_client.jsx';
+import Client from 'client/web_client.jsx';
+
+import {ActionTypes} from 'utils/constants.jsx';
+
+export function loadEmoji(getProfiles = true) {
+ Client.listEmoji(
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_CUSTOM_EMOJIS,
+ emojis: data
+ });
+
+ if (getProfiles) {
+ loadProfilesForEmoji(data);
+ }
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'listEmoji');
+ }
+ );
+}
+
+function loadProfilesForEmoji(emojiList) {
+ const profilesToLoad = {};
+ for (let i = 0; i < emojiList.length; i++) {
+ const emoji = emojiList[i];
+ if (!UserStore.hasProfile(emoji.creator_id)) {
+ profilesToLoad[emoji.creator_id] = true;
+ }
+ }
+
+ const list = Object.keys(profilesToLoad);
+ if (list.length === 0) {
+ return;
+ }
+
+ AsyncClient.getProfilesByIds(list);
+}
diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx
index 941aa34f4..23ff5a295 100644
--- a/webapp/actions/global_actions.jsx
+++ b/webapp/actions/global_actions.jsx
@@ -12,7 +12,8 @@ import TeamStore from 'stores/team_store.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import SearchStore from 'stores/search_store.jsx';
-import {handleNewPost} from 'actions/post_actions.jsx';
+import {handleNewPost, loadPosts, loadPostsBefore, loadPostsAfter} from 'actions/post_actions.jsx';
+import {loadProfilesAndTeamMembersForDMSidebar} from 'actions/user_actions.jsx';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
@@ -43,9 +44,9 @@ export function emitChannelClickEvent(channel) {
function switchToChannel(chan) {
AsyncClient.getChannels(true);
AsyncClient.getMoreChannels(true);
- AsyncClient.getChannelExtraInfo(chan.id);
+ AsyncClient.getChannelStats(chan.id);
AsyncClient.updateLastViewedAt(chan.id);
- AsyncClient.getPosts(chan.id);
+ loadPosts(chan.id);
trackPage();
AppDispatcher.handleViewAction({
@@ -108,7 +109,7 @@ export function emitInitialLoad(callback) {
if (data.team_members) {
AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_TEAM_MEMBERS,
+ type: ActionTypes.RECEIVED_MY_TEAM_MEMBERS,
team_members: data.team_members
});
}
@@ -143,9 +144,9 @@ export function doFocusPost(channelId, postId, data) {
});
AsyncClient.getChannels(true);
AsyncClient.getMoreChannels(true);
- AsyncClient.getChannelExtraInfo(channelId);
- AsyncClient.getPostsBefore(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
- AsyncClient.getPostsAfter(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
+ AsyncClient.getChannelStats(channelId);
+ loadPostsBefore(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
+ loadPostsAfter(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
}
export function emitPostFocusEvent(postId, onSuccess) {
@@ -246,14 +247,14 @@ export function emitLoadMorePostsFocusedTopEvent() {
export function loadMorePostsTop(id, isFocusPost) {
const earliestPostId = PostStore.getEarliestPost(id).id;
if (PostStore.requestVisibilityIncrease(id, Constants.POST_CHUNK_SIZE)) {
- AsyncClient.getPostsBefore(earliestPostId, 0, Constants.POST_CHUNK_SIZE, isFocusPost);
+ loadPostsBefore(earliestPostId, 0, Constants.POST_CHUNK_SIZE, isFocusPost);
}
}
export function emitLoadMorePostsFocusedBottomEvent() {
const id = PostStore.getFocusedPostId();
const latestPostId = PostStore.getLatestPost(id).id;
- AsyncClient.getPostsAfter(latestPostId, 0, Constants.POST_CHUNK_SIZE, Boolean(id));
+ loadPostsAfter(latestPostId, 0, Constants.POST_CHUNK_SIZE, Boolean(id));
}
export function emitUserPostedEvent(post) {
@@ -362,7 +363,7 @@ export function emitClearSuggestions(suggestionId) {
export function emitPreferenceChangedEvent(preference) {
if (preference.category === Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW) {
- AsyncClient.getDirectProfiles();
+ loadProfilesAndTeamMembersForDMSidebar();
}
AppDispatcher.handleServerAction({
@@ -437,7 +438,7 @@ export function loadDefaultLocale() {
export function viewLoggedIn() {
AsyncClient.getChannels();
AsyncClient.getMoreChannels();
- AsyncClient.getChannelExtraInfo();
+ AsyncClient.getChannelStats();
// Clear pending posts (shouldn't have pending posts if we are loading)
PostStore.clearPendingPosts();
diff --git a/webapp/actions/integration_actions.jsx b/webapp/actions/integration_actions.jsx
new file mode 100644
index 000000000..5fd2b024d
--- /dev/null
+++ b/webapp/actions/integration_actions.jsx
@@ -0,0 +1,114 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
+
+import TeamStore from 'stores/team_store.jsx';
+import UserStore from 'stores/user_store.jsx';
+
+import * as AsyncClient from 'utils/async_client.jsx';
+import Client from 'client/web_client.jsx';
+
+import {ActionTypes} from 'utils/constants.jsx';
+
+export function loadIncomingHooks() {
+ Client.listIncomingHooks(
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_INCOMING_WEBHOOKS,
+ teamId: TeamStore.getCurrentId(),
+ incomingWebhooks: data
+ });
+
+ loadProfilesForIncomingHooks(data);
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'listIncomingHooks');
+ }
+ );
+}
+
+function loadProfilesForIncomingHooks(hooks) {
+ const profilesToLoad = {};
+ for (let i = 0; i < hooks.length; i++) {
+ const hook = hooks[i];
+ if (!UserStore.hasProfile(hook.user_id)) {
+ profilesToLoad[hook.user_id] = true;
+ }
+ }
+
+ const list = Object.keys(profilesToLoad);
+ if (list.length === 0) {
+ return;
+ }
+
+ AsyncClient.getProfilesByIds(list);
+}
+
+export function loadOutgoingHooks() {
+ Client.listOutgoingHooks(
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_OUTGOING_WEBHOOKS,
+ teamId: TeamStore.getCurrentId(),
+ outgoingWebhooks: data
+ });
+
+ loadProfilesForOutgoingHooks(data);
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'listOutgoingHooks');
+ }
+ );
+}
+
+function loadProfilesForOutgoingHooks(hooks) {
+ const profilesToLoad = {};
+ for (let i = 0; i < hooks.length; i++) {
+ const hook = hooks[i];
+ if (!UserStore.hasProfile(hook.creator_id)) {
+ profilesToLoad[hook.creator_id] = true;
+ }
+ }
+
+ const list = Object.keys(profilesToLoad);
+ if (list.length === 0) {
+ return;
+ }
+
+ AsyncClient.getProfilesByIds(list);
+}
+
+export function loadTeamCommands() {
+ Client.listTeamCommands(
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_COMMANDS,
+ teamId: Client.teamId,
+ commands: data
+ });
+
+ loadProfilesForCommands(data);
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'loadTeamCommands');
+ }
+ );
+}
+
+function loadProfilesForCommands(commands) {
+ const profilesToLoad = {};
+ for (let i = 0; i < commands.length; i++) {
+ const command = commands[i];
+ if (!UserStore.hasProfile(command.creator_id)) {
+ profilesToLoad[command.creator_id] = true;
+ }
+ }
+
+ const list = Object.keys(profilesToLoad);
+ if (list.length === 0) {
+ return;
+ }
+
+ AsyncClient.getProfilesByIds(list);
+}
diff --git a/webapp/actions/post_actions.jsx b/webapp/actions/post_actions.jsx
index 63e3feec5..462576021 100644
--- a/webapp/actions/post_actions.jsx
+++ b/webapp/actions/post_actions.jsx
@@ -8,6 +8,8 @@ import PostStore from 'stores/post_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
+import {loadStatusesForChannel} from 'actions/status_actions.jsx';
+
import * as PostUtils from 'utils/post_utils.jsx';
import Client from 'client/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
@@ -52,6 +54,8 @@ export function handleNewPost(post, msg) {
post,
websocketMessageProps
});
+
+ loadProfilesForPosts(data.posts);
},
(err) => {
AsyncClient.dispatchError(err, 'getPost');
@@ -115,7 +119,7 @@ export function setUnreadPost(channelId, postId) {
member.last_viewed_at = lastViewed;
member.msg_count = channel.total_msg_count - unreadPosts;
member.mention_count = 0;
- ChannelStore.setChannelMember(member);
+ ChannelStore.storeMyChannelMember(member);
ChannelStore.setUnreadCount(channelId);
AsyncClient.setLastViewedAt(lastViewed, channelId);
}
@@ -153,9 +157,156 @@ export function getFlaggedPosts() {
results: data,
is_flagged_posts: true
});
+
+ loadProfilesForPosts(data.posts);
},
(err) => {
AsyncClient.dispatchError(err, 'getFlaggedPosts');
}
);
}
+
+export function loadPosts(channelId = ChannelStore.getCurrentId()) {
+ const postList = PostStore.getAllPosts(channelId);
+ const latestPostTime = PostStore.getLatestPostFromPageTime(channelId);
+
+ if (!postList || Object.keys(postList).length === 0 || postList.order.length < Constants.POST_CHUNK_SIZE || latestPostTime === 0) {
+ loadPostsPage(channelId, Constants.POST_CHUNK_SIZE);
+ return;
+ }
+
+ Client.getPosts(
+ channelId,
+ latestPostTime,
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_POSTS,
+ id: channelId,
+ before: true,
+ numRequested: 0,
+ post_list: data
+ });
+
+ loadProfilesForPosts(data.posts);
+ loadStatusesForChannel(channelId);
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'loadPosts');
+ }
+ );
+}
+
+export function loadPostsPage(channelId = ChannelStore.getCurrentId(), max = Constants.POST_CHUNK_SIZE) {
+ 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,
+ post_list: data
+ });
+
+ 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,
+ 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');
+ }
+ );
+}
+
+function loadProfilesForPosts(posts) {
+ const profilesToLoad = {};
+ for (const pid in posts) {
+ if (!posts.hasOwnProperty(pid)) {
+ continue;
+ }
+
+ const post = posts[pid];
+ if (!UserStore.hasProfile(post.user_id)) {
+ profilesToLoad[post.user_id] = true;
+ }
+ }
+
+ const list = Object.keys(profilesToLoad);
+ if (list.length === 0) {
+ return;
+ }
+
+ AsyncClient.getProfilesByIds(list);
+}
diff --git a/webapp/actions/status_actions.jsx b/webapp/actions/status_actions.jsx
new file mode 100644
index 000000000..c198c52ac
--- /dev/null
+++ b/webapp/actions/status_actions.jsx
@@ -0,0 +1,133 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
+
+import ChannelStore from 'stores/channel_store.jsx';
+import PostStore from 'stores/post_store.jsx';
+import PreferenceStore from 'stores/preference_store.jsx';
+
+import Client from 'client/web_client.jsx';
+
+import {ActionTypes, Preferences, Constants} from 'utils/constants.jsx';
+
+export function loadStatusesForChannel(channelId = ChannelStore.getCurrentId()) {
+ const postList = PostStore.getVisiblePosts(channelId);
+ if (!postList || !postList.posts) {
+ return;
+ }
+
+ const statusesToLoad = {};
+ for (const pid in postList.posts) {
+ if (!postList.posts.hasOwnProperty(pid)) {
+ continue;
+ }
+
+ const post = postList.posts[pid];
+ statusesToLoad[post.user_id] = true;
+ }
+
+ loadStatusesByIds(Object.keys(statusesToLoad));
+}
+
+export function loadStatusesForDMSidebar() {
+ const dmPrefs = PreferenceStore.getCategory(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW);
+ const statusesToLoad = [];
+
+ for (const [key, value] of dmPrefs) {
+ if (value === 'true') {
+ statusesToLoad.push(key);
+ }
+ }
+
+ loadStatusesByIds(statusesToLoad);
+}
+
+export function loadStatusesForChannelAndSidebar() {
+ const statusesToLoad = {};
+
+ const channelId = ChannelStore.getCurrentId();
+ const postList = PostStore.getVisiblePosts(channelId);
+ if (postList && postList.posts) {
+ for (const pid in postList.posts) {
+ if (!postList.posts.hasOwnProperty(pid)) {
+ continue;
+ }
+
+ const post = postList.posts[pid];
+ statusesToLoad[post.user_id] = true;
+ }
+ }
+
+ const dmPrefs = PreferenceStore.getCategory(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW);
+
+ for (const [key, value] of dmPrefs) {
+ if (value === 'true') {
+ statusesToLoad[key] = true;
+ }
+ }
+
+ loadStatusesByIds(Object.keys(statusesToLoad));
+}
+
+export function loadStatusesForProfilesList(users) {
+ if (users == null) {
+ return;
+ }
+
+ const statusesToLoad = [];
+ for (let i = 0; i < users.length; i++) {
+ statusesToLoad.push(users[i].id);
+ }
+
+ loadStatusesByIds(statusesToLoad);
+}
+
+export function loadStatusesForProfilesMap(users) {
+ if (users == null) {
+ return;
+ }
+
+ const statusesToLoad = [];
+ for (const userId in users) {
+ if (!users.hasOwnProperty(userId)) {
+ return;
+ }
+ statusesToLoad.push(userId);
+ }
+
+ loadStatusesByIds(statusesToLoad);
+}
+
+export function loadStatusesByIds(userIds) {
+ if (userIds.length === 0) {
+ return;
+ }
+
+ Client.getStatusesByIds(
+ userIds,
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_STATUSES,
+ statuses: data
+ });
+ }
+ );
+}
+
+let intervalId = '';
+
+export function startPeriodicStatusUpdates() {
+ clearInterval(intervalId);
+
+ intervalId = setInterval(
+ () => {
+ loadStatusesForChannelAndSidebar();
+ },
+ Constants.STATUS_INTERVAL
+ );
+}
+
+export function stopPeriodicStatusUpdates() {
+ clearInterval(intervalId);
+}
diff --git a/webapp/actions/team_actions.jsx b/webapp/actions/team_actions.jsx
index 3bf25c193..e0403529e 100644
--- a/webapp/actions/team_actions.jsx
+++ b/webapp/actions/team_actions.jsx
@@ -2,6 +2,7 @@
// See License.txt for license information.
import UserStore from 'stores/user_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
@@ -19,8 +20,6 @@ export function checkIfTeamExists(teamName, onSuccess, onError) {
export function createTeam(team, onSuccess, onError) {
Client.createTeam(team,
(rteam) => {
- AsyncClient.getDirectProfiles();
-
AppDispatcher.handleServerAction({
type: ActionTypes.CREATED_TEAM,
team: rteam,
@@ -36,3 +35,25 @@ export function createTeam(team, onSuccess, onError) {
onError
);
}
+
+export function removeUserFromTeam(teamId, userId, success, error) {
+ Client.removeUserFromTeam(
+ teamId,
+ userId,
+ () => {
+ TeamStore.removeMemberInTeam(teamId, userId);
+ AsyncClient.getUser(userId);
+
+ if (success) {
+ success();
+ }
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'removeUserFromTeam');
+
+ if (error) {
+ error(err);
+ }
+ }
+ );
+}
diff --git a/webapp/actions/user_actions.jsx b/webapp/actions/user_actions.jsx
index 2d5fd805c..900353701 100644
--- a/webapp/actions/user_actions.jsx
+++ b/webapp/actions/user_actions.jsx
@@ -2,12 +2,17 @@
// See License.txt for license information.
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
-import Client from 'client/web_client.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
+import ChannelStore from 'stores/channel_store.jsx';
+
+import {loadStatusesForProfilesList, loadStatusesForProfilesMap} from 'actions/status_actions.jsx';
+
+import {getDirectChannelName} from 'utils/utils.jsx';
+import * as AsyncClient from 'utils/async_client.jsx';
+import Client from 'client/web_client.jsx';
import {ActionTypes, Preferences} from 'utils/constants.jsx';
@@ -29,9 +34,179 @@ export function switchFromLdapToEmail(email, password, ldapPassword, onSuccess,
);
}
-export function getMoreDmList() {
- AsyncClient.getTeamMembers(TeamStore.getCurrentId());
- AsyncClient.getProfilesForDirectMessageList();
+export function loadProfilesAndTeamMembers(offset, limit, teamId = TeamStore.getCurrentId(), success, error) {
+ Client.getProfilesInTeam(
+ teamId,
+ offset,
+ limit,
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_PROFILES_IN_TEAM,
+ profiles: data,
+ team_id: teamId,
+ offset,
+ count: Object.keys(data).length
+ });
+
+ loadTeamMembersForProfilesMap(data, teamId, success, error);
+ loadStatusesForProfilesMap(data);
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'getProfilesInTeam');
+ }
+ );
+}
+
+export function loadTeamMembersForProfilesMap(profiles, teamId = TeamStore.getCurrentId(), success, error) {
+ const membersToLoad = {};
+ for (const pid in profiles) {
+ if (!profiles.hasOwnProperty(pid)) {
+ continue;
+ }
+
+ if (!TeamStore.hasActiveMemberInTeam(teamId, pid)) {
+ membersToLoad[pid] = true;
+ }
+ }
+
+ const list = Object.keys(membersToLoad);
+ if (list.length === 0) {
+ if (success) {
+ success({});
+ }
+ return;
+ }
+
+ loadTeamMembersForProfiles(list, teamId, success, error);
+}
+
+export function loadTeamMembersForProfilesList(profiles, teamId = TeamStore.getCurrentId(), success, error) {
+ const membersToLoad = {};
+ for (let i = 0; i < profiles.length; i++) {
+ const pid = profiles[i].id;
+
+ if (!TeamStore.hasActiveMemberInTeam(teamId, pid)) {
+ membersToLoad[pid] = true;
+ }
+ }
+
+ const list = Object.keys(membersToLoad);
+ if (list.length === 0) {
+ if (success) {
+ success({});
+ }
+ return;
+ }
+
+ loadTeamMembersForProfiles(list, teamId, success, error);
+}
+
+function loadTeamMembersForProfiles(userIds, teamId, success, error) {
+ Client.getTeamMembersByIds(
+ teamId,
+ userIds,
+ (data) => {
+ const memberMap = {};
+ for (let i = 0; i < data.length; i++) {
+ memberMap[data[i].user_id] = data[i];
+ }
+
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_MEMBERS_IN_TEAM,
+ team_id: teamId,
+ team_members: memberMap
+ });
+
+ if (success) {
+ success(data);
+ }
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'getTeamMembersByIds');
+
+ if (error) {
+ error(err);
+ }
+ }
+ );
+}
+
+function populateDMChannelsWithProfiles(userIds) {
+ const currentUserId = UserStore.getCurrentId();
+
+ for (let i = 0; i < userIds.length; i++) {
+ const channelName = getDirectChannelName(currentUserId, userIds[i]);
+ const channel = ChannelStore.getByName(channelName);
+ if (channel) {
+ UserStore.saveUserIdInChannel(channel.id, userIds[i]);
+ }
+ }
+}
+
+export function loadProfilesAndTeamMembersForDMSidebar() {
+ const dmPrefs = PreferenceStore.getCategory(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW);
+ const teamId = TeamStore.getCurrentId();
+ const profilesToLoad = [];
+ const membersToLoad = [];
+
+ for (const [key, value] of dmPrefs) {
+ if (value === 'true') {
+ if (!UserStore.hasProfile(key)) {
+ profilesToLoad.push(key);
+ }
+ membersToLoad.push(key);
+ }
+ }
+
+ if (profilesToLoad.length > 0) {
+ Client.getProfilesByIds(
+ profilesToLoad,
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_PROFILES,
+ profiles: data
+ });
+
+ // Use membersToLoad so we get all the DM profiles even if they were already loaded
+ populateDMChannelsWithProfiles(membersToLoad);
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'getProfilesByIds');
+ }
+ );
+ } else {
+ populateDMChannelsWithProfiles(membersToLoad);
+ }
+
+ if (membersToLoad.length > 0) {
+ Client.getTeamMembersByIds(
+ teamId,
+ membersToLoad,
+ (data) => {
+ const memberMap = {};
+ for (let i = 0; i < data.length; i++) {
+ memberMap[data[i].user_id] = data[i];
+ }
+
+ const nonMembersMap = {};
+ for (let i = 0; i < membersToLoad.length; i++) {
+ if (!memberMap[membersToLoad[i]]) {
+ nonMembersMap[membersToLoad[i]] = true;
+ }
+ }
+
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_MEMBERS_IN_TEAM,
+ team_id: teamId,
+ team_members: memberMap,
+ non_team_members: nonMembersMap
+ });
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'getTeamMembersByIds');
+ }
+ );
+ }
}
export function saveTheme(teamId, theme, onSuccess, onError) {
@@ -82,3 +257,62 @@ function onThemeSaved(teamId, theme, onSuccess) {
onSuccess();
}
+
+export function searchUsers(term, teamId = TeamStore.getCurrentId(), options = {}, success, error) {
+ Client.searchUsers(
+ term,
+ teamId,
+ options,
+ (data) => {
+ loadStatusesForProfilesList(data);
+
+ if (success) {
+ success(data);
+ }
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'searchUsers');
+
+ if (error) {
+ error(err);
+ }
+ }
+ );
+}
+
+export function autocompleteUsersInChannel(username, channelId, success, error) {
+ Client.autocompleteUsersInChannel(
+ username,
+ channelId,
+ (data) => {
+ if (success) {
+ success(data);
+ }
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'autocompleteUsersInChannel');
+
+ if (error) {
+ error(err);
+ }
+ }
+ );
+}
+
+export function autocompleteUsersInTeam(username, success, error) {
+ Client.autocompleteUsersInTeam(
+ username,
+ (data) => {
+ if (success) {
+ success(data);
+ }
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'autocompleteUsersInTeam');
+
+ if (error) {
+ error(err);
+ }
+ }
+ );
+}
diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx
index 08449b87e..14a150692 100644
--- a/webapp/actions/websocket_actions.jsx
+++ b/webapp/actions/websocket_actions.jsx
@@ -3,8 +3,6 @@
import $ from 'jquery';
-import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
-
import UserStore from 'stores/user_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import PostStore from 'stores/post_store.jsx';
@@ -20,10 +18,11 @@ import * as Utils from 'utils/utils.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
-import * as UserActions from 'actions/user_actions.jsx';
-import {handleNewPost} from 'actions/post_actions.jsx';
+import {handleNewPost, loadPosts} from 'actions/post_actions.jsx';
+import {loadProfilesAndTeamMembersForDMSidebar} from 'actions/user_actions.jsx';
+import * as StatusActions from 'actions/status_actions.jsx';
-import {Constants, SocketEvents, ActionTypes} from 'utils/constants.jsx';
+import {Constants, SocketEvents, UserStatuses} from 'utils/constants.jsx';
import {browserHistory} from 'react-router/es6';
@@ -53,6 +52,7 @@ export function initialize() {
connUrl += Client.getUsersRoute() + '/websocket';
WebSocketClient.setEventCallback(handleEvent);
+ WebSocketClient.setFirstConnectCallback(handleFirstConnect);
WebSocketClient.setReconnectCallback(handleReconnect);
WebSocketClient.setCloseCallback(handleClose);
WebSocketClient.initialize(connUrl);
@@ -64,22 +64,19 @@ export function close() {
}
export function getStatuses() {
- WebSocketClient.getStatuses(
- (resp) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_STATUSES,
- statuses: resp.data
- });
- }
- );
+ StatusActions.loadStatusesForChannelAndSidebar();
+}
+
+function handleFirstConnect() {
+ getStatuses();
+ ErrorStore.clearLastError();
+ ErrorStore.emitChange();
}
function handleReconnect() {
if (Client.teamId) {
AsyncClient.getChannels();
- AsyncClient.getPosts(ChannelStore.getCurrentId());
- AsyncClient.getTeamMembers(TeamStore.getCurrentId());
- AsyncClient.getProfiles();
+ loadPosts(ChannelStore.getCurrentId());
}
getStatuses();
@@ -112,7 +109,7 @@ function handleEvent(msg) {
break;
case SocketEvents.NEW_USER:
- handleNewUserEvent();
+ handleNewUserEvent(msg);
break;
case SocketEvents.LEAVE_TEAM:
@@ -170,6 +167,10 @@ function handleEvent(msg) {
function handleNewPostEvent(msg) {
const post = JSON.parse(msg.data.post);
handleNewPost(post, msg);
+
+ if (UserStore.getStatus(post.user_id) !== UserStatuses.ONLINE) {
+ StatusActions.loadStatusesByIds([post.user_id]);
+ }
}
function handlePostEditEvent(msg) {
@@ -196,36 +197,33 @@ function handlePostDeleteEvent(msg) {
}
}
-function handleNewUserEvent() {
- AsyncClient.getTeamMembers(TeamStore.getCurrentId());
- AsyncClient.getProfiles();
- AsyncClient.getDirectProfiles();
- AsyncClient.getChannelExtraInfo();
+function handleNewUserEvent(msg) {
+ AsyncClient.getUser(msg.user_id);
+ AsyncClient.getChannelStats();
+ loadProfilesAndTeamMembersForDMSidebar();
}
function handleLeaveTeamEvent(msg) {
if (UserStore.getCurrentId() === msg.data.user_id) {
- TeamStore.removeTeamMember(msg.broadcast.team_id);
+ TeamStore.removeMyTeamMember(msg.broadcast.team_id);
- // if the are on the team begin removed redirect them to the root
+ // if they are on the team being removed redirect them to the root
if (TeamStore.getCurrentId() === msg.broadcast.team_id) {
TeamStore.setCurrentId('');
Client.setTeamId('');
browserHistory.push('/');
}
- } else if (TeamStore.getCurrentId() === msg.broadcast.team_id) {
- UserActions.getMoreDmList();
}
}
function handleDirectAddedEvent(msg) {
AsyncClient.getChannel(msg.broadcast.channel_id);
- AsyncClient.getDirectProfiles();
+ loadProfilesAndTeamMembersForDMSidebar();
}
function handleUserAddedEvent(msg) {
if (ChannelStore.getCurrentId() === msg.broadcast.channel_id) {
- AsyncClient.getChannelExtraInfo();
+ AsyncClient.getChannelStats();
}
if (TeamStore.getCurrentId() === msg.data.team_id && UserStore.getCurrentId() === msg.data.user_id) {
@@ -248,7 +246,7 @@ function handleUserRemovedEvent(msg) {
$('#removed_from_channel').modal('show');
}
} else if (ChannelStore.getCurrentId() === msg.broadcast.channel_id) {
- AsyncClient.getChannelExtraInfo();
+ AsyncClient.getChannelStats();
}
}
@@ -287,6 +285,10 @@ function handlePreferenceChangedEvent(msg) {
function handleUserTypingEvent(msg) {
GlobalActions.emitRemoteUserTypingEvent(msg.broadcast.channel_id, msg.data.user_id, msg.data.parent_id);
+
+ if (UserStore.getStatus(msg.data.user_id) !== UserStatuses.ONLINE) {
+ StatusActions.loadStatusesByIds([msg.data.user_id]);
+ }
}
function handleStatusChangedEvent(msg) {
@@ -301,4 +303,4 @@ function handleHelloEvent(msg) {
function handleWebrtc(msg) {
const data = msg.data;
return WebrtcActions.handle(data);
-} \ No newline at end of file
+}