diff --git a/app/components/autocomplete/channel_mention/channel_mention.js b/app/components/autocomplete/channel_mention/channel_mention.js
index 03604bc8f..1d718017a 100644
--- a/app/components/autocomplete/channel_mention/channel_mention.js
+++ b/app/components/autocomplete/channel_mention/channel_mention.js
@@ -34,6 +34,7 @@ export default class ChannelMention extends PureComponent {
onResultCountChange: PropTypes.func.isRequired,
privateChannels: PropTypes.array,
publicChannels: PropTypes.array,
+ directAndGroupMessages: PropTypes.array,
deletedPublicChannels: PropTypes.instanceOf(Set),
requestStatus: PropTypes.string.isRequired,
theme: PropTypes.object.isRequired,
@@ -55,16 +56,15 @@ export default class ChannelMention extends PureComponent {
}
runSearch = debounce((currentTeamId, matchTerm) => {
- if (!isMinimumServerVersion(this.props.serverVersion, 5, 4)) {
- this.props.actions.searchChannels(currentTeamId, matchTerm);
+ if (isMinimumServerVersion(this.props.serverVersion, 5, 4)) {
+ this.props.actions.autocompleteChannelsForSearch(currentTeamId, matchTerm);
return;
}
-
- this.props.actions.autocompleteChannelsForSearch(currentTeamId, matchTerm);
+ this.props.actions.searchChannels(currentTeamId, matchTerm);
}, 200);
componentWillReceiveProps(nextProps) {
- const {isSearch, matchTerm, myChannels, otherChannels, privateChannels, publicChannels, requestStatus, myMembers, deletedPublicChannels} = nextProps;
+ const {isSearch, matchTerm, myChannels, otherChannels, privateChannels, publicChannels, directAndGroupMessages, requestStatus, myMembers, deletedPublicChannels} = nextProps;
if ((matchTerm !== this.props.matchTerm && matchTerm === null) || this.state.mentionComplete) {
// if the term changes but is null or the mention has been completed we render this component as null
@@ -91,6 +91,7 @@ export default class ChannelMention extends PureComponent {
if (requestStatus !== RequestStatus.STARTED &&
(myChannels !== this.props.myChannels || otherChannels !== this.props.otherChannels ||
privateChannels !== this.props.privateChannels || publicChannels !== this.props.publicChannels ||
+ directAndGroupMessages !== this.props.directAndGroupMessages ||
myMembers !== this.props.myMembers || deletedPublicChannels !== this.props.deletedPublicChannels)) {
// if the request is complete and the term is not null we show the autocomplete
const sections = [];
@@ -112,6 +113,15 @@ export default class ChannelMention extends PureComponent {
key: 'privateChannels',
});
}
+
+ if (directAndGroupMessages.length && isMinimumServerVersion(this.props.serverVersion, 5, 4)) {
+ sections.push({
+ id: t('suggestion.search.direct'),
+ defaultMessage: 'Direct Messages',
+ data: directAndGroupMessages,
+ key: 'directAndGroupMessages',
+ });
+ }
} else {
if (myChannels.length) {
sections.push({
diff --git a/app/components/autocomplete/channel_mention/index.js b/app/components/autocomplete/channel_mention/index.js
index 1ac50077a..ab988decd 100644
--- a/app/components/autocomplete/channel_mention/index.js
+++ b/app/components/autocomplete/channel_mention/index.js
@@ -13,6 +13,7 @@ import {
filterOtherChannels,
filterPublicChannels,
filterPrivateChannels,
+ filterDirectAndGroupMessages,
getDeletedPublicChannelsIds,
getMatchTermForChannelMention,
} from 'app/selectors/autocomplete';
@@ -30,9 +31,11 @@ function mapStateToProps(state, ownProps) {
let otherChannels;
let publicChannels;
let privateChannels;
+ let directAndGroupMessages;
if (isSearch) {
publicChannels = filterPublicChannels(state, matchTerm);
privateChannels = filterPrivateChannels(state, matchTerm);
+ directAndGroupMessages = filterDirectAndGroupMessages(state, matchTerm);
} else {
myChannels = filterMyChannels(state, matchTerm);
otherChannels = filterOtherChannels(state, matchTerm);
@@ -45,6 +48,7 @@ function mapStateToProps(state, ownProps) {
publicChannels,
deletedPublicChannels: getDeletedPublicChannelsIds(state),
privateChannels,
+ directAndGroupMessages,
currentTeamId: getCurrentTeamId(state),
matchTerm,
requestStatus: state.requests.channels.getChannels.status,
diff --git a/app/components/autocomplete/channel_mention_item/channel_mention_item.js b/app/components/autocomplete/channel_mention_item/channel_mention_item.js
index a8966a83e..4257a3c72 100644
--- a/app/components/autocomplete/channel_mention_item/channel_mention_item.js
+++ b/app/components/autocomplete/channel_mention_item/channel_mention_item.js
@@ -8,6 +8,8 @@ import {
TouchableOpacity,
} from 'react-native';
+import {General} from 'mattermost-redux/constants';
+
import {makeStyleSheetFromTheme} from 'app/utils/theme';
export default class ChannelMentionItem extends PureComponent {
@@ -15,13 +17,20 @@ export default class ChannelMentionItem extends PureComponent {
channelId: PropTypes.string.isRequired,
displayName: PropTypes.string,
name: PropTypes.string,
+ type: PropTypes.string,
onPress: PropTypes.func.isRequired,
theme: PropTypes.object.isRequired,
};
completeMention = () => {
- const {onPress, name} = this.props;
- onPress(name);
+ const {onPress, displayName, name, type} = this.props;
+ if (type === General.DM_CHANNEL) {
+ onPress('@' + displayName.replace(/ /g, ''));
+ } else if (type === General.DM_CHANNEL) {
+ onPress('@' + displayName.replace(/ /g, ''));
+ } else {
+ onPress(name);
+ }
};
render() {
@@ -30,10 +39,22 @@ export default class ChannelMentionItem extends PureComponent {
displayName,
name,
theme,
+ type,
} = this.props;
const style = getStyleFromTheme(theme);
+ if (type === General.DM_CHANNEL || type === General.GM_CHANNEL) {
+ return (
+
+ {'@' + displayName}
+
+ );
+ }
return (
state.entities.channels.channels,
+ (state, matchTerm) => matchTerm,
+ (myChannels, originalChannels, matchTerm) => {
+ if (matchTerm === null) {
+ return null;
+ }
+
+ let channels;
+ if (matchTerm) {
+ channels = myChannels.filter((c) => {
+ if (c.type === General.DM_CHANNEL && (originalChannels[c.id].display_name.startsWith(matchTerm))) {
+ return true;
+ }
+ if (c.type === General.GM_CHANNEL && (c.name.startsWith(matchTerm) || c.display_name.replace(/ /g, '').startsWith(matchTerm))) {
+ return true;
+ }
+ return false;
+ });
+ } else {
+ channels = myChannels.filter((c) => {
+ return c.type === General.DM_CHANNEL || c.type === General.GM_CHANNEL;
+ });
+ }
+
+ return channels.map((c) => c.id);
+ }
+);
+
export const makeGetMatchTermForDateMention = () => {
let lastMatchTerm = null;
let lastValue;
diff --git a/app/selectors/channel.js b/app/selectors/channel.js
index 9cb6e7366..6c058bccd 100644
--- a/app/selectors/channel.js
+++ b/app/selectors/channel.js
@@ -27,3 +27,13 @@ export const getChannelMembersForDm = createSelector(
return [otherUser];
}
);
+
+export const getChannelNameForSearchAutocomplete = createSelector(
+ (state, channelId) => state.entities.channels.channels[channelId],
+ (channel) => {
+ if (channel && channel.display_name) {
+ return channel.display_name;
+ }
+ return '';
+ }
+);
diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json
index 32c6c5e98..e2bd74a88 100644
--- a/assets/base/i18n/en.json
+++ b/assets/base/i18n/en.json
@@ -481,6 +481,7 @@
"suggestion.mention.morechannels": "Other Channels",
"suggestion.mention.nonmembers": "Not in Channel",
"suggestion.mention.special": "Special Mentions",
+ "suggestion.search.direct": "Direct Messages",
"suggestion.search.private": "Private Channels",
"suggestion.search.public": "Public Channels",
"user.settings.display.clockDisplay": "Clock Display",