diff --git a/app/models/server/models/Rooms.js b/app/models/server/models/Rooms.js index fdfa62320099..8455d1a5c27f 100644 --- a/app/models/server/models/Rooms.js +++ b/app/models/server/models/Rooms.js @@ -552,38 +552,40 @@ export class Rooms extends Base { return this._db.find(query, options); } - findByNameOrFNameAndTypeIncludingTeamRooms(name, type, teamIds, options) { + findByNameOrFNameAndRoomIdsIncludingTeamRooms(text, teamIds, roomIds, options) { + const searchTerm = text && new RegExp(text, 'i'); + const query = { - t: type, - teamMain: { - $exists: false, - }, $and: [ + { teamMain: { $exists: false } }, + { prid: { $exists: false } }, { $or: [ { - teamId: { - $exists: false, - }, + t: 'c', + teamId: { $exists: false }, }, { - teamId: { - $in: teamIds, - }, + t: 'c', + teamId: { $in: teamIds }, }, + ...roomIds?.length > 0 ? [{ + _id: { + $in: roomIds, + }, + }] : [], ], }, - { + ...searchTerm ? [{ $or: [{ - name, + name: searchTerm, }, { - fname: name, + fname: searchTerm, }], - }, + }] : [], ], }; - // do not use cache return this._db.find(query, options); } @@ -603,7 +605,7 @@ export class Rooms extends Base { }; if (text) { - const regex = new RegExp(s.trim(escapeRegExp(text)), 'i'); + const regex = new RegExp(text, 'i'); query.$and.push({ $or: [{ diff --git a/client/views/directory/ChannelsTable.js b/client/views/directory/ChannelsTable.js index 9c817ae378cf..842a880acb14 100644 --- a/client/views/directory/ChannelsTable.js +++ b/client/views/directory/ChannelsTable.js @@ -101,16 +101,17 @@ function ChannelsTable() { ); const channelRoute = useRoute('channel'); + const groupsRoute = useRoute('group'); const { value: data = { result: [] } } = useEndpointData('directory', query); const onClick = useMemo( - () => (name) => (e) => { + () => (name, type) => (e) => { if (e.type === 'click' || e.key === 'Enter') { - channelRoute.push({ name }); + type === 'c' ? channelRoute.push({ name }) : groupsRoute.push({ name }); } }, - [channelRoute], + [channelRoute, groupsRoute], ); const formatDate = useFormatDate(); @@ -122,8 +123,8 @@ function ChannelsTable() { return ( { +const getChannelsAndGroups = (user, canViewAnon, searchTerm, sort, pagination) => { if ((!user && !canViewAnon) || (user && !hasPermission(user._id, 'view-c-room'))) { return; } const teams = Promise.await(Team.getAllPublicTeams()); - const teamIds = teams.map(({ _id }) => _id); + const publicTeamIds = teams.map(({ _id }) => _id); - const result = Rooms.findByNameOrFNameAndTypeIncludingTeamRooms(searchTerm, 'c', teamIds, { + const userTeamsIds = Promise.await(Team.listTeamsBySubscriberUserId(user._id, { projection: { teamId: 1 } }))?.map(({ teamId }) => teamId) || []; + const userRooms = user.__rooms; + + const cursor = Rooms.findByNameOrFNameAndRoomIdsIncludingTeamRooms(searchTerm, [...userTeamsIds, ...publicTeamIds], userRooms, { ...pagination, sort: { featured: -1, @@ -74,11 +77,15 @@ const getChannels = (user, canViewAnon, searchTerm, sort, pagination) => { teamId: 1, }, }); + const total = cursor.count(); // count ignores the `skip` and `limit` options + const result = cursor.fetch(); - const total = result.count(); // count ignores the `skip` and `limit` options - const results = result.fetch().map((room) => { + const teamIds = result.filter(({ teamId }) => teamId).map(({ teamId }) => teamId); + const teamsMains = Promise.await(Team.listByIds([...new Set(teamIds)], { projection: { _id: 1, name: 1 } })); + + const results = result.map((room) => { if (room.teamId) { - const team = teams.find((team) => team._id === room.teamId); + const team = teamsMains.find((mainRoom) => mainRoom._id === room.teamId); if (team) { room.belongsTo = team.name; } @@ -202,7 +209,7 @@ const getUsers = (user, text, workspace, sort, pagination) => { Meteor.methods({ browseChannels({ text = '', workspace = '', type = 'channels', sortBy = 'name', sortDirection = 'asc', page, offset, limit = 10 }) { - const regex = new RegExp(s.trim(escapeRegExp(text)), 'i'); + const searchTerm = s.trim(escapeRegExp(text)); if (!['channels', 'users', 'teams'].includes(type) || !['asc', 'desc'].includes(sortDirection) || ((!page && page !== 0) && (!offset && offset !== 0))) { return; @@ -230,9 +237,9 @@ Meteor.methods({ switch (type) { case 'channels': - return getChannels(user, canViewAnonymous, regex, sortChannels(sortBy, sortDirection), pagination); + return getChannelsAndGroups(user, canViewAnonymous, searchTerm, sortChannels(sortBy, sortDirection), pagination); case 'teams': - return getTeams(user, text, sortChannels(sortBy, sortDirection), pagination); + return getTeams(user, searchTerm, sortChannels(sortBy, sortDirection), pagination); case 'users': return getUsers(user, text, workspace, sortUsers(sortBy, sortDirection), pagination); default: diff --git a/server/sdk/types/ITeamService.ts b/server/sdk/types/ITeamService.ts index c301b966c564..8709ae0c452c 100644 --- a/server/sdk/types/ITeamService.ts +++ b/server/sdk/types/ITeamService.ts @@ -82,4 +82,5 @@ export interface ITeamService { getAllPublicTeams(options: FindOneOptions): Promise>; getMembersByTeamIds(teamIds: Array, options: FindOneOptions): Promise>; update(uid: string, teamId: string, updateData: ITeamUpdateData): Promise; + listTeamsBySubscriberUserId(uid: string, options?: FindOneOptions): Promise | null>; }