MM-11567: Autocomplete search in: for DMs and GMs (#2133)
* MM-11567: Autocomplete search in: for DMs and GMs * More robust behavior on older versions and a fix on autocompletion * Moving get display_name for search to a selector
This commit is contained in:
parent
9668bdc894
commit
9bd89930b7
7 changed files with 88 additions and 8 deletions
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<TouchableOpacity
|
||||
key={channelId}
|
||||
onPress={this.completeMention}
|
||||
style={style.row}
|
||||
>
|
||||
<Text style={style.rowDisplayName}>{'@' + displayName}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={channelId}
|
||||
|
|
|
|||
|
|
@ -7,14 +7,18 @@ import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
|||
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {getChannelNameForSearchAutocomplete} from 'app/selectors/channel';
|
||||
|
||||
import ChannelMentionItem from './channel_mention_item';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
const channel = getChannel(state, ownProps.channelId);
|
||||
const displayName = getChannelNameForSearchAutocomplete(state, ownProps.channelId);
|
||||
|
||||
return {
|
||||
displayName: channel.display_name,
|
||||
displayName,
|
||||
name: channel.name,
|
||||
type: channel.type,
|
||||
theme: getTheme(state),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,6 +231,36 @@ export const filterPrivateChannels = createSelector(
|
|||
}
|
||||
);
|
||||
|
||||
export const filterDirectAndGroupMessages = createSelector(
|
||||
getMyChannels,
|
||||
(state) => 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;
|
||||
|
|
|
|||
|
|
@ -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 '';
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue