Start moving webapp to Redux (#6140)
* Start moving webapp to Redux * Fix localforage import * Updates per feedback * Feedback udpates and a few fixes * Minor updates * Fix statuses, config not loading properly, getMe sanitizing too much * Fix preferences * Fix user autocomplete * Fix sessions and audits * Fix error handling for all redux actions * Use new directory structure for components and containers * Refresh immediately on logout instead of after timeout * Add fetch polyfill
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
cc07c00507
Коммит
6c4c706313
@@ -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
|
||||
};
|
||||
24
webapp/components/access_history_modal/index.js
Обычный файл
24
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);
|
||||
@@ -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
|
||||
};
|
||||
25
webapp/components/activity_log_modal/index.js
Обычный файл
25
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);
|
||||
@@ -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
|
||||
};
|
||||
24
webapp/components/add_users_to_team/index.js
Обычный файл
24
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);
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
};
|
||||
24
webapp/components/channel_invite_modal/index.js
Обычный файл
24
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);
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
);
|
||||
|
||||
25
webapp/components/more_direct_channels/index.js
Обычный файл
25
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);
|
||||
@@ -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
|
||||
};
|
||||
@@ -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';
|
||||
|
||||
24
webapp/components/popover_list_members/index.js
Обычный файл
24
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);
|
||||
@@ -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
|
||||
};
|
||||
@@ -136,6 +136,7 @@ export default class Root extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Root.defaultProps = {
|
||||
};
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
24
webapp/components/team_members_dropdown/index.js
Обычный файл
24
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);
|
||||
@@ -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
|
||||
};
|
||||
@@ -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';
|
||||
|
||||
|
||||
24
webapp/components/user_settings/user_settings_general/index.js
Обычный файл
24
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);
|
||||
@@ -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);
|
||||
24
webapp/components/user_settings/user_settings_security/index.js
Обычный файл
24
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);
|
||||
@@ -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
|
||||
};
|
||||
Ссылка в новой задаче
Block a user