From 8bfa1ff09ff3d593cb7c98786d719d2bc42d3851 Mon Sep 17 00:00:00 2001 From: Seongbin Hong <37045096+VertexToEdge@users.noreply.github.com> Date: Wed, 25 Mar 2026 04:45:59 +0900 Subject: [PATCH] fix: allow substring matching when searching channel members (#35017) * fix: allow substring matching when searching channel members * fix lint error --------- Co-authored-by: Mattermost Build --- .../src/selectors/entities/users.test.ts | 28 ++++++++++++------- .../src/selectors/entities/users.ts | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/users.test.ts b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/users.test.ts index 73594136ece..bafb796ceff 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/users.test.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/users.test.ts @@ -41,6 +41,8 @@ describe('Selectors.Users', () => { const user7 = TestHelper.fakeUserWithId(); user7.delete_at = 1; user7.roles = 'system_admin system_user'; + const user8 = TestHelper.fakeUserWithId(); + user8.nickname = 'vertex_to_edge'; const profiles: Record = {}; profiles[user1.id] = user1; profiles[user2.id] = user2; @@ -49,6 +51,7 @@ describe('Selectors.Users', () => { profiles[user5.id] = user5; profiles[user6.id] = user6; profiles[user7.id] = user7; + profiles[user8.id] = user8; const profilesInTeam: Record> = {}; profilesInTeam[team1.id] = new Set([user1.id, user2.id, user7.id]); @@ -75,7 +78,7 @@ describe('Selectors.Users', () => { profilesNotInTeam[team1.id] = new Set([user3.id, user4.id]); const profilesInChannel: Record> = {}; - profilesInChannel[channel1.id] = new Set([user1.id]); + profilesInChannel[channel1.id] = new Set([user1.id, user8.id]); profilesInChannel[channel2.id] = new Set([user1.id, user2.id]); const membersInChannel: Record> = {}; @@ -85,6 +88,10 @@ describe('Selectors.Users', () => { scheme_user: true, scheme_admin: true, }; + membersInChannel[channel1.id][user8.id] = { + ...TestHelper.fakeChannelMember(user8.id, channel1.id), + scheme_user: true, + }; membersInChannel[channel2.id] = {}; membersInChannel[channel2.id][user1.id] = { ...TestHelper.fakeChannelMember(user1.id, channel2.id), @@ -264,7 +271,7 @@ describe('Selectors.Users', () => { describe('getProfiles', () => { it('getProfiles without filter', () => { - const users = [user1, user2, user3, user4, user5, user6, user7].sort(sortByUsername); + const users = [user1, user2, user3, user4, user5, user6, user7, user8].sort(sortByUsername); expect(Selectors.getProfiles(testState)).toEqual(users); }); @@ -277,7 +284,7 @@ describe('Selectors.Users', () => { expect(Selectors.getProfiles(testState, {inactive: true})).toEqual(users); }); it('getProfiles with active', () => { - const users = [user1, user3, user4, user5, user6].sort(sortByUsername); + const users = [user1, user3, user4, user5, user6, user8].sort(sortByUsername); expect(Selectors.getProfiles(testState, {active: true})).toEqual(users); }); it('getProfiles with multiple filters', () => { @@ -465,6 +472,7 @@ describe('Selectors.Users', () => { expect(Selectors.searchProfilesInCurrentChannel(testState, user1.username)).toEqual([user1]); expect(Selectors.searchProfilesInCurrentChannel(testState, 'engineer at mattermost')).toEqual([user1]); expect(Selectors.searchProfilesInCurrentChannel(testState, user1.username, true)).toEqual([]); + expect(Selectors.searchProfilesInCurrentChannel(testState, 'to_edge', true)).toEqual([user8]); }); it('searchProfilesNotInCurrentChannel', () => { @@ -525,7 +533,7 @@ describe('Selectors.Users', () => { it('makeGetProfilesInChannel', () => { const getProfilesInChannel = Selectors.makeGetProfilesInChannel(); - expect(getProfilesInChannel(testState, channel1.id)).toEqual([user1]); + expect(getProfilesInChannel(testState, channel1.id)).toEqual([user1, user8]); const users = [user1, user2].sort(sortByUsername); expect(getProfilesInChannel(testState, channel2.id)).toEqual(users); @@ -555,8 +563,8 @@ describe('Selectors.Users', () => { }; const getProfilesInChannel = Selectors.makeGetProfilesInChannel(); - expect(getProfilesInChannel(state, channel1.id)).toEqual([user1]); - expect(getProfilesInChannel(state, channel1.id, {})).toEqual([user1]); + expect(getProfilesInChannel(state, channel1.id)).toEqual([user1, user8]); + expect(getProfilesInChannel(state, channel1.id, {})).toEqual([user1, user8]); }); it('makeGetProfilesNotInChannel', () => { @@ -874,7 +882,7 @@ describe('Selectors.Users', () => { describe('filterProfiles', () => { it('no filter, return all users', () => { - expect(Object.keys(Selectors.filterProfiles(profiles)).length).toEqual(7); + expect(Object.keys(Selectors.filterProfiles(profiles)).length).toEqual(8); }); it('filter role', () => { @@ -901,7 +909,7 @@ describe('Selectors.Users', () => { const filter = { exclude_roles: ['system_admin'], }; - expect(Object.keys(Selectors.filterProfiles(profiles, filter)).length).toEqual(4); + expect(Object.keys(Selectors.filterProfiles(profiles, filter)).length).toEqual(5); }); it('exclude bots', () => { @@ -920,7 +928,7 @@ describe('Selectors.Users', () => { ...profiles, [botUser.id]: botUser, }; - expect(Object.keys(Selectors.filterProfiles(newProfiles, filter)).length).toEqual(7); + expect(Object.keys(Selectors.filterProfiles(newProfiles, filter)).length).toEqual(8); }); it('filter inactive', () => { @@ -934,7 +942,7 @@ describe('Selectors.Users', () => { const filter = { active: true, }; - expect(Object.keys(Selectors.filterProfiles(profiles, filter)).length).toEqual(5); + expect(Object.keys(Selectors.filterProfiles(profiles, filter)).length).toEqual(6); }); }); }); diff --git a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/users.ts b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/users.ts index eb8faafeebc..319cac0ac9a 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/users.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/users.ts @@ -510,7 +510,7 @@ export function makeSearchProfilesInChannel() { } export function searchProfilesInCurrentChannel(state: GlobalState, term: string, skipCurrent = false): UserProfile[] { - const profiles = filterProfilesStartingWithTerm(getProfilesInCurrentChannel(state), term); + const profiles = filterProfilesMatchingWithTerm(getProfilesInCurrentChannel(state), term); if (skipCurrent) { removeCurrentUserFromList(profiles, getCurrentUserId(state));