diff --git a/app/ui-flextab/client/tabs/membersList.html b/app/ui-flextab/client/tabs/membersList.html index e9f0fc82874..6a1ada15a98 100644 --- a/app/ui-flextab/client/tabs/membersList.html +++ b/app/ui-flextab/client/tabs/membersList.html @@ -22,30 +22,30 @@ {{#unless loading}} -
-
{{{_ "Showing_online_users" total_showing=totalShowing online=totalOnline total=total}}}
-
+
+
{{{_ "Showing_online_users" total_showing=totalShowing online=totalOnline total=total}}}
+
{{/unless}}
- {{#if loading}} - {{> loading}} - {{else}} - - {{/if}} + {{#if loading}} + {{> loading}} + {{else}} + + {{/if}} {{#if hasMore}} - + {{/if}}
diff --git a/app/ui-flextab/client/tabs/membersList.js b/app/ui-flextab/client/tabs/membersList.js index 82d3e7ff599..d3f667cb830 100644 --- a/app/ui-flextab/client/tabs/membersList.js +++ b/app/ui-flextab/client/tabs/membersList.js @@ -8,7 +8,6 @@ import { ChatRoom, Subscriptions } from '../../../models'; import { settings } from '../../../settings'; import { t, isRtl, handleError, roomTypes } from '../../../utils'; import { WebRTC } from '../../../webrtc/client'; -import _ from 'underscore'; import { getActions } from './userActions'; Template.membersList.helpers({ @@ -30,14 +29,6 @@ Template.membersList.helpers({ return ChatRoom.findOne(this.rid, { reactive: false }).t === 'd'; }, - seeAll() { - if (Template.instance().showAllUsers.get()) { - return t('Show_only_online'); - } else { - return t('Show_all'); - } - }, - roomUsers() { const onlineUsers = RoomManager.onlineUsers.get(); const roomUsers = Template.instance().users.get(); @@ -83,33 +74,21 @@ Template.membersList.helpers({ }; }); - if (settings.get('UI_Use_Real_Name')) { - users = _.sortBy(users, (u) => u.user.name); - } else { - users = _.sortBy(users, (u) => u.user.username); - } - // show online users first. - // sortBy is stable, so we can do this - users = _.sortBy(users, (u) => u.status === 'offline'); - - let hasMore = undefined; - const usersLimit = Template.instance().usersLimit.get(); - if (usersLimit) { - hasMore = users.length > usersLimit; - users = _.first(users, usersLimit) || []; - } - const totalShowing = users.length; + const usersTotal = users.length; + const { total, loading, usersLimit, loadingMore } = Template.instance(); + const hasMore = loadingMore.get() || (usersTotal < total.get() && usersLimit.get() <= usersTotal); + const totalShowing = usersTotal; - const ret = { + return { _id: this.rid, - total: Template.instance().total.get(), + total: total.get(), totalShowing, - loading: Template.instance().loading.get(), + loading: loading.get(), totalOnline, users, hasMore, + rid: this.rid, }; - return ret; }, canAddUser() { @@ -171,7 +150,12 @@ Template.membersList.helpers({ } return this.user.username; - } }); + }, + + loadingMore() { + return Template.instance().loadingMore.get(); + }, +}); Template.membersList.events({ 'click .js-add'() { @@ -189,15 +173,7 @@ Template.membersList.events({ 'change .js-type'(e, instance) { const seeAll = instance.showAllUsers.get(); instance.showAllUsers.set(!seeAll); - }, - 'click .see-all'(e, instance) { - const seeAll = instance.showAllUsers.get(); - instance.showAllUsers.set(!seeAll); - - if (!seeAll) { - return instance.usersLimit.set(100); - } - + instance.usersLimit.set(100); }, 'click .js-more'(e, instance) { e.currentTarget.parentElement.classList.add('active'); @@ -269,7 +245,21 @@ Template.membersList.events({ }, 'click .show-more-users'(e, instance) { - return instance.usersLimit.set(instance.usersLimit.get() + 100); + const { showAllUsers, usersLimit, users, total, loadingMore } = instance; + + loadingMore.set(true); + Meteor.call('getUsersOfRoom', this.rid, showAllUsers.get(), { limit: usersLimit.get() + 100, skip: 0 }, (error, result) => { + if (error) { + console.error(error); + loadingMore.set(false); + return; + } + users.set(result.records); + total.set(result.total); + loadingMore.set(false); + }); + + usersLimit.set(usersLimit.get() + 100); }, }); @@ -284,20 +274,24 @@ Template.membersList.onCreated(function() { this.users = new ReactiveVar([]); this.total = new ReactiveVar; this.loading = new ReactiveVar(true); + this.loadingMore = new ReactiveVar(false); this.tabBar = Template.instance().tabBar; Tracker.autorun(() => { if (this.data.rid == null) { return; } this.loading.set(true); - return Meteor.call('getUsersOfRoom', this.data.rid, this.showAllUsers.get(), (error, users) => { + return Meteor.call('getUsersOfRoom', this.data.rid, this.showAllUsers.get(), { limit: 100, skip: 0 }, (error, users) => { + if (error) { + console.error(error); + return this.loading.set(false); + } + this.users.set(users.records); this.total.set(users.total); return this.loading.set(false); - } - ); - } - ); + }); + }); this.clearUserDetail = () => { this.showDetail.set(false); diff --git a/server/methods/getUsersOfRoom.js b/server/methods/getUsersOfRoom.js index e999182c455..02d4524f3e7 100644 --- a/server/methods/getUsersOfRoom.js +++ b/server/methods/getUsersOfRoom.js @@ -1,9 +1,48 @@ import { Meteor } from 'meteor/meteor'; import { Subscriptions } from '../../app/models'; import { hasPermission } from '../../app/authorization'; +import { settings } from '../../app/settings'; + +function findUsers({ rid, status, skip, limit }) { + return Subscriptions.model.rawCollection().aggregate([ + { $match: { rid } }, + { + $lookup: + { + from: 'users', + localField: 'u._id', + foreignField: '_id', + as: 'u', + }, + }, + { + $project: { + 'u._id': 1, + 'u.name': 1, + 'u.username': 1, + 'u.status': 1, + }, + }, + ...(status ? [{ $match: { 'u.status': status } }] : []), + { + $sort: { + [settings.get('UI_Use_Real_Name') ? 'u.name' : 'u.username']: 1, + }, + }, + ...(skip > 0 ? [{ $skip: skip }] : []), + ...(limit > 0 ? [{ $limit: limit }] : []), + { + $project: { + _id: { $arrayElemAt: ['$u._id', 0] }, + name: { $arrayElemAt: ['$u.name', 0] }, + username: { $arrayElemAt: ['$u.username', 0] }, + }, + }, + ]).toArray(); +} Meteor.methods({ - async getUsersOfRoom(rid, showAll) { + async getUsersOfRoom(rid, showAll, { limit, skip } = {}) { const userId = Meteor.userId(); if (!userId) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getUsersOfRoom' }); @@ -18,38 +57,26 @@ Meteor.methods({ throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getUsersOfRoom' }); } - const subscriptions = Subscriptions.findByRoomIdWhenUsernameExists(rid); + const total = Subscriptions.findByRoomIdWhenUsernameExists(rid).count(); + const users = await findUsers({ rid, status: { $ne: 'offline' }, limit, skip }); + + if (showAll && users.length < limit) { + const offlineUsers = await findUsers({ + rid, + status: { $eq: 'offline' }, + limit: limit - users.length, + skip, + }); + + return { + total, + records: users.concat(offlineUsers), + }; + } return { - total: subscriptions.count(), - records: await Subscriptions.model.rawCollection().aggregate([ - { $match: { rid } }, - { - $lookup: - { - from: 'users', - localField: 'u._id', - foreignField: '_id', - as: 'u', - }, - }, - { - $project: { - 'u._id': 1, - 'u.name': 1, - 'u.username': 1, - 'u.status': 1, - }, - }, - ...(showAll ? [] : [{ $match: { 'u.status': { $in: ['online', 'away', 'busy'] } } }]), - { - $project: { - _id: { $arrayElemAt: ['$u._id', 0] }, - name: { $arrayElemAt: ['$u.name', 0] }, - username: { $arrayElemAt: ['$u.username', 0] }, - }, - }, - ]).toArray(), + total, + records: users, }; }, });