Merge release-3.10 into master (#6654)
* PLT-6787 Fixed being able to send a post before files finished uploading (#6617) * Fix quick switcher for channels/users not stored locally (#6610) * Fix button text on confirm mention modal (#6609) * fix post delete permission of channel admin (#6608) * open comment thread for the most recent reply-able message (#6605) * Use mutex flag with yarn to prevent concurrent builds interfering (#6619) * Use mutex flag with yarn to prevent concurrent builds interfering * Remove yarn mutex file with clean * Minor bug fixes (#6615) * PLT-6774 - Fixing color for offline icon * PLT-6784 - Fixing status icon * Fixing icon margin * Updating caret position * PLT-6070 Have ChannelMentionProvider stop searching after a term returns no results (#6620) * Fixing JS error (#6623) * Minor bug fixes (#6622) * PLT-6808 - Updating channel switcher on mobile * PLT-6743 - Updating scrollbar styling * Login instead of failing if user exists in OAuth sign-up flow (#6627) * PLT-6802 Disable team switcher (#6626) * Disable team switcher * Fix ESLint errors * PLT-6807 Ensured select teams page can scroll on iOS (#6630) * Do not redirect from account switch pages on 401 (#6631) * Fixing loadtest command and renaming to /test (#6624) * PLT-6820 Update mattermost-redux dependency (#6632) * translations PR 20170612 (#6629) * Bump HTTP client timeout to 30 seconds (#6633) * For team unreads return empty array instead of null (#6636) * PLT-6831 Fix status modal localization IDs (#6637) * Fix status modal localization IDs * Update test snapshot
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c0a0065472
Коммит
528f2dc6c3
@@ -21,16 +21,18 @@ export default function CommentIcon(props) {
|
||||
iconStyle = iconStyle + ' ' + props.searchStyle;
|
||||
}
|
||||
|
||||
let commentIconId = props.channelId + props.idPrefix;
|
||||
let selectorId = props.idPrefix;
|
||||
if (props.idCount > -1) {
|
||||
commentIconId += props.idCount;
|
||||
selectorId += props.idCount;
|
||||
}
|
||||
|
||||
const id = Utils.createSafeId(props.idPrefix + '_' + props.id);
|
||||
|
||||
return (
|
||||
<a
|
||||
id={Utils.createSafeId(commentIconId)}
|
||||
id={id}
|
||||
href='#'
|
||||
className={iconStyle}
|
||||
className={iconStyle + ' ' + selectorId}
|
||||
onClick={props.handleCommentClick}
|
||||
>
|
||||
<span
|
||||
@@ -48,12 +50,12 @@ CommentIcon.propTypes = {
|
||||
handleCommentClick: PropTypes.func.isRequired,
|
||||
searchStyle: PropTypes.string,
|
||||
commentCount: PropTypes.number,
|
||||
channelId: PropTypes.string
|
||||
id: PropTypes.string
|
||||
};
|
||||
|
||||
CommentIcon.defaultProps = {
|
||||
idCount: -1,
|
||||
searchStyle: '',
|
||||
commentCount: 0,
|
||||
channelId: ''
|
||||
};
|
||||
id: ''
|
||||
};
|
||||
|
||||
@@ -142,11 +142,7 @@ export default class CreateComment extends React.Component {
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (this.state.uploadsInProgress.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state.submitting) {
|
||||
if (this.state.uploadsInProgress.length > 0 || this.state.submitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,10 @@ export default class CreatePost extends React.Component {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (this.state.uploadsInProgress.length > 0 || this.state.submitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
const post = {};
|
||||
post.file_ids = [];
|
||||
post.message = this.state.message;
|
||||
@@ -493,7 +497,9 @@ export default class CreatePost extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastPostEl = document.getElementById(this.state.channelId + 'commentIcon0');
|
||||
const latestNonEphemeralPost = PostStore.getLatestNonEphemeralPost(this.state.channelId);
|
||||
const latestNonEphemeralPostId = latestNonEphemeralPost == null ? '' : latestNonEphemeralPost.id;
|
||||
const lastPostEl = document.getElementById(`commentIcon_${this.state.channelId}_${latestNonEphemeralPostId}`);
|
||||
|
||||
if (!e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey && e.keyCode === KeyCodes.UP && this.state.message === '') {
|
||||
e.preventDefault();
|
||||
@@ -761,7 +767,7 @@ export default class CreatePost extends React.Component {
|
||||
<ConfirmModal
|
||||
title={notifyAllTitle}
|
||||
message={notifyAllMessage}
|
||||
confirmButton={notifyAllConfirm}
|
||||
confirmButtonText={notifyAllConfirm}
|
||||
show={this.state.showConfirmModal}
|
||||
onConfirm={this.handleNotifyAllConfirmation}
|
||||
onCancel={this.handleNotifyModalCancel}
|
||||
|
||||
@@ -45,8 +45,6 @@ import {Link} from 'react-router/es6';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import React from 'react';
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import {getMyTeams} from 'mattermost-redux/selectors/entities/teams';
|
||||
|
||||
export default class Navbar extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -220,14 +218,9 @@ export default class Navbar extends React.Component {
|
||||
}
|
||||
|
||||
handleQuickSwitchKeyPress(e) {
|
||||
if (Utils.cmdOrCtrlPressed(e, true) && !e.shiftKey && e.keyCode === Constants.KeyCodes.K) {
|
||||
e.preventDefault();
|
||||
if (e.altKey) {
|
||||
if (getMyTeams(store.getState()).length <= 1) {
|
||||
return;
|
||||
}
|
||||
this.toggleQuickSwitchModal('team');
|
||||
} else {
|
||||
if (Utils.cmdOrCtrlPressed(e) && !e.shiftKey && e.keyCode === Constants.KeyCodes.K) {
|
||||
if (!e.altKey) {
|
||||
e.preventDefault();
|
||||
this.toggleQuickSwitchModal('channel');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ export default class PostInfo extends React.Component {
|
||||
idCount={idCount}
|
||||
handleCommentClick={this.props.handleCommentClick}
|
||||
commentCount={this.props.commentCount}
|
||||
channelId={ChannelStore.getCurrentId()}
|
||||
id={ChannelStore.getCurrentId() + '_' + post.id}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {getMyTeams} from 'mattermost-redux/selectors/entities/teams';
|
||||
|
||||
import QuickSwitchModal from './quick_switch_modal.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps,
|
||||
showTeamSwitcher: getMyTeams(state).length > 1
|
||||
showTeamSwitcher: false
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import store from 'stores/redux_store.jsx';
|
||||
const getState = store.getState;
|
||||
|
||||
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getUserByUsername} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
const CHANNEL_MODE = 'channel';
|
||||
const TEAM_MODE = 'team';
|
||||
@@ -141,24 +140,22 @@ export default class QuickSwitchModal extends React.PureComponent {
|
||||
if (this.state.mode === CHANNEL_MODE) {
|
||||
const selectedChannel = selected.channel;
|
||||
if (selectedChannel.type === Constants.DM_CHANNEL) {
|
||||
const user = getUserByUsername(getState(), selectedChannel.name);
|
||||
|
||||
if (user) {
|
||||
openDirectChannelToUser(
|
||||
user.id,
|
||||
(ch) => {
|
||||
channel = ch;
|
||||
this.switchToChannel(channel);
|
||||
},
|
||||
() => {
|
||||
channel = null;
|
||||
this.switchToChannel(channel);
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
openDirectChannelToUser(
|
||||
selectedChannel.id,
|
||||
(ch) => {
|
||||
channel = ch;
|
||||
this.switchToChannel(channel);
|
||||
},
|
||||
() => {
|
||||
channel = null;
|
||||
this.switchToChannel(channel);
|
||||
}
|
||||
);
|
||||
} else if (selectedChannel.type === Constants.GM_CHANNEL) {
|
||||
channel = getChannel(getState(), selectedChannel.id);
|
||||
this.switchToChannel(channel);
|
||||
} else {
|
||||
this.switchToChannel(selectedChannel);
|
||||
}
|
||||
} else {
|
||||
browserHistory.push('/' + selected.name);
|
||||
@@ -287,7 +284,7 @@ export default class QuickSwitchModal extends React.PureComponent {
|
||||
help = (
|
||||
<FormattedMessage
|
||||
id='quick_switch_modal.help_no_team'
|
||||
defaultMessage='Start typing then use ↑↓ to browse, ↵ to select, and ESC to dismiss.'
|
||||
defaultMessage='Type to find a channel. Use ↑↓ to browse, ↵ to select, ESC to dismiss.'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ export default class ResetStatusModal extends React.PureComponent {
|
||||
const userStatus = toTitleCase(this.state.currentUserStatus.status || '');
|
||||
const manualStatusTitle = (
|
||||
<FormattedMessage
|
||||
id='modal.manual_status.title'
|
||||
id='modal.manaul_status.title'
|
||||
defaultMessage='Your status is set to "{status}"'
|
||||
values={{
|
||||
status: userStatus
|
||||
@@ -96,21 +96,21 @@ export default class ResetStatusModal extends React.PureComponent {
|
||||
|
||||
const manualStatusMessage = (
|
||||
<FormattedMessage
|
||||
id='modal.manual_status.message'
|
||||
id='modal.manaul_status.message'
|
||||
defaultMessage='Would you like to switch your status to "Online"?'
|
||||
/>
|
||||
);
|
||||
|
||||
const manualStatusButton = (
|
||||
<FormattedMessage
|
||||
id='modal.manual_status.button'
|
||||
id='modal.manaul_status.button'
|
||||
defaultMessage='Yes, set my status to "Online"'
|
||||
/>
|
||||
);
|
||||
|
||||
const manualStatusCancel = (
|
||||
<FormattedMessage
|
||||
id='modal.manual_status.cancel'
|
||||
id='modal.manaul_status.cancel'
|
||||
defaultMessage='No, keep it as "{status}"'
|
||||
values={{
|
||||
status: userStatus
|
||||
@@ -120,7 +120,7 @@ export default class ResetStatusModal extends React.PureComponent {
|
||||
|
||||
const manualStatusCheckbox = (
|
||||
<FormattedMessage
|
||||
id='modal.manual_status.ask'
|
||||
id='modal.manaul_status.ask'
|
||||
defaultMessage='Do not ask me again'
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -54,6 +54,7 @@ export default class ChannelMentionProvider extends Provider {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.lastTermWithNoResults = '';
|
||||
this.lastCompletedWord = '';
|
||||
}
|
||||
|
||||
@@ -65,6 +66,11 @@ export default class ChannelMentionProvider extends Provider {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.lastTermWithNoResults && pretext.startsWith(this.lastTermWithNoResults)) {
|
||||
// Just give up since we know it won't return any results
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.lastCompletedWord && captured[0].startsWith(this.lastCompletedWord)) {
|
||||
// It appears we're still matching a channel handle that we already completed
|
||||
return false;
|
||||
@@ -79,12 +85,14 @@ export default class ChannelMentionProvider extends Provider {
|
||||
|
||||
autocompleteChannels(
|
||||
prefix,
|
||||
(data) => {
|
||||
(channels) => {
|
||||
if (this.shouldCancelDispatch(prefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const channels = data;
|
||||
if (channels.length === 0) {
|
||||
this.lastTermWithNoResults = pretext;
|
||||
}
|
||||
|
||||
// Wrap channels in an outer object to avoid overwriting the 'type' property.
|
||||
const wrappedChannels = [];
|
||||
|
||||
@@ -109,7 +109,7 @@ export default class SwitchChannelProvider extends Provider {
|
||||
|
||||
// Dispatch suggestions for local data
|
||||
const channels = getChannelsInCurrentTeam(getState()).concat(getGroupChannels(getState()));
|
||||
const users = Object.assign([], searchProfiles(getState(), channelPrefix, true), true);
|
||||
const users = Object.assign([], searchProfiles(getState(), channelPrefix, true));
|
||||
this.formatChannelsAndDispatch(channelPrefix, suggestionId, channels, users, true);
|
||||
|
||||
// Fetch data from the server and dispatch
|
||||
@@ -141,7 +141,7 @@ export default class SwitchChannelProvider extends Provider {
|
||||
return;
|
||||
}
|
||||
|
||||
const users = Object.assign([], searchProfiles(getState(), channelPrefix, true), usersFromServer);
|
||||
const users = Object.assign([], searchProfiles(getState(), channelPrefix, true), usersFromServer.users);
|
||||
const channels = getChannelsInCurrentTeam(getState()).concat(getGroupChannels(getState())).concat(channelsFromServer);
|
||||
this.formatChannelsAndDispatch(channelPrefix, suggestionId, channels, users);
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user