diff options
Diffstat (limited to 'webapp/components')
35 files changed, 476 insertions, 337 deletions
diff --git a/webapp/components/access_history_modal.jsx b/webapp/components/access_history_modal/access_history_modal.jsx index 25c7ef380..da03fdb5b 100644 --- a/webapp/components/access_history_modal.jsx +++ b/webapp/components/access_history_modal/access_history_modal.jsx @@ -1,12 +1,11 @@ // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import LoadingScreen from './loading_screen.jsx'; -import AuditTable from './audit_table.jsx'; +import LoadingScreen from 'components/loading_screen.jsx'; +import AuditTable from 'components/audit_table.jsx'; import UserStore from 'stores/user_store.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import * as Utils from 'utils/utils.jsx'; import $ from 'jquery'; @@ -16,6 +15,13 @@ import {Modal} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; export default class AccessHistoryModal extends React.Component { + static propTypes = { + onHide: React.PropTypes.func.isRequired, + actions: React.PropTypes.shape({ + getUserAudits: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -37,7 +43,7 @@ export default class AccessHistoryModal extends React.Component { } onShow() { - AsyncClient.getAudits(); + this.props.actions.getUserAudits(UserStore.getCurrentId(), 0, 200); if (!Utils.isMobile()) { $('.modal-body').perfectScrollbar(); } @@ -100,7 +106,3 @@ export default class AccessHistoryModal extends React.Component { ); } } - -AccessHistoryModal.propTypes = { - onHide: React.PropTypes.func.isRequired -}; diff --git a/webapp/components/access_history_modal/index.js b/webapp/components/access_history_modal/index.js new file mode 100644 index 000000000..4842ca730 --- /dev/null +++ b/webapp/components/access_history_modal/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 {getUserAudits} from 'mattermost-redux/actions/users'; + +import AccessHistoryModal from './access_history_modal.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getUserAudits + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(AccessHistoryModal); diff --git a/webapp/components/activity_log_modal.jsx b/webapp/components/activity_log_modal/activity_log_modal.jsx index 8890a1d19..c94909754 100644 --- a/webapp/components/activity_log_modal.jsx +++ b/webapp/components/activity_log_modal/activity_log_modal.jsx @@ -1,11 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import LoadingScreen from './loading_screen.jsx'; +import LoadingScreen from 'components/loading_screen.jsx'; import UserStore from 'stores/user_store.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import * as Utils from 'utils/utils.jsx'; import $ from 'jquery'; @@ -13,9 +12,15 @@ import React from 'react'; import {Modal} from 'react-bootstrap'; import {FormattedMessage, FormattedTime, FormattedDate} from 'react-intl'; -import {revokeSession} from 'actions/admin_actions.jsx'; - export default class ActivityLogModal extends React.Component { + static propTypes = { + onHide: React.PropTypes.func.isRequired, + actions: React.PropTypes.shape({ + getSessions: React.PropTypes.func.isRequired, + revokeSession: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -35,7 +40,6 @@ export default class ActivityLogModal extends React.Component { getStateFromStores() { return { sessions: UserStore.getSessions(), - serverError: null, clientError: null }; } @@ -47,18 +51,11 @@ export default class ActivityLogModal extends React.Component { setTimeout(() => { modalContent.removeClass('animation--highlight'); }, 1500); - revokeSession(altId, - null, - (err) => { - const state = this.getStateFromStores(); - state.serverError = err; - this.setState(state); - } - ); + this.props.actions.revokeSession(UserStore.getCurrentId(), altId); } onShow() { - AsyncClient.getSessions(); + this.props.actions.getSessions(UserStore.getCurrentId()); if (!Utils.isMobile()) { $('.modal-body').perfectScrollbar(); } @@ -302,7 +299,3 @@ export default class ActivityLogModal extends React.Component { ); } } - -ActivityLogModal.propTypes = { - onHide: React.PropTypes.func.isRequired -}; diff --git a/webapp/components/activity_log_modal/index.js b/webapp/components/activity_log_modal/index.js new file mode 100644 index 000000000..1c4890c65 --- /dev/null +++ b/webapp/components/activity_log_modal/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 {revokeSession, getSessions} from 'mattermost-redux/actions/users'; + +import ActivityLogModal from './activity_log_modal.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getSessions, + revokeSession + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(ActivityLogModal); diff --git a/webapp/components/add_users_to_team.jsx b/webapp/components/add_users_to_team/add_users_to_team.jsx index f0936c0d7..ae6fd8c4e 100644 --- a/webapp/components/add_users_to_team.jsx +++ b/webapp/components/add_users_to_team/add_users_to_team.jsx @@ -10,7 +10,6 @@ import {searchUsersNotInTeam} from 'actions/user_actions.jsx'; import UserStore from 'stores/user_store.jsx'; import TeamStore from 'stores/team_store.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import Constants from 'utils/constants.jsx'; import {displayUsernameForUser} from 'utils/utils.jsx'; import Client from 'client/web_client.jsx'; @@ -20,10 +19,20 @@ import {Modal} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; import {browserHistory} from 'react-router/es6'; +import store from 'stores/redux_store.jsx'; +import {searchProfilesNotInCurrentTeam} from 'mattermost-redux/selectors/entities/users'; + const USERS_PER_PAGE = 50; const MAX_SELECTABLE_VALUES = 20; export default class AddUsersToTeam extends React.Component { + static propTypes = { + onModalDismissed: React.PropTypes.func, + actions: React.PropTypes.shape({ + getProfilesNotInTeam: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -34,11 +43,12 @@ export default class AddUsersToTeam extends React.Component { this.onChange = this.onChange.bind(this); this.search = this.search.bind(this); this.addValue = this.addValue.bind(this); + this.handlePageChange = this.handlePageChange.bind(this); this.searchTimeoutId = 0; this.state = { - users: null, + users: Object.assign([], UserStore.getProfileListNotInTeam(TeamStore.getCurrentId(), true)), values: [], show: true, search: false @@ -50,7 +60,7 @@ export default class AddUsersToTeam extends React.Component { UserStore.addNotInTeamChangeListener(this.onChange); UserStore.addStatusesChangeListener(this.onChange); - AsyncClient.getProfilesNotInTeam(TeamStore.getCurrentId(), 0, USERS_PER_PAGE * 2); + this.props.actions.getProfilesNotInTeam(TeamStore.getCurrentId(), 0, USERS_PER_PAGE * 2); } componentWillUnmount() { @@ -97,13 +107,14 @@ export default class AddUsersToTeam extends React.Component { this.setState({values}); } - onChange(force) { - if (this.state.search && !force) { - return; + onChange() { + let users; + if (this.term) { + users = Object.assign([], searchProfilesNotInCurrentTeam(store.getState(), this.term, true)); + } else { + users = Object.assign([], UserStore.getProfileListNotInTeam(TeamStore.getCurrentId(), true)); } - const users = Object.assign([], UserStore.getProfileListNotInTeam(TeamStore.getCurrentId(), true)); - for (let i = 0; i < users.length; i++) { const user = Object.assign({}, users[i]); user.value = user.id; @@ -118,53 +129,25 @@ export default class AddUsersToTeam extends React.Component { handlePageChange(page, prevPage) { if (page > prevPage) { - AsyncClient.getProfilesNotInTeam((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE); + this.props.actions.getProfilesNotInTeam(TeamStore.getCurrentId(), page + 1, USERS_PER_PAGE); } } search(term) { clearTimeout(this.searchTimeoutId); + this.term = term; if (term === '') { - this.onChange(true); - this.setState({search: false}); - this.searchTimeoutId = ''; + this.onChange(); return; } - const teamId = TeamStore.getCurrentId(); - - const searchTimeoutId = setTimeout( + this.searchTimeoutId = setTimeout( () => { - searchUsersNotInTeam( - term, - teamId, - {}, - (users) => { - if (searchTimeoutId !== this.searchTimeoutId) { - return; - } - - let indexToDelete = -1; - for (let i = 0; i < users.length; i++) { - if (users[i].id === UserStore.getCurrentId()) { - indexToDelete = i; - } - users[i].value = users[i].id; - users[i].label = '@' + users[i].username; - } - - if (indexToDelete !== -1) { - users.splice(indexToDelete, 1); - } - this.setState({search: true, users}); - } - ); + searchUsersNotInTeam(term, TeamStore.getCurrentId(), {}); }, Constants.SEARCH_TIMEOUT_MILLISECONDS ); - - this.searchTimeoutId = searchTimeoutId; } handleDelete(values) { @@ -272,7 +255,3 @@ export default class AddUsersToTeam extends React.Component { ); } } - -AddUsersToTeam.propTypes = { - onModalDismissed: React.PropTypes.func -}; diff --git a/webapp/components/add_users_to_team/index.js b/webapp/components/add_users_to_team/index.js new file mode 100644 index 000000000..d38aeb4e5 --- /dev/null +++ b/webapp/components/add_users_to_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 {getProfilesNotInTeam} from 'mattermost-redux/actions/users'; + +import AddUsersToTeam from './add_users_to_team.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getProfilesNotInTeam + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(AddUsersToTeam); diff --git a/webapp/components/admin_console/system_users/system_users.jsx b/webapp/components/admin_console/system_users/system_users.jsx index 0b967dead..7bc4b81ed 100644 --- a/webapp/components/admin_console/system_users/system_users.jsx +++ b/webapp/components/admin_console/system_users/system_users.jsx @@ -23,6 +23,9 @@ import * as Utils from 'utils/utils.jsx'; import SystemUsersList from './system_users_list.jsx'; +import store from 'stores/redux_store.jsx'; +import {searchProfiles, searchProfilesInTeam} from 'mattermost-redux/selectors/entities/users'; + const ALL_USERS = ''; const NO_TEAM = 'no_team'; @@ -120,25 +123,18 @@ export default class SystemUsers extends React.Component { updateUsersFromStore(teamId = this.state.teamId, term = this.state.term) { if (term) { - if (teamId === this.state.teamId) { - // Search results aren't in the store, so manually update the users in them - const users = [...this.state.users]; - - for (let i = 0; i < users.length; i++) { - const user = users[i]; - - if (UserStore.hasProfile(user.id)) { - users[i] = UserStore.getProfile(user.id); - } - } - - this.setState({ - users - }); + let users; + if (teamId) { + users = searchProfilesInTeam(store.getState(), teamId, term); } else { - this.doSearch(teamId, term, true); + users = searchProfiles(store.getState(), term); } + if (users.length === 0 && UserStore.hasProfile(term)) { + users = [UserStore.getProfile(term)]; + } + + this.setState({users}); return; } @@ -179,11 +175,11 @@ export default class SystemUsers extends React.Component { // Paging isn't supported while searching if (this.state.teamId === ALL_USERS) { - loadProfiles((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE, this.loadComplete); + loadProfiles(page, USERS_PER_PAGE, this.loadComplete); } else if (this.state.teamId === NO_TEAM) { loadProfilesWithoutTeam(page + 1, USERS_PER_PAGE, this.loadComplete); } else { - loadProfilesAndTeamMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE, this.state.teamId, this.loadComplete); + loadProfilesAndTeamMembers(page + 1, USERS_PER_PAGE, this.state.teamId, this.loadComplete); } } @@ -204,11 +200,9 @@ export default class SystemUsers extends React.Component { doSearch(teamId, term, now = false) { clearTimeout(this.searchTimeoutId); + this.term = term; - this.setState({ - loading: true, - users: [] - }); + this.setState({loading: true}); const options = { [UserSearchOptions.ALLOW_INACTIVE]: true @@ -217,74 +211,45 @@ export default class SystemUsers extends React.Component { options[UserSearchOptions.WITHOUT_TEAM] = true; } - const searchTimeoutId = setTimeout( + this.searchTimeoutId = setTimeout( () => { searchUsers( term, teamId, options, (users) => { - if (searchTimeoutId !== this.searchTimeoutId) { - return; - } - - if (users.length > 0) { - this.setState({ - loading: false, - users - }); - } else if (term.length === USER_ID_LENGTH) { + if (users.length === 0 && term.length === USER_ID_LENGTH) { // This term didn't match any users name, but it does look like it might be a user's ID - this.getUserById(term, searchTimeoutId); + this.getUserById(term); } else { - this.setState({ - loading: false - }); + this.setState({loading: false}); } }, () => { - this.setState({ - loading: false - }); + this.setState({loading: false}); } ); }, now ? 0 : Constants.SEARCH_TIMEOUT_MILLISECONDS ); - - this.searchTimeoutId = searchTimeoutId; } - getUserById(id, searchTimeoutId) { + getUserById(id) { if (UserStore.hasProfile(id)) { - this.setState({ - loading: false, - users: [UserStore.getProfile(id)] - }); - + this.setState({loading: false}); return; } getUser( id, - (user) => { - if (searchTimeoutId !== this.searchTimeoutId) { - return; - } - + () => { this.setState({ - loading: false, - users: [user] + loading: false }); }, () => { - if (searchTimeoutId !== this.searchTimeoutId) { - return; - } - this.setState({ - loading: false, - users: [] + loading: false }); } ); diff --git a/webapp/components/channel_header.jsx b/webapp/components/channel_header.jsx index 5ebe1b745..82864d48c 100644 --- a/webapp/components/channel_header.jsx +++ b/webapp/components/channel_header.jsx @@ -5,11 +5,11 @@ import $ from 'jquery'; import 'bootstrap'; import NavbarSearchBox from './search_bar.jsx'; import MessageWrapper from './message_wrapper.jsx'; -import PopoverListMembers from './popover_list_members.jsx'; +import PopoverListMembers from 'components/popover_list_members'; import EditChannelHeaderModal from './edit_channel_header_modal.jsx'; import EditChannelPurposeModal from './edit_channel_purpose_modal.jsx'; import ChannelInfoModal from './channel_info_modal.jsx'; -import ChannelInviteModal from './channel_invite_modal.jsx'; +import ChannelInviteModal from 'components/channel_invite_modal'; import ChannelMembersModal from './channel_members_modal.jsx'; import ChannelNotificationsModal from './channel_notifications_modal.jsx'; import DeleteChannelModal from './delete_channel_modal.jsx'; diff --git a/webapp/components/channel_invite_modal.jsx b/webapp/components/channel_invite_modal/channel_invite_modal.jsx index d41948a2b..847af16f6 100644 --- a/webapp/components/channel_invite_modal.jsx +++ b/webapp/components/channel_invite_modal/channel_invite_modal.jsx @@ -1,9 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import ChannelInviteButton from './channel_invite_button.jsx'; +import ChannelInviteButton from 'components/channel_invite_button.jsx'; import SearchableUserList from 'components/searchable_user_list/searchable_user_list_container.jsx'; -import LoadingScreen from './loading_screen.jsx'; +import LoadingScreen from 'components/loading_screen.jsx'; import ChannelStore from 'stores/channel_store.jsx'; import UserStore from 'stores/user_store.jsx'; @@ -19,9 +19,20 @@ import React from 'react'; import {Modal} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; +import store from 'stores/redux_store.jsx'; +import {searchProfilesNotInCurrentChannel} from 'mattermost-redux/selectors/entities/users'; + const USERS_PER_PAGE = 50; export default class ChannelInviteModal extends React.Component { + static propTypes = { + onHide: React.PropTypes.func.isRequired, + channel: React.PropTypes.object.isRequired, + actions: React.PropTypes.shape({ + getProfilesNotInChannel: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -39,10 +50,9 @@ export default class ChannelInviteModal extends React.Component { const teamStats = TeamStore.getCurrentStats(); this.state = { - users: null, + users: UserStore.getProfileListNotInChannel(props.channel.id, true), total: teamStats.active_member_count - channelStats.member_count, show: true, - search: false, statusChange: false }; } @@ -53,7 +63,7 @@ export default class ChannelInviteModal extends React.Component { UserStore.addNotInChannelChangeListener(this.onChange); UserStore.addStatusesChangeListener(this.onStatusChange); - AsyncClient.getProfilesNotInChannel(this.props.channel.id, 0); + this.props.actions.getProfilesNotInChannel(TeamStore.getCurrentId(), this.props.channel.id, 0); AsyncClient.getTeamStats(TeamStore.getCurrentId()); } @@ -64,17 +74,19 @@ export default class ChannelInviteModal extends React.Component { UserStore.removeStatusesChangeListener(this.onStatusChange); } - onChange(force) { - if (this.state.search && !force) { - this.search(this.term); - return; + onChange() { + let users; + if (this.term) { + users = searchProfilesNotInCurrentChannel(store.getState(), this.term, true); + } else { + users = UserStore.getProfileListNotInChannel(this.props.channel.id, true); } const channelStats = ChannelStore.getStats(this.props.channel.id); const teamStats = TeamStore.getCurrentStats(); this.setState({ - users: UserStore.getProfileListNotInChannel(this.props.channel.id, true), + users, total: teamStats.active_member_count - channelStats.member_count }); } @@ -103,40 +115,24 @@ export default class ChannelInviteModal extends React.Component { } nextPage(page) { - AsyncClient.getProfilesNotInChannel(this.props.channel.id, (page + 1) * USERS_PER_PAGE, USERS_PER_PAGE); + this.props.actions.getProfilesNotInChannel(TeamStore.getCurrentId(), this.props.channel.id, (page + 1) * USERS_PER_PAGE, USERS_PER_PAGE); } search(term) { clearTimeout(this.searchTimeoutId); - this.term = term; if (term === '') { - this.onChange(true); - this.setState({search: false}); - this.searchTimeoutId = ''; + this.onChange(); return; } - const searchTimeoutId = setTimeout( + this.searchTimeoutId = setTimeout( () => { - searchUsers( - term, - TeamStore.getCurrentId(), - {not_in_channel_id: this.props.channel.id}, - (users) => { - if (searchTimeoutId !== this.searchTimeoutId) { - return; - } - - this.setState({search: true, users}); - } - ); + searchUsers(term, TeamStore.getCurrentId(), {not_in_channel_id: this.props.channel.id}); }, Constants.SEARCH_TIMEOUT_MILLISECONDS ); - - this.searchTimeoutId = searchTimeoutId; } render() { @@ -190,8 +186,3 @@ export default class ChannelInviteModal extends React.Component { ); } } - -ChannelInviteModal.propTypes = { - onHide: React.PropTypes.func.isRequired, - channel: React.PropTypes.object.isRequired -}; diff --git a/webapp/components/channel_invite_modal/index.js b/webapp/components/channel_invite_modal/index.js new file mode 100644 index 000000000..c8bdb54f5 --- /dev/null +++ b/webapp/components/channel_invite_modal/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 {getProfilesNotInChannel} from 'mattermost-redux/actions/users'; + +import ChannelInviteModal from './channel_invite_modal.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getProfilesNotInChannel + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(ChannelInviteModal); diff --git a/webapp/components/login/login_controller.jsx b/webapp/components/login/login_controller.jsx index 482135a5e..34fdc536c 100644 --- a/webapp/components/login/login_controller.jsx +++ b/webapp/components/login/login_controller.jsx @@ -209,19 +209,15 @@ export default class LoginController extends React.Component { } finishSignin(team) { - GlobalActions.emitInitialLoad( - () => { - const query = this.props.location.query; - GlobalActions.loadDefaultLocale(); - if (query.redirect_to) { - browserHistory.push(query.redirect_to); - } else if (team) { - browserHistory.push(`/${team.name}`); - } else { - GlobalActions.redirectUserToDefaultTeam(); - } - } - ); + const query = this.props.location.query; + GlobalActions.loadDefaultLocale(); + if (query.redirect_to) { + browserHistory.push(query.redirect_to); + } else if (team) { + browserHistory.push(`/${team.name}`); + } else { + GlobalActions.redirectUserToDefaultTeam(); + } } handleLoginIdChange(e) { diff --git a/webapp/components/member_list_channel.jsx b/webapp/components/member_list_channel.jsx index e9eef9fb8..df000c132 100644 --- a/webapp/components/member_list_channel.jsx +++ b/webapp/components/member_list_channel.jsx @@ -17,6 +17,9 @@ import * as UserAgent from 'utils/user_agent.jsx'; import React from 'react'; +import store from 'stores/redux_store.jsx'; +import {searchProfilesInCurrentChannel} from 'mattermost-redux/selectors/entities/users'; + const USERS_PER_PAGE = 50; export default class MemberListChannel extends React.Component { @@ -29,6 +32,7 @@ export default class MemberListChannel extends React.Component { this.loadComplete = this.loadComplete.bind(this); this.searchTimeoutId = 0; + this.term = ''; const stats = ChannelStore.getCurrentStats(); @@ -37,8 +41,6 @@ export default class MemberListChannel extends React.Component { teamMembers: Object.assign({}, TeamStore.getMembersInTeam()), channelMembers: Object.assign({}, ChannelStore.getMembersInChannel()), total: stats.member_count, - search: false, - term: '', loading: true }; } @@ -66,16 +68,16 @@ export default class MemberListChannel extends React.Component { this.setState({loading: false}); } - onChange(force) { - if (this.state.search && !force) { - return; - } else if (this.state.search) { - this.search(this.state.term); - return; + onChange() { + let users; + if (this.term) { + users = searchProfilesInCurrentChannel(store.getState(), this.term); + } else { + users = UserStore.getProfileListInChannel(); } this.setState({ - users: UserStore.getProfileListInChannel(), + users, teamMembers: Object.assign({}, TeamStore.getMembersInTeam()), channelMembers: Object.assign({}, ChannelStore.getMembersInChannel()) }); @@ -87,43 +89,30 @@ export default class MemberListChannel extends React.Component { } nextPage(page) { - loadProfilesAndTeamMembersAndChannelMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE); + loadProfilesAndTeamMembersAndChannelMembers(page + 1, USERS_PER_PAGE); } search(term) { clearTimeout(this.searchTimeoutId); + this.term = term; if (term === '') { - this.setState({ - search: false, - term, - users: UserStore.getProfileListInChannel(), - teamMembers: Object.assign([], TeamStore.getMembersInTeam()), - channelMembers: Object.assign([], ChannelStore.getMembersInChannel()) - }); + this.setState({loading: false}); this.searchTimeoutId = ''; + this.onChange(); return; } const searchTimeoutId = setTimeout( () => { - searchUsers( - term, - TeamStore.getCurrentId(), - {}, + searchUsers(term, TeamStore.getCurrentId(), {}, (users) => { if (searchTimeoutId !== this.searchTimeoutId) { return; } - this.setState({ - loading: true, - search: true, - users, - term, - teamMembers: Object.assign([], TeamStore.getMembersInTeam()), - channelMembers: Object.assign([], ChannelStore.getMembersInChannel()) - }); + this.setState({loading: true}); + loadTeamMembersAndChannelMembersForProfilesList(users, TeamStore.getCurrentId(), ChannelStore.getCurrentId(), this.loadComplete); } ); diff --git a/webapp/components/member_list_team.jsx b/webapp/components/member_list_team.jsx index 0aa1e6e57..212536dc8 100644 --- a/webapp/components/member_list_team.jsx +++ b/webapp/components/member_list_team.jsx @@ -2,7 +2,7 @@ // See License.txt for license information. import SearchableUserList from 'components/searchable_user_list/searchable_user_list_container.jsx'; -import TeamMembersDropdown from 'components/team_members_dropdown.jsx'; +import TeamMembersDropdown from 'components/team_members_dropdown'; import UserStore from 'stores/user_store.jsx'; import TeamStore from 'stores/team_store.jsx'; @@ -16,6 +16,9 @@ import * as UserAgent from 'utils/user_agent.jsx'; import React from 'react'; +import store from 'stores/redux_store.jsx'; +import {searchProfilesInCurrentTeam} from 'mattermost-redux/selectors/entities/users'; + const USERS_PER_PAGE = 50; export default class MemberListTeam extends React.Component { @@ -29,6 +32,7 @@ export default class MemberListTeam extends React.Component { this.loadComplete = this.loadComplete.bind(this); this.searchTimeoutId = 0; + this.term = ''; const stats = TeamStore.getCurrentStats(); @@ -36,8 +40,6 @@ export default class MemberListTeam extends React.Component { users: UserStore.getProfileListInTeam(), teamMembers: Object.assign([], TeamStore.getMembersInTeam()), total: stats.total_member_count, - search: false, - term: '', loading: true }; } @@ -67,15 +69,15 @@ export default class MemberListTeam extends React.Component { this.onChange(true); } - onChange(force) { - if (this.state.search && !force) { - return; - } else if (this.state.search) { - this.search(this.state.term); - return; + onChange() { + let users; + if (this.term) { + users = searchProfilesInCurrentTeam(store.getState(), this.term); + } else { + users = UserStore.getProfileListInTeam(); } - this.setState({users: UserStore.getProfileListInTeam(), teamMembers: Object.assign([], TeamStore.getMembersInTeam())}); + this.setState({users, teamMembers: Object.assign([], TeamStore.getMembersInTeam())}); } onStatsChange() { @@ -84,15 +86,17 @@ export default class MemberListTeam extends React.Component { } nextPage(page) { - loadProfilesAndTeamMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE); + loadProfilesAndTeamMembers(page, USERS_PER_PAGE); } search(term) { clearTimeout(this.searchTimeoutId); + this.term = term; if (term === '') { - this.setState({search: false, term, users: UserStore.getProfileListInTeam(), teamMembers: Object.assign([], TeamStore.getMembersInTeam())}); + this.setState({loading: false}); this.searchTimeoutId = ''; + this.onChange(); return; } @@ -106,7 +110,7 @@ export default class MemberListTeam extends React.Component { if (searchTimeoutId !== this.searchTimeoutId) { return; } - this.setState({loading: true, search: true, users, term, teamMembers: Object.assign([], TeamStore.getMembersInTeam())}); + this.setState({loading: true}); loadTeamMembersForProfilesList(users, TeamStore.getCurrentId(), this.loadComplete); } ); diff --git a/webapp/components/more_direct_channels/index.js b/webapp/components/more_direct_channels/index.js new file mode 100644 index 000000000..a56f45886 --- /dev/null +++ b/webapp/components/more_direct_channels/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 {getProfiles, getProfilesInTeam} from 'mattermost-redux/actions/users'; + +import MoreDirectChannels from './more_direct_channels.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getProfiles, + getProfilesInTeam + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(MoreDirectChannels); diff --git a/webapp/components/more_direct_channels.jsx b/webapp/components/more_direct_channels/more_direct_channels.jsx index c8a0d22ee..50e2c4e48 100644 --- a/webapp/components/more_direct_channels.jsx +++ b/webapp/components/more_direct_channels/more_direct_channels.jsx @@ -10,7 +10,6 @@ import {openDirectChannelToUser, openGroupChannelToUsers} from 'actions/channel_ import UserStore from 'stores/user_store.jsx'; import TeamStore from 'stores/team_store.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import Constants from 'utils/constants.jsx'; import {displayUsernameForUser} from 'utils/utils.jsx'; import Client from 'client/web_client.jsx'; @@ -20,10 +19,22 @@ import {Modal} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; import {browserHistory} from 'react-router/es6'; +import store from 'stores/redux_store.jsx'; +import {searchProfiles, searchProfilesInCurrentTeam} from 'mattermost-redux/selectors/entities/users'; + const USERS_PER_PAGE = 50; const MAX_SELECTABLE_VALUES = Constants.MAX_USERS_IN_GM - 1; export default class MoreDirectChannels extends React.Component { + static propTypes = { + startingUsers: React.PropTypes.arrayOf(React.PropTypes.object), + onModalDismissed: React.PropTypes.func, + actions: React.PropTypes.shape({ + getProfiles: React.PropTypes.func.isRequired, + getProfilesInTeam: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -36,6 +47,7 @@ export default class MoreDirectChannels extends React.Component { this.addValue = this.addValue.bind(this); this.searchTimeoutId = 0; + this.term = ''; this.listType = global.window.mm_config.RestrictDirectMessage; const values = []; @@ -63,9 +75,9 @@ export default class MoreDirectChannels extends React.Component { UserStore.addStatusesChangeListener(this.onChange); if (this.listType === 'any') { - AsyncClient.getProfiles(0, USERS_PER_PAGE * 2); + this.props.actions.getProfiles(0, USERS_PER_PAGE * 2); } else { - AsyncClient.getProfilesInTeam(TeamStore.getCurrentId(), 0, USERS_PER_PAGE * 2); + this.props.actions.getProfilesInTeam(TeamStore.getCurrentId(), 0, USERS_PER_PAGE * 2); } } @@ -134,13 +146,15 @@ export default class MoreDirectChannels extends React.Component { this.setState({values}); } - onChange(force) { - if (this.state.search && !force) { - return; - } - + onChange() { let users; - if (this.listType === 'any') { + if (this.term) { + if (this.listType === 'any') { + users = Object.assign([], searchProfiles(store.getState(), this.term, true)); + } else { + users = Object.assign([], searchProfilesInCurrentTeam(store.getState(), this.term, true)); + } + } else if (this.listType === 'any') { users = Object.assign([], UserStore.getProfileList(true)); } else { users = Object.assign([], UserStore.getProfileListInTeam(TeamStore.getCurrentId(), true)); @@ -160,17 +174,20 @@ export default class MoreDirectChannels extends React.Component { handlePageChange(page, prevPage) { if (page > prevPage) { - AsyncClient.getProfiles((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE); + if (this.listType === 'any') { + this.props.actions.getProfiles(page + 1, USERS_PER_PAGE); + } else { + this.props.actions.getProfilesInTeam(page + 1, USERS_PER_PAGE); + } } } search(term) { clearTimeout(this.searchTimeoutId); + this.term = term; if (term === '') { - this.onChange(true); - this.setState({search: false}); - this.searchTimeoutId = ''; + this.onChange(); return; } @@ -181,37 +198,12 @@ export default class MoreDirectChannels extends React.Component { teamId = TeamStore.getCurrentId(); } - const searchTimeoutId = setTimeout( + this.searchTimeoutId = setTimeout( () => { - searchUsers( - term, - teamId, - {}, - (users) => { - if (searchTimeoutId !== this.searchTimeoutId) { - return; - } - - let indexToDelete = -1; - for (let i = 0; i < users.length; i++) { - if (users[i].id === UserStore.getCurrentId()) { - indexToDelete = i; - } - users[i].value = users[i].id; - users[i].label = '@' + users[i].username; - } - - if (indexToDelete !== -1) { - users.splice(indexToDelete, 1); - } - this.setState({search: true, users}); - } - ); + searchUsers(term, teamId); }, Constants.SEARCH_TIMEOUT_MILLISECONDS ); - - this.searchTimeoutId = searchTimeoutId; } handleDelete(values) { @@ -334,8 +326,3 @@ export default class MoreDirectChannels extends React.Component { ); } } - -MoreDirectChannels.propTypes = { - startingUsers: React.PropTypes.arrayOf(React.PropTypes.object), - onModalDismissed: React.PropTypes.func -}; diff --git a/webapp/components/navbar.jsx b/webapp/components/navbar.jsx index 22d2b8ae4..33df0b423 100644 --- a/webapp/components/navbar.jsx +++ b/webapp/components/navbar.jsx @@ -7,7 +7,7 @@ import EditChannelPurposeModal from './edit_channel_purpose_modal.jsx'; import MessageWrapper from './message_wrapper.jsx'; import NotifyCounts from './notify_counts.jsx'; import ChannelInfoModal from './channel_info_modal.jsx'; -import ChannelInviteModal from './channel_invite_modal.jsx'; +import ChannelInviteModal from 'components/channel_invite_modal'; import ChannelMembersModal from './channel_members_modal.jsx'; import ChannelNotificationsModal from './channel_notifications_modal.jsx'; import DeleteChannelModal from './delete_channel_modal.jsx'; diff --git a/webapp/components/popover_list_members/index.js b/webapp/components/popover_list_members/index.js new file mode 100644 index 000000000..3e9087e0d --- /dev/null +++ b/webapp/components/popover_list_members/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 {getProfilesInChannel} from 'mattermost-redux/actions/users'; + +import PopoverListMembers from './popover_list_members.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getProfilesInChannel + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(PopoverListMembers); diff --git a/webapp/components/popover_list_members.jsx b/webapp/components/popover_list_members/popover_list_members.jsx index 3af53cb70..e435126ff 100644 --- a/webapp/components/popover_list_members.jsx +++ b/webapp/components/popover_list_members/popover_list_members.jsx @@ -7,13 +7,12 @@ import TeamStore from 'stores/team_store.jsx'; import UserStore from 'stores/user_store.jsx'; import ChannelStore from 'stores/channel_store.jsx'; -import TeamMembersModal from './team_members_modal.jsx'; -import ChannelMembersModal from './channel_members_modal.jsx'; -import ChannelInviteModal from './channel_invite_modal.jsx'; +import TeamMembersModal from 'components/team_members_modal.jsx'; +import ChannelMembersModal from 'components/channel_members_modal.jsx'; +import ChannelInviteModal from 'components/channel_invite_modal'; import {openDirectChannelToUser} from 'actions/channel_actions.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import Client from 'client/web_client.jsx'; import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; @@ -26,6 +25,15 @@ import {FormattedMessage} from 'react-intl'; import {browserHistory} from 'react-router/es6'; export default class PopoverListMembers extends React.Component { + static propTypes = { + channel: React.PropTypes.object.isRequired, + members: React.PropTypes.array.isRequired, + memberCount: React.PropTypes.number, + actions: React.PropTypes.shape({ + getProfilesInChannel: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -239,7 +247,7 @@ export default class PopoverListMembers extends React.Component { ref='member_popover_target' onClick={(e) => { this.setState({popoverTarget: e.target, showPopover: !this.state.showPopover}); - AsyncClient.getProfilesInChannel(this.props.channel.id, 0); + this.props.actions.getProfilesInChannel(this.props.channel.id, 0); }} > {countText} @@ -272,8 +280,3 @@ export default class PopoverListMembers extends React.Component { } } -PopoverListMembers.propTypes = { - channel: React.PropTypes.object.isRequired, - members: React.PropTypes.array.isRequired, - memberCount: React.PropTypes.number -}; diff --git a/webapp/components/root.jsx b/webapp/components/root.jsx index b49b4d509..6907e84e4 100644 --- a/webapp/components/root.jsx +++ b/webapp/components/root.jsx @@ -136,6 +136,7 @@ export default class Root extends React.Component { ); } } + Root.defaultProps = { }; diff --git a/webapp/components/sidebar.jsx b/webapp/components/sidebar.jsx index 72dcac992..8667802cc 100644 --- a/webapp/components/sidebar.jsx +++ b/webapp/components/sidebar.jsx @@ -4,7 +4,7 @@ import $ from 'jquery'; import ReactDOM from 'react-dom'; import NewChannelFlow from './new_channel_flow.jsx'; -import MoreDirectChannels from './more_direct_channels.jsx'; +import MoreDirectChannels from 'components/more_direct_channels'; import MoreChannels from 'components/more_channels.jsx'; import SidebarHeader from './sidebar_header.jsx'; import UnreadChannelIndicator from './unread_channel_indicator.jsx'; diff --git a/webapp/components/sidebar_header_dropdown.jsx b/webapp/components/sidebar_header_dropdown.jsx index 728017b27..256019b64 100644 --- a/webapp/components/sidebar_header_dropdown.jsx +++ b/webapp/components/sidebar_header_dropdown.jsx @@ -14,7 +14,7 @@ import AboutBuildModal from './about_build_modal.jsx'; import SidebarHeaderDropdownButton from './sidebar_header_dropdown_button.jsx'; import TeamMembersModal from './team_members_modal.jsx'; import UserSettingsModal from './user_settings/user_settings_modal.jsx'; -import AddUsersToTeam from './add_users_to_team.jsx'; +import AddUsersToTeam from 'components/add_users_to_team'; import {Constants, WebrtcActionTypes} from 'utils/constants.jsx'; diff --git a/webapp/components/sidebar_right_menu.jsx b/webapp/components/sidebar_right_menu.jsx index 784f06eac..aac7d58cc 100644 --- a/webapp/components/sidebar_right_menu.jsx +++ b/webapp/components/sidebar_right_menu.jsx @@ -6,7 +6,7 @@ import TeamMembersModal from './team_members_modal.jsx'; import ToggleModalButton from './toggle_modal_button.jsx'; import UserSettingsModal from './user_settings/user_settings_modal.jsx'; import AboutBuildModal from './about_build_modal.jsx'; -import AddUsersToTeam from './add_users_to_team.jsx'; +import AddUsersToTeam from 'components/add_users_to_team'; import UserStore from 'stores/user_store.jsx'; import TeamStore from 'stores/team_store.jsx'; diff --git a/webapp/components/signup/components/signup_email.jsx b/webapp/components/signup/components/signup_email.jsx index c33fb45e0..976b0648b 100644 --- a/webapp/components/signup/components/signup_email.jsx +++ b/webapp/components/signup/components/signup_email.jsx @@ -8,7 +8,7 @@ import {trackEvent} from 'actions/diagnostics_actions.jsx'; import BrowserStore from 'stores/browser_store.jsx'; import {getInviteInfo} from 'actions/team_actions.jsx'; -import {loginById, createUserWithInvite} from 'actions/user_actions.jsx'; +import {loadMe, loginById, createUserWithInvite} from 'actions/user_actions.jsx'; import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; @@ -108,7 +108,7 @@ export default class SignupEmail extends React.Component { } finishSignup() { - GlobalActions.emitInitialLoad( + loadMe( () => { const query = this.props.location.query; GlobalActions.loadDefaultLocale(); @@ -132,7 +132,7 @@ export default class SignupEmail extends React.Component { BrowserStore.setGlobalItem(this.state.hash, JSON.stringify({usedBefore: true})); } - GlobalActions.emitInitialLoad( + loadMe( () => { const query = this.props.location.query; if (query.redirect_to) { diff --git a/webapp/components/signup/components/signup_ldap.jsx b/webapp/components/signup/components/signup_ldap.jsx index 80fac3ecc..a101c248f 100644 --- a/webapp/components/signup/components/signup_ldap.jsx +++ b/webapp/components/signup/components/signup_ldap.jsx @@ -5,7 +5,7 @@ import FormError from 'components/form_error.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; import {addUserToTeamFromInvite} from 'actions/team_actions.jsx'; -import {webLoginByLdap} from 'actions/user_actions.jsx'; +import {loadMe, webLoginByLdap} from 'actions/user_actions.jsx'; import {trackEvent} from 'actions/diagnostics_actions.jsx'; import * as Utils from 'utils/utils.jsx'; @@ -97,7 +97,7 @@ export default class SignupLdap extends React.Component { } finishSignup() { - GlobalActions.emitInitialLoad( + loadMe( () => { const query = this.props.location.query; GlobalActions.loadDefaultLocale(); diff --git a/webapp/components/signup/signup_controller.jsx b/webapp/components/signup/signup_controller.jsx index 701fe1d30..0c969e5ed 100644 --- a/webapp/components/signup/signup_controller.jsx +++ b/webapp/components/signup/signup_controller.jsx @@ -13,6 +13,7 @@ import * as AsyncClient from 'utils/async_client.jsx'; import Client from 'client/web_client.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; import {addUserToTeamFromInvite, getInviteInfo} from 'actions/team_actions.jsx'; +import {loadMe} from 'actions/user_actions.jsx'; import logoImage from 'images/logo.png'; import ErrorBar from 'components/error_bar.jsx'; @@ -74,7 +75,7 @@ export default class SignupController extends React.Component { hash, inviteId, (team) => { - GlobalActions.emitInitialLoad( + loadMe( () => { browserHistory.push('/' + team.name + '/channels/town-square'); } diff --git a/webapp/components/suggestion/at_mention_provider.jsx b/webapp/components/suggestion/at_mention_provider.jsx index ddf9d46e7..4d55e9db6 100644 --- a/webapp/components/suggestion/at_mention_provider.jsx +++ b/webapp/components/suggestion/at_mention_provider.jsx @@ -127,14 +127,14 @@ export default class AtMentionProvider extends Provider { return; } - const members = data.in_channel; + const members = Object.assign([], data.users); for (const id of Object.keys(members)) { - members[id].type = Constants.MENTION_MEMBERS; + members[id] = {...members[id], type: Constants.MENTION_MEMBERS}; } - const nonmembers = data.out_of_channel; + const nonmembers = data.out_of_channel || []; for (const id of Object.keys(nonmembers)) { - nonmembers[id].type = Constants.MENTION_NONMEMBERS; + nonmembers[id] = {...nonmembers[id], type: Constants.MENTION_NONMEMBERS}; } let specialMentions = []; diff --git a/webapp/components/suggestion/search_user_provider.jsx b/webapp/components/suggestion/search_user_provider.jsx index 6fcc7f7e9..d55f35c87 100644 --- a/webapp/components/suggestion/search_user_provider.jsx +++ b/webapp/components/suggestion/search_user_provider.jsx @@ -72,7 +72,7 @@ export default class SearchUserProvider extends Provider { return; } - const users = data.in_team; + const users = Object.assign([], data.users); const mentions = users.map((user) => user.username); AppDispatcher.handleServerAction({ diff --git a/webapp/components/suggestion/switch_channel_provider.jsx b/webapp/components/suggestion/switch_channel_provider.jsx index 3d295951c..67cda61ea 100644 --- a/webapp/components/suggestion/switch_channel_provider.jsx +++ b/webapp/components/suggestion/switch_channel_provider.jsx @@ -67,7 +67,9 @@ export default class SwitchChannelProvider extends Provider { autocompleteUsers( channelPrefix, - (users) => { + (data) => { + const users = Object.assign([], data.users); + if (this.shouldCancelDispatch(channelPrefix)) { return; } diff --git a/webapp/components/team_members_dropdown/index.js b/webapp/components/team_members_dropdown/index.js new file mode 100644 index 000000000..54e002a6e --- /dev/null +++ b/webapp/components/team_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 {getUser} from 'mattermost-redux/actions/users'; + +import TeamMembersDropdown from './team_members_dropdown.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getUser + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(TeamMembersDropdown); diff --git a/webapp/components/team_members_dropdown.jsx b/webapp/components/team_members_dropdown/team_members_dropdown.jsx index 7c2b763c3..704a60dae 100644 --- a/webapp/components/team_members_dropdown.jsx +++ b/webapp/components/team_members_dropdown/team_members_dropdown.jsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import ConfirmModal from './confirm_modal.jsx'; +import ConfirmModal from 'components/confirm_modal.jsx'; import TeamStore from 'stores/team_store.jsx'; import UserStore from 'stores/user_store.jsx'; @@ -18,6 +18,14 @@ import {FormattedMessage} from 'react-intl'; import {browserHistory} from 'react-router/es6'; export default class TeamMembersDropdown extends React.Component { + static propTypes = { + user: React.PropTypes.object.isRequired, + teamMember: React.PropTypes.object.isRequired, + actions: React.PropTypes.shape({ + getUser: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -48,7 +56,7 @@ export default class TeamMembersDropdown extends React.Component { this.props.user.id, 'team_user', () => { - AsyncClient.getUser(this.props.user.id); + this.props.actions.getUser(this.props.user.id); if (this.props.user.id === me.id) { loadMyTeamMembers(); @@ -110,7 +118,7 @@ export default class TeamMembersDropdown extends React.Component { this.props.user.id, 'team_user team_admin', () => { - AsyncClient.getUser(this.props.user.id); + this.props.actions.getUser(this.props.user.id); }, (err) => { this.setState({serverError: err.message}); @@ -145,7 +153,7 @@ export default class TeamMembersDropdown extends React.Component { this.props.user.id, this.state.newRole, () => { - AsyncClient.getUser(this.props.user.id); + this.props.actions.getUser(this.props.user.id); const teamUrl = TeamStore.getCurrentTeamUrl(); if (teamUrl) { @@ -385,8 +393,3 @@ export default class TeamMembersDropdown extends React.Component { ); } } - -TeamMembersDropdown.propTypes = { - user: React.PropTypes.object.isRequired, - teamMember: React.PropTypes.object.isRequired -}; diff --git a/webapp/components/user_settings/user_settings.jsx b/webapp/components/user_settings/user_settings.jsx index d9d5423fe..b01274b32 100644 --- a/webapp/components/user_settings/user_settings.jsx +++ b/webapp/components/user_settings/user_settings.jsx @@ -4,8 +4,8 @@ import UserStore from 'stores/user_store.jsx'; import * as utils from 'utils/utils.jsx'; import NotificationsTab from './user_settings_notifications.jsx'; -import SecurityTab from './user_settings_security.jsx'; -import GeneralTab from './user_settings_general.jsx'; +import SecurityTab from './user_settings_security'; +import GeneralTab from './user_settings_general'; import DisplayTab from './user_settings_display.jsx'; import AdvancedTab from './user_settings_advanced.jsx'; diff --git a/webapp/components/user_settings/user_settings_general/index.js b/webapp/components/user_settings/user_settings_general/index.js new file mode 100644 index 000000000..90fd58bf2 --- /dev/null +++ b/webapp/components/user_settings/user_settings_general/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 {getMe} from 'mattermost-redux/actions/users'; + +import UserSettingsGeneralTab from './user_settings_general.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getMe + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(UserSettingsGeneralTab); diff --git a/webapp/components/user_settings/user_settings_general.jsx b/webapp/components/user_settings/user_settings_general/user_settings_general.jsx index ce4349519..79132d929 100644 --- a/webapp/components/user_settings/user_settings_general.jsx +++ b/webapp/components/user_settings/user_settings_general/user_settings_general.jsx @@ -2,16 +2,15 @@ // See License.txt for license information. import $ from 'jquery'; -import SettingItemMin from '../setting_item_min.jsx'; -import SettingItemMax from '../setting_item_max.jsx'; -import SettingPicture from '../setting_picture.jsx'; +import SettingItemMin from 'components/setting_item_min.jsx'; +import SettingItemMax from 'components/setting_item_max.jsx'; +import SettingPicture from 'components/setting_picture.jsx'; import UserStore from 'stores/user_store.jsx'; import ErrorStore from 'stores/error_store.jsx'; import Client from 'client/web_client.jsx'; import Constants from 'utils/constants.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import * as Utils from 'utils/utils.jsx'; import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage, FormattedDate} from 'react-intl'; @@ -80,6 +79,19 @@ const holders = defineMessages({ import React from 'react'; class UserSettingsGeneralTab extends React.Component { + static propTypes = { + intl: intlShape.isRequired, + user: React.PropTypes.object.isRequired, + updateSection: React.PropTypes.func.isRequired, + updateTab: React.PropTypes.func.isRequired, + activeSection: React.PropTypes.string.isRequired, + closeModal: React.PropTypes.func.isRequired, + collapseModal: React.PropTypes.func.isRequired, + actions: React.PropTypes.shape({ + getMe: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); this.submitActive = false; @@ -205,7 +217,7 @@ class UserSettingsGeneralTab extends React.Component { updateUser(user, type, () => { this.updateSection(''); - AsyncClient.getMe(); + this.props.actions.getMe(); const verificationEnabled = global.window.mm_config.SendEmailNotifications === 'true' && global.window.mm_config.RequireEmailVerification === 'true' && emailUpdated; if (verificationEnabled) { @@ -1194,14 +1206,4 @@ class UserSettingsGeneralTab extends React.Component { } } -UserSettingsGeneralTab.propTypes = { - intl: intlShape.isRequired, - user: React.PropTypes.object.isRequired, - updateSection: React.PropTypes.func.isRequired, - updateTab: React.PropTypes.func.isRequired, - activeSection: React.PropTypes.string.isRequired, - closeModal: React.PropTypes.func.isRequired, - collapseModal: React.PropTypes.func.isRequired -}; - export default injectIntl(UserSettingsGeneralTab); diff --git a/webapp/components/user_settings/user_settings_security/index.js b/webapp/components/user_settings/user_settings_security/index.js new file mode 100644 index 000000000..cdbabd055 --- /dev/null +++ b/webapp/components/user_settings/user_settings_security/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 {getMe} from 'mattermost-redux/actions/users'; + +import SecurityTab from './user_settings_security.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getMe + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(SecurityTab); diff --git a/webapp/components/user_settings/user_settings_security.jsx b/webapp/components/user_settings/user_settings_security/user_settings_security.jsx index ead579c19..d4a372454 100644 --- a/webapp/components/user_settings/user_settings_security.jsx +++ b/webapp/components/user_settings/user_settings_security/user_settings_security.jsx @@ -1,15 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import SettingItemMin from '../setting_item_min.jsx'; -import SettingItemMax from '../setting_item_max.jsx'; -import AccessHistoryModal from '../access_history_modal.jsx'; -import ActivityLogModal from '../activity_log_modal.jsx'; -import ToggleModalButton from '../toggle_modal_button.jsx'; +import SettingItemMin from 'components/setting_item_min.jsx'; +import SettingItemMax from 'components/setting_item_max.jsx'; +import AccessHistoryModal from 'components/access_history_modal'; +import ActivityLogModal from 'components/activity_log_modal'; +import ToggleModalButton from 'components/toggle_modal_button.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; @@ -23,6 +22,19 @@ import {browserHistory, Link} from 'react-router/es6'; import icon50 from 'images/icon50x50.png'; export default class SecurityTab extends React.Component { + static propTypes = { + user: React.PropTypes.object, + activeSection: React.PropTypes.string, + updateSection: React.PropTypes.func, + updateTab: React.PropTypes.func, + closeModal: React.PropTypes.func.isRequired, + collapseModal: React.PropTypes.func.isRequired, + setEnforceFocus: React.PropTypes.func.isRequired, + actions: React.PropTypes.shape({ + getMe: React.PropTypes.func.isRequired + }).isRequired + } + constructor(props) { super(props); @@ -98,7 +110,7 @@ export default class SecurityTab extends React.Component { newPassword, () => { this.props.updateSection(''); - AsyncClient.getMe(); + this.props.actions.getMe(); this.setState(this.getDefaultState()); }, (err) => { @@ -1022,12 +1034,3 @@ SecurityTab.defaultProps = { user: {}, activeSection: '' }; -SecurityTab.propTypes = { - user: React.PropTypes.object, - activeSection: React.PropTypes.string, - updateSection: React.PropTypes.func, - updateTab: React.PropTypes.func, - closeModal: React.PropTypes.func.isRequired, - collapseModal: React.PropTypes.func.isRequired, - setEnforceFocus: React.PropTypes.func.isRequired -}; |