summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api4/channel.go5
-rw-r--r--api4/channel_test.go2
-rw-r--r--app/channel.go12
-rw-r--r--webapp/actions/channel_actions.jsx403
-rw-r--r--webapp/actions/global_actions.jsx15
-rw-r--r--webapp/actions/post_actions.jsx3
-rw-r--r--webapp/actions/team_actions.jsx5
-rw-r--r--webapp/actions/websocket_actions.jsx20
-rw-r--r--webapp/components/channel_members_dropdown/channel_members_dropdown.jsx (renamed from webapp/components/channel_members_dropdown.jsx)24
-rw-r--r--webapp/components/channel_members_dropdown/index.js24
-rw-r--r--webapp/components/channel_members_modal.jsx2
-rw-r--r--webapp/components/channel_view.jsx2
-rw-r--r--webapp/components/member_list_channel/index.js24
-rw-r--r--webapp/components/member_list_channel/member_list_channel.jsx (renamed from webapp/components/member_list_channel.jsx)16
-rw-r--r--webapp/components/more_channels/index.js24
-rw-r--r--webapp/components/more_channels/more_channels.jsx (renamed from webapp/components/more_channels.jsx)20
-rw-r--r--webapp/components/needs_team/index.js25
-rw-r--r--webapp/components/needs_team/needs_team.jsx (renamed from webapp/components/needs_team.jsx)41
-rw-r--r--webapp/components/new_channel_flow.jsx6
-rw-r--r--webapp/components/post_view/index.js24
-rw-r--r--webapp/components/post_view/post_view_cache.jsx9
-rw-r--r--webapp/components/rename_channel_modal.jsx5
-rw-r--r--webapp/components/sidebar.jsx2
-rw-r--r--webapp/components/team_members_dropdown/index.js4
-rw-r--r--webapp/components/team_members_dropdown/team_members_dropdown.jsx8
-rw-r--r--webapp/package.json2
-rw-r--r--webapp/root.jsx11
-rw-r--r--webapp/routes/route_team.jsx52
-rw-r--r--webapp/stores/channel_store.jsx171
-rw-r--r--webapp/utils/async_client.jsx229
30 files changed, 499 insertions, 691 deletions
diff --git a/api4/channel.go b/api4/channel.go
index 5d1651d74..c8235c5f1 100644
--- a/api4/channel.go
+++ b/api4/channel.go
@@ -456,11 +456,6 @@ func searchChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- if len(props.Term) == 0 {
- c.SetInvalidParam("term")
- return
- }
-
if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_LIST_TEAM_CHANNELS) {
c.SetPermissionError(model.PERMISSION_LIST_TEAM_CHANNELS)
return
diff --git a/api4/channel_test.go b/api4/channel_test.go
index 3c9b6d720..345bbefaf 100644
--- a/api4/channel_test.go
+++ b/api4/channel_test.go
@@ -721,7 +721,7 @@ func TestSearchChannels(t *testing.T) {
search.Term = ""
_, resp = Client.SearchChannels(th.BasicTeam.Id, search)
- CheckBadRequestStatus(t, resp)
+ CheckNoError(t, resp)
search.Term = th.BasicChannel.Name
_, resp = Client.SearchChannels(model.NewId(), search)
diff --git a/app/channel.go b/app/channel.go
index 17fa02ad3..0d9cb5a94 100644
--- a/app/channel.go
+++ b/app/channel.go
@@ -490,7 +490,11 @@ func AddChannelMember(userId string, channel *model.Channel, userRequestorId str
return nil, err
}
- go PostAddToChannelMessage(userRequestor, user, channel)
+ if userId == userRequestorId {
+ postJoinChannelMessage(user, channel)
+ } else {
+ go PostAddToChannelMessage(userRequestor, user, channel)
+ }
UpdateChannelLastViewedAt([]string{channel.Id}, userRequestor.Id)
@@ -961,7 +965,11 @@ func RemoveUserFromChannel(userIdToRemove string, removerUserId string, channel
return err
}
- go PostRemoveFromChannelMessage(removerUserId, user, channel)
+ if userIdToRemove == removerUserId {
+ postLeaveChannelMessage(user, channel)
+ } else {
+ go PostRemoveFromChannelMessage(removerUserId, user, channel)
+ }
return nil
}
diff --git a/webapp/actions/channel_actions.jsx b/webapp/actions/channel_actions.jsx
index d441a0e94..79dfe3212 100644
--- a/webapp/actions/channel_actions.jsx
+++ b/webapp/actions/channel_actions.jsx
@@ -20,6 +20,29 @@ import {Constants, Preferences, ActionTypes} from 'utils/constants.jsx';
import {browserHistory} from 'react-router/es6';
+// Redux actions
+import store from 'stores/redux_store.jsx';
+const dispatch = store.dispatch;
+const getState = store.getState;
+
+import {
+ viewChannel,
+ addChannelMember,
+ removeChannelMember,
+ updateChannelMemberRoles,
+ createDirectChannel,
+ fetchMyChannelsAndMembers,
+ joinChannel as joinChannelRedux,
+ leaveChannel as leaveChannelRedux,
+ updateChannel as updateChannelRedux,
+ searchChannels,
+ updateChannelNotifyProps as updateChannelNotifyPropsRedux,
+ createChannel as createChannelRedux,
+ patchChannel,
+ getChannelMembersByIds,
+ deleteChannel as deleteChannelRedux
+} from 'mattermost-redux/actions/channels';
+
export function goToChannel(channel) {
if (channel.fake) {
const user = UserStore.getProfileByUsername(channel.display_name);
@@ -66,7 +89,7 @@ export function executeCommand(message, args, success, error) {
export function setChannelAsRead(channelIdParam) {
const channelId = channelIdParam || ChannelStore.getCurrentId();
- AsyncClient.viewChannel();
+ viewChannel(channelId)(dispatch, getState);
ChannelStore.resetCounts(channelId);
ChannelStore.emitChange();
if (channelId === ChannelStore.getCurrentId()) {
@@ -75,97 +98,52 @@ export function setChannelAsRead(channelIdParam) {
}
export function addUserToChannel(channelId, userId, success, error) {
- Client.addChannelMember(
- channelId,
- userId,
+ addChannelMember(channelId, userId)(dispatch, getState).then(
(data) => {
- UserStore.removeProfileNotInChannel(channelId, userId);
- const profile = UserStore.getProfile(userId);
- if (profile) {
- UserStore.saveProfileInChannel(channelId, profile);
- UserStore.emitInChannelChange();
- }
- UserStore.emitNotInChannelChange();
-
- if (success) {
+ if (data && success) {
success(data);
- }
- },
- (err) => {
- AsyncClient.dispatchError(err, 'addChannelMember');
-
- if (error) {
- error(err);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.addChannelMember.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function removeUserFromChannel(channelId, userId, success, error) {
- Client.removeChannelMember(
- channelId,
- userId,
+ removeChannelMember(channelId, userId)(dispatch, getState).then(
(data) => {
- UserStore.removeProfileInChannel(channelId, userId);
- const profile = UserStore.getProfile(userId);
- if (profile) {
- UserStore.saveProfileNotInChannel(channelId, profile);
- UserStore.emitNotInChannelChange();
- }
- UserStore.emitInChannelChange();
-
- ChannelStore.removeMemberInChannel(channelId, userId);
- ChannelStore.emitChange();
-
- if (success) {
+ if (data && success) {
success(data);
- }
- },
- (err) => {
- AsyncClient.dispatchError(err, 'removeChannelMember');
-
- if (error) {
- error(err);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.removeChannelMember.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function makeUserChannelAdmin(channelId, userId, success, error) {
- Client.updateChannelMemberRoles(
- channelId,
- userId,
- 'channel_user channel_admin',
- () => {
- getChannelMembersForUserIds(channelId, [userId]);
-
- if (success) {
- success();
- }
- },
- (err) => {
- if (error) {
- error(err);
+ updateChannelMemberRoles(channelId, userId, 'channel_user channel_admin')(dispatch, getState).then(
+ (data) => {
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.updateChannelMember.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function makeUserChannelMember(channelId, userId, success, error) {
- Client.updateChannelMemberRoles(
- channelId,
- userId,
- 'channel_user',
- () => {
- getChannelMembersForUserIds(channelId, [userId]);
-
- if (success) {
- success();
- }
- },
- (err) => {
- if (error) {
- error(err);
+ updateChannelMemberRoles(channelId, userId, 'channel_user')(dispatch, getState).then(
+ (data) => {
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.updateChannelMember.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
@@ -193,37 +171,15 @@ export function openDirectChannelToUser(userId, success, error) {
return;
}
- Client.createDirectChannel(
- userId,
+ createDirectChannel(UserStore.getCurrentId(), userId)(dispatch, getState).then(
(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, userId, 'true');
- loadProfilesForSidebar();
-
- AsyncClient.savePreference(
- Preferences.CATEGORY_DIRECT_CHANNEL_SHOW,
- userId,
- 'true'
- );
-
- if (success) {
- success(data2.channel, false);
- }
- }
- );
- },
- () => {
- browserHistory.push(TeamStore.getCurrentTeamUrl() + '/channels/' + channelName);
- if (error) {
- error();
+ loadProfilesForSidebar();
+ if (data && success) {
+ success(data, false);
+ } else if (data == null && error) {
+ browserHistory.push(TeamStore.getCurrentTeamUrl() + '/channels/' + channelName);
+ const serverError = getState().requests.channels.createChannel.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
@@ -283,11 +239,11 @@ export function unmarkFavorite(channelId) {
}
export function loadChannelsForCurrentUser() {
- AsyncClient.getChannels().then(() => {
- AsyncClient.getMyChannelMembers().then(() => {
+ fetchMyChannelsAndMembers(TeamStore.getCurrentId())(dispatch, getState).then(
+ () => {
loadDMsAndGMsForUnreads();
- });
- });
+ }
+ );
}
export function loadDMsAndGMsForUnreads() {
@@ -309,214 +265,125 @@ export function loadDMsAndGMsForUnreads() {
}
export function joinChannel(channel, success, error) {
- Client.joinChannel(
- channel.id,
- () => {
- ChannelStore.removeMoreChannel(channel.id);
- ChannelStore.storeChannel(channel);
-
- if (success) {
- success();
- }
- },
- () => {
- if (error) {
- error();
+ joinChannelRedux(UserStore.getCurrentId(), null, channel.id)(dispatch, getState).then(
+ (data) => {
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.joinChannel.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function updateChannel(channel, success, error) {
- Client.updateChannel(
- channel,
- () => {
- AsyncClient.getChannel(channel.id);
-
- if (success) {
- success();
- }
- },
- (err) => {
- if (error) {
- error(err);
+ updateChannelRedux(channel)(dispatch, getState).then(
+ (data) => {
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.updateChannel.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function searchMoreChannels(term, success, error) {
- Client.searchMoreChannels(
- term,
+ searchChannels(TeamStore.getCurrentId(), term)(dispatch, getState).then(
(data) => {
- if (success) {
+ if (data && success) {
success(data);
- }
- },
- (err) => {
- if (error) {
- error(err);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.getChannels.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function autocompleteChannels(term, success, error) {
- Client.autocompleteChannels(
- term,
+ searchChannels(TeamStore.getCurrentId(), term)(dispatch, getState).then(
(data) => {
- if (success) {
+ if (data && success) {
success(data);
- }
- },
- (err) => {
- AsyncClient.dispatchError(err, 'autocompleteChannels');
-
- if (error) {
- error(err);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.getChannels.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function updateChannelNotifyProps(data, options, success, error) {
- Client.updateChannelNotifyProps(Object.assign({}, data, options),
- () => {
- const member = ChannelStore.getMyMember(data.channel_id);
- member.notify_props = Object.assign(member.notify_props, options);
- ChannelStore.storeMyChannelMember(member);
-
- if (success) {
- success();
- }
- },
- (err) => {
- if (error) {
- error(err);
+ updateChannelNotifyPropsRedux(data.user_id, data.channel_id, Object.assign({}, data, options))(dispatch, getState).then(
+ (result) => {
+ if (result && success) {
+ success(result);
+ } else if (result == null && error) {
+ const serverError = getState().requests.channels.updateChannelNotifyProps.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function createChannel(channel, success, error) {
- Client.createChannel(
- channel,
+ createChannelRedux(channel)(dispatch, getState).then(
(data) => {
- const existing = ChannelStore.getChannelById(data.id);
- if (existing) {
- if (success) {
- success({channel: existing});
- }
- } else {
- Client.getChannel(
- data.id,
- (data2) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNEL,
- channel: data2.channel,
- member: data2.channel
- });
-
- if (success) {
- success(data2);
- }
- },
- (err) => {
- AsyncClient.dispatchError(err, 'getChannel');
-
- if (error) {
- error(err);
- }
- }
- );
- }
- },
- (err) => {
- if (error) {
- error(err);
- } else {
- AsyncClient.dispatchError(err, 'createChannel');
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.createChannel.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
-export function updateChannelPurpose(channelId, purposeValue, success, error) {
- Client.updateChannelPurpose(
- channelId,
- purposeValue,
- () => {
- AsyncClient.getChannel(channelId);
-
- if (success) {
- success();
- }
- },
- (err) => {
- if (error) {
- error(err);
+export function updateChannelPurpose(channelId, purpose, success, error) {
+ patchChannel(channelId, {purpose})(dispatch, getState).then(
+ (data) => {
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.updateChannel.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function updateChannelHeader(channelId, header, success, error) {
- Client.updateChannelHeader(
- channelId,
- header,
- (channelData) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNEL,
- channel: channelData
- });
-
- if (success) {
- success(channelData);
- }
- },
- (err) => {
- if (error) {
- error(err);
+ patchChannel(channelId, {header})(dispatch, getState).then(
+ (data) => {
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.updateChannel.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
export function getChannelMembersForUserIds(channelId, userIds, success, error) {
- Client.getChannelMembersByIds(
- channelId,
- userIds,
+ getChannelMembersByIds(channelId, userIds)(dispatch, getState).then(
(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_CHANNEL,
- channel_id: channelId,
- channel_members: memberMap
- });
-
- if (success) {
+ if (data && success) {
success(data);
- }
- },
- (err) => {
- AsyncClient.dispatchError(err, 'getChannelMembersByIds');
-
- if (error) {
- error(err);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.members.error;
+ error({id: serverError.server_error_id, ...serverError});
}
}
);
}
-export function leaveChannel(channelId, success, error) {
- Client.leaveChannel(channelId,
+export function leaveChannel(channelId, success) {
+ leaveChannelRedux(channelId)(dispatch, getState).then(
() => {
- loadChannelsForCurrentUser();
-
if (ChannelUtils.isFavoriteChannelId(channelId)) {
unmarkFavorite(channelId);
}
@@ -527,33 +394,19 @@ export function leaveChannel(channelId, success, error) {
if (success) {
success();
}
- },
- (err) => {
- AsyncClient.dispatchError(err, 'handleLeave');
-
- if (error) {
- error(err);
- }
}
);
}
export function deleteChannel(channelId, success, error) {
- Client.deleteChannel(
- channelId,
- () => {
- loadChannelsForCurrentUser();
-
- if (success) {
- success();
- }
- },
- (err) => {
- AsyncClient.dispatchError(err, 'handleDelete');
-
- if (error) {
- error(err);
- }
+ deleteChannelRedux(channelId)(dispatch, getState).then(
+ (data) => {
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.channels.members.error;
+ error({id: serverError.server_error_id, ...serverError});
}
- );
+ }
+ );
}
diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx
index 9709f5f80..1dd5d6952 100644
--- a/webapp/actions/global_actions.jsx
+++ b/webapp/actions/global_actions.jsx
@@ -35,8 +35,8 @@ import {browserHistory} from 'react-router/es6';
import store from 'stores/redux_store.jsx';
const dispatch = store.dispatch;
const getState = store.getState;
-import {ChannelTypes} from 'mattermost-redux/action_types';
import {removeUserFromTeam} from 'mattermost-redux/actions/teams';
+import {viewChannel, getChannelStats, getChannelMember} from 'mattermost-redux/actions/channels';
export function emitChannelClickEvent(channel) {
function userVisitedFakeChannel(chan, success, fail) {
@@ -53,12 +53,12 @@ export function emitChannelClickEvent(channel) {
}
function switchToChannel(chan) {
const channelMember = ChannelStore.getMyMember(chan.id);
- const getMyChannelMemberPromise = AsyncClient.getChannelMember(chan.id, UserStore.getCurrentId());
+ const getMyChannelMemberPromise = getChannelMember(chan.id, UserStore.getCurrentId())(dispatch, getState);
const oldChannelId = ChannelStore.getCurrentId();
getMyChannelMemberPromise.then(() => {
- AsyncClient.getChannelStats(chan.id, true);
- AsyncClient.viewChannel(chan.id, oldChannelId);
+ getChannelStats(chan.id)(dispatch, getState);
+ viewChannel(chan.id)(dispatch, getState);
loadPosts(chan.id);
});
@@ -83,11 +83,6 @@ export function emitChannelClickEvent(channel) {
channelMember,
prev: oldChannelId
});
-
- dispatch({
- type: ChannelTypes.SELECT_CHANNEL,
- data: chan.id
- }, getState);
}
if (channel.fake) {
@@ -113,7 +108,7 @@ export function doFocusPost(channelId, postId, data) {
post_list: data
});
loadChannelsForCurrentUser();
- AsyncClient.getChannelStats(channelId);
+ getChannelStats(channelId)(dispatch, getState);
loadPostsBefore(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
loadPostsAfter(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true);
}
diff --git a/webapp/actions/post_actions.jsx b/webapp/actions/post_actions.jsx
index 36abfc2be..4b7ade862 100644
--- a/webapp/actions/post_actions.jsx
+++ b/webapp/actions/post_actions.jsx
@@ -25,6 +25,7 @@ import store from 'stores/redux_store.jsx';
const dispatch = store.dispatch;
const getState = store.getState;
import {getProfilesByIds} from 'mattermost-redux/actions/users';
+import {getChannelMember} from 'mattermost-redux/actions/channels';
export function handleNewPost(post, msg) {
let websocketMessageProps = {};
@@ -40,7 +41,7 @@ export function handleNewPost(post, msg) {
Client.setTeamId(msg.data.team_id);
}
- AsyncClient.getChannelMember(post.channel_id, UserStore.getCurrentId()).then(() => completePostReceive(post, websocketMessageProps));
+ getChannelMember(post.channel_id, UserStore.getCurrentId())(dispatch, getState).then(() => completePostReceive(post, websocketMessageProps));
}
if (msg && msg.data) {
diff --git a/webapp/actions/team_actions.jsx b/webapp/actions/team_actions.jsx
index 83fbfa0a9..44b554ded 100644
--- a/webapp/actions/team_actions.jsx
+++ b/webapp/actions/team_actions.jsx
@@ -2,8 +2,8 @@
// See License.txt for license information.
import TeamStore from 'stores/team_store.jsx';
+import ChannelStore from 'stores/channel_store.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
import Client from 'client/web_client.jsx';
import {browserHistory} from 'react-router/es6';
@@ -14,6 +14,7 @@ const dispatch = store.dispatch;
const getState = store.getState;
import {getUser} from 'mattermost-redux/actions/users';
+import {viewChannel} from 'mattermost-redux/actions/channels';
import {
createTeam as createTeamRedux,
updateTeam as updateTeamRedux,
@@ -165,7 +166,7 @@ export function inviteMembers(data, success, error) {
}
export function switchTeams(url) {
- AsyncClient.viewChannel();
+ viewChannel(ChannelStore.getCurrentId())(dispatch, getState);
browserHistory.push(url);
}
diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx
index 57f78f95f..c6de42647 100644
--- a/webapp/actions/websocket_actions.jsx
+++ b/webapp/actions/websocket_actions.jsx
@@ -30,6 +30,13 @@ import {ActionTypes, Constants, Preferences, SocketEvents, UserStatuses} from 'u
import {browserHistory} from 'react-router/es6';
+// Redux actions
+import store from 'stores/redux_store.jsx';
+const dispatch = store.dispatch;
+const getState = store.getState;
+import {viewChannel, getChannelAndMyMember, getChannelStats} from 'mattermost-redux/actions/channels';
+import {ChannelTypes} from 'mattermost-redux/action_types';
+
const MAX_WEBSOCKET_FAILS = 7;
export function initialize() {
@@ -241,7 +248,7 @@ function handlePostEditEvent(msg) {
// Update channel state
if (ChannelStore.getCurrentId() === msg.broadcast.channel_id) {
if (window.isActive) {
- AsyncClient.viewChannel();
+ viewChannel(ChannelStore.getCurrentId())(dispatch, getState);
}
}
}
@@ -297,18 +304,18 @@ function handleUpdateTeamEvent(msg) {
}
function handleDirectAddedEvent(msg) {
- AsyncClient.getChannel(msg.broadcast.channel_id);
+ getChannelAndMyMember(msg.broadcast.channel_id)(dispatch, getState);
PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, msg.data.teammate_id, 'true');
loadProfilesForSidebar();
}
function handleUserAddedEvent(msg) {
if (ChannelStore.getCurrentId() === msg.broadcast.channel_id) {
- AsyncClient.getChannelStats();
+ getChannelStats(ChannelStore.getCurrentId())(dispatch, getState);
}
if (TeamStore.getCurrentId() === msg.data.team_id && UserStore.getCurrentId() === msg.data.user_id) {
- AsyncClient.getChannel(msg.broadcast.channel_id);
+ getChannelAndMyMember(msg.broadcast.channel_id)(dispatch, getState);
}
}
@@ -327,7 +334,7 @@ function handleUserRemovedEvent(msg) {
$('#removed_from_channel').modal('show');
}
} else if (ChannelStore.getCurrentId() === msg.broadcast.channel_id) {
- AsyncClient.getChannelStats();
+ getChannelStats(ChannelStore.getCurrentId())(dispatch, getState);
}
}
@@ -343,7 +350,7 @@ function handleChannelCreatedEvent(msg) {
const teamId = msg.data.team_id;
if (TeamStore.getCurrentId() === teamId && !ChannelStore.getChannelById(channelId)) {
- AsyncClient.getChannel(channelId);
+ getChannelAndMyMember(channelId)(dispatch, getState);
}
}
@@ -352,6 +359,7 @@ function handleChannelDeletedEvent(msg) {
const teamUrl = TeamStore.getCurrentTeamRelativeUrl();
browserHistory.push(teamUrl + '/channels/' + Constants.DEFAULT_CHANNEL);
}
+ dispatch({type: ChannelTypes.RECEIVED_CHANNEL_DELETED, data: {id: msg.data.channel_id, team_id: msg.broadcast.team_id}}, getState);
loadChannelsForCurrentUser();
}
diff --git a/webapp/components/channel_members_dropdown.jsx b/webapp/components/channel_members_dropdown/channel_members_dropdown.jsx
index e44108f3c..f7d42ce9b 100644
--- a/webapp/components/channel_members_dropdown.jsx
+++ b/webapp/components/channel_members_dropdown/channel_members_dropdown.jsx
@@ -7,7 +7,6 @@ import UserStore from 'stores/user_store.jsx';
import {removeUserFromChannel, makeUserChannelAdmin, makeUserChannelMember} from 'actions/channel_actions.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
import {canManageMembers} from 'utils/channel_utils.jsx';
import {Constants} from 'utils/constants.jsx';
@@ -16,6 +15,16 @@ import React from 'react';
import {FormattedMessage} from 'react-intl';
export default class ChannelMembersDropdown extends React.Component {
+ static propTypes = {
+ channel: React.PropTypes.object.isRequired,
+ user: React.PropTypes.object.isRequired,
+ teamMember: React.PropTypes.object.isRequired,
+ channelMember: React.PropTypes.object.isRequired,
+ actions: React.PropTypes.shape({
+ getChannelStats: React.PropTypes.func.isRequired
+ }).isRequired
+ }
+
constructor(props) {
super(props);
@@ -35,7 +44,7 @@ export default class ChannelMembersDropdown extends React.Component {
this.props.channel.id,
this.props.user.id,
() => {
- AsyncClient.getChannelStats(this.props.channel.id);
+ this.props.actions.getChannelStats(this.props.channel.id);
},
(err) => {
this.setState({serverError: err.message});
@@ -48,7 +57,7 @@ export default class ChannelMembersDropdown extends React.Component {
this.props.channel.id,
this.props.user.id,
() => {
- AsyncClient.getChannelStats(this.props.channel.id);
+ this.props.actions.getChannelStats(this.props.channel.id);
},
(err) => {
this.setState({serverError: err.message});
@@ -61,7 +70,7 @@ export default class ChannelMembersDropdown extends React.Component {
this.props.channel.id,
this.props.user.id,
() => {
- AsyncClient.getChannelStats(this.props.channel.id);
+ this.props.actions.getChannelStats(this.props.channel.id);
},
(err) => {
this.setState({serverError: err.message});
@@ -255,10 +264,3 @@ export default class ChannelMembersDropdown extends React.Component {
);
}
}
-
-ChannelMembersDropdown.propTypes = {
- channel: React.PropTypes.object.isRequired,
- user: React.PropTypes.object.isRequired,
- teamMember: React.PropTypes.object.isRequired,
- channelMember: React.PropTypes.object.isRequired
-};
diff --git a/webapp/components/channel_members_dropdown/index.js b/webapp/components/channel_members_dropdown/index.js
new file mode 100644
index 000000000..11a626e46
--- /dev/null
+++ b/webapp/components/channel_members_dropdown/index.js
@@ -0,0 +1,24 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {connect} from 'react-redux';
+import {bindActionCreators} from 'redux';
+import {getChannelStats} from 'mattermost-redux/actions/channels';
+
+import ChannelMembersDropdown from './channel_members_dropdown.jsx';
+
+function mapStateToProps(state, ownProps) {
+ return {
+ ...ownProps
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({
+ getChannelStats
+ }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(ChannelMembersDropdown);
diff --git a/webapp/components/channel_members_modal.jsx b/webapp/components/channel_members_modal.jsx
index dab51a1bd..492bc8809 100644
--- a/webapp/components/channel_members_modal.jsx
+++ b/webapp/components/channel_members_modal.jsx
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import MemberListChannel from './member_list_channel.jsx';
+import MemberListChannel from 'components/member_list_channel';
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
diff --git a/webapp/components/channel_view.jsx b/webapp/components/channel_view.jsx
index d6a931e0b..e9fb4cf94 100644
--- a/webapp/components/channel_view.jsx
+++ b/webapp/components/channel_view.jsx
@@ -8,7 +8,7 @@ import * as UserAgent from 'utils/user_agent.jsx';
import ChannelHeader from 'components/channel_header.jsx';
import FileUploadOverlay from 'components/file_upload_overlay.jsx';
import CreatePost from 'components/create_post.jsx';
-import PostViewCache from 'components/post_view/post_view_cache.jsx';
+import PostViewCache from 'components/post_view';
import ChannelStore from 'stores/channel_store.jsx';
diff --git a/webapp/components/member_list_channel/index.js b/webapp/components/member_list_channel/index.js
new file mode 100644
index 000000000..c0f70709e
--- /dev/null
+++ b/webapp/components/member_list_channel/index.js
@@ -0,0 +1,24 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {connect} from 'react-redux';
+import {bindActionCreators} from 'redux';
+import {getChannelStats} from 'mattermost-redux/actions/channels';
+
+import MemberListChannel from './member_list_channel.jsx';
+
+function mapStateToProps(state, ownProps) {
+ return {
+ ...ownProps
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({
+ getChannelStats
+ }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(MemberListChannel);
diff --git a/webapp/components/member_list_channel.jsx b/webapp/components/member_list_channel/member_list_channel.jsx
index df000c132..af2304433 100644
--- a/webapp/components/member_list_channel.jsx
+++ b/webapp/components/member_list_channel/member_list_channel.jsx
@@ -1,7 +1,7 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import ChannelMembersDropdown from 'components/channel_members_dropdown.jsx';
+import ChannelMembersDropdown from 'components/channel_members_dropdown';
import SearchableUserList from 'components/searchable_user_list/searchable_user_list_container.jsx';
import ChannelStore from 'stores/channel_store.jsx';
@@ -9,7 +9,6 @@ import UserStore from 'stores/user_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import {searchUsers, loadProfilesAndTeamMembersAndChannelMembers, loadTeamMembersAndChannelMembersForProfilesList} from 'actions/user_actions.jsx';
-import {getChannelStats} from 'utils/async_client.jsx';
import Constants from 'utils/constants.jsx';
@@ -23,6 +22,13 @@ import {searchProfilesInCurrentChannel} from 'mattermost-redux/selectors/entitie
const USERS_PER_PAGE = 50;
export default class MemberListChannel extends React.Component {
+ static propTypes = {
+ channel: React.PropTypes.object.isRequired,
+ actions: React.PropTypes.shape({
+ getChannelStats: React.PropTypes.func.isRequired
+ }).isRequired
+ }
+
constructor(props) {
super(props);
@@ -53,7 +59,7 @@ export default class MemberListChannel extends React.Component {
ChannelStore.addStatsChangeListener(this.onStatsChange);
loadProfilesAndTeamMembersAndChannelMembers(0, Constants.PROFILE_CHUNK_SIZE, TeamStore.getCurrentId(), ChannelStore.getCurrentId(), this.loadComplete);
- getChannelStats(ChannelStore.getCurrentId());
+ this.props.actions.getChannelStats(ChannelStore.getCurrentId());
}
componentWillUnmount() {
@@ -163,7 +169,3 @@ export default class MemberListChannel extends React.Component {
);
}
}
-
-MemberListChannel.propTypes = {
- channel: React.PropTypes.object.isRequired
-};
diff --git a/webapp/components/more_channels/index.js b/webapp/components/more_channels/index.js
new file mode 100644
index 000000000..b3ce839ef
--- /dev/null
+++ b/webapp/components/more_channels/index.js
@@ -0,0 +1,24 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {connect} from 'react-redux';
+import {bindActionCreators} from 'redux';
+import {getChannels} from 'mattermost-redux/actions/channels';
+
+import MoreChannels from './more_channels.jsx';
+
+function mapStateToProps(state, ownProps) {
+ return {
+ ...ownProps
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({
+ getChannels
+ }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(MoreChannels);
diff --git a/webapp/components/more_channels.jsx b/webapp/components/more_channels/more_channels.jsx
index 02a0628ba..3643d916b 100644
--- a/webapp/components/more_channels.jsx
+++ b/webapp/components/more_channels/more_channels.jsx
@@ -1,14 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import SearchableChannelList from './searchable_channel_list.jsx';
+import SearchableChannelList from 'components/searchable_channel_list.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import Constants from 'utils/constants.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
import {joinChannel, searchMoreChannels} from 'actions/channel_actions.jsx';
import {showCreateOption} from 'utils/channel_utils.jsx';
@@ -23,6 +22,14 @@ const CHANNELS_PER_PAGE = 50;
const SEARCH_TIMEOUT_MILLISECONDS = 100;
export default class MoreChannels extends React.Component {
+ static propTypes = {
+ onModalDismissed: React.PropTypes.func,
+ handleNewChannel: React.PropTypes.func,
+ actions: React.PropTypes.shape({
+ getChannels: React.PropTypes.func.isRequired
+ }).isRequired
+ }
+
constructor(props) {
super(props);
@@ -47,7 +54,7 @@ export default class MoreChannels extends React.Component {
componentDidMount() {
ChannelStore.addChangeListener(this.onChange);
- AsyncClient.getMoreChannelsPage(0, CHANNELS_CHUNK_SIZE * 2);
+ this.props.actions.getChannels(TeamStore.getCurrentId(), 0, CHANNELS_CHUNK_SIZE * 2);
}
componentWillUnmount() {
@@ -76,7 +83,7 @@ export default class MoreChannels extends React.Component {
}
nextPage(page) {
- AsyncClient.getMoreChannelsPage((page + 1) * CHANNELS_PER_PAGE, CHANNELS_PER_PAGE);
+ this.props.actions.getChannels(TeamStore.getCurrentId(), (page + 1) * CHANNELS_PER_PAGE, CHANNELS_PER_PAGE);
}
handleJoin(channel, done) {
@@ -194,8 +201,3 @@ export default class MoreChannels extends React.Component {
);
}
}
-
-MoreChannels.propTypes = {
- onModalDismissed: React.PropTypes.func,
- handleNewChannel: React.PropTypes.func
-};
diff --git a/webapp/components/needs_team/index.js b/webapp/components/needs_team/index.js
new file mode 100644
index 000000000..ba809fd10
--- /dev/null
+++ b/webapp/components/needs_team/index.js
@@ -0,0 +1,25 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {connect} from 'react-redux';
+import {bindActionCreators} from 'redux';
+import {viewChannel, getMyChannelMembers} from 'mattermost-redux/actions/channels';
+
+import NeedsTeam from './needs_team.jsx';
+
+function mapStateToProps(state, ownProps) {
+ return {
+ ...ownProps
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({
+ viewChannel,
+ getMyChannelMembers
+ }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(NeedsTeam);
diff --git a/webapp/components/needs_team.jsx b/webapp/components/needs_team/needs_team.jsx
index 42f05c1a9..2ae3cbeec 100644
--- a/webapp/components/needs_team.jsx
+++ b/webapp/components/needs_team/needs_team.jsx
@@ -7,7 +7,6 @@ import $ from 'jquery';
import {browserHistory} from 'react-router/es6';
import * as Utils from 'utils/utils.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
@@ -26,9 +25,9 @@ import ErrorBar from 'components/error_bar.jsx';
import SidebarRight from 'components/sidebar_right.jsx';
import SidebarRightMenu from 'components/sidebar_right_menu.jsx';
import Navbar from 'components/navbar.jsx';
-import WebrtcSidebar from './webrtc/components/webrtc_sidebar.jsx';
+import WebrtcSidebar from 'components/webrtc/components/webrtc_sidebar.jsx';
-import WebrtcNotification from './webrtc/components/webrtc_notification.jsx';
+import WebrtcNotification from 'components/webrtc/components/webrtc_notification.jsx';
// Modals
import GetPostLinkModal from 'components/get_post_link_modal.jsx';
@@ -48,6 +47,23 @@ import * as UserAgent from 'utils/user_agent.jsx';
const UNREAD_CHECK_TIME_MILLISECONDS = 10000;
export default class NeedsTeam extends React.Component {
+ static propTypes = {
+ children: React.PropTypes.oneOfType([
+ React.PropTypes.arrayOf(React.PropTypes.element),
+ React.PropTypes.element
+ ]),
+ navbar: React.PropTypes.element,
+ sidebar: React.PropTypes.element,
+ team_sidebar: React.PropTypes.element,
+ center: React.PropTypes.element,
+ params: React.PropTypes.object,
+ user: React.PropTypes.object,
+ actions: React.PropTypes.shape({
+ viewChannel: React.PropTypes.func.isRequired,
+ getMyChannelMembers: React.PropTypes.func.isRequired
+ }).isRequired
+ }
+
constructor(params) {
super(params);
@@ -102,13 +118,13 @@ export default class NeedsTeam extends React.Component {
// Set up tracking for whether the window is active
window.isActive = true;
$(window).on('focus', () => {
- AsyncClient.viewChannel();
+ this.props.actions.viewChannel(ChannelStore.getCurrentId());
ChannelStore.resetCounts(ChannelStore.getCurrentId());
ChannelStore.emitChange();
window.isActive = true;
if (new Date().getTime() - this.blurTime > UNREAD_CHECK_TIME_MILLISECONDS) {
- AsyncClient.getMyChannelMembers().then(loadProfilesForSidebar);
+ this.props.actions.getMyChannelMembers(TeamStore.getCurrentId()).then(loadProfilesForSidebar);
}
});
@@ -116,7 +132,7 @@ export default class NeedsTeam extends React.Component {
window.isActive = false;
this.blurTime = new Date().getTime();
if (UserStore.getCurrentUser()) {
- AsyncClient.viewChannel('');
+ this.props.actions.viewChannel('');
}
});
@@ -216,16 +232,3 @@ export default class NeedsTeam extends React.Component {
);
}
}
-
-NeedsTeam.propTypes = {
- children: React.PropTypes.oneOfType([
- React.PropTypes.arrayOf(React.PropTypes.element),
- React.PropTypes.element
- ]),
- navbar: React.PropTypes.element,
- sidebar: React.PropTypes.element,
- team_sidebar: React.PropTypes.element,
- center: React.PropTypes.element,
- params: React.PropTypes.object,
- user: React.PropTypes.object
-};
diff --git a/webapp/components/new_channel_flow.jsx b/webapp/components/new_channel_flow.jsx
index 0ca504534..91dd04c0c 100644
--- a/webapp/components/new_channel_flow.jsx
+++ b/webapp/components/new_channel_flow.jsx
@@ -3,7 +3,6 @@
import * as Utils from 'utils/utils.jsx';
import TeamStore from 'stores/team_store.jsx';
-import UserStore from 'stores/user_store.jsx';
import {cleanUpUrlable} from 'utils/url.jsx';
import NewChannelModal from './new_channel_modal.jsx';
@@ -68,9 +67,8 @@ export default class NewChannelFlow extends React.Component {
return;
}
- const cu = UserStore.getCurrentUser();
const channel = {
- team_id: cu.team_id,
+ team_id: TeamStore.getCurrentId(),
name: this.state.channelName,
display_name: this.state.channelDisplayName,
purpose: this.state.channelPurpose,
@@ -82,7 +80,7 @@ export default class NewChannelFlow extends React.Component {
channel,
(data) => {
this.doOnModalExited = () => {
- browserHistory.push(TeamStore.getCurrentTeamRelativeUrl() + '/channels/' + data.channel.name);
+ browserHistory.push(TeamStore.getCurrentTeamRelativeUrl() + '/channels/' + data.name);
};
this.props.onModalDismissed();
diff --git a/webapp/components/post_view/index.js b/webapp/components/post_view/index.js
new file mode 100644
index 000000000..b42b486ab
--- /dev/null
+++ b/webapp/components/post_view/index.js
@@ -0,0 +1,24 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {connect} from 'react-redux';
+import {bindActionCreators} from 'redux';
+import {viewChannel} from 'mattermost-redux/actions/channels';
+
+import PostViewCache from './post_view_cache.jsx';
+
+function mapStateToProps(state, ownProps) {
+ return {
+ ...ownProps
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({
+ viewChannel
+ }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(PostViewCache);
diff --git a/webapp/components/post_view/post_view_cache.jsx b/webapp/components/post_view/post_view_cache.jsx
index d7cb360d1..beb20360a 100644
--- a/webapp/components/post_view/post_view_cache.jsx
+++ b/webapp/components/post_view/post_view_cache.jsx
@@ -5,13 +5,18 @@ import PostViewController from './post_view_controller.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
import React from 'react';
const MAXIMUM_CACHED_VIEWS = 5;
export default class PostViewCache extends React.Component {
+ static propTypes = {
+ actions: React.PropTypes.shape({
+ viewChannel: React.PropTypes.func.isRequired
+ }).isRequired
+ }
+
constructor(props) {
super(props);
@@ -32,7 +37,7 @@ export default class PostViewCache extends React.Component {
componentWillUnmount() {
if (UserStore.getCurrentUser()) {
- AsyncClient.viewChannel('', this.state.currentChannelId || '');
+ this.props.actions.viewChannel('', this.state.currentChannelId || '');
}
ChannelStore.removeChangeListener(this.onChannelChange);
}
diff --git a/webapp/components/rename_channel_modal.jsx b/webapp/components/rename_channel_modal.jsx
index f7d8fad28..96897eb52 100644
--- a/webapp/components/rename_channel_modal.jsx
+++ b/webapp/components/rename_channel_modal.jsx
@@ -2,6 +2,7 @@
// See License.txt for license information.
import ReactDOM from 'react-dom';
+import {browserHistory} from 'react-router/es6';
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
import {cleanUpUrlable, getShortenedURL} from 'utils/url.jsx';
@@ -164,8 +165,10 @@ export class RenameChannelModal extends React.Component {
}
updateChannel(channel,
- () => {
+ (data) => {
this.handleHide();
+ const team = TeamStore.get(data.team_id);
+ browserHistory.push('/' + team.name + '/channels/' + data.name);
},
(err) => {
this.setState({
diff --git a/webapp/components/sidebar.jsx b/webapp/components/sidebar.jsx
index 8667802cc..71559de02 100644
--- a/webapp/components/sidebar.jsx
+++ b/webapp/components/sidebar.jsx
@@ -5,7 +5,7 @@ import $ from 'jquery';
import ReactDOM from 'react-dom';
import NewChannelFlow from './new_channel_flow.jsx';
import MoreDirectChannels from 'components/more_direct_channels';
-import MoreChannels from 'components/more_channels.jsx';
+import MoreChannels from 'components/more_channels';
import SidebarHeader from './sidebar_header.jsx';
import UnreadChannelIndicator from './unread_channel_indicator.jsx';
import TutorialTip from './tutorial/tutorial_tip.jsx';
diff --git a/webapp/components/team_members_dropdown/index.js b/webapp/components/team_members_dropdown/index.js
index 9486c89fa..e7b5910a2 100644
--- a/webapp/components/team_members_dropdown/index.js
+++ b/webapp/components/team_members_dropdown/index.js
@@ -5,6 +5,7 @@ import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {getUser} from 'mattermost-redux/actions/users';
import {getTeamStats} from 'mattermost-redux/actions/teams';
+import {getChannelStats} from 'mattermost-redux/actions/channels';
import TeamMembersDropdown from './team_members_dropdown.jsx';
@@ -18,7 +19,8 @@ function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
getUser,
- getTeamStats
+ getTeamStats,
+ getChannelStats
}, dispatch)
};
}
diff --git a/webapp/components/team_members_dropdown/team_members_dropdown.jsx b/webapp/components/team_members_dropdown/team_members_dropdown.jsx
index 00441ba37..f01997d12 100644
--- a/webapp/components/team_members_dropdown/team_members_dropdown.jsx
+++ b/webapp/components/team_members_dropdown/team_members_dropdown.jsx
@@ -10,7 +10,6 @@ import ChannelStore from 'stores/channel_store.jsx';
import {removeUserFromTeam, updateTeamMemberRoles} from 'actions/team_actions.jsx';
import {loadMyTeamMembers, updateActive} from 'actions/user_actions.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
import React from 'react';
@@ -23,7 +22,8 @@ export default class TeamMembersDropdown extends React.Component {
teamMember: React.PropTypes.object.isRequired,
actions: React.PropTypes.shape({
getUser: React.PropTypes.func.isRequired,
- getTeamStats: React.PropTypes.func.isRequired
+ getTeamStats: React.PropTypes.func.isRequired,
+ getChannelStats: React.PropTypes.func.isRequired
}).isRequired
}
@@ -88,7 +88,7 @@ export default class TeamMembersDropdown extends React.Component {
handleMakeActive() {
updateActive(this.props.user.id, true,
() => {
- AsyncClient.getChannelStats(ChannelStore.getCurrentId());
+ this.props.actions.getChannelStats(ChannelStore.getCurrentId());
this.props.actions.getTeamStats(this.props.teamMember.team_id);
},
(err) => {
@@ -100,7 +100,7 @@ export default class TeamMembersDropdown extends React.Component {
handleMakeNotActive() {
updateActive(this.props.user.id, false,
() => {
- AsyncClient.getChannelStats(ChannelStore.getCurrentId());
+ this.props.actions.getChannelStats(ChannelStore.getCurrentId());
this.props.actions.getTeamStats(this.props.teamMember.team_id);
},
(err) => {
diff --git a/webapp/package.json b/webapp/package.json
index 0067e2fb9..e7203f0d6 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -22,7 +22,7 @@
"localforage": "1.5.0",
"marked": "mattermost/marked#8f5902fff9bad793cd6c66e0c44002c9e79e1317",
"match-at": "0.1.0",
- "mattermost-redux": "mattermost/mattermost-redux#webapp-part3",
+ "mattermost-redux": "mattermost/mattermost-redux#webapp-part4",
"object-assign": "4.1.1",
"pdfjs-dist": "1.7.363",
"perfect-scrollbar": "0.6.16",
diff --git a/webapp/root.jsx b/webapp/root.jsx
index b2da6a54c..6a63e6dad 100644
--- a/webapp/root.jsx
+++ b/webapp/root.jsx
@@ -16,9 +16,6 @@ import BrowserStore from 'stores/browser_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
import * as I18n from 'i18n/i18n.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
-
-import {getClientConfig, getLicenseConfig, setUrl} from 'mattermost-redux/actions/general';
// Import our styles
import 'bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css';
@@ -26,7 +23,13 @@ import 'google-fonts/google-fonts.css';
import 'sass/styles.scss';
import 'katex/dist/katex.min.css';
+// Redux actions
import store from 'stores/redux_store.jsx';
+const dispatch = store.dispatch;
+const getState = store.getState;
+
+import {viewChannel} from 'mattermost-redux/actions/channels';
+import {getClientConfig, getLicenseConfig, setUrl} from 'mattermost-redux/actions/general';
// Import the root of our routing tree
import rRoot from 'routes/route_root.jsx';
@@ -85,7 +88,7 @@ function preRenderSetup(callwhendone) {
$(window).off('beforeunload');
BrowserStore.setLastServerVersion('');
if (UserStore.getCurrentUser()) {
- AsyncClient.viewChannel('', ChannelStore.getCurrentId() || '');
+ viewChannel('', ChannelStore.getCurrentId() || '')(dispatch, getState);
}
Websockets.close();
}
diff --git a/webapp/routes/route_team.jsx b/webapp/routes/route_team.jsx
index 0a3c0a59f..45494dca5 100644
--- a/webapp/routes/route_team.jsx
+++ b/webapp/routes/route_team.jsx
@@ -6,14 +6,12 @@ import * as RouteUtils from 'routes/route_utils.jsx';
import {browserHistory} from 'react-router/es6';
import TeamStore from 'stores/team_store.jsx';
+import UserStore from 'stores/user_store.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import {loadStatusesForChannelAndSidebar} from 'actions/status_actions.jsx';
import {reconnect} from 'actions/websocket_actions.jsx';
-import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
import Constants from 'utils/constants.jsx';
-const ActionTypes = Constants.ActionTypes;
import * as AsyncClient from 'utils/async_client.jsx';
-import Client from 'client/web_client.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import BrowserStore from 'stores/browser_store.jsx';
@@ -22,6 +20,13 @@ import integrationsRoute from 'routes/route_integrations.jsx';
import {loadNewDMIfNeeded, loadNewGMIfNeeded, loadProfilesForSidebar} from 'actions/user_actions.jsx';
+// Redux actions
+import store from 'stores/redux_store.jsx';
+const dispatch = store.dispatch;
+const getState = store.getState;
+
+import {fetchMyChannelsAndMembers, joinChannel} from 'mattermost-redux/actions/channels';
+
function onChannelEnter(nextState, replace, callback) {
doChannelChange(nextState, replace, callback);
}
@@ -40,22 +45,16 @@ function doChannelChange(state, replace, callback) {
}
if (!channel) {
- Client.joinChannelByName(
- state.params.channel,
+ joinChannel(UserStore.getCurrentId(), TeamStore.getCurrentId(), null, state.params.channel)(dispatch, getState).then(
(data) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNEL,
- channel: data
- });
-
- GlobalActions.emitChannelClickEvent(data);
- callback();
- },
- () => {
- if (state.params.team) {
- replace('/' + state.params.team + '/channels/town-square');
- } else {
- replace('/');
+ if (data) {
+ GlobalActions.emitChannelClickEvent(data.channel);
+ } else if (data == null) {
+ if (state.params.team) {
+ replace('/' + state.params.team + '/channels/town-square');
+ } else {
+ replace('/');
+ }
}
callback();
}
@@ -107,26 +106,17 @@ function preNeedsTeam(nextState, replace, callback) {
if (nextState.location.pathname.indexOf('/channels/') > -1 ||
nextState.location.pathname.indexOf('/pl/') > -1) {
AsyncClient.getMyTeamsUnread();
- AsyncClient.getMyChannelMembersForTeam(team.id);
+ fetchMyChannelsAndMembers(team.id)(dispatch, getState);
}
const d1 = $.Deferred(); //eslint-disable-line new-cap
- Client.getChannels(
- (data) => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNELS,
- channels: data
- });
-
+ fetchMyChannelsAndMembers(team.id)(dispatch, getState).then(
+ () => {
loadStatusesForChannelAndSidebar();
loadProfilesForSidebar();
d1.resolve();
- },
- (err) => {
- AsyncClient.dispatchError(err, 'getChannels');
- d1.resolve();
}
);
@@ -166,7 +156,7 @@ export default {
emojiRoute,
{
getComponents: (location, callback) => {
- System.import('components/needs_team.jsx').then(RouteUtils.importComponentSuccess(callback));
+ System.import('components/needs_team').then(RouteUtils.importComponentSuccess(callback));
},
childRoutes: [
{
diff --git a/webapp/stores/channel_store.jsx b/webapp/stores/channel_store.jsx
index 8530d0620..d33f3ac9a 100644
--- a/webapp/stores/channel_store.jsx
+++ b/webapp/stores/channel_store.jsx
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
+import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import TeamStore from 'stores/team_store.jsx';
@@ -17,21 +17,44 @@ const CHANGE_EVENT = 'change';
const STATS_EVENT = 'stats';
const LAST_VIEVED_EVENT = 'last_viewed';
+import store from 'stores/redux_store.jsx';
+import * as Selectors from 'mattermost-redux/selectors/entities/channels';
+import {ChannelTypes, UserTypes} from 'mattermost-redux/action_types';
+
class ChannelStoreClass extends EventEmitter {
constructor(props) {
super(props);
this.setMaxListeners(600);
this.clear();
+
+ this.entities = store.getState().entities.channels;
+
+ store.subscribe(() => {
+ const newEntities = store.getState().entities.channels;
+
+ if (newEntities.currentTeamId !== this.entities.currentChannelId) {
+ this.emitChange();
+ }
+ if (newEntities.channels !== this.entities.channels) {
+ this.emitChange();
+ }
+ if (newEntities.myMembers !== this.entities.myMembers) {
+ this.setUnreadCountsByMembers(Object.values(newEntities.myMembers));
+ this.emitChange();
+ }
+ if (newEntities.membersInChannel !== this.entities.membersInChannel) {
+ this.emitChange();
+ }
+ if (newEntities.stats !== this.entities.stats) {
+ this.emitStatsChange();
+ }
+
+ this.entities = newEntities;
+ });
}
clear() {
- this.currentId = null;
this.postMode = this.POST_MODE_CHANNEL;
- this.channels = [];
- this.members_in_channel = {};
- this.myChannelMembers = {};
- this.moreChannels = {};
- this.stats = {};
this.unreadCounts = {};
}
@@ -126,17 +149,25 @@ class ChannelStoreClass extends EventEmitter {
}
setCurrentId(id) {
- this.currentId = id;
+ store.dispatch({
+ type: ChannelTypes.SELECT_CHANNEL,
+ data: id
+ });
}
resetCounts(id) {
- const cm = this.myChannelMembers;
- for (const cmid in cm) {
- if (cm[cmid].channel_id === id) {
+ const members = Object.assign({}, this.getMyMembers());
+ for (const cmid in members) {
+ if (!members.hasOwnProperty(cmid)) {
+ continue;
+ }
+ const member = {...members[cmid]};
+ if (member.channel_id === id) {
const channel = this.get(id);
if (channel) {
- cm[cmid].msg_count = channel.total_msg_count;
- cm[cmid].mention_count = 0;
+ member.msg_count = channel.total_msg_count;
+ member.mention_count = 0;
+ this.storeMyChannelMember(member);
this.setUnreadCountByChannel(id);
}
break;
@@ -145,7 +176,7 @@ class ChannelStoreClass extends EventEmitter {
}
getCurrentId() {
- return this.currentId;
+ return Selectors.getCurrentChannelId(store.getState());
}
getCurrent() {
@@ -176,7 +207,7 @@ class ChannelStoreClass extends EventEmitter {
let stats;
if (channelId) {
- stats = this.stats[channelId];
+ stats = Selectors.getAllChannelStats(store.getState())[channelId];
}
if (stats) {
@@ -214,54 +245,67 @@ class ChannelStoreClass extends EventEmitter {
}
storeChannels(channels) {
- this.channels = channels;
+ store.dispatch({
+ type: ChannelTypes.RECEIVED_CHANNELS,
+ data: channels,
+ teamId: channels[0].team_id
+ });
}
getChannels() {
- return this.channels;
+ return Selectors.getMyChannels(store.getState());
}
getChannelById(id) {
- return this.channels.filter((c) => c.id === id)[0];
+ return Selectors.getChannelsInCurrentTeam(store.getState())[id];
}
storeMyChannelMember(channelMember) {
- const members = Object.assign({}, this.getMyMembers());
- members[channelMember.channel_id] = channelMember;
- this.storeMyChannelMembers(members);
+ store.dispatch({
+ type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
+ data: channelMember
+ });
}
storeMyChannelMembers(channelMembers) {
- this.myChannelMembers = channelMembers;
+ store.dispatch({
+ type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS,
+ data: Object.values(channelMembers)
+ });
}
storeMyChannelMembersList(channelMembers) {
- channelMembers.forEach((m) => {
- this.myChannelMembers[m.channel_id] = m;
+ store.dispatch({
+ type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS,
+ data: channelMembers
});
}
getMyMembers() {
- return this.myChannelMembers;
+ return Selectors.getMyChannelMemberships(store.getState());
}
saveMembersInChannel(channelId = this.getCurrentId(), members) {
- const oldMembers = this.members_in_channel[channelId] || {};
- this.members_in_channel[channelId] = Object.assign({}, oldMembers, members);
+ store.dispatch({
+ type: ChannelTypes.RECEIVED_CHANNEL_MEMBERS,
+ data: Object.values(members)
+ });
}
removeMemberInChannel(channelId = this.getCurrentId(), userId) {
- if (this.members_in_channel[channelId]) {
- Reflect.deleteProperty(this.members_in_channel[channelId], userId);
- }
+ store.dispatch({
+ type: UserTypes.RECEIVED_PROFILE_NOT_IN_CHANNEL,
+ data: {id: channelId, user_id: userId}
+ });
}
getMembersInChannel(channelId = this.getCurrentId()) {
- return Object.assign({}, this.members_in_channel[channelId]) || {};
+ return Selectors.getChannelMembersInChannels(store.getState())[channelId] || {};
}
hasActiveMemberInChannel(channelId = this.getCurrentId(), userId) {
- if (this.members_in_channel[channelId] && this.members_in_channel[channelId][userId]) {
+ const members = this.getMembersInChannel(channelId);
+ if (members && members[userId]) {
return true;
}
@@ -269,33 +313,24 @@ class ChannelStoreClass extends EventEmitter {
}
storeMoreChannels(channels, teamId = TeamStore.getCurrentId()) {
- const newChannels = {};
- for (let i = 0; i < channels.length; i++) {
- newChannels[channels[i].id] = channels[i];
- }
- this.moreChannels[teamId] = Object.assign({}, this.moreChannels[teamId], newChannels);
- }
-
- removeMoreChannel(channelId, teamId = TeamStore.getCurrentId()) {
- Reflect.deleteProperty(this.moreChannels[teamId], channelId);
- }
-
- getMoreChannels(teamId = TeamStore.getCurrentId()) {
- return Object.assign({}, this.moreChannels[teamId]);
+ store.dispatch({
+ type: ChannelTypes.RECEIVED_CHANNELS,
+ data: channels,
+ teamId
+ });
}
- getMoreChannelsList(teamId = TeamStore.getCurrentId()) {
- const teamChannels = this.moreChannels[teamId] || {};
-
- if (!ChannelUtils) {
- ChannelUtils = require('utils/channel_utils.jsx'); //eslint-disable-line global-require
- }
-
- return Object.keys(teamChannels).map((cid) => teamChannels[cid]).sort(ChannelUtils.sortChannelsByDisplayName);
+ getMoreChannels() {
+ const channels = Selectors.getOtherChannels(store.getState());
+ const channelMap = {};
+ channels.forEach((c) => {
+ channelMap[c.id] = c;
+ });
+ return channelMap;
}
- storeStats(stats) {
- this.stats = stats;
+ getMoreChannelsList() {
+ return Selectors.getOtherChannels(store.getState());
}
isDefault(channel) {
@@ -317,8 +352,8 @@ class ChannelStoreClass extends EventEmitter {
}
setUnreadCountsByCurrentMembers() {
- Object.keys(this.myChannelMembers).forEach((key) => {
- this.setUnreadCountByChannel(this.myChannelMembers[key].channel_id);
+ Object.keys(this.getMyMembers()).forEach((key) => {
+ this.setUnreadCountByChannel(this.getMyMember(key).channel_id);
});
}
@@ -415,7 +450,12 @@ class ChannelStoreClass extends EventEmitter {
return;
}
- this.get(id).total_msg_count++;
+ const channel = {...this.get(id)};
+ channel.total_msg_count++;
+ store.dispatch({
+ type: ChannelTypes.RECEIVED_CHANNEL,
+ data: channel
+ });
if (markRead) {
this.resetCounts(id);
@@ -436,7 +476,12 @@ class ChannelStoreClass extends EventEmitter {
if (mentions.indexOf(UserStore.getCurrentId()) !== -1) {
this.unreadCounts[id].mentions++;
- this.getMyMember(id).mention_count++;
+ const member = {...this.getMyMember(id)};
+ member.mention_count++;
+ store.dispatch({
+ type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
+ data: member
+ });
}
}
}
@@ -510,10 +555,10 @@ ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
ChannelStore.emitChange();
break;
case ActionTypes.RECEIVED_CHANNEL_STATS:
- var stats = Object.assign({}, ChannelStore.getStats());
- stats[action.stats.channel_id] = action.stats;
- ChannelStore.storeStats(stats);
- ChannelStore.emitStatsChange();
+ store.dispatch({
+ type: ChannelTypes.RECEIVED_CHANNEL_STATS,
+ data: action.stats
+ });
break;
case ActionTypes.RECEIVED_POST:
diff --git a/webapp/utils/async_client.jsx b/webapp/utils/async_client.jsx
index 47327c5e5..712d447e8 100644
--- a/webapp/utils/async_client.jsx
+++ b/webapp/utils/async_client.jsx
@@ -2,10 +2,8 @@
// See License.txt for license information.
import BrowserStore from 'stores/browser_store.jsx';
-import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
import TeamStore from 'stores/team_store.jsx';
-import ErrorStore from 'stores/error_store.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
@@ -62,233 +60,6 @@ export function checkVersion() {
}
}
-export function getChannels() {
- return new Promise((resolve, reject) => {
- if (isCallInProgress('getChannels')) {
- resolve();
- return;
- }
-
- callTracker.getChannels = utils.getTimestamp();
-
- Client.getChannels(
- (data) => {
- callTracker.getChannels = 0;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNELS,
- channels: data
- });
- resolve();
- },
- (err) => {
- callTracker.getChannels = 0;
- dispatchError(err, 'getChannels');
- reject(new Error('Unable to getChannels'));
- }
- );
- });
-}
-
-export function getChannel(id) {
- if (isCallInProgress('getChannel' + id)) {
- return;
- }
-
- callTracker['getChannel' + id] = utils.getTimestamp();
-
- Client.getChannel(id,
- (data) => {
- callTracker['getChannel' + id] = 0;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNEL,
- channel: data.channel,
- member: data.member
- });
- },
- (err) => {
- callTracker['getChannel' + id] = 0;
- dispatchError(err, 'getChannel');
- }
- );
-}
-
-export function getMyChannelMembers() {
- return new Promise((resolve, reject) => {
- if (isCallInProgress('getMyChannelMembers')) {
- resolve();
- return;
- }
-
- callTracker.getMyChannelMembers = utils.getTimestamp();
-
- Client.getMyChannelMembers(
- (data) => {
- callTracker.getMyChannelMembers = 0;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_MY_CHANNEL_MEMBERS,
- members: data
- });
- resolve();
- },
- (err) => {
- callTracker.getMyChannelMembers = 0;
- dispatchError(err, 'getMyChannelMembers');
- reject(new Error('Unable to getMyChannelMembers'));
- }
- );
- });
-}
-
-export function getMyChannelMembersForTeam(teamId) {
- return new Promise((resolve, reject) => {
- if (isCallInProgress(`getMyChannelMembers${teamId}`)) {
- resolve();
- return;
- }
-
- callTracker[`getMyChannelMembers${teamId}`] = utils.getTimestamp();
-
- Client.getMyChannelMembersForTeam(
- teamId,
- (data) => {
- callTracker[`getMyChannelMembers${teamId}`] = 0;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_MY_CHANNEL_MEMBERS,
- members: data
- });
- resolve();
- },
- (err) => {
- callTracker[`getMyChannelMembers${teamId}`] = 0;
- dispatchError(err, 'getMyChannelMembersForTeam');
- reject(new Error('Unable to getMyChannelMembersForTeam'));
- }
- );
- });
-}
-
-export function viewChannel(channelId = ChannelStore.getCurrentId(), prevChannelId = '', time = 0) {
- if (channelId == null || !Client.teamId) {
- return;
- }
-
- if (isCallInProgress(`viewChannel${channelId}`)) {
- return;
- }
-
- callTracker[`viewChannel${channelId}`] = utils.getTimestamp();
- Client.viewChannel(
- channelId,
- prevChannelId,
- time,
- () => {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_PREFERENCE,
- preference: {
- category: 'last',
- name: TeamStore.getCurrentId(),
- value: channelId
- }
- });
-
- callTracker[`viewChannel${channelId}`] = 0;
- ErrorStore.clearLastError();
- },
- (err) => {
- callTracker[`viewChannel${channelId}`] = 0;
- const count = ErrorStore.getConnectionErrorCount();
- ErrorStore.setConnectionErrorCount(count + 1);
- dispatchError(err, 'viewChannel');
- }
- );
-}
-
-export function getMoreChannelsPage(offset, limit) {
- if (isCallInProgress('getMoreChannelsPage')) {
- return;
- }
-
- callTracker.getMoreChannelsPage = utils.getTimestamp();
- Client.getMoreChannelsPage(
- offset,
- limit,
- (data) => {
- callTracker.getMoreChannelsPage = 0;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_MORE_CHANNELS,
- channels: data
- });
- },
- (err) => {
- callTracker.getMoreChannelsPage = 0;
- dispatchError(err, 'getMoreChannelsPage');
- }
- );
-}
-
-export function getChannelStats(channelId = ChannelStore.getCurrentId(), doVersionCheck = false) {
- if (isCallInProgress('getChannelStats' + channelId) || channelId == null) {
- return;
- }
-
- callTracker['getChannelStats' + channelId] = utils.getTimestamp();
-
- Client.getChannelStats(
- channelId,
- (data) => {
- callTracker['getChannelStats' + channelId] = 0;
-
- if (doVersionCheck) {
- checkVersion();
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNEL_STATS,
- stats: data
- });
- },
- (err) => {
- callTracker['getChannelStats' + channelId] = 0;
- dispatchError(err, 'getChannelStats');
- }
- );
-}
-
-export function getChannelMember(channelId, userId) {
- return new Promise((resolve, reject) => {
- if (isCallInProgress(`getChannelMember${channelId}${userId}`)) {
- resolve();
- return;
- }
-
- callTracker[`getChannelMember${channelId}${userId}`] = utils.getTimestamp();
-
- Client.getChannelMember(
- channelId,
- userId,
- (data) => {
- callTracker[`getChannelMember${channelId}${userId}`] = 0;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNEL_MEMBER,
- member: data
- });
- resolve();
- },
- (err) => {
- callTracker[`getChannelMember${channelId}${userId}`] = 0;
- dispatchError(err, 'getChannelMember');
- reject(new Error('Unable to getChannelMeber'));
- }
- );
- });
-}
-
export function getUser(userId, success, error) {
const callName = `getUser${userId}`;