PLT-4815 Refactor 'More Channels' modal into the new modal pattern (#4742)
* Refactor 'More Channels' modal into the new modal pattern * Fix unit test * Readded CSS changes
Этот коммит содержится в:
коммит произвёл
enahum
родитель
c35b95709e
Коммит
7f48a7fc9d
@@ -43,6 +43,8 @@ export default class UserList extends React.Component {
|
|||||||
this.search = this.search.bind(this);
|
this.search = this.search.bind(this);
|
||||||
this.loadComplete = this.loadComplete.bind(this);
|
this.loadComplete = this.loadComplete.bind(this);
|
||||||
|
|
||||||
|
this.searchTimeoutId = 0;
|
||||||
|
|
||||||
const stats = TeamStore.getStats(this.props.params.team);
|
const stats = TeamStore.getStats(this.props.params.team);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -148,14 +150,21 @@ export default class UserList extends React.Component {
|
|||||||
const options = {};
|
const options = {};
|
||||||
options[UserSearchOptions.ALLOW_INACTIVE] = true;
|
options[UserSearchOptions.ALLOW_INACTIVE] = true;
|
||||||
|
|
||||||
searchUsers(
|
clearTimeout(this.searchTimeoutId);
|
||||||
term,
|
|
||||||
this.props.params.team,
|
this.searchTimeoutId = setTimeout(
|
||||||
options,
|
() => {
|
||||||
(users) => {
|
searchUsers(
|
||||||
this.setState({loading: true, search: true, users});
|
term,
|
||||||
loadTeamMembersForProfilesList(users, this.props.params.team, this.loadComplete);
|
this.props.params.team,
|
||||||
}
|
options,
|
||||||
|
(users) => {
|
||||||
|
this.setState({loading: true, search: true, users});
|
||||||
|
loadTeamMembersForProfilesList(users, this.props.params.team, this.loadComplete);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {searchUsers} from 'actions/user_actions.jsx';
|
|||||||
|
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
import * as AsyncClient from 'utils/async_client.jsx';
|
||||||
import * as UserAgent from 'utils/user_agent.jsx';
|
import * as UserAgent from 'utils/user_agent.jsx';
|
||||||
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Modal} from 'react-bootstrap';
|
import {Modal} from 'react-bootstrap';
|
||||||
@@ -32,6 +33,7 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
this.search = this.search.bind(this);
|
this.search = this.search.bind(this);
|
||||||
|
|
||||||
this.term = '';
|
this.term = '';
|
||||||
|
this.searchTimeoutId = 0;
|
||||||
|
|
||||||
const channelStats = ChannelStore.getStats(props.channel.id);
|
const channelStats = ChannelStore.getStats(props.channel.id);
|
||||||
const teamStats = TeamStore.getCurrentStats();
|
const teamStats = TeamStore.getCurrentStats();
|
||||||
@@ -113,13 +115,20 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
searchUsers(
|
clearTimeout(this.searchTimeoutId);
|
||||||
term,
|
|
||||||
TeamStore.getCurrentId(),
|
this.searchTimeoutId = setTimeout(
|
||||||
{not_in_channel_id: this.props.channel.id},
|
() => {
|
||||||
(users) => {
|
searchUsers(
|
||||||
this.setState({search: true, users});
|
term,
|
||||||
}
|
TeamStore.getCurrentId(),
|
||||||
|
{not_in_channel_id: this.props.channel.id},
|
||||||
|
(users) => {
|
||||||
|
this.setState({search: true, users});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {removeUserFromChannel} from 'actions/channel_actions.jsx';
|
|||||||
|
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
import * as AsyncClient from 'utils/async_client.jsx';
|
||||||
import * as UserAgent from 'utils/user_agent.jsx';
|
import * as UserAgent from 'utils/user_agent.jsx';
|
||||||
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Modal} from 'react-bootstrap';
|
import {Modal} from 'react-bootstrap';
|
||||||
@@ -33,6 +34,7 @@ export default class ChannelMembersModal extends React.Component {
|
|||||||
this.nextPage = this.nextPage.bind(this);
|
this.nextPage = this.nextPage.bind(this);
|
||||||
|
|
||||||
this.term = '';
|
this.term = '';
|
||||||
|
this.searchTimeoutId = 0;
|
||||||
|
|
||||||
const stats = ChannelStore.getStats(props.channel.id);
|
const stats = ChannelStore.getStats(props.channel.id);
|
||||||
|
|
||||||
@@ -128,13 +130,20 @@ export default class ChannelMembersModal extends React.Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
searchUsers(
|
clearTimeout(this.searchTimeoutId);
|
||||||
term,
|
|
||||||
TeamStore.getCurrentId(),
|
this.searchTimeoutId = setTimeout(
|
||||||
{in_channel_id: this.props.channel.id},
|
() => {
|
||||||
(users) => {
|
searchUsers(
|
||||||
this.setState({search: true, users});
|
term,
|
||||||
}
|
TeamStore.getCurrentId(),
|
||||||
|
{in_channel_id: this.props.channel.id},
|
||||||
|
(users) => {
|
||||||
|
this.setState({search: true, users});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ export default class MemberListTeam extends React.Component {
|
|||||||
this.search = this.search.bind(this);
|
this.search = this.search.bind(this);
|
||||||
this.loadComplete = this.loadComplete.bind(this);
|
this.loadComplete = this.loadComplete.bind(this);
|
||||||
|
|
||||||
|
this.searchTimeoutId = 0;
|
||||||
|
|
||||||
const stats = TeamStore.getCurrentStats();
|
const stats = TeamStore.getCurrentStats();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -86,14 +88,21 @@ export default class MemberListTeam extends React.Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
searchUsers(
|
clearTimeout(this.searchTimeoutId);
|
||||||
term,
|
|
||||||
TeamStore.getCurrentId(),
|
this.searchTimeoutId = setTimeout(
|
||||||
{},
|
() => {
|
||||||
(users) => {
|
searchUsers(
|
||||||
this.setState({loading: true, search: true, users, term, teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
term,
|
||||||
loadTeamMembersForProfilesList(users, TeamStore.getCurrentId(), this.loadComplete);
|
TeamStore.getCurrentId(),
|
||||||
}
|
{},
|
||||||
|
(users) => {
|
||||||
|
this.setState({loading: true, search: true, users, term, teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
||||||
|
loadTeamMembersForProfilesList(users, TeamStore.getCurrentId(), this.loadComplete);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import $ from 'jquery';
|
|
||||||
import NewChannelFlow from './new_channel_flow.jsx';
|
|
||||||
import SearchableChannelList from './searchable_channel_list.jsx';
|
import SearchableChannelList from './searchable_channel_list.jsx';
|
||||||
|
|
||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
@@ -13,11 +11,11 @@ import Constants from 'utils/constants.jsx';
|
|||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
import * as AsyncClient from 'utils/async_client.jsx';
|
||||||
import {joinChannel, searchMoreChannels} from 'actions/channel_actions.jsx';
|
import {joinChannel, searchMoreChannels} from 'actions/channel_actions.jsx';
|
||||||
|
|
||||||
import {FormattedMessage} from 'react-intl';
|
|
||||||
import {browserHistory} from 'react-router/es6';
|
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
|
import {Modal} from 'react-bootstrap';
|
||||||
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
import {browserHistory} from 'react-router/es6';
|
||||||
|
|
||||||
const CHANNELS_CHUNK_SIZE = 50;
|
const CHANNELS_CHUNK_SIZE = 50;
|
||||||
const CHANNELS_PER_PAGE = 50;
|
const CHANNELS_PER_PAGE = 50;
|
||||||
@@ -29,7 +27,8 @@ export default class MoreChannels extends React.Component {
|
|||||||
|
|
||||||
this.onChange = this.onChange.bind(this);
|
this.onChange = this.onChange.bind(this);
|
||||||
this.handleJoin = this.handleJoin.bind(this);
|
this.handleJoin = this.handleJoin.bind(this);
|
||||||
this.handleNewChannel = this.handleNewChannel.bind(this);
|
this.handleHide = this.handleHide.bind(this);
|
||||||
|
this.handleExit = this.handleExit.bind(this);
|
||||||
this.nextPage = this.nextPage.bind(this);
|
this.nextPage = this.nextPage.bind(this);
|
||||||
this.search = this.search.bind(this);
|
this.search = this.search.bind(this);
|
||||||
|
|
||||||
@@ -38,8 +37,7 @@ export default class MoreChannels extends React.Component {
|
|||||||
this.searchTimeoutId = 0;
|
this.searchTimeoutId = 0;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
channelType: '',
|
show: true,
|
||||||
showNewChannelModal: false,
|
|
||||||
search: false,
|
search: false,
|
||||||
channels: null,
|
channels: null,
|
||||||
serverError: null
|
serverError: null
|
||||||
@@ -47,23 +45,24 @@ export default class MoreChannels extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const self = this;
|
|
||||||
ChannelStore.addChangeListener(this.onChange);
|
ChannelStore.addChangeListener(this.onChange);
|
||||||
|
AsyncClient.getMoreChannelsPage(0, CHANNELS_CHUNK_SIZE * 2);
|
||||||
$(this.refs.modal).on('shown.bs.modal', () => {
|
|
||||||
AsyncClient.getMoreChannelsPage(0, CHANNELS_CHUNK_SIZE * 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
$(this.refs.modal).on('show.bs.modal', (e) => {
|
|
||||||
const button = e.relatedTarget;
|
|
||||||
self.setState({channelType: $(button).attr('data-channeltype')});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
ChannelStore.removeChangeListener(this.onChange);
|
ChannelStore.removeChangeListener(this.onChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleHide() {
|
||||||
|
this.setState({show: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleExit() {
|
||||||
|
if (this.props.onModalDismissed) {
|
||||||
|
this.props.onModalDismissed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onChange(force) {
|
onChange(force) {
|
||||||
if (this.state.search && !force) {
|
if (this.state.search && !force) {
|
||||||
return;
|
return;
|
||||||
@@ -83,11 +82,12 @@ export default class MoreChannels extends React.Component {
|
|||||||
joinChannel(
|
joinChannel(
|
||||||
channel,
|
channel,
|
||||||
() => {
|
() => {
|
||||||
$(this.refs.modal).modal('hide');
|
|
||||||
browserHistory.push(TeamStore.getCurrentTeamRelativeUrl() + '/channels/' + channel.name);
|
browserHistory.push(TeamStore.getCurrentTeamRelativeUrl() + '/channels/' + channel.name);
|
||||||
if (done) {
|
if (done) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.handleHide();
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
this.setState({serverError: err.message});
|
this.setState({serverError: err.message});
|
||||||
@@ -98,11 +98,6 @@ export default class MoreChannels extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNewChannel() {
|
|
||||||
$(this.refs.modal).modal('hide');
|
|
||||||
this.setState({showNewChannelModal: true});
|
|
||||||
}
|
|
||||||
|
|
||||||
search(term) {
|
search(term) {
|
||||||
if (term === '') {
|
if (term === '') {
|
||||||
this.onChange(true);
|
this.onChange(true);
|
||||||
@@ -135,7 +130,7 @@ export default class MoreChannels extends React.Component {
|
|||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
className='btn btn-primary channel-create-btn'
|
className='btn btn-primary channel-create-btn'
|
||||||
onClick={this.handleNewChannel}
|
onClick={this.props.handleNewChannel}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='more_channels.create'
|
id='more_channels.create'
|
||||||
@@ -167,58 +162,38 @@ export default class MoreChannels extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Modal
|
||||||
className='modal fade more-channel__modal'
|
dialogClassName='more-modal more-public-channels'
|
||||||
id='more_channels'
|
show={this.state.show}
|
||||||
ref='modal'
|
onHide={this.handleHide}
|
||||||
tabIndex='-1'
|
onExited={this.handleExit}
|
||||||
role='dialog'
|
|
||||||
aria-hidden='true'
|
|
||||||
>
|
>
|
||||||
<div className='modal-dialog'>
|
<Modal.Header closeButton={true}>
|
||||||
<div className='modal-content'>
|
<Modal.Title>
|
||||||
<div className='modal-header'>
|
<FormattedMessage
|
||||||
<button
|
id='more_channels.title'
|
||||||
type='button'
|
defaultMessage='More Channels'
|
||||||
className='close'
|
/>
|
||||||
data-dismiss='modal'
|
</Modal.Title>
|
||||||
>
|
{createNewChannelButton}
|
||||||
<span aria-hidden='true'>{'×'}</span>
|
</Modal.Header>
|
||||||
<span className='sr-only'>
|
<Modal.Body>
|
||||||
<FormattedMessage
|
<SearchableChannelList
|
||||||
id='more_channels.close'
|
channels={this.state.channels}
|
||||||
defaultMessage='Close'
|
channelsPerPage={CHANNELS_PER_PAGE}
|
||||||
/>
|
nextPage={this.nextPage}
|
||||||
</span>
|
search={this.search}
|
||||||
</button>
|
handleJoin={this.handleJoin}
|
||||||
<h4 className='modal-title'>
|
noResultsText={createChannelHelpText}
|
||||||
<FormattedMessage
|
/>
|
||||||
id='more_channels.title'
|
{serverError}
|
||||||
defaultMessage='More Channels'
|
</Modal.Body>
|
||||||
/>
|
</Modal>
|
||||||
</h4>
|
|
||||||
{createNewChannelButton}
|
|
||||||
<NewChannelFlow
|
|
||||||
show={this.state.showNewChannelModal}
|
|
||||||
channelType={this.state.channelType}
|
|
||||||
onModalDismissed={() => this.setState({showNewChannelModal: false})}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='modal-body'>
|
|
||||||
<SearchableChannelList
|
|
||||||
channels={this.state.channels}
|
|
||||||
channelsPerPage={CHANNELS_PER_PAGE}
|
|
||||||
nextPage={this.nextPage}
|
|
||||||
search={this.search}
|
|
||||||
handleJoin={this.handleJoin}
|
|
||||||
noResultsText={createChannelHelpText}
|
|
||||||
/>
|
|
||||||
{serverError}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MoreChannels.propTypes = {
|
||||||
|
onModalDismissed: React.PropTypes.func,
|
||||||
|
handleNewChannel: React.PropTypes.func
|
||||||
|
};
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
this.nextPage = this.nextPage.bind(this);
|
this.nextPage = this.nextPage.bind(this);
|
||||||
this.search = this.search.bind(this);
|
this.search = this.search.bind(this);
|
||||||
|
|
||||||
|
this.searchTimeoutId = 0;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
users: null,
|
users: null,
|
||||||
loadingDMChannel: -1,
|
loadingDMChannel: -1,
|
||||||
@@ -168,19 +170,26 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
teamId = TeamStore.getCurrentId();
|
teamId = TeamStore.getCurrentId();
|
||||||
}
|
}
|
||||||
|
|
||||||
searchUsers(
|
clearTimeout(this.searchTimeoutId);
|
||||||
term,
|
|
||||||
teamId,
|
this.searchTimeoutId = setTimeout(
|
||||||
{},
|
() => {
|
||||||
(users) => {
|
searchUsers(
|
||||||
for (let i = 0; i < users.length; i++) {
|
term,
|
||||||
if (users[i].id === UserStore.getCurrentId()) {
|
teamId,
|
||||||
users.splice(i, 1);
|
{},
|
||||||
break;
|
(users) => {
|
||||||
|
for (let i = 0; i < users.length; i++) {
|
||||||
|
if (users[i].id === UserStore.getCurrentId()) {
|
||||||
|
users.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({search: true, users});
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
this.setState({search: true, users});
|
},
|
||||||
}
|
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import GetPublicLinkModal from 'components/get_public_link_modal.jsx';
|
|||||||
import GetTeamInviteLinkModal from 'components/get_team_invite_link_modal.jsx';
|
import GetTeamInviteLinkModal from 'components/get_team_invite_link_modal.jsx';
|
||||||
import EditPostModal from 'components/edit_post_modal.jsx';
|
import EditPostModal from 'components/edit_post_modal.jsx';
|
||||||
import DeletePostModal from 'components/delete_post_modal.jsx';
|
import DeletePostModal from 'components/delete_post_modal.jsx';
|
||||||
import MoreChannelsModal from 'components/more_channels.jsx';
|
|
||||||
import TeamSettingsModal from 'components/team_settings_modal.jsx';
|
import TeamSettingsModal from 'components/team_settings_modal.jsx';
|
||||||
import RemovedFromChannelModal from 'components/removed_from_channel_modal.jsx';
|
import RemovedFromChannelModal from 'components/removed_from_channel_modal.jsx';
|
||||||
import ImportThemeModal from 'components/user_settings/import_theme_modal.jsx';
|
import ImportThemeModal from 'components/user_settings/import_theme_modal.jsx';
|
||||||
@@ -181,7 +180,6 @@ export default class NeedsTeam extends React.Component {
|
|||||||
<LeaveTeamModal/>
|
<LeaveTeamModal/>
|
||||||
<ImportThemeModal/>
|
<ImportThemeModal/>
|
||||||
<TeamSettingsModal/>
|
<TeamSettingsModal/>
|
||||||
<MoreChannelsModal/>
|
|
||||||
<EditPostModal/>
|
<EditPostModal/>
|
||||||
<DeletePostModal/>
|
<DeletePostModal/>
|
||||||
<RemovedFromChannelModal/>
|
<RemovedFromChannelModal/>
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ export default class SearchableChannelList extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div className='filtered-user-list'>
|
<div className='filtered-user-list'>
|
||||||
<div className='filter-row'>
|
<div className='filter-row'>
|
||||||
<div className='col-sm-6'>
|
<div className='col-sm-12'>
|
||||||
<input
|
<input
|
||||||
ref='filter'
|
ref='filter'
|
||||||
className='form-control filter-textbox'
|
className='form-control filter-textbox'
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
import UserList from 'components/user_list.jsx';
|
import UserList from 'components/user_list.jsx';
|
||||||
|
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import Constants from 'utils/constants.jsx';
|
|
||||||
const KeyCodes = Constants.KeyCodes;
|
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@@ -21,8 +19,6 @@ export default class SearchableUserList extends React.Component {
|
|||||||
this.nextPage = this.nextPage.bind(this);
|
this.nextPage = this.nextPage.bind(this);
|
||||||
this.previousPage = this.previousPage.bind(this);
|
this.previousPage = this.previousPage.bind(this);
|
||||||
this.doSearch = this.doSearch.bind(this);
|
this.doSearch = this.doSearch.bind(this);
|
||||||
this.onSearchBoxKeyPress = this.onSearchBoxKeyPress.bind(this);
|
|
||||||
this.onSearchBoxChange = this.onSearchBoxChange.bind(this);
|
|
||||||
|
|
||||||
this.nextTimeoutId = 0;
|
this.nextTimeoutId = 0;
|
||||||
|
|
||||||
@@ -71,20 +67,6 @@ export default class SearchableUserList extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchBoxKeyPress(e) {
|
|
||||||
if (e.charCode === KeyCodes.ENTER) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.doSearch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onSearchBoxChange(e) {
|
|
||||||
if (e.target.value === '') {
|
|
||||||
this.props.search(''); // clear search
|
|
||||||
this.setState({page: 0, search: false});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let nextButton;
|
let nextButton;
|
||||||
let previousButton;
|
let previousButton;
|
||||||
@@ -158,28 +140,14 @@ export default class SearchableUserList extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div className='filtered-user-list'>
|
<div className='filtered-user-list'>
|
||||||
<div className='filter-row'>
|
<div className='filter-row'>
|
||||||
<div className='col-xs-9 col-sm-5'>
|
<div className='col-xs-12'>
|
||||||
<input
|
<input
|
||||||
ref='filter'
|
ref='filter'
|
||||||
className='form-control filter-textbox'
|
className='form-control filter-textbox'
|
||||||
placeholder={Utils.localizeMessage('filtered_user_list.search', 'Press enter to search')}
|
placeholder={Utils.localizeMessage('filtered_user_list.search', 'Search users')}
|
||||||
onKeyPress={this.onSearchBoxKeyPress}
|
onInput={this.doSearch}
|
||||||
onChange={this.onSearchBoxChange}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='col-xs-3 col-sm-2 filter-button'>
|
|
||||||
<button
|
|
||||||
type='button'
|
|
||||||
className='btn btn-primary'
|
|
||||||
onClick={this.doSearch}
|
|
||||||
disabled={this.props.users == null}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='filtered_user_list.searchButton'
|
|
||||||
defaultMessage='Search'
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='col-sm-12'>
|
<div className='col-sm-12'>
|
||||||
<span className='member-count pull-left'>{count}</span>
|
<span className='member-count pull-left'>{count}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import $ from 'jquery';
|
|||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import NewChannelFlow from './new_channel_flow.jsx';
|
import NewChannelFlow from './new_channel_flow.jsx';
|
||||||
import MoreDirectChannels from './more_direct_channels.jsx';
|
import MoreDirectChannels from './more_direct_channels.jsx';
|
||||||
|
import MoreChannels from 'components/more_channels.jsx';
|
||||||
import SidebarHeader from './sidebar_header.jsx';
|
import SidebarHeader from './sidebar_header.jsx';
|
||||||
import UnreadChannelIndicator from './unread_channel_indicator.jsx';
|
import UnreadChannelIndicator from './unread_channel_indicator.jsx';
|
||||||
import TutorialTip from './tutorial/tutorial_tip.jsx';
|
import TutorialTip from './tutorial/tutorial_tip.jsx';
|
||||||
@@ -19,7 +20,6 @@ import * as AsyncClient from 'utils/async_client.jsx';
|
|||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import * as ChannelUtils from 'utils/channel_utils.jsx';
|
import * as ChannelUtils from 'utils/channel_utils.jsx';
|
||||||
import * as ChannelActions from 'actions/channel_actions.jsx';
|
import * as ChannelActions from 'actions/channel_actions.jsx';
|
||||||
import * as UserAgent from 'utils/user_agent.jsx';
|
|
||||||
|
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
@@ -53,6 +53,7 @@ export default class Sidebar extends React.Component {
|
|||||||
this.handleLeaveDirectChannel = this.handleLeaveDirectChannel.bind(this);
|
this.handleLeaveDirectChannel = this.handleLeaveDirectChannel.bind(this);
|
||||||
|
|
||||||
this.showMoreChannelsModal = this.showMoreChannelsModal.bind(this);
|
this.showMoreChannelsModal = this.showMoreChannelsModal.bind(this);
|
||||||
|
this.hideMoreChannelsModal = this.hideMoreChannelsModal.bind(this);
|
||||||
this.showNewChannelModal = this.showNewChannelModal.bind(this);
|
this.showNewChannelModal = this.showNewChannelModal.bind(this);
|
||||||
this.hideNewChannelModal = this.hideNewChannelModal.bind(this);
|
this.hideNewChannelModal = this.hideNewChannelModal.bind(this);
|
||||||
this.showMoreDirectChannelsModal = this.showMoreDirectChannelsModal.bind(this);
|
this.showMoreDirectChannelsModal = this.showMoreDirectChannelsModal.bind(this);
|
||||||
@@ -72,6 +73,7 @@ export default class Sidebar extends React.Component {
|
|||||||
const state = this.getStateFromStores();
|
const state = this.getStateFromStores();
|
||||||
state.newChannelModalType = '';
|
state.newChannelModalType = '';
|
||||||
state.showDirectChannelsModal = false;
|
state.showDirectChannelsModal = false;
|
||||||
|
state.showMoreChannelsModal = false;
|
||||||
state.loadingDMChannel = -1;
|
state.loadingDMChannel = -1;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
@@ -340,13 +342,11 @@ export default class Sidebar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showMoreChannelsModal() {
|
showMoreChannelsModal() {
|
||||||
// manually show the modal because using data-toggle messes with keyboard focus when the modal is dismissed
|
this.setState({showMoreChannelsModal: true});
|
||||||
$('#more_channels').modal({'data-channeltype': 'O'}).modal('show');
|
}
|
||||||
$('#more_channels').on('shown.bs.modal', () => {
|
|
||||||
if (!UserAgent.isMobile()) {
|
hideMoreChannelsModal() {
|
||||||
$('#more_channels input').focus();
|
this.setState({showMoreChannelsModal: false});
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showNewChannelModal(type) {
|
showNewChannelModal(type) {
|
||||||
@@ -552,6 +552,7 @@ export default class Sidebar extends React.Component {
|
|||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// Check if we have all info needed to render
|
// Check if we have all info needed to render
|
||||||
if (this.state.currentTeam == null || this.state.currentUser == null) {
|
if (this.state.currentTeam == null || this.state.currentUser == null) {
|
||||||
@@ -721,12 +722,24 @@ export default class Sidebar extends React.Component {
|
|||||||
if (this.state.showDirectChannelsModal) {
|
if (this.state.showDirectChannelsModal) {
|
||||||
moreDirectChannelsModal = (
|
moreDirectChannelsModal = (
|
||||||
<MoreDirectChannels
|
<MoreDirectChannels
|
||||||
show={true}
|
|
||||||
onModalDismissed={this.hideMoreDirectChannelsModal}
|
onModalDismissed={this.hideMoreDirectChannelsModal}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let moreChannelsModal;
|
||||||
|
if (this.state.showMoreChannelsModal) {
|
||||||
|
moreChannelsModal = (
|
||||||
|
<MoreChannels
|
||||||
|
onModalDismissed={this.hideMoreChannelsModal}
|
||||||
|
handleNewChannel={() => {
|
||||||
|
this.hideMoreChannelsModal();
|
||||||
|
this.showNewChannelModal(Constants.OPEN_CHANNEL);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='sidebar--left'
|
className='sidebar--left'
|
||||||
@@ -739,6 +752,7 @@ export default class Sidebar extends React.Component {
|
|||||||
onModalDismissed={this.hideNewChannelModal}
|
onModalDismissed={this.hideNewChannelModal}
|
||||||
/>
|
/>
|
||||||
{moreDirectChannelsModal}
|
{moreDirectChannelsModal}
|
||||||
|
{moreChannelsModal}
|
||||||
|
|
||||||
<SidebarHeader
|
<SidebarHeader
|
||||||
teamDisplayName={this.state.currentTeam.display_name}
|
teamDisplayName={this.state.currentTeam.display_name}
|
||||||
|
|||||||
@@ -1259,7 +1259,7 @@
|
|||||||
"filtered_user_list.countTotal": "{count} {count, plural, =0 {0 members} one {member} other {members}} of {total} total",
|
"filtered_user_list.countTotal": "{count} {count, plural, =0 {0 members} one {member} other {members}} of {total} total",
|
||||||
"filtered_user_list.countTotalPage": "{startCount, number} - {endCount, number} {count, plural, =0 {0 members} one {member} other {members}} of {total} total",
|
"filtered_user_list.countTotalPage": "{startCount, number} - {endCount, number} {count, plural, =0 {0 members} one {member} other {members}} of {total} total",
|
||||||
"filtered_user_list.member": "Member",
|
"filtered_user_list.member": "Member",
|
||||||
"filtered_user_list.search": "Press enter to search",
|
"filtered_user_list.search": "Search users",
|
||||||
"filtered_user_list.searchButton": "Search",
|
"filtered_user_list.searchButton": "Search",
|
||||||
"filtered_user_list.show": "Filter:",
|
"filtered_user_list.show": "Filter:",
|
||||||
"filtered_user_list.team_only": "Members of this Team",
|
"filtered_user_list.team_only": "Members of this Team",
|
||||||
|
|||||||
@@ -483,6 +483,7 @@
|
|||||||
.filter-row {
|
.filter-row {
|
||||||
@include clearfix;
|
@include clearfix;
|
||||||
margin: 5px 0 10px;
|
margin: 5px 0 10px;
|
||||||
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.member-count {
|
.member-count {
|
||||||
|
|||||||
@@ -75,12 +75,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app__body {
|
.app__body {
|
||||||
.more-modal {
|
|
||||||
.filter-row {
|
|
||||||
width: 330px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-modal-body {
|
.edit-modal-body {
|
||||||
.custom-textarea {
|
.custom-textarea {
|
||||||
max-height: 30vh;
|
max-height: 30vh;
|
||||||
@@ -1172,6 +1166,19 @@
|
|||||||
|
|
||||||
@media screen and (max-width: 640px) {
|
@media screen and (max-width: 640px) {
|
||||||
.app__body {
|
.app__body {
|
||||||
|
.modal {
|
||||||
|
.more-modal {
|
||||||
|
.modal-body {
|
||||||
|
max-height: calc(100vh - 62px);
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-modal__list {
|
||||||
|
max-height: calc(100vh - 230px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.post {
|
.post {
|
||||||
.open {
|
.open {
|
||||||
> .dropdown-menu__content {
|
> .dropdown-menu__content {
|
||||||
@@ -1329,10 +1336,13 @@
|
|||||||
@media screen and (max-width: 550px) {
|
@media screen and (max-width: 550px) {
|
||||||
.app__body {
|
.app__body {
|
||||||
.more-modal {
|
.more-modal {
|
||||||
|
.filter-row {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
&.more-direct-channels {
|
&.more-direct-channels {
|
||||||
.filter-row {
|
.filter-row {
|
||||||
padding-bottom: 50px;
|
padding-bottom: 50px;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.member-show {
|
.member-show {
|
||||||
@@ -1391,22 +1401,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app__body {
|
.app__body {
|
||||||
.more-modal {
|
|
||||||
.modal-body {
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-modal__list {
|
|
||||||
max-height: calc(100vh - 260px);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.more-direct-channels {
|
|
||||||
.more-modal__list {
|
|
||||||
max-height: calc(100vh - 295px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
&.more-channel__modal {
|
&.more-channel__modal {
|
||||||
.more-modal__list {
|
.more-modal__list {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
|
|
||||||
var Utils;
|
var Utils;
|
||||||
import {ActionTypes, Constants} from 'utils/constants.jsx';
|
import {ActionTypes, Constants} from 'utils/constants.jsx';
|
||||||
const NotificationPrefs = Constants.NotificationPrefs;
|
const NotificationPrefs = Constants.NotificationPrefs;
|
||||||
@@ -233,24 +235,25 @@ class ChannelStoreClass extends EventEmitter {
|
|||||||
return this.myChannelMembers;
|
return this.myChannelMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
storeMoreChannels(channels) {
|
storeMoreChannels(channels, teamId = TeamStore.getCurrentId()) {
|
||||||
const newChannels = {};
|
const newChannels = {};
|
||||||
for (let i = 0; i < channels.length; i++) {
|
for (let i = 0; i < channels.length; i++) {
|
||||||
newChannels[channels[i].id] = channels[i];
|
newChannels[channels[i].id] = channels[i];
|
||||||
}
|
}
|
||||||
this.moreChannels = Object.assign({}, this.moreChannels, newChannels);
|
this.moreChannels[teamId] = Object.assign({}, this.moreChannels[teamId], newChannels);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeMoreChannel(channelId) {
|
removeMoreChannel(channelId, teamId = TeamStore.getCurrentId()) {
|
||||||
Reflect.deleteProperty(this.moreChannels, channelId);
|
Reflect.deleteProperty(this.moreChannels[teamId], channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMoreChannels() {
|
getMoreChannels(teamId = TeamStore.getCurrentId()) {
|
||||||
return Object.assign({}, this.moreChannels);
|
return Object.assign({}, this.moreChannels[teamId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMoreChannelsList() {
|
getMoreChannelsList(teamId = TeamStore.getCurrentId()) {
|
||||||
return Object.keys(this.moreChannels).map((cid) => this.moreChannels[cid]);
|
const teamChannels = this.moreChannels[teamId] || {};
|
||||||
|
return Object.keys(teamChannels).map((cid) => teamChannels[cid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
storeStats(stats) {
|
storeStats(stats) {
|
||||||
|
|||||||
@@ -863,7 +863,8 @@ export const Constants = {
|
|||||||
MENTION_SPECIAL: 'mention.special',
|
MENTION_SPECIAL: 'mention.special',
|
||||||
DEFAULT_NOTIFICATION_DURATION: 5000,
|
DEFAULT_NOTIFICATION_DURATION: 5000,
|
||||||
STATUS_INTERVAL: 60000,
|
STATUS_INTERVAL: 60000,
|
||||||
AUTOCOMPLETE_TIMEOUT: 100
|
AUTOCOMPLETE_TIMEOUT: 100,
|
||||||
|
SEARCH_TIMEOUT_MILLISECONDS: 100
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Constants;
|
export default Constants;
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user