From a65ba8469703e060f61f3ded1c6b9a70902d4c23 Mon Sep 17 00:00:00 2001 From: Scott Bishel Date: Mon, 28 Oct 2024 12:41:55 -0600 Subject: [PATCH] filter remote users if remote dms not supported (#28953) * filter remote users if remote dms not supported * move filter to selectors * lint fix * add test * add filter to search --- .../more_direct_channels/index.test.tsx | 91 +++++++++++++++++++ .../components/more_direct_channels/index.ts | 18 ++-- .../src/selectors/entities/users.test.ts | 83 ++++++++++++++++- .../src/selectors/entities/users.ts | 23 +++-- 4 files changed, 198 insertions(+), 17 deletions(-) create mode 100644 webapp/channels/src/components/more_direct_channels/index.test.tsx diff --git a/webapp/channels/src/components/more_direct_channels/index.test.tsx b/webapp/channels/src/components/more_direct_channels/index.test.tsx new file mode 100644 index 0000000000..6300b855aa --- /dev/null +++ b/webapp/channels/src/components/more_direct_channels/index.test.tsx @@ -0,0 +1,91 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {TestHelper} from 'utils/test_helper'; + +import type {GlobalState} from 'types/store'; + +import {makeMapStateToProps} from './index'; + +describe('mapStateToProps', () => { + const mockedUser = TestHelper.getUserMock(); + const currentTeamId = 'team-id'; + const currentUserId = 'user-id'; + + const initialState = { + entities: { + users: { + currentUserId, + profiles: { + mockedUser_1: { + ...mockedUser, + id: 'mockedUser_1', + remote_id: 'remote', + }, + mockedUser_2: { + ...mockedUser, + id: 'mockedUser_2', + remote_id: 'remote', + }, + mockedUser_3: { + ...mockedUser, + id: 'mockedUser_3', + }, + mockedUser_4: { + ...mockedUser, + id: 'mockedUser_4', + }, + }, + profilesInTeam: { + [currentTeamId]: [ + 'mockedUser_1', + 'mockedUser_2', + 'mockedUser_3', + 'mockedUser_4', + ], + }, + }, + teams: { + currentTeamId, + teams: { + [currentTeamId]: { + id: currentTeamId, + }, + }, + }, + general: { + config: { + FeatureFlagEnableSharedChannelsDMs: 'false', + }, + }, + }, + views: { + search: { + modalSearch: '', + }, + }, + } as unknown as GlobalState; + + test('should not include remote users', () => { + const f = makeMapStateToProps(); + const props = f(initialState, {isExistingChannel: false}); + expect(props.users.length).toEqual(2); + }); + + test('should include remote users', () => { + const testState = { + ...initialState, + entities: { + ...initialState.entities, + general: { + config: { + FeatureFlagEnableSharedChannelsDMs: 'true', + }, + }, + }, + } as unknown as GlobalState; + const f = makeMapStateToProps(); + const props = f(testState, {isExistingChannel: false}); + expect(props.users.length).toEqual(4); + }); +}); diff --git a/webapp/channels/src/components/more_direct_channels/index.ts b/webapp/channels/src/components/more_direct_channels/index.ts index a3e4b5dc89..4bdfb3c678 100644 --- a/webapp/channels/src/components/more_direct_channels/index.ts +++ b/webapp/channels/src/components/more_direct_channels/index.ts @@ -14,7 +14,7 @@ import { getTotalUsersStats, searchProfiles, } from 'mattermost-redux/actions/users'; -import {getConfig} from 'mattermost-redux/selectors/entities/general'; +import {getConfig, getFeatureFlagValue} from 'mattermost-redux/selectors/entities/general'; import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; import { getCurrentUserId, @@ -39,7 +39,7 @@ type OwnProps = { isExistingChannel: boolean; } -const makeMapStateToProps = () => { +export const makeMapStateToProps = () => { const searchProfilesStartingWithTerm = makeSearchProfilesStartingWithTerm(); return (state: GlobalState, ownProps: OwnProps) => { @@ -54,17 +54,23 @@ const makeMapStateToProps = () => { const searchTerm = state.views.search.modalSearch; + let filters; + const enableSharedChannelsDMs = getFeatureFlagValue(state, 'EnableSharedChannelsDMs') === 'true'; + if (!enableSharedChannelsDMs) { + filters = {exclude_remote: true}; + } + let users: UserProfile[]; if (searchTerm) { if (restrictDirectMessage === 'any') { - users = searchProfilesStartingWithTerm(state, searchTerm, false); + users = searchProfilesStartingWithTerm(state, searchTerm, false, filters); } else { - users = searchProfilesInCurrentTeam(state, searchTerm, false); + users = searchProfilesInCurrentTeam(state, searchTerm, false, filters); } } else if (restrictDirectMessage === 'any') { - users = selectProfiles(state); + users = selectProfiles(state, filters); } else { - users = getProfilesInCurrentTeam(state); + users = getProfilesInCurrentTeam(state, filters); } const team = getCurrentTeam(state); 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 f0cc3d02d4..9485f6f710 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 @@ -293,10 +293,87 @@ describe('Selectors.Users', () => { }); }); - it('getProfilesInCurrentTeam', () => { - const users = [user1, user2, user7].sort(sortByUsername); - expect(Selectors.getProfilesInCurrentTeam(testState)).toEqual(users); + describe('getProfilesInCurrentTeam', () => { + it('getProfilesInCurrentTeam', () => { + const users = [user1, user2, user7].sort(sortByUsername); + expect(Selectors.getProfilesInCurrentTeam(testState)).toEqual(users); + }); + + const remoteUser = TestHelper.fakeUserWithId(); + remoteUser.remote_id = 'remoteID'; + const state = { + ...testState, + entities: { + ...testState.entities, + users: { + ...testState.entities.users, + profiles: { + ...testState.entities.users.profiles, + [remoteUser.id]: remoteUser, + }, + profilesInTeam: { + ...testState.entities.users.profilesInTeam, + [team1.id]: new Set([...testState.entities.users.profilesInTeam[team1.id], remoteUser.id]), + }, + }, + teams: { + ...testState.teams, + currentTeamId: team1.id, + membersInTeam, + }, + }, + }; + + it('getProfilesInCurrentTeam include remote', () => { + const users = [user1, user2, user7, remoteUser].sort(sortByUsername); + expect(Selectors.getProfilesInCurrentTeam(state)).toEqual(users); + }); + + it('getProfilesInCurrentTeam with remote filter', () => { + const users = [user1, user2, user7].sort(sortByUsername); + const filters = {exclude_remote: true}; + expect(Selectors.getProfilesInCurrentTeam(state, filters)).toEqual(users); + }); }); + + describe('getProfilesNotInCurrentChannel', () => { + it('getProfilesNotInCurrentChannel', () => { + const users = [user2, user3].sort(sortByUsername); + expect(Selectors.getProfilesNotInCurrentChannel(testState)).toEqual(users); + }); + + const remoteUser = TestHelper.fakeUserWithId(); + remoteUser.remote_id = 'remoteID'; + const state = { + ...testState, + entities: { + ...testState.entities, + users: { + ...testState.entities.users, + profiles: { + ...testState.entities.users.profiles, + [remoteUser.id]: remoteUser, + }, + profilesNotInChannel: { + ...testState.entities.users.profilesNotInChannel, + [channel1.id]: new Set([...testState.entities.users.profilesNotInChannel[channel1.id], remoteUser.id]), + }, + }, + }, + }; + + it('getProfilesNotInCurrentChannel include remote', () => { + const users = [user2, user3, remoteUser].sort(sortByUsername); + expect(Selectors.getProfilesNotInCurrentChannel(state)).toEqual(users); + }); + + it('getProfilesNotInCurrentChannel with remote filter', () => { + const users = [user2, user3].sort(sortByUsername); + const filters = {exclude_remote: true}; + expect(Selectors.getProfilesNotInCurrentChannel(state, filters)).toEqual(users); + }); + }); + describe('getProfilesInTeam', () => { it('getProfilesInTeam without filter', () => { const users = [user1, user2, user7].sort(sortByUsername); 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 e1e14e9ebe..a8360bcc96 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 @@ -49,6 +49,7 @@ export type Filters = { channel_roles?: string[]; team_roles?: string[]; exclude_bots?: boolean; + exclude_remote?: boolean; }; export function getUserIdsInChannels(state: GlobalState): RelationOneToManyUnique { @@ -334,6 +335,10 @@ export function filterProfiles(profiles: IDMappedObjects, filters?: users = users.filter((user) => user.delete_at === 0); } + if (filters.exclude_remote) { + users = users.filter((user) => !user.remote_id); + } + return users.reduce((acc, user) => { acc[user.id] = user; return acc; @@ -371,21 +376,23 @@ export const getActiveProfilesInCurrentChannelWithoutSorting: (state: GlobalStat }, ); -export const getProfilesNotInCurrentChannel: (state: GlobalState) => UserProfile[] = createSelector( +export const getProfilesNotInCurrentChannel: (state: GlobalState, filters?: Filters) => UserProfile[] = createSelector( 'getProfilesNotInCurrentChannel', getUsers, getProfileSetNotInCurrentChannel, - (profiles, notInCurrentChannelProfileSet) => { - return sortAndInjectProfiles(profiles, notInCurrentChannelProfileSet); + (state: GlobalState, filters?: Filters) => filters, + (profiles, notInCurrentChannelProfileSet, filters) => { + return sortAndInjectProfiles(filterProfiles(profiles, filters), notInCurrentChannelProfileSet); }, ); -export const getProfilesInCurrentTeam: (state: GlobalState) => UserProfile[] = createSelector( +export const getProfilesInCurrentTeam: (state: GlobalState, filters?: Filters) => UserProfile[] = createSelector( 'getProfilesInCurrentTeam', getUsers, getProfileSetInCurrentTeam, - (profiles, currentTeamProfileSet) => { - return sortAndInjectProfiles(profiles, currentTeamProfileSet); + (state: GlobalState, filters?: Filters) => filters, + (profiles, currentTeamProfileSet, filters) => { + return sortAndInjectProfiles(filterProfiles(profiles, filters), currentTeamProfileSet); }, ); @@ -524,8 +531,8 @@ export function searchProfilesNotInCurrentChannel(state: GlobalState, term: stri return profiles; } -export function searchProfilesInCurrentTeam(state: GlobalState, term: string, skipCurrent = false): UserProfile[] { - const profiles = filterProfilesStartingWithTerm(getProfilesInCurrentTeam(state), term); +export function searchProfilesInCurrentTeam(state: GlobalState, term: string, skipCurrent = false, filters?: Filters): UserProfile[] { + const profiles = filterProfilesStartingWithTerm(getProfilesInCurrentTeam(state, filters), term); if (skipCurrent) { removeCurrentUserFromList(profiles, getCurrentUserId(state)); }