Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Global search #7628

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,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 education institutions and hosting providers worldwide
Expand Down
1 change: 1 addition & 0 deletions packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,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",
"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)",
"GoogleTagManager_id": "Google Tag Manager Id",
Expand Down
1 change: 1 addition & 0 deletions packages/rocketchat-i18n/i18n/fi.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ <h2>{{_ "Search_Messages"}}</h2>
<div class="input-line search">
<input type="text" id="message-search" class="search content-background-color" placeholder="{{tSearchMessages}}" autocomplete="off" />
<i class="icon-search secondary-font-color"></i>
<label><input type="checkbox" id="global-search" checked>{{_ "Global_Search"}}</label>
</div>
</form>
</div>
Expand Down
24 changes: 16 additions & 8 deletions packages/rocketchat-ui-flextab/client/tabs/messageSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@ 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();
}
return 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
});
Expand Down Expand Up @@ -46,6 +54,7 @@ Template.messageSearch.helpers({
message() {
return _.extend(this, { customClass: 'search' });
}

});

Template.messageSearch.events({
Expand All @@ -65,10 +74,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 .message-cog'(e, t) {
Expand Down Expand Up @@ -103,20 +112,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);
Expand Down
5 changes: 5 additions & 0 deletions packages/rocketchat-ui-message/client/message.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
{{/if}}
{{/if}}
<button type="button" class="user user-card-message color-primary-font-color" data-username="{{u.username}}" tabindex="1">{{getName}}{{#if showUsername}} <span class="message-alias border-component-color color-info-font-color">@{{u.username}}</span>{{/if}}</button>
{{#if fromSearch}}
<span class="info color-info-font-color">
<i class="{{roomIcon}}" aria-label=""></i>{{channelName}}
</span>
{{/if}}
<span class="info border-component-color color-info-font-color">
{{#each roleTags}}
<span class="role-tag background-info-font-color" data-role="{{description}}">{{description}}</span>
Expand Down
9 changes: 9 additions & 0 deletions packages/rocketchat-ui-message/client/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,15 @@ Template.message.helpers({
if (subscription == null) {
return 'hidden';
}
},
channelName() {
return Session.get(`roomData${ this.rid }`).name;
},
roomIcon() {
return RocketChat.roomTypes.getIcon(Session.get(`roomData${ this.rid }`).t);
},
fromSearch() {
return (this.customClass==='search');
}
});

Expand Down
24 changes: 16 additions & 8 deletions server/methods/messageSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Meteor.methods({
};

check(text, String);
check(rid, String);
check(rid, Match.Maybe(String));
check(limit, Match.Optional(Number));

const currentUserId = Meteor.userId();
Expand Down Expand Up @@ -182,17 +182,25 @@ Meteor.methods({
query._hidden = {
$ne: true // don't return _hidden messages
};
if (rid != null) {
if (rid) {
query.rid = rid;
// check if user can access rid room
if (Meteor.call('canAccessRoom', rid, currentUserId) !== false) {
if (!RocketChat.settings.get('Message_ShowEditedStatus')) {
options.fields = {
'editedAt': 0
};
}
result.messages = RocketChat.models.Messages.find(query, options).fetch();
return result;
}
} else {
query.rid = {
$in : RocketChat.models.Rooms.findByContainingUsername(currentUserName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rely's on the username on the room object. I'm not sure if we plan to keep here.

I do worry about how heavy this could be...

Our community server for example we have 145k users. I can only imagine this plus then querying across all rooms in... could be very heavy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about if global search would be admin-enableable feature?
I see that on large installations this needs highly more optimized search function but on smaller environments current implementation could be acceptable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RocketChat/core what do you guys think? Should we have this as something that can be turned on?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not in a position to test this feature, nor do I understand what this bit of code does. Is the proposed new search always doing a global search? Perhaps defaulting to searching the current channel, and requiring the user to select a global search option would result in very few global searches being done, ie only when necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, in large environments global search could be used as DoS-attack by normal users.
Therefore allowing user to enable global search while searching should be only secondary, admin should decide this primarily.

On smaller environments (depends on multiple factors I think) your point still stands.

If time permits, I'll add option to admin.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works fine for us, our environment is small, and we will enable the option. I would hate to be in a big environment and denied access to global search just because it might be abused.

Compromises could include allowing users to specify up to, say, 5 channels to include in their search, or a search string syntax that can specify up to 5 channels to search. Eg "channel:general,random".

Or, as I suggested earlier, an option to repeat the current search on the next channel in the list.

.fetch()
.map(room => room._id)
};
}
if (!RocketChat.settings.get('Message_ShowEditedStatus')) {
options.fields = {
'editedAt': 0
};
}
result.messages = RocketChat.models.Messages.find(query, options).fetch();
}

return result;
Expand Down