diff --git a/packages/rocketchat-api/server/api.js b/packages/rocketchat-api/server/api.js index df2e1a9dd72..7350271ee1b 100644 --- a/packages/rocketchat-api/server/api.js +++ b/packages/rocketchat-api/server/api.js @@ -222,15 +222,20 @@ class API extends Restivus { post() { const args = loginCompatibility(this.bodyParams); + console.log('args ->', args); + const invocation = new DDPCommon.MethodInvocation({ connection: { close() {} } }); + console.log('invocation ->', invocation); + let auth; try { auth = DDP._CurrentInvocation.withValue(invocation, () => Meteor.call('login', args)); + console.log('UTH ->', auth); } catch (error) { let e = error; if (error.reason === 'User not found') { diff --git a/packages/rocketchat-lib/lib/roomTypes/conversation.js b/packages/rocketchat-lib/lib/roomTypes/conversation.js index 009dbf59ccb..6f7caa07bdc 100644 --- a/packages/rocketchat-lib/lib/roomTypes/conversation.js +++ b/packages/rocketchat-lib/lib/roomTypes/conversation.js @@ -3,7 +3,7 @@ import { RoomTypeConfig } from '../RoomTypeConfig'; export class ConversationRoomType extends RoomTypeConfig { constructor() { super({ - identifier: 'activity', + identifier: 'merged', order: 30, label: 'Conversations' }); @@ -11,6 +11,6 @@ export class ConversationRoomType extends RoomTypeConfig { condition() { const user = Meteor.user(); - return RocketChat.getUserPreference(user, 'roomsListExhibitionMode') === 'activity'; + return RocketChat.getUserPreference(user, 'mergeChannels'); } } diff --git a/packages/rocketchat-lib/lib/roomTypes/direct.js b/packages/rocketchat-lib/lib/roomTypes/direct.js index 3a8c6c8455f..44078e0e919 100644 --- a/packages/rocketchat-lib/lib/roomTypes/direct.js +++ b/packages/rocketchat-lib/lib/roomTypes/direct.js @@ -62,8 +62,8 @@ export class DirectMessageRoomType extends RoomTypeConfig { condition() { const user = Meteor.user(); - const roomsListExhibitionMode = RocketChat.getUserPreference(user, 'roomsListExhibitionMode'); - return !roomsListExhibitionMode || ['unread', 'category'].includes(roomsListExhibitionMode) && RocketChat.authz.hasAtLeastOnePermission(['view-d-room', 'view-joined-room']); + const mergeChannels = RocketChat.getUserPreference(user, 'mergeChannels'); + return !mergeChannels && RocketChat.authz.hasAtLeastOnePermission(['view-d-room', 'view-joined-room']); } getUserStatus(roomId) { diff --git a/packages/rocketchat-lib/lib/roomTypes/favorite.js b/packages/rocketchat-lib/lib/roomTypes/favorite.js index 55e061547d7..2b927c0767a 100644 --- a/packages/rocketchat-lib/lib/roomTypes/favorite.js +++ b/packages/rocketchat-lib/lib/roomTypes/favorite.js @@ -10,4 +10,8 @@ export class FavoriteRoomType extends RoomTypeConfig { label: 'Favorites' }); } + condition() { + const user = Meteor.user(); + return RocketChat.settings.get('Favorite_Rooms') && RocketChat.getUserPreference(user, 'sidebarShowFavorites'); + } } diff --git a/packages/rocketchat-lib/lib/roomTypes/index.js b/packages/rocketchat-lib/lib/roomTypes/index.js index 739421c89b3..4c0fd94d732 100644 --- a/packages/rocketchat-lib/lib/roomTypes/index.js +++ b/packages/rocketchat-lib/lib/roomTypes/index.js @@ -1,4 +1,3 @@ -import { ChannelsRoomType } from './channels'; import { ConversationRoomType } from './conversation'; import { DirectMessageRoomType } from './direct'; import { FavoriteRoomType } from './favorite'; @@ -7,7 +6,6 @@ import { PublicRoomType } from './public'; import { UnreadRoomType } from './unread'; export { - ChannelsRoomType, ConversationRoomType, DirectMessageRoomType, FavoriteRoomType, diff --git a/packages/rocketchat-lib/lib/roomTypes/private.js b/packages/rocketchat-lib/lib/roomTypes/private.js index c0a3fdbfe2f..4b7aea97640 100644 --- a/packages/rocketchat-lib/lib/roomTypes/private.js +++ b/packages/rocketchat-lib/lib/roomTypes/private.js @@ -44,9 +44,9 @@ export class PrivateRoomType extends RoomTypeConfig { condition() { const user = Meteor.user(); - const roomsListExhibitionMode = RocketChat.getUserPreference(user, 'roomsListExhibitionMode'); + // const roomsListExhibitionMode = RocketChat.getUserPreference(user, 'roomsListExhibitionMode'); const mergeChannels = RocketChat.getUserPreference(user, 'mergeChannels'); - return !roomsListExhibitionMode || ['unread', 'category'].includes(roomsListExhibitionMode) && !mergeChannels && RocketChat.authz.hasAllPermission('view-p-room'); + return !mergeChannels && RocketChat.authz.hasAllPermission('view-p-room'); } isGroupChat() { diff --git a/packages/rocketchat-lib/lib/roomTypes/public.js b/packages/rocketchat-lib/lib/roomTypes/public.js index 442423364c9..fb9c9e277ad 100644 --- a/packages/rocketchat-lib/lib/roomTypes/public.js +++ b/packages/rocketchat-lib/lib/roomTypes/public.js @@ -42,9 +42,9 @@ export class PublicRoomType extends RoomTypeConfig { condition() { const user = Meteor.user(); - const roomsListExhibitionMode = RocketChat.getUserPreference(user, 'roomsListExhibitionMode'); + // const roomsListExhibitionMode = RocketChat.getUserPreference(user, 'roomsListExhibitionMode'); const mergeChannels = RocketChat.getUserPreference(user, 'mergeChannels'); - return !roomsListExhibitionMode || ['unread', 'category'].includes(roomsListExhibitionMode) && !mergeChannels && (RocketChat.authz.hasAtLeastOnePermission(['view-c-room', 'view-joined-room']) || RocketChat.settings.get('Accounts_AllowAnonymousRead') === true); + return !mergeChannels && (RocketChat.authz.hasAtLeastOnePermission(['view-c-room', 'view-joined-room']) || RocketChat.settings.get('Accounts_AllowAnonymousRead') === true); } showJoinLink(roomId) { diff --git a/packages/rocketchat-lib/lib/roomTypes/unread.js b/packages/rocketchat-lib/lib/roomTypes/unread.js index 395036c6508..0e15cf0aa6f 100644 --- a/packages/rocketchat-lib/lib/roomTypes/unread.js +++ b/packages/rocketchat-lib/lib/roomTypes/unread.js @@ -13,6 +13,6 @@ export class UnreadRoomType extends RoomTypeConfig { condition() { const user = Meteor.user(); - return RocketChat.getUserPreference(user, 'roomsListExhibitionMode') === 'unread'; + return RocketChat.getUserPreference(user, 'sidebarShowUnread'); } } diff --git a/packages/rocketchat-lib/startup/defaultRoomTypes.js b/packages/rocketchat-lib/startup/defaultRoomTypes.js index 3bb90fc2929..9f9e006f132 100644 --- a/packages/rocketchat-lib/startup/defaultRoomTypes.js +++ b/packages/rocketchat-lib/startup/defaultRoomTypes.js @@ -1,5 +1,4 @@ import { - ChannelsRoomType, ConversationRoomType, DirectMessageRoomType, FavoriteRoomType, @@ -11,7 +10,6 @@ import { RocketChat.roomTypes.add(new UnreadRoomType()); RocketChat.roomTypes.add(new FavoriteRoomType()); RocketChat.roomTypes.add(new ConversationRoomType()); -RocketChat.roomTypes.add(new ChannelsRoomType()); RocketChat.roomTypes.add(new PublicRoomType()); RocketChat.roomTypes.add(new PrivateRoomType()); RocketChat.roomTypes.add(new DirectMessageRoomType()); diff --git a/packages/rocketchat-theme/client/imports/components/popover.css b/packages/rocketchat-theme/client/imports/components/popover.css index 72a8fabeffa..702117b30f3 100644 --- a/packages/rocketchat-theme/client/imports/components/popover.css +++ b/packages/rocketchat-theme/client/imports/components/popover.css @@ -101,6 +101,10 @@ } } + &--bold { + font-weight: bold; + } + &--star-filled .rc-icon { fill: currentColor; } diff --git a/packages/rocketchat-ui-sidenav/client/roomList.js b/packages/rocketchat-ui-sidenav/client/roomList.js index 17219a65d42..6a538a1ef3a 100644 --- a/packages/rocketchat-ui-sidenav/client/roomList.js +++ b/packages/rocketchat-ui-sidenav/client/roomList.js @@ -5,37 +5,47 @@ import { UiTextContext } from 'meteor/rocketchat:lib'; Template.roomList.helpers({ rooms() { - if (this.identifier === 'unread') { - const query = { - alert: true, - open: true, - hideUnreadStatus: {$ne: true} - }; - return ChatSubscription.find(query, {sort: {'t': 1, 'name': 1}}); - } + + /* + modes: + sortby activity/alphabetical + merge channels into one list + show favorites + show unread + */ + if (this.anonymous) { return RocketChat.models.Rooms.find({t: 'c'}, {sort: {name: 1}}); } - - const favoritesEnabled = RocketChat.settings.get('Favorite_Rooms'); - + const user = Meteor.user(); + const sortBy = RocketChat.getUserPreference(user, 'sidebarSortby') || 'activity'; const query = { open: true }; - const sort = { 't': 1 }; - if (this.identifier === 'd' && RocketChat.settings.get('UI_Use_Real_Name')) { - sort.fname = 1; - } else { - sort.name = 1; + + const sort = {}; + + if (sortBy === 'activity') { + sort.t = 1; + } else { // alphabetical + sort[this.identifier === 'd' && RocketChat.settings.get('UI_Use_Real_Name') ? 'fname' : 'name'] = /descending/.test(sortBy) ? -1 : 1; } + + if (this.identifier === 'unread') { + query.alert = true; + query.hideUnreadStatus = {$ne: true}; + return ChatSubscription.find(query, {sort}); + } + + const favoritesEnabled = RocketChat.settings.get('Favorite_Rooms') && RocketChat.getUserPreference(user, 'sidebarShowFavorites'); + if (this.identifier === 'f') { query.f = favoritesEnabled; } else { let types = [this.identifier]; - const user = Meteor.user(); - if (this.identifier === 'activity') { + if (this.identifier === 'merged') { types = ['c', 'p', 'd']; } @@ -43,10 +53,10 @@ Template.roomList.helpers({ types = ['c', 'p']; } - if (this.identifier === 'tokens' && user && user.services && user.services.tokenpass) { - query.tokens = { $exists: true }; - } else if (this.identifier === 'c' || this.identifier === 'p') { + if (['c', 'p'].includes(this.identifier)) { query.tokens = { $exists: false }; + } else if (this.identifier === 'tokens' && user && user.services && user.services.tokenpass) { + query.tokens = { $exists: true }; } if (RocketChat.getUserPreference(user, 'roomsListExhibitionMode') === 'unread') { @@ -59,15 +69,28 @@ Template.roomList.helpers({ query.t = {$in: types}; query.f = {$ne: favoritesEnabled}; } - if (this.identifier === 'activity') { - const list = ChatSubscription.find(query).fetch().map(sub => { - const lm = RocketChat.models.Rooms.findOne(sub.rid, {fields: {_updatedAt: 1}})._updatedAt; + + if (sortBy === 'activity') { + const list = ChatSubscription.find(query, {sort: {rid : 1}}).fetch(); + const ids = list.map(sub => sub.rid); + const rooms = RocketChat.models.Rooms.find({ + _id: { $in : ids} + }, + { + sort : { + _id: 1 + }, + fields: {_updatedAt: 1} + }).fetch(); + + + return _.sortBy(list.map((sub, i) => { + const lm = rooms[i]._updatedAt; return { lm: lm && lm.toISOString(), ...sub }; - }); - return _.sortBy(list, 'lm').reverse(); + }), 'lm').reverse(); } return ChatSubscription.find(query, {sort}); }, @@ -83,7 +106,7 @@ Template.roomList.helpers({ or is unread and has one room */ - return !['unread', 'f'].includes(group.identifier) || rooms.count(); + return !['unread', 'f'].includes(group.identifier) || (rooms.length || rooms.count && rooms.count()); }, roomType(room) { diff --git a/packages/rocketchat-ui-sidenav/client/sidebarHeader.js b/packages/rocketchat-ui-sidenav/client/sidebarHeader.js index d63d595c434..dcb9056db7f 100644 --- a/packages/rocketchat-ui-sidenav/client/sidebarHeader.js +++ b/packages/rocketchat-ui-sidenav/client/sidebarHeader.js @@ -21,7 +21,32 @@ const toolbarButtons = [ }, { name: t('Sort'), - icon: 'sort' + icon: 'sort', + action: (e) => { + const sidebarHeader = document.querySelector('.sidebar__header'); + const sidebarHeaderPadding = parseInt(getComputedStyle(sidebarHeader)['padding-left'].replace('px', '')) * 2; + const sidebarHeaderMargin = parseInt(getComputedStyle(sidebarHeader)['margin-left'].replace('px', '')) * 2; + const options = []; + const config = { + template: 'sortlist', + mousePosition: () => ({ + x: e.currentTarget.getBoundingClientRect().left, + y: e.currentTarget.getBoundingClientRect().bottom + 50 + }), + customCSSProperties: () => ({ + top: `${ e.currentTarget.getBoundingClientRect().bottom + 10 }px`, + left: `${ e.currentTarget.getBoundingClientRect().left - 10 }px` + }), + data: { + change : (value) => { + // return instance.form[key].set(key === 'desktopNotificationDuration' ? parseInt(value) : value); + }, + // value: instance.form[key].get(), + options + } + }; + popover.open(config); + } }, { name: t('Create_A_New_Channel'), @@ -187,6 +212,6 @@ Template.sidebarHeader.helpers({ Template.sidebarHeader.events({ 'click .js-button'(e) { - return this.action && this.action.apply(this); + return this.action && this.action.apply(this, [e]); } }); diff --git a/packages/rocketchat-ui-sidenav/client/sortlist.html b/packages/rocketchat-ui-sidenav/client/sortlist.html new file mode 100644 index 00000000000..aff7c36ffed --- /dev/null +++ b/packages/rocketchat-ui-sidenav/client/sortlist.html @@ -0,0 +1,56 @@ + diff --git a/packages/rocketchat-ui-sidenav/client/sortlist.js b/packages/rocketchat-ui-sidenav/client/sortlist.js new file mode 100644 index 00000000000..6b152312aa7 --- /dev/null +++ b/packages/rocketchat-ui-sidenav/client/sortlist.js @@ -0,0 +1,36 @@ +/* globals menu*/ + +Template.sortlist.helpers({ + favorite() { + return RocketChat.settings.get('Favorite_Rooms'); + }, + checked(prop, field) { + const user = Meteor.user(); + if (prop === 'sidebarShowFavorites') { + return RocketChat.getUserPreference(user, 'sidebarShowFavorites'); + } + if (prop === 'mergeChannels') { + return RocketChat.getUserPreference(user, 'mergeChannels'); + } + if (prop === 'sidebarShowUnread') { + return RocketChat.getUserPreference(user, 'sidebarShowUnread'); + } + if (prop === 'sidebarSortby') { + return (RocketChat.getUserPreference(user, 'sidebarSortby') || 'activity') === field; + } + } +}); + +Template.sortlist.events({ + 'change input'({currentTarget}) { + const name = currentTarget.getAttribute('name'); + const value = currentTarget.getAttribute('type') === 'checkbox' ? currentTarget.checked : currentTarget.value; + Meteor.call('saveUserPreferences', { + [name] : value + }); + } +}); + +Template.sortlist.onRendered(function() { + +}); diff --git a/packages/rocketchat-ui-sidenav/package.js b/packages/rocketchat-ui-sidenav/package.js index b8cc33e7a30..752ba50ba53 100644 --- a/packages/rocketchat-ui-sidenav/package.js +++ b/packages/rocketchat-ui-sidenav/package.js @@ -28,6 +28,7 @@ Package.onUse(function(api) { api.addFiles('client/sideNav.html', 'client'); api.addFiles('client/toolbar.html', 'client'); api.addFiles('client/roomList.html', 'client'); + api.addFiles('client/sortlist.html', 'client'); api.addFiles('client/userStatus.html', 'client'); api.addFiles('client/createCombinedFlex.js', 'client'); @@ -39,5 +40,6 @@ Package.onUse(function(api) { api.addFiles('client/sidebarItem.js', 'client'); api.addFiles('client/sideNav.js', 'client'); api.addFiles('client/roomList.js', 'client'); + api.addFiles('client/sortlist.js', 'client'); api.addFiles('client/toolbar.js', 'client'); }); diff --git a/server/methods/saveUserPreferences.js b/server/methods/saveUserPreferences.js index b70ff3e98bf..6dad8488504 100644 --- a/server/methods/saveUserPreferences.js +++ b/server/methods/saveUserPreferences.js @@ -1,6 +1,6 @@ Meteor.methods({ saveUserPreferences(settings) { - check(settings, Match.ObjectIncluding({ + const keys = { language: Match.Optional(String), newRoomNotification: Match.Optional(String), newMessageNotification: Match.Optional(String), @@ -16,7 +16,7 @@ Meteor.methods({ desktopNotifications: Match.Optional(String), mobileNotifications: Match.Optional(String), enableAutoAway: Match.Optional(Boolean), - highlights: [String], + highlights: Match.Optional([String]), desktopNotificationDuration: Match.Optional(Number), viewMode: Match.Optional(Number), hideUsernames: Match.Optional(Boolean), @@ -25,26 +25,39 @@ Meteor.methods({ hideFlexTab: Match.Optional(Boolean), sendOnEnter: Match.Optional(String), roomCounterSidebar: Match.Optional(Boolean), - mergeChannels: Match.Optional(Number), - idleTimeLimit: Match.Optional(Number) - })); + idleTimeLimit: Match.Optional(Number), + // sidebarMergeChannels: Match.Optional(Boolean), + sidebarShowFavorites: Match.Optional(Boolean), + sidebarShowUnread: Match.Optional(Boolean), + sidebarSortby: Match.Optional(String) + }; + check(settings, Match.ObjectIncluding(keys)); + if (settings.mergeChannels) { + check(settings, Match.ObjectIncluding({ + mergeChannels: Match.OneOf(Number, Boolean) + })); + } + const user = Meteor.userId(); + if (!user) { + return false; + } + + if (settings.language != null) { + RocketChat.models.Users.setLanguage(user, settings.language); + } + + if (settings.mergeChannels != null) { + settings.mergeChannels = ['1', true].includes(settings.mergeChannels); + } - if (Meteor.userId()) { - if (settings.language != null) { - RocketChat.models.Users.setLanguage(Meteor.userId(), settings.language); - } - if (settings.mergeChannels !== -1) { - settings.mergeChannels = settings.mergeChannels === '1'; - } else { - delete settings.mergeChannels; - } + if (settings.roomsListExhibitionMode != null) { settings.roomsListExhibitionMode = ['category', 'unread', 'activity'].includes(settings.roomsListExhibitionMode) ? settings.roomsListExhibitionMode : 'category'; + } - RocketChat.models.Users.setPreferences(Meteor.userId(), settings); + RocketChat.models.Users.setPreferences(user, settings); - return true; - } + return true; } });