diff options
Diffstat (limited to 'webapp')
27 files changed, 366 insertions, 369 deletions
diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx index bd9178604..9709f5f80 100644 --- a/webapp/actions/global_actions.jsx +++ b/webapp/actions/global_actions.jsx @@ -36,6 +36,7 @@ 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'; export function emitChannelClickEvent(channel) { function userVisitedFakeChannel(chan, success, fail) { @@ -189,16 +190,7 @@ export function emitPostFocusRightHandSideFromSearch(post, isMentionSearch) { } export function emitLeaveTeam() { - Client.removeUserFromTeam( - TeamStore.getCurrentId(), - UserStore.getCurrentId(), - () => { - // DO nothing. The websocket should cause a re-direct - }, - (err) => { - AsyncClient.dispatchError(err, 'removeUserFromTeam'); - } - ); + removeUserFromTeam(TeamStore.getCurrentId(), UserStore.getCurrentId())(dispatch, getState); } export function emitLoadMorePostsEvent() { @@ -467,7 +459,6 @@ export function emitUserLoggedOutEvent(redirectTo = '/', shouldSignalLogout = tr export function clientLogout(redirectTo = '/') { BrowserStore.clear(); ErrorStore.clearLastError(); - TeamStore.clear(); ChannelStore.clear(); stopPeriodicStatusUpdates(); WebsocketActions.close(); diff --git a/webapp/actions/team_actions.jsx b/webapp/actions/team_actions.jsx index f263108fd..83fbfa0a9 100644 --- a/webapp/actions/team_actions.jsx +++ b/webapp/actions/team_actions.jsx @@ -1,15 +1,10 @@ // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import UserStore from 'stores/user_store.jsx'; import TeamStore from 'stores/team_store.jsx'; -import Constants from 'utils/constants.jsx'; -const ActionTypes = Constants.ActionTypes; - import * as AsyncClient from 'utils/async_client.jsx'; import Client from 'client/web_client.jsx'; -import AppDispatcher from 'dispatcher/app_dispatcher.jsx'; import {browserHistory} from 'react-router/es6'; @@ -19,85 +14,84 @@ const dispatch = store.dispatch; const getState = store.getState; import {getUser} from 'mattermost-redux/actions/users'; +import { + createTeam as createTeamRedux, + updateTeam as updateTeamRedux, + removeUserFromTeam as removeUserFromTeamRedux, + getTeamStats, + checkIfTeamExists as checkIfTeamExistsRedux, + updateTeamMemberRoles as updateTeamMemberRolesRedux, + addUsersToTeam as addUsersToTeamRedux, + sendEmailInvitesToTeam, + getTeamsForUser as getTeamsForUserRedux, + getTeamMembersForUser as getTeamMembersForUserRedux +} from 'mattermost-redux/actions/teams'; export function checkIfTeamExists(teamName, onSuccess, onError) { - Client.findTeamByName(teamName, onSuccess, onError); + checkIfTeamExistsRedux(teamName)(dispatch, getState).then( + (exists) => { + if (exists != null && onSuccess) { + onSuccess(exists); + } else if (exists == null && onError) { + const serverError = getState().requests.teams.getTeam.error; + onError({id: serverError.server_error_id, ...serverError}); + } + } + ); } export function createTeam(team, onSuccess, onError) { - Client.createTeam(team, + createTeamRedux(team)(dispatch, getState).then( (rteam) => { - AppDispatcher.handleServerAction({ - type: ActionTypes.CREATED_TEAM, - team: rteam, - member: {team_id: rteam.id, user_id: UserStore.getCurrentId(), roles: 'team_admin team_user'} - }); - - browserHistory.push('/' + rteam.name + '/channels/town-square'); - - if (onSuccess) { + if (rteam && onSuccess) { + browserHistory.push('/' + rteam.name + '/channels/town-square'); onSuccess(rteam); + } else if (rteam == null && onError) { + const serverError = getState().requests.teams.createTeam.error; + onError({id: serverError.server_error_id, ...serverError}); } - }, - onError + } ); } export function updateTeam(team, onSuccess, onError) { - Client.updateTeam(team, + updateTeamRedux(team)(dispatch, getState).then( (rteam) => { - AppDispatcher.handleServerAction({ - type: ActionTypes.UPDATE_TEAM, - team: rteam - }); - - browserHistory.push('/' + rteam.name + '/channels/town-square'); - - if (onSuccess) { + if (rteam && onSuccess) { + browserHistory.push('/' + rteam.name + '/channels/town-square'); onSuccess(rteam); + } else if (rteam == null && onError) { + const serverError = getState().requests.teams.updateTeam.error; + onError({id: serverError.server_error_id, ...serverError}); } }, - onError ); } export function removeUserFromTeam(teamId, userId, success, error) { - Client.removeUserFromTeam( - teamId, - userId, - () => { - TeamStore.removeMemberInTeam(teamId, userId); - UserStore.removeProfileFromTeam(teamId, userId); - UserStore.emitInTeamChange(); + removeUserFromTeamRedux(teamId, userId)(dispatch, getState).then( + (data) => { getUser(userId)(dispatch, getState); - AsyncClient.getTeamStats(teamId); + getTeamStats(teamId)(dispatch, getState); - if (success) { + if (data && success) { success(); + } else if (data == null && error) { + const serverError = getState().requests.teams.removeUserFromTeam.error; + error({id: serverError.server_error_id, ...serverError}); } }, - (err) => { - AsyncClient.dispatchError(err, 'removeUserFromTeam'); - - if (error) { - error(err); - } - } ); } export function updateTeamMemberRoles(teamId, userId, newRoles, success, error) { - Client.updateTeamMemberRoles(teamId, userId, newRoles, - () => { - AsyncClient.getTeamMember(teamId, userId); - - if (success) { + updateTeamMemberRolesRedux(teamId, userId, newRoles)(dispatch, getState).then( + (data) => { + if (data && success) { success(); - } - }, - (err) => { - if (error) { - error(err); + } else if (data == null && error) { + const serverError = getState().requests.teams.updateTeamMember.error; + error({id: serverError.server_error_id, ...serverError}); } } ); @@ -122,25 +116,13 @@ export function addUserToTeamFromInvite(data, hash, inviteId, success, error) { } export function addUsersToTeam(teamId, userIds, success, error) { - Client.addUsersToTeam( - teamId, - userIds, + addUsersToTeamRedux(teamId, userIds)(dispatch, getState).then( (teamMembers) => { - teamMembers.forEach((member) => { - TeamStore.removeMemberNotInTeam(teamId, member.user_id); - UserStore.removeProfileNotInTeam(teamId, member.user_id); - }); - UserStore.emitNotInTeamChange(); - - if (success) { + if (teamMembers && success) { success(teamMembers); - } - }, - (err) => { - AsyncClient.dispatchError(err, 'addUsersToTeam'); - - if (error) { - error(err); + } else if (teamMembers == null && error) { + const serverError = getState().requests.teams.addUserToTeam.error; + error({id: serverError.server_error_id, ...serverError}); } } ); @@ -163,16 +145,20 @@ export function getInviteInfo(inviteId, success, error) { } export function inviteMembers(data, success, error) { - Client.inviteMembers( - data, - () => { - if (success) { + if (!data.invites) { + success(); + } + const emails = []; + data.invites.forEach((i) => { + emails.push(i.email); + }); + sendEmailInvitesToTeam(TeamStore.getCurrentId(), emails)(dispatch, getState).then( + (result) => { + if (result && success) { success(); - } - }, - (err) => { - if (err) { - error(err); + } else if (result == null && error) { + const serverError = getState().requests.teams.emailInvite.error; + error({id: serverError.server_error_id, ...serverError}); } } ); @@ -184,9 +170,27 @@ export function switchTeams(url) { } export function getTeamsForUser(userId, success, error) { - Client.getTeamsForUser(userId, success, error); + getTeamsForUserRedux(userId)(dispatch, getState).then( + (result) => { + if (result && success) { + success(result); + } else if (result == null && error) { + const serverError = getState().requests.teams.getTeams.error; + error({id: serverError.server_error_id, ...serverError}); + } + } + ); } export function getTeamMembersForUser(userId, success, error) { - Client.getTeamMembersForUser(userId, success, error); + getTeamMembersForUserRedux(userId)(dispatch, getState).then( + (result) => { + if (result && success) { + success(result); + } else if (result == null && error) { + const serverError = getState().requests.teams.getTeamMembers.error; + error({id: serverError.server_error_id, ...serverError}); + } + } + ); } diff --git a/webapp/actions/user_actions.jsx b/webapp/actions/user_actions.jsx index d810b4c2e..c4e0f4fc6 100644 --- a/webapp/actions/user_actions.jsx +++ b/webapp/actions/user_actions.jsx @@ -39,10 +39,12 @@ import { updateUserPassword, createUser, login, - loadMe as loadMeRedux + loadMe as loadMeRedux, + updateUserRoles as updateUserRolesRedux } from 'mattermost-redux/actions/users'; import {getClientConfig, getLicenseConfig} from 'mattermost-redux/actions/general'; +import {getTeamMembersByIds, getMyTeamMembers} from 'mattermost-redux/actions/teams'; export function loadMe(callback) { loadMeRedux()(dispatch, getState).then( @@ -169,30 +171,13 @@ export function loadProfilesWithoutTeam(page, perPage, success) { } function loadTeamMembersForProfiles(userIds, teamId, success, error) { - Client.getTeamMembersByIds( - teamId, - userIds, + getTeamMembersByIds(teamId, 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_TEAM, - team_id: teamId, - team_members: memberMap - }); - - if (success) { + if (data && success) { success(data); - } - }, - (err) => { - AsyncClient.dispatchError(err, 'getTeamMembersByIds'); - - if (error) { - error(err); + } else if (data == null && error) { + const serverError = getState().requests.teams.getTeamMembers.error; + error({id: serverError.server_error_id, ...serverError}); } } ); @@ -585,7 +570,7 @@ export function updateUserNotifyProps(props, success, error) { } export function updateUserRoles(userId, newRoles, success, error) { - updateUserRoles(userId, newRoles)(dispatch, getState).then( + updateUserRolesRedux(userId, newRoles)(dispatch, getState).then( (data) => { if (data && success) { success(data); @@ -852,13 +837,9 @@ export function getMissingProfiles(ids) { } export function loadMyTeamMembers() { - Client.getMyTeamMembers((data) => { - AppDispatcher.handleServerAction({ - type: ActionTypes.RECEIVED_MY_TEAM_MEMBERS, - team_members: data - }); - AsyncClient.getMyTeamsUnread(); - }, (err) => { - AsyncClient.dispatchError(err, 'getMyTeamMembers'); - }); + getMyTeamMembers()(dispatch, getState).then( + () => { + AsyncClient.getMyTeamsUnread(); + } + ); } diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx index bd220947a..9ed17c21d 100644 --- a/webapp/actions/websocket_actions.jsx +++ b/webapp/actions/websocket_actions.jsx @@ -280,7 +280,6 @@ function handleLeaveTeamEvent(msg) { // if they are on the team being removed redirect them to default team if (TeamStore.getCurrentId() === msg.data.team_id) { - TeamStore.setCurrentId(''); Client.setTeamId(''); BrowserStore.removeGlobalItem('team'); BrowserStore.removeGlobalItem(msg.data.team_id); diff --git a/webapp/components/admin_console/system_users/index.js b/webapp/components/admin_console/system_users/index.js new file mode 100644 index 000000000..24144d701 --- /dev/null +++ b/webapp/components/admin_console/system_users/index.js @@ -0,0 +1,27 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; +import {getTeams, getTeamStats} from 'mattermost-redux/actions/teams'; +import {getUser} from 'mattermost-redux/actions/users'; + +import SystemUsers from './system_users.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getTeams, + getTeamStats, + getUser + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(SystemUsers); diff --git a/webapp/components/admin_console/system_users/system_users.jsx b/webapp/components/admin_console/system_users/system_users.jsx index 7bc4b81ed..29fcd634b 100644 --- a/webapp/components/admin_console/system_users/system_users.jsx +++ b/webapp/components/admin_console/system_users/system_users.jsx @@ -16,7 +16,7 @@ import AnalyticsStore from 'stores/analytics_store.jsx'; import TeamStore from 'stores/team_store.jsx'; import UserStore from 'stores/user_store.jsx'; -import {getAllTeams, getStandardAnalytics, getTeamStats, getUser} from 'utils/async_client.jsx'; +import {getStandardAnalytics} from 'utils/async_client.jsx'; import {Constants, StatTypes, UserSearchOptions} from 'utils/constants.jsx'; import {convertTeamMapToList} from 'utils/team_utils.jsx'; import * as Utils from 'utils/utils.jsx'; @@ -33,6 +33,14 @@ const USER_ID_LENGTH = 26; const USERS_PER_PAGE = 50; export default class SystemUsers extends React.Component { + static propTypes = { + actions: React.PropTypes.shape({ + getTeams: React.PropTypes.func.isRequired, + getTeamStats: React.PropTypes.func.isRequired, + getUser: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -76,7 +84,7 @@ export default class SystemUsers extends React.Component { UserStore.addWithoutTeamChangeListener(this.updateUsersFromStore); this.loadDataForTeam(this.state.teamId); - getAllTeams(); + this.props.actions.getTeams(0, 1000); } componentWillUpdate(nextProps, nextState) { @@ -155,7 +163,7 @@ export default class SystemUsers extends React.Component { loadProfilesWithoutTeam(0, Constants.PROFILE_CHUNK_SIZE, this.loadComplete); } else { loadProfilesAndTeamMembers(0, Constants.PROFILE_CHUNK_SIZE, teamId, this.loadComplete); - getTeamStats(teamId); + this.props.actions.getTeamStats(teamId); } } @@ -240,7 +248,7 @@ export default class SystemUsers extends React.Component { return; } - getUser( + this.props.actions.getUser( id, () => { this.setState({ diff --git a/webapp/components/analytics/team_analytics/index.js b/webapp/components/analytics/team_analytics/index.js new file mode 100644 index 000000000..270967a1b --- /dev/null +++ b/webapp/components/analytics/team_analytics/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 {getTeams} from 'mattermost-redux/actions/teams'; + +import TeamAnalytics from './team_analytics.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getTeams + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(TeamAnalytics); diff --git a/webapp/components/analytics/team_analytics.jsx b/webapp/components/analytics/team_analytics/team_analytics.jsx index 700dc5a10..828f29f51 100644 --- a/webapp/components/analytics/team_analytics.jsx +++ b/webapp/components/analytics/team_analytics/team_analytics.jsx @@ -15,14 +15,20 @@ import * as AsyncClient from 'utils/async_client.jsx'; import {StatTypes} from 'utils/constants.jsx'; import {convertTeamMapToList} from 'utils/team_utils.jsx'; -import LineChart from './line_chart.jsx'; -import StatisticCount from './statistic_count.jsx'; -import TableChart from './table_chart.jsx'; -import {formatPostsPerDayData, formatUsersWithPostsPerDayData} from './system_analytics.jsx'; +import LineChart from 'components/analytics/line_chart.jsx'; +import StatisticCount from 'components/analytics/statistic_count.jsx'; +import TableChart from 'components/analytics/table_chart.jsx'; +import {formatPostsPerDayData, formatUsersWithPostsPerDayData} from 'components/analytics/system_analytics.jsx'; const LAST_ANALYTICS_TEAM = 'last_analytics_team'; export default class TeamAnalytics extends React.Component { + static propTypes = { + actions: React.PropTypes.shape({ + getTeams: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -50,7 +56,7 @@ export default class TeamAnalytics extends React.Component { } if (this.state.teams.length === 0) { - AsyncClient.getAllTeams(); + this.props.actions.getTeams(0, 1000); } } diff --git a/webapp/components/channel_invite_modal/channel_invite_modal.jsx b/webapp/components/channel_invite_modal/channel_invite_modal.jsx index 847af16f6..4be0d23e5 100644 --- a/webapp/components/channel_invite_modal/channel_invite_modal.jsx +++ b/webapp/components/channel_invite_modal/channel_invite_modal.jsx @@ -11,7 +11,6 @@ import TeamStore from 'stores/team_store.jsx'; import {searchUsers} from 'actions/user_actions.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import * as UserAgent from 'utils/user_agent.jsx'; import Constants from 'utils/constants.jsx'; @@ -29,7 +28,8 @@ export default class ChannelInviteModal extends React.Component { onHide: React.PropTypes.func.isRequired, channel: React.PropTypes.object.isRequired, actions: React.PropTypes.shape({ - getProfilesNotInChannel: React.PropTypes.func.isRequired + getProfilesNotInChannel: React.PropTypes.func.isRequired, + getTeamStats: React.PropTypes.func.isRequired }).isRequired } @@ -64,7 +64,7 @@ export default class ChannelInviteModal extends React.Component { UserStore.addStatusesChangeListener(this.onStatusChange); this.props.actions.getProfilesNotInChannel(TeamStore.getCurrentId(), this.props.channel.id, 0); - AsyncClient.getTeamStats(TeamStore.getCurrentId()); + this.props.actions.getTeamStats(TeamStore.getCurrentId()); } componentWillUnmount() { diff --git a/webapp/components/channel_invite_modal/index.js b/webapp/components/channel_invite_modal/index.js index c8bdb54f5..a89a94a4c 100644 --- a/webapp/components/channel_invite_modal/index.js +++ b/webapp/components/channel_invite_modal/index.js @@ -4,6 +4,7 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {getProfilesNotInChannel} from 'mattermost-redux/actions/users'; +import {getTeamStats} from 'mattermost-redux/actions/teams'; import ChannelInviteModal from './channel_invite_modal.jsx'; @@ -16,7 +17,8 @@ function mapStateToProps(state, ownProps) { function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ - getProfilesNotInChannel + getProfilesNotInChannel, + getTeamStats }, dispatch) }; } diff --git a/webapp/components/member_list_team/index.js b/webapp/components/member_list_team/index.js new file mode 100644 index 000000000..dc5b0b9f2 --- /dev/null +++ b/webapp/components/member_list_team/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 {getTeamStats} from 'mattermost-redux/actions/teams'; + +import MemberListTeam from './member_list_team.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getTeamStats + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(MemberListTeam); diff --git a/webapp/components/member_list_team.jsx b/webapp/components/member_list_team/member_list_team.jsx index 212536dc8..40d65c7f1 100644 --- a/webapp/components/member_list_team.jsx +++ b/webapp/components/member_list_team/member_list_team.jsx @@ -8,7 +8,6 @@ import UserStore from 'stores/user_store.jsx'; import TeamStore from 'stores/team_store.jsx'; import {searchUsers, loadProfilesAndTeamMembers, loadTeamMembersForProfilesList} from 'actions/user_actions.jsx'; -import {getTeamStats} from 'utils/async_client.jsx'; import Constants from 'utils/constants.jsx'; @@ -22,11 +21,17 @@ import {searchProfilesInCurrentTeam} from 'mattermost-redux/selectors/entities/u const USERS_PER_PAGE = 50; export default class MemberListTeam extends React.Component { + static propTypes = { + isAdmin: React.PropTypes.bool, + actions: React.PropTypes.shape({ + getTeamStats: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); this.onChange = this.onChange.bind(this); - this.onTeamChange = this.onTeamChange.bind(this); this.onStatsChange = this.onStatsChange.bind(this); this.search = this.search.bind(this); this.loadComplete = this.loadComplete.bind(this); @@ -45,19 +50,19 @@ export default class MemberListTeam extends React.Component { } componentDidMount() { - UserStore.addInTeamChangeListener(this.onTeamChange); + UserStore.addInTeamChangeListener(this.onChange); UserStore.addStatusesChangeListener(this.onChange); - TeamStore.addChangeListener(this.onTeamChange); + TeamStore.addChangeListener(this.onChange); TeamStore.addStatsChangeListener(this.onStatsChange); loadProfilesAndTeamMembers(0, Constants.PROFILE_CHUNK_SIZE, TeamStore.getCurrentId(), this.loadComplete); - getTeamStats(TeamStore.getCurrentId()); + this.props.actions.getTeamStats(TeamStore.getCurrentId()); } componentWillUnmount() { - UserStore.removeInTeamChangeListener(this.onTeamChange); + UserStore.removeInTeamChangeListener(this.onChange); UserStore.removeStatusesChangeListener(this.onChange); - TeamStore.removeChangeListener(this.onTeamChange); + TeamStore.removeChangeListener(this.onChange); TeamStore.removeStatsChangeListener(this.onStatsChange); } @@ -65,10 +70,6 @@ export default class MemberListTeam extends React.Component { this.setState({loading: false}); } - onTeamChange() { - this.onChange(true); - } - onChange() { let users; if (this.term) { @@ -163,7 +164,3 @@ export default class MemberListTeam extends React.Component { ); } } - -MemberListTeam.propTypes = { - isAdmin: React.PropTypes.bool -}; diff --git a/webapp/components/select_team/index.js b/webapp/components/select_team/index.js new file mode 100644 index 000000000..87691a853 --- /dev/null +++ b/webapp/components/select_team/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 {getTeams} from 'mattermost-redux/actions/teams'; + +import SelectTeam from './select_team.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getTeams + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(SelectTeam); diff --git a/webapp/components/select_team/select_team.jsx b/webapp/components/select_team/select_team.jsx index 43472bdad..e6179a2fd 100644 --- a/webapp/components/select_team/select_team.jsx +++ b/webapp/components/select_team/select_team.jsx @@ -7,7 +7,6 @@ import * as UserAgent from 'utils/user_agent.jsx'; import * as Utils from 'utils/utils.jsx'; import ErrorBar from 'components/error_bar.jsx'; import LoadingScreen from 'components/loading_screen.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; import SelectTeamItem from './components/select_team_item.jsx'; @@ -19,6 +18,11 @@ import React from 'react'; import logoImage from 'images/logo.png'; export default class SelectTeam extends React.Component { + static propTypes = { + actions: React.PropTypes.shape({ + getTeams: React.PropTypes.func.isRequired + }).isRequired + } constructor(props) { super(props); @@ -33,7 +37,7 @@ export default class SelectTeam extends React.Component { componentDidMount() { TeamStore.addChangeListener(this.onTeamChange); - AsyncClient.getAllTeamListings(); + this.props.actions.getTeams(0, 200); } componentWillUnmount() { diff --git a/webapp/components/team_general_tab.jsx b/webapp/components/team_general_tab.jsx index 21ad6a8a2..0a71546e8 100644 --- a/webapp/components/team_general_tab.jsx +++ b/webapp/components/team_general_tab.jsx @@ -86,7 +86,7 @@ class GeneralTab extends React.Component { var state = {serverError: '', clientError: ''}; - var data = this.props.team; + var data = {...this.props.team}; data.allow_open_invite = this.state.allow_open_invite; updateTeam(data, () => { @@ -119,7 +119,7 @@ class GeneralTab extends React.Component { return; } - var data = this.props.team; + var data = {...this.props.team}; data.display_name = this.state.name; updateTeam(data, () => { @@ -152,7 +152,7 @@ class GeneralTab extends React.Component { return; } - var data = this.props.team; + var data = {...this.props.team}; data.invite_id = this.state.invite_id; updateTeam(data, () => { @@ -189,7 +189,7 @@ class GeneralTab extends React.Component { return; } - var data = this.props.team; + var data = {...this.props.team}; data.description = this.state.description; updateTeam(data, () => { diff --git a/webapp/components/team_members_dropdown/index.js b/webapp/components/team_members_dropdown/index.js index 54e002a6e..9486c89fa 100644 --- a/webapp/components/team_members_dropdown/index.js +++ b/webapp/components/team_members_dropdown/index.js @@ -4,6 +4,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 TeamMembersDropdown from './team_members_dropdown.jsx'; @@ -16,7 +17,8 @@ function mapStateToProps(state, ownProps) { function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ - getUser + getUser, + getTeamStats }, dispatch) }; } diff --git a/webapp/components/team_members_dropdown/team_members_dropdown.jsx b/webapp/components/team_members_dropdown/team_members_dropdown.jsx index 704a60dae..00441ba37 100644 --- a/webapp/components/team_members_dropdown/team_members_dropdown.jsx +++ b/webapp/components/team_members_dropdown/team_members_dropdown.jsx @@ -22,7 +22,8 @@ export default class TeamMembersDropdown extends React.Component { user: React.PropTypes.object.isRequired, teamMember: React.PropTypes.object.isRequired, actions: React.PropTypes.shape({ - getUser: React.PropTypes.func.isRequired + getUser: React.PropTypes.func.isRequired, + getTeamStats: React.PropTypes.func.isRequired }).isRequired } @@ -76,7 +77,7 @@ export default class TeamMembersDropdown extends React.Component { () => { UserStore.removeProfileFromTeam(this.props.teamMember.team_id, this.props.user.id); UserStore.emitInTeamChange(); - AsyncClient.getTeamStats(this.props.teamMember.team_id); + this.props.actions.getTeamStats(this.props.teamMember.team_id); }, (err) => { this.setState({serverError: err.message}); @@ -88,7 +89,7 @@ export default class TeamMembersDropdown extends React.Component { updateActive(this.props.user.id, true, () => { AsyncClient.getChannelStats(ChannelStore.getCurrentId()); - AsyncClient.getTeamStats(this.props.teamMember.team_id); + this.props.actions.getTeamStats(this.props.teamMember.team_id); }, (err) => { this.setState({serverError: err.message}); @@ -100,7 +101,7 @@ export default class TeamMembersDropdown extends React.Component { updateActive(this.props.user.id, false, () => { AsyncClient.getChannelStats(ChannelStore.getCurrentId()); - AsyncClient.getTeamStats(this.props.teamMember.team_id); + this.props.actions.getTeamStats(this.props.teamMember.team_id); }, (err) => { this.setState({serverError: err.message}); diff --git a/webapp/components/team_members_modal.jsx b/webapp/components/team_members_modal.jsx index 87b0ff294..a2b963e09 100644 --- a/webapp/components/team_members_modal.jsx +++ b/webapp/components/team_members_modal.jsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import MemberListTeam from './member_list_team.jsx'; +import MemberListTeam from 'components/member_list_team'; import TeamStore from 'stores/team_store.jsx'; import {FormattedMessage} from 'react-intl'; diff --git a/webapp/components/team_sidebar/index.js b/webapp/components/team_sidebar/index.js new file mode 100644 index 000000000..d130555fd --- /dev/null +++ b/webapp/components/team_sidebar/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 {getTeams} from 'mattermost-redux/actions/teams'; + +import TeamSidebar from './team_sidebar_controller.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getTeams + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(TeamSidebar); diff --git a/webapp/components/team_sidebar/team_sidebar_controller.jsx b/webapp/components/team_sidebar/team_sidebar_controller.jsx index 758b51426..316466c06 100644 --- a/webapp/components/team_sidebar/team_sidebar_controller.jsx +++ b/webapp/components/team_sidebar/team_sidebar_controller.jsx @@ -6,7 +6,6 @@ import TeamButton from './components/team_button.jsx'; import TeamStore from 'stores/team_store.jsx'; import UserStore from 'stores/user_store.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import {sortTeamsByDisplayName} from 'utils/team_utils.jsx'; import * as Utils from 'utils/utils.jsx'; @@ -15,6 +14,12 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; export default class TeamSidebar extends React.Component { + static propTypes = { + actions: React.PropTypes.shape({ + getTeams: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -44,7 +49,7 @@ export default class TeamSidebar extends React.Component { window.addEventListener('resize', this.handleResize); TeamStore.addChangeListener(this.onChange); TeamStore.addUnreadChangeListener(this.onChange); - AsyncClient.getAllTeamListings(); + this.props.actions.getTeams(0, 200); this.setStyles(); } diff --git a/webapp/package.json b/webapp/package.json index 51f1a37ee..0067e2fb9 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-part2", + "mattermost-redux": "mattermost/mattermost-redux#webapp-part3", "object-assign": "4.1.1", "pdfjs-dist": "1.7.363", "perfect-scrollbar": "0.6.16", diff --git a/webapp/routes/route_admin_console.jsx b/webapp/routes/route_admin_console.jsx index 7dde044cb..f7244f02b 100644 --- a/webapp/routes/route_admin_console.jsx +++ b/webapp/routes/route_admin_console.jsx @@ -41,8 +41,8 @@ import NativeAppLinkSettings from 'components/admin_console/native_app_link_sett import ComplianceSettings from 'components/admin_console/compliance_settings.jsx'; import RateSettings from 'components/admin_console/rate_settings.jsx'; import DeveloperSettings from 'components/admin_console/developer_settings.jsx'; -import SystemUsers from 'components/admin_console/system_users/system_users.jsx'; -import TeamAnalytics from 'components/analytics/team_analytics.jsx'; +import SystemUsers from 'components/admin_console/system_users'; +import TeamAnalytics from 'components/analytics/team_analytics'; import LicenseSettings from 'components/admin_console/license_settings.jsx'; import Audits from 'components/admin_console/audits.jsx'; import Logs from 'components/admin_console/logs.jsx'; diff --git a/webapp/routes/route_root.jsx b/webapp/routes/route_root.jsx index 4f22edb80..52727c275 100644 --- a/webapp/routes/route_root.jsx +++ b/webapp/routes/route_root.jsx @@ -149,7 +149,7 @@ export default { { path: 'select_team', getComponents: (location, callback) => { - System.import('components/select_team/select_team.jsx').then(RouteUtils.importComponentSuccess(callback)); + System.import('components/select_team').then(RouteUtils.importComponentSuccess(callback)); } }, { diff --git a/webapp/routes/route_team.jsx b/webapp/routes/route_team.jsx index e8ef3f410..0a3c0a59f 100644 --- a/webapp/routes/route_team.jsx +++ b/webapp/routes/route_team.jsx @@ -174,7 +174,7 @@ export default { onEnter: onChannelEnter, getComponents: (location, callback) => { Promise.all([ - System.import('components/team_sidebar/team_sidebar_controller.jsx'), + System.import('components/team_sidebar'), System.import('components/sidebar.jsx'), System.import('components/channel_view.jsx') ]).then( @@ -187,7 +187,7 @@ export default { onEnter: onPermalinkEnter, getComponents: (location, callback) => { Promise.all([ - System.import('components/team_sidebar/team_sidebar_controller.jsx'), + System.import('components/team_sidebar'), System.import('components/sidebar.jsx'), System.import('components/permalink_view.jsx') ]).then( @@ -199,7 +199,7 @@ export default { path: 'tutorial', getComponents: (location, callback) => { Promise.all([ - System.import('components/team_sidebar/team_sidebar_controller.jsx'), + System.import('components/team_sidebar'), System.import('components/sidebar.jsx'), System.import('components/tutorial/tutorial_view.jsx') ]).then( diff --git a/webapp/stores/admin_store.jsx b/webapp/stores/admin_store.jsx index 8d83dc360..2826e6ddf 100644 --- a/webapp/stores/admin_store.jsx +++ b/webapp/stores/admin_store.jsx @@ -13,6 +13,8 @@ const CONFIG_CHANGE_EVENT = 'config_change'; const ALL_TEAMS_EVENT = 'all_team_change'; const SERVER_COMPLIANCE_REPORT_CHANGE_EVENT = 'server_compliance_reports_change'; +import store from 'stores/redux_store.jsx'; + class AdminStoreClass extends EventEmitter { constructor() { super(); @@ -21,8 +23,19 @@ class AdminStoreClass extends EventEmitter { this.audits = null; this.config = null; this.clusterId = null; - this.teams = {}; this.complianceReports = null; + + this.entities = store.getState().entities.teams; + + store.subscribe(() => { + const newEntities = store.getState().entities.teams; + + if (newEntities.teams !== this.entities.teams) { + this.emitAllTeamsChange(); + } + + this.entities = newEntities; + }); } emitLogChange() { @@ -126,15 +139,11 @@ class AdminStoreClass extends EventEmitter { } getAllTeams() { - return this.teams; - } - - saveAllTeams(teams) { - this.teams = teams; + return store.getState().entities.teams.teams; } getTeam(id) { - return this.teams[id]; + return this.getAllTeams()[id]; } } @@ -161,10 +170,6 @@ AdminStoreClass.dispatchToken = AppDispatcher.register((payload) => { AdminStore.saveClusterId(action.clusterId); AdminStore.emitConfigChange(); break; - case ActionTypes.RECEIVED_ALL_TEAMS: - AdminStore.saveAllTeams(action.teams); - AdminStore.emitAllTeamsChange(); - break; default: } }); diff --git a/webapp/stores/team_store.jsx b/webapp/stores/team_store.jsx index 0317379fc..ac48e4352 100644 --- a/webapp/stores/team_store.jsx +++ b/webapp/stores/team_store.jsx @@ -26,31 +26,33 @@ var Utils; class TeamStoreClass extends EventEmitter { constructor() { super(); - this.clear(); + + this.entities = store.getState().entities.teams; store.subscribe(() => { const newEntities = store.getState().entities.teams; + if (newEntities.currentTeamId !== this.entities.currentTeamId) { + this.emitChange(); + } if (newEntities.teams !== this.entities.teams) { this.emitChange(); } if (newEntities.myMembers !== this.entities.myMembers) { this.emitChange(); + this.emitUnreadChange(); + } + if (newEntities.membersInTeam !== this.entities.membersInTeam) { + this.emitChange(); + } + if (newEntities.stats !== this.entities.stats) { + this.emitStatsChange(); } this.entities = newEntities; }); } - clear() { - this.entities = {}; - this.members_in_team = {}; - this.members_not_in_team = {}; - this.stats = {}; - this.teamListings = {}; - this.currentTeamId = ''; - } - emitChange() { this.emit(CHANGE_EVENT); } @@ -107,15 +109,19 @@ class TeamStoreClass extends EventEmitter { } getAll() { - return store.getState().entities.teams.teams; + const list = Selectors.getMyTeams(store.getState()); + const teams = {}; + list.forEach((t) => { + teams[t.id] = t; + }); + return teams; } getCurrentId() { - return this.currentTeamId; + return Selectors.getCurrentTeamId(store.getState()); } setCurrentId(id) { - this.currentTeamId = id; store.dispatch({ type: TeamTypes.SELECT_TEAM, data: id @@ -123,7 +129,7 @@ class TeamStoreClass extends EventEmitter { } getCurrent() { - const team = this.getAll()[this.currentTeamId]; + const team = Selectors.getCurrentTeam(store.getState()); if (team) { return team; @@ -133,7 +139,7 @@ class TeamStoreClass extends EventEmitter { } getCurrentTeamUrl() { - return this.getTeamUrl(this.currentTeamId); + return this.getTeamUrl(this.getCurrentId()); } getCurrentTeamRelativeUrl() { @@ -171,7 +177,7 @@ class TeamStoreClass extends EventEmitter { let stats; if (teamId) { - stats = this.stats[teamId]; + stats = Selectors.getTeamStats(store.getState())[teamId]; } if (stats) { @@ -199,22 +205,10 @@ class TeamStoreClass extends EventEmitter { updateTeam(team) { const t = JSON.parse(team); - const teams = this.getAll(); + const teams = Object.assign({}, this.getAll(), this.getTeamListings()); if (teams && teams[t.id]) { this.saveTeam(t); } - - if (this.teamListings && this.teamListings[t.id]) { - if (t.allow_open_invite) { - this.teamListings[t.id] = t; - } else { - Reflect.deleteProperty(this.teamListings, t.id); - } - } else if (t.allow_open_invite) { - this.teamListings[t.id] = t; - } - - this.emitChange(); } saveMyTeam(team) { @@ -223,7 +217,10 @@ class TeamStoreClass extends EventEmitter { } saveStats(teamId, stats) { - this.stats[teamId] = stats; + store.dispatch({ + type: TeamTypes.RECEIVED_TEAM_STATS, + data: stats + }); } saveMyTeamMembers(members) { @@ -274,52 +271,37 @@ class TeamStoreClass extends EventEmitter { } saveMembersInTeam(teamId = this.getCurrentId(), members) { - const oldMembers = this.members_in_team[teamId] || {}; - this.members_in_team[teamId] = Object.assign({}, oldMembers, members); - } - - saveMembersNotInTeam(teamId = this.getCurrentId(), nonmembers) { - this.members_not_in_team[teamId] = nonmembers; + store.dispatch({ + type: TeamTypes.RECEIVED_MEMBERS_IN_TEAM, + data: Object.values(members) + }); } removeMemberInTeam(teamId = this.getCurrentId(), userId) { - if (this.members_in_team[teamId]) { - Reflect.deleteProperty(this.members_in_team[teamId], userId); - } - } - - removeMemberNotInTeam(teamId = this.getCurrentId(), userId) { - if (this.members_not_in_team[teamId]) { - Reflect.deleteProperty(this.members_not_in_team[teamId], userId); - } + store.dispatch({ + type: TeamTypes.REMOVE_MEMBER_FROM_TEAM, + data: {team_id: teamId, user_id: userId} + }); } getMembersInTeam(teamId = this.getCurrentId()) { - return Object.assign({}, this.members_in_team[teamId]) || {}; + return Selectors.getMembersInTeams(store.getState())[teamId] || {}; } - hasActiveMemberInTeam(teamId = this.getCurrentId(), userId) { - if (this.members_in_team[teamId] && this.members_in_team[teamId][userId]) { - return true; - } - - return false; + getMemberInTeam(teamId = this.getCurrentId(), userId) { + return Selectors.getTeamMember(store.getState(), teamId, userId); } - hasMemberNotInTeam(teamId = this.getCurrentId(), userId) { - if (this.members_not_in_team[teamId] && this.members_not_in_team[teamId][userId]) { + hasActiveMemberInTeam(teamId = this.getCurrentId(), userId) { + if (this.getMemberInTeam(teamId, userId)) { return true; } return false; } - saveTeamListings(teams) { - this.teamListings = teams; - } - getTeamListings() { - return this.teamListings; + return Selectors.getJoinableTeams(store.getState()); } isTeamAdminForAnyTeam() { @@ -384,6 +366,11 @@ class TeamStoreClass extends EventEmitter { const member = Object.assign({}, this.getMyTeamMembers().filter((m) => m.team_id === id)[0]); member.msg_count++; + + store.dispatch({ + type: TeamTypes.RECEIVED_MY_TEAM_MEMBER, + data: member + }); } incrementMentionsIfNeeded(id, msgProps) { @@ -395,6 +382,11 @@ class TeamStoreClass extends EventEmitter { if (mentions.indexOf(UserStore.getCurrentId()) !== -1) { const member = Object.assign({}, this.getMyTeamMembers().filter((m) => m.team_id === id)[0]); member.mention_count++; + + store.dispatch({ + type: TeamTypes.RECEIVED_MY_TEAM_MEMBER, + data: member + }); } } } @@ -440,9 +432,6 @@ TeamStore.dispatchToken = AppDispatcher.register((payload) => { break; case ActionTypes.RECEIVED_MEMBERS_IN_TEAM: TeamStore.saveMembersInTeam(action.team_id, action.team_members); - if (action.non_team_members) { - TeamStore.saveMembersNotInTeam(action.team_id, action.non_team_members); - } TeamStore.emitChange(); break; case ActionTypes.RECEIVED_TEAM_STATS: diff --git a/webapp/utils/async_client.jsx b/webapp/utils/async_client.jsx index cb911cb55..47327c5e5 100644 --- a/webapp/utils/async_client.jsx +++ b/webapp/utils/async_client.jsx @@ -418,50 +418,6 @@ export function getConfig(success, error) { ); } -export function getAllTeams() { - if (isCallInProgress('getAllTeams')) { - return; - } - - callTracker.getAllTeams = utils.getTimestamp(); - Client.getAllTeams( - (data) => { - callTracker.getAllTeams = 0; - - AppDispatcher.handleServerAction({ - type: ActionTypes.RECEIVED_ALL_TEAMS, - teams: data - }); - }, - (err) => { - callTracker.getAllTeams = 0; - dispatchError(err, 'getAllTeams'); - } - ); -} - -export function getAllTeamListings() { - if (isCallInProgress('getAllTeamListings')) { - return; - } - - callTracker.getAllTeamListings = utils.getTimestamp(); - Client.getAllTeamListings( - (data) => { - callTracker.getAllTeamListings = 0; - - AppDispatcher.handleServerAction({ - type: ActionTypes.RECEIVED_ALL_TEAM_LISTINGS, - teams: data - }); - }, - (err) => { - callTracker.getAllTeams = 0; - dispatchError(err, 'getAllTeamListings'); - } - ); -} - export function search(terms, isOrSearch) { if (isCallInProgress('search_' + String(terms))) { return; @@ -559,57 +515,6 @@ export function getStatuses() { ); } -export function getMyTeam() { - if (isCallInProgress('getMyTeam')) { - return null; - } - - callTracker.getMyTeam = utils.getTimestamp(); - return Client.getMyTeam( - (data) => { - callTracker.getMyTeam = 0; - - AppDispatcher.handleServerAction({ - type: ActionTypes.RECEIVED_MY_TEAM, - team: data - }); - }, - (err) => { - callTracker.getMyTeam = 0; - dispatchError(err, 'getMyTeam'); - } - ); -} - -export function getTeamMember(teamId, userId) { - const callName = `getTeamMember${teamId}${userId}`; - if (isCallInProgress(callName)) { - return; - } - - callTracker[callName] = utils.getTimestamp(); - Client.getTeamMember( - teamId, - userId, - (data) => { - callTracker[callName] = 0; - - const memberMap = {}; - memberMap[userId] = data; - - AppDispatcher.handleServerAction({ - type: ActionTypes.RECEIVED_MEMBERS_IN_TEAM, - team_id: teamId, - team_members: memberMap - }); - }, - (err) => { - callTracker[callName] = 0; - dispatchError(err, 'getTeamMember'); - } - ); -} - export function getMyTeamsUnread(teamId) { const members = TeamStore.getMyTeamMembers(); if (members.length > 1) { @@ -637,31 +542,6 @@ export function getMyTeamsUnread(teamId) { } } -export function getTeamStats(teamId) { - const callName = `getTeamStats${teamId}`; - if (isCallInProgress(callName)) { - return; - } - - callTracker[callName] = utils.getTimestamp(); - Client.getTeamStats( - teamId, - (data) => { - callTracker[callName] = 0; - - AppDispatcher.handleServerAction({ - type: ActionTypes.RECEIVED_TEAM_STATS, - team_id: teamId, - stats: data - }); - }, - (err) => { - callTracker[callName] = 0; - dispatchError(err, 'getTeamStats'); - } - ); -} - export function getAllPreferences() { if (isCallInProgress('getAllPreferences')) { return; |