diff options
Diffstat (limited to 'webapp')
27 files changed, 488 insertions, 683 deletions
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}`; |