MM-18571: Include self user in autocomplete (#3761)

* Include current user in search

* Removed unused parameters

* Include new text in i18n

* Update autocomplete tests to include current user

* Use FormattedText

* Update app/selectors/autocomplete.test.js

Co-Authored-By: Miguel Alatzar <migbot@users.noreply.github.com>

Co-authored-by: Miguel Alatzar <migbot@users.noreply.github.com>
This commit is contained in:
Chris Dobson 2020-01-09 11:47:40 +00:00 committed by Saturnino Abril
parent 7733a714de
commit ce53a7ac29
5 changed files with 62 additions and 14 deletions

View file

@ -13,6 +13,7 @@ import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone
import {BotTag, GuestTag} from 'app/components/tag';
import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import FormattedText from 'app/components/formatted_text';
export default class AtMentionItem extends PureComponent {
static propTypes = {
@ -25,6 +26,7 @@ export default class AtMentionItem extends PureComponent {
isBot: PropTypes.bool,
theme: PropTypes.object.isRequired,
isLandscape: PropTypes.bool.isRequired,
isCurrentUser: PropTypes.bool.isRequired,
};
static defaultProps = {
@ -47,6 +49,7 @@ export default class AtMentionItem extends PureComponent {
isBot,
isLandscape,
isGuest,
isCurrentUser,
} = this.props;
const style = getStyleFromTheme(theme);
@ -78,6 +81,12 @@ export default class AtMentionItem extends PureComponent {
/>
{hasFullName && <Text style={style.rowUsername}>{' - '}</Text>}
{hasFullName && <Text style={style.rowFullname}>{`${firstName} ${lastName}`}</Text>}
{isCurrentUser &&
<FormattedText
style={style.rowFullname}
id='suggestion.mention.you'
defaultMessage='(you)'
/>}
</TouchableWithFeedback>
);
}

View file

@ -3,7 +3,7 @@
import {connect} from 'react-redux';
import {getUser} from 'mattermost-redux/selectors/entities/users';
import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
@ -23,6 +23,7 @@ function mapStateToProps(state, ownProps) {
isGuest: isGuest(user),
theme: getTheme(state),
isLandscape: isLandscape(state),
isCurrentUser: getCurrentUserId(state) === user.id,
};
}

View file

@ -7,7 +7,7 @@ import {General} from 'mattermost-redux/constants';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {getMyChannels, getOtherChannels} from 'mattermost-redux/selectors/entities/channels';
import {
getCurrentUser, getCurrentUserId, getProfilesInCurrentChannel,
getCurrentUser, getProfilesInCurrentChannel,
getProfilesNotInCurrentChannel, getProfilesInCurrentTeam,
} from 'mattermost-redux/selectors/entities/users';
import {sortChannelsByDisplayName} from 'mattermost-redux/utils/channel_utils';
@ -64,9 +64,8 @@ export const getMatchTermForChannelMention = (() => {
export const filterMembersInChannel = createSelector(
getProfilesInCurrentChannel,
getCurrentUserId,
(state, matchTerm) => matchTerm,
(profilesInChannel, currentUserId, matchTerm) => {
(profilesInChannel, matchTerm) => {
if (matchTerm === null) {
return null;
}
@ -74,12 +73,12 @@ export const filterMembersInChannel = createSelector(
let profiles;
if (matchTerm) {
profiles = profilesInChannel.filter((p) => {
return ((p.id !== currentUserId && p.delete_at === 0) && (
return (p.delete_at === 0 && (
p.username.toLowerCase().includes(matchTerm) || p.email.toLowerCase().includes(matchTerm) ||
p.first_name.toLowerCase().includes(matchTerm) || p.last_name.toLowerCase().includes(matchTerm)));
});
} else {
profiles = profilesInChannel.filter((p) => p.id !== currentUserId && p.delete_at === 0);
profiles = profilesInChannel.filter((p) => p.delete_at === 0);
}
// already sorted
@ -89,9 +88,8 @@ export const filterMembersInChannel = createSelector(
export const filterMembersNotInChannel = createSelector(
getProfilesNotInCurrentChannel,
getCurrentUserId,
(state, matchTerm) => matchTerm,
(profilesNotInChannel, currentUserId, matchTerm) => {
(profilesNotInChannel, matchTerm) => {
if (matchTerm === null) {
return null;
}
@ -104,7 +102,7 @@ export const filterMembersNotInChannel = createSelector(
p.email.toLowerCase().includes(matchTerm) ||
p.first_name.toLowerCase().includes(matchTerm) ||
p.last_name.toLowerCase().includes(matchTerm)
) && (p.delete_at === 0 && p.id !== currentUserId);
) && p.delete_at === 0;
});
} else {
profiles = profilesNotInChannel.filter((p) => p.delete_at === 0);

View file

@ -6,6 +6,7 @@ import assert from 'assert';
import {
getMatchTermForAtMention,
filterMembersNotInChannel,
filterMembersInChannel,
} from 'app/selectors/autocomplete';
/* eslint-disable max-nested-callbacks */
@ -67,24 +68,24 @@ describe('Selectors.Autocomplete', () => {
users: {
currentUserId: 'current-user-id',
profiles: {
'current-user-id': {id: 'current-user-id', username: 'current', delete_at: 0},
'current-user-id': {id: 'current-user-id', username: 'current', first_name: 'Current', last_name: 'User', email: 'current@user.com', delete_at: 0},
'test-user-id': {id: 'test-user-id', username: 'test', first_name: 'Test', last_name: 'User', email: 'test@example.com', delete_at: 0},
'another-user-id': {id: 'another-user-id', username: 'another', first_name: 'Another', last_name: 'One', email: 'another@example.com', delete_at: 0},
'deleted-user-id': {id: 'deleted-user-id', username: 'deleted', first_name: 'Remvoed', last_name: 'Friend', email: 'deleted@example.com', delete_at: 123},
},
profilesNotInChannel: {
'current-channel-id': new Set(['test-user-id', 'another-user-id', 'deleted-user-id']),
'current-channel-id': new Set(['current-user-id', 'test-user-id', 'another-user-id', 'deleted-user-id']),
},
},
},
};
let profiles = filterMembersNotInChannel(state, '');
expect(profiles.length).toBe(2);
expect(profiles.length).toBe(3);
// filter to get the current user, should return zero results
// filter to get the current user, should return single result
profiles = filterMembersNotInChannel(state, 'current');
expect(profiles.length).toBe(0);
expect(profiles.length).toBe(1);
profiles = filterMembersNotInChannel(state, 'tes');
expect(profiles.length).toBe(1);
@ -95,4 +96,42 @@ describe('Selectors.Autocomplete', () => {
profiles = filterMembersNotInChannel(state, 'example');
expect(profiles.length).toBe(2);
});
it('Should return profiles in channel', () => {
const state = {
entities: {
channels: {
currentChannelId: 'current-channel-id',
},
users: {
currentUserId: 'current-user-id',
profiles: {
'current-user-id': {id: 'current-user-id', username: 'current', first_name: 'Current', last_name: 'User', email: 'current@user.com', delete_at: 0},
'test-user-id': {id: 'test-user-id', username: 'test', first_name: 'Test', last_name: 'User', email: 'test@example.com', delete_at: 0},
'another-user-id': {id: 'another-user-id', username: 'another', first_name: 'Another', last_name: 'One', email: 'another@example.com', delete_at: 0},
'deleted-user-id': {id: 'deleted-user-id', username: 'deleted', first_name: 'Removed', last_name: 'Friend', email: 'deleted@example.com', delete_at: 123},
'another-channel-user-id': {id: 'another-channel-user-id', username: 'another_channel', first_name: 'Another', last_name: 'Channel', email: 'another_channel@example.com', delete_at: 0},
},
profilesInChannel: {
'current-channel-id': new Set(['current-user-id', 'test-user-id', 'another-user-id', 'deleted-user-id']),
},
},
},
};
let profiles = filterMembersInChannel(state, '');
expect(profiles).toHaveLength(3);
profiles = filterMembersInChannel(state, 'current');
expect(profiles).toHaveLength(1);
profiles = filterMembersInChannel(state, 'tes');
expect(profiles.length).toBe(1);
profiles = filterMembersInChannel(state, 'one');
expect(profiles.length).toBe(1);
profiles = filterMembersInChannel(state, 'example');
expect(profiles.length).toBe(2);
});
});

View file

@ -562,6 +562,7 @@
"suggestion.mention.morechannels": "Other Channels",
"suggestion.mention.nonmembers": "Not in Channel",
"suggestion.mention.special": "Special Mentions",
"suggestion.mention.you": "(you)",
"suggestion.search.direct": "Direct Messages",
"suggestion.search.private": "Private Channels",
"suggestion.search.public": "Public Channels",