diff --git a/README.md b/README.md index 436faf958081c..1dc6c97699677 100644 --- a/README.md +++ b/README.md @@ -297,6 +297,7 @@ It is a great solution for communities and companies wanting to privately host t - File Upload / Sharing - Scalable file sharing - S3 uploads with CDN downloads - Full text search +- Global search (from all channels/rooms at once) - Live chat / Messaging call center - LDAP Authentication - CAS 1.0, 2.0 support for educational institutions and hosting providers worldwide diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index b5294036a25cb..60d32127e5e8c 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -774,6 +774,7 @@ "Give_a_unique_name_for_the_custom_oauth": "Give a unique name for the custom oauth", "Give_the_application_a_name_This_will_be_seen_by_your_users": "Give the application a name. This will be seen by your users.", "Global": "Global", + "Global_Search": "Global search", "Google_Vision_usage_limit_exceeded": "Google Vision usage limit exceeded", "GoogleCloudStorage": "Google Cloud Storage", "GoogleNaturalLanguage_ServiceAccount_Description": "Service account key JSON file. More information can be found [here](https://cloud.google.com/natural-language/docs/common/auth#set_up_a_service_account)", @@ -1241,6 +1242,7 @@ "Message_DateFormat_Description": "See also: Moment.js", "Message_deleting_blocked": "This message cannot be deleted anymore", "Message_editing": "Message editing", + "Message_GlobalSearch": "Global Search", "Message_GroupingPeriod": "Grouping Period (in seconds)", "Message_GroupingPeriodDescription": "Messages will be grouped with previous message if both are from the same user and the elapsed time was less than the informed time in seconds.", "Message_HideType_au": "Hide \"User Added\" messages", diff --git a/packages/rocketchat-i18n/i18n/fi.i18n.json b/packages/rocketchat-i18n/i18n/fi.i18n.json index 298417328fee8..e668e23641179 100644 --- a/packages/rocketchat-i18n/i18n/fi.i18n.json +++ b/packages/rocketchat-i18n/i18n/fi.i18n.json @@ -468,6 +468,7 @@ "Give_a_unique_name_for_the_custom_oauth": "Anna yksilöllinen nimi mukautettua oauth varten", "Give_the_application_a_name_This_will_be_seen_by_your_users": "Anna sovelluksen nimi. Käyttäjät näkevät tämän.", "Global": "Yleinen", + "Global_Search": "Hae kaikilta kanavilta", "GoogleTagManager_id": "Google Tag Manager Id", "Guest_Pool": "Vieraspooli", "Hash": "Hash", diff --git a/packages/rocketchat-lib/server/startup/settings.js b/packages/rocketchat-lib/server/startup/settings.js index 2271edd7005c8..1aa1c27c51eb9 100644 --- a/packages/rocketchat-lib/server/startup/settings.js +++ b/packages/rocketchat-lib/server/startup/settings.js @@ -1313,10 +1313,16 @@ RocketChat.settings.addGroup('Message', function() { 'public': true }); - return this.add('Message_HideType_mute_unmute', false, { + this.add('Message_HideType_mute_unmute', false, { type: 'boolean', 'public': true }); + + this.add('Message_GlobalSearch', false, { + type: 'boolean', + 'public': true, + alert: 'This feature is currently in beta and could decrease the application performance! Please report bugs to github.com/RocketChat/Rocket.Chat/issues' + }); }); RocketChat.settings.addGroup('Meta', function() { diff --git a/packages/rocketchat-ui-flextab/client/tabs/messageSearch.html b/packages/rocketchat-ui-flextab/client/tabs/messageSearch.html index 28d2d1cc7f075..91b5d256cc5d1 100644 --- a/packages/rocketchat-ui-flextab/client/tabs/messageSearch.html +++ b/packages/rocketchat-ui-flextab/client/tabs/messageSearch.html @@ -14,6 +14,11 @@ + {{#if allowGlobalSearch}} + + {{/if}} diff --git a/packages/rocketchat-ui-flextab/client/tabs/messageSearch.js b/packages/rocketchat-ui-flextab/client/tabs/messageSearch.js index c5be5304680e6..5fd559a1f1882 100644 --- a/packages/rocketchat-ui-flextab/client/tabs/messageSearch.js +++ b/packages/rocketchat-ui-flextab/client/tabs/messageSearch.js @@ -10,11 +10,22 @@ Meteor.startup(function() { ], action() { const message = this._arguments[1]; + if (Session.get('openedRoom') === message.rid) { + return RoomHistoryManager.getSurroundingMessages(message, 50); + } + + FlowRouter.goToRoomById(message.rid); + // RocketChat.MessageAction.hideDropDown(); + if (window.matchMedia('(max-width: 500px)').matches) { Template.instance().tabBar.close(); } - RoomHistoryManager.getSurroundingMessages(message, 50); + window.setTimeout(() => { + RoomHistoryManager.getSurroundingMessages(message, 50); + }, 400); + // 400ms is popular among game devs as a good delay before transition starts + // ie. 50, 100, 200, 400, 800 are the favored timings }, order: 100, group: 'menu' @@ -48,6 +59,10 @@ Template.messageSearch.helpers({ message() { return _.extend(this, { customClass: 'search', actionContext: 'search'}); + }, + + allowGlobalSearch() { + return RocketChat.settings.get('Message_GlobalSearch'); } }); @@ -68,10 +83,10 @@ Template.messageSearch.events({ } else if (value === t.currentSearchTerm.get()) { return; } - + const globalSearch = $('#global-search').is(':checked'); t.hasMore.set(true); t.limit.set(20); - return t.search(); + return t.search(globalSearch); }, 500), 'click .load-more button'(e, t) { @@ -89,20 +104,19 @@ Template.messageSearch.events({ Template.messageSearch.onCreated(function() { this.currentSearchTerm = new ReactiveVar(''); - this.searchResult = new ReactiveVar; - + this.searchResult = new ReactiveVar(); this.hasMore = new ReactiveVar(true); this.limit = new ReactiveVar(20); this.ready = new ReactiveVar(true); - return this.search = () => { + return this.search = (globalSearch = false) => { this.ready.set(false); const value = this.$('#message-search').val(); return Tracker.nonreactive(() => { - return Meteor.call('messageSearch', value, Session.get('openedRoom'), this.limit.get(), (error, result) => { + return Meteor.call('messageSearch', value, (globalSearch) ? undefined: Session.get('openedRoom'), this.limit.get(), (error, result) => { this.currentSearchTerm.set(value); this.ready.set(true); - if ((result != null) && (((result.messages != null ? result.messages.length : undefined) > 0) || ((result.users != null ? result.users.length : undefined) > 0) || ((result.channels != null ? result.channels.length : undefined) > 0))) { + if ((result != null) && (((result.messages !== null ? result.messages.length : undefined) > 0) || ((result.users != null ? result.users.length : undefined) > 0) || ((result.channels != null ? result.channels.length : undefined) > 0))) { this.searchResult.set(result); if (((result.messages != null ? result.messages.length : undefined) + (result.users != null ? result.users.length : undefined) + (result.channels != null ? result.channels.length : undefined)) < this.limit.get()) { return this.hasMore.set(false); diff --git a/packages/rocketchat-ui-message/client/message.html b/packages/rocketchat-ui-message/client/message.html index 9beba25aa67e7..21d59b1f887ed 100644 --- a/packages/rocketchat-ui-message/client/message.html +++ b/packages/rocketchat-ui-message/client/message.html @@ -50,6 +50,11 @@ {{_ "Only_you_can_see_this_message"}} {{/if}} + {{#if fromSearch}} + + {{>icon icon=roomIcon}}{{channelName}} + + {{/if}}
{{#if isSnippet}}
{{_ "Snippet_name"}}: {{snippetName}}
diff --git a/packages/rocketchat-ui-message/client/message.js b/packages/rocketchat-ui-message/client/message.js index 8938fa7721419..3b42c51c3880d 100644 --- a/packages/rocketchat-ui-message/client/message.js +++ b/packages/rocketchat-ui-message/client/message.js @@ -265,6 +265,20 @@ Template.message.helpers({ return 'hidden'; } }, + channelName() { + const subscription = RocketChat.models.Subscriptions.findOne({rid: this.rid}); + return subscription && subscription.name; + }, + roomIcon() { + const room = Session.get(`roomData${ this.rid }`); + if (room && room.t === 'd') { + return 'at'; + } + return RocketChat.roomTypes.getIcon(room && room.t); + }, + fromSearch() { + return this.customClass === 'search'; + }, actionContext() { return this.actionContext; }, diff --git a/server/methods/messageSearch.js b/server/methods/messageSearch.js index fc241f7025cc1..2d84ca0af10e5 100644 --- a/server/methods/messageSearch.js +++ b/server/methods/messageSearch.js @@ -3,7 +3,7 @@ import s from 'underscore.string'; Meteor.methods({ messageSearch(text, rid, limit) { check(text, String); - check(rid, String); + check(rid, Match.Maybe(String)); check(limit, Match.Optional(Number)); // TODO: Evaluate why we are returning `users` and `channels`, as the only thing that gets set is the `messages`. @@ -21,12 +21,17 @@ Meteor.methods({ } // Don't process anything else if the user can't access the room - if (!Meteor.call('canAccessRoom', rid, currentUserId)) { + if (rid) { + if (!Meteor.call('canAccessRoom', rid, currentUserId)) { + return result; + } + } else if (RocketChat.settings.get('Message_GlobalSearch') !== true) { return result; } - const currentUserName = Meteor.user().username; - const currentUserTimezoneOffset = Meteor.user().utcOffset; + const user = Meteor.user(); + const currentUserName = user.username; + const currentUserTimezoneOffset = user.utcOffset; const query = {}; const options = { @@ -204,13 +209,23 @@ Meteor.methods({ query._hidden = { $ne: true // don't return _hidden messages }; - query.rid = rid; + + if (rid) { + query.rid = rid; + } else { + query.rid = { + $in: RocketChat.models.Subscriptions.findByUserId(user._id) + .fetch() + .map(subscription => subscription.rid) + }; + } if (!RocketChat.settings.get('Message_ShowEditedStatus')) { options.fields = { 'editedAt': 0 }; } + result.messages = RocketChat.models.Messages.find(query, options).fetch(); }