FEATURE: displays groups in menu search (#7090)

FEATURE: displays groups in menu search (#7090)

diff --git a/app/assets/javascripts/discourse/lib/search.js.es6 b/app/assets/javascripts/discourse/lib/search.js.es6
index a3f47f7..32c2262 100644
--- a/app/assets/javascripts/discourse/lib/search.js.es6
+++ b/app/assets/javascripts/discourse/lib/search.js.es6
@@ -16,6 +16,7 @@ export function translateResults(results, opts) {
   results.posts = results.posts || [];
   results.categories = results.categories || [];
   results.tags = results.tags || [];
+  results.groups = results.groups || [];
 
   const topicMap = {};
   results.topics = results.topics.map(function(topic) {
@@ -43,6 +44,17 @@ export function translateResults(results, opts) {
     })
     .compact();
 
+  results.groups = results.groups
+    .map(group => {
+      const groupName = Handlebars.Utils.escapeExpression(group.name);
+      return {
+        id: group.id,
+        name: groupName,
+        url: Discourse.getURL(`/g/${groupName}`)
+      };
+    })
+    .compact();
+
   results.tags = results.tags
     .map(function(tag) {
       const tagName = Handlebars.Utils.escapeExpression(tag.name);
@@ -62,7 +74,8 @@ export function translateResults(results, opts) {
       ["topic", "posts"],
       ["category", "categories"],
       ["tag", "tags"],
-      ["user", "users"]
+      ["user", "users"],
+      ["group", "groups"]
     ].forEach(function(pair) {
       const type = pair[0];
       const name = pair[1];
diff --git a/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 b/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6
index 19d6420..69ecf7a 100644
--- a/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6
+++ b/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6
@@ -5,6 +5,7 @@ import { createWidget } from "discourse/widgets/widget";
 import { h } from "virtual-dom";
 import highlightText from "discourse/lib/highlight-text";
 import { escapeExpression, formatUsername } from "discourse/lib/utilities";
+import { iconNode } from "discourse-common/lib/icon-library";
 
 class Highlighted extends RawHtml {
   constructor(html, term) {
@@ -26,15 +27,15 @@ function createSearchResult({ type, linkField, builder }) {
         let searchResultId;
 
         if (type === "topic") {
-          searchResultId = r.get("topic_id");
+          searchResultId = r.topic_id;
         } else {
-          searchResultId = r.get("id");
+          searchResultId = r.id;
         }
 
         return h(
           "li.item",
           this.attach("link", {
-            href: r.get(linkField),
+            href: r[linkField],
             contents: () => builder.call(this, r, attrs.term),
             className: "search-link",
             searchResultId,
@@ -68,12 +69,11 @@ createSearchResult({
   type: "tag",
   linkField: "url",
   builder(t) {
-    const tag = escapeExpression(t.get("id"));
+    const tag = escapeExpression(t.id);
     return h(
-      "a",
+      "span",
       {
-        attributes: { href: t.get("url") },
-        className: `widget-link search-link tag-${tag} discourse-tag ${
+        className: `tag-${tag} discourse-tag ${
           Discourse.SiteSettings.tag_style
         }`
       },
@@ -113,6 +113,21 @@ createSearchResult({
 });
 
 createSearchResult({
+  type: "group",
+  linkField: "url",
+  builder(group) {
+    const groupName = escapeExpression(group.name);
+    return h(
+      "span",
+      {
+        className: `group-${groupName} discourse-group`
+      },
+      [iconNode("users"), h("span", groupName)]
+    );
+  }
+});
+
+createSearchResult({
   type: "topic",
   linkField: "url",
   builder(result, term) {
diff --git a/app/assets/stylesheets/common/base/search-menu.scss b/app/assets/stylesheets/common/base/search-menu.scss
index e008e56..a38e5b1 100644
--- a/app/assets/stylesheets/common/base/search-menu.scss
+++ b/app/assets/stylesheets/common/base/search-menu.scss
@@ -38,6 +38,8 @@
     flex-direction: row;
 
     .list {
+      min-width: 100px;
+
       .item {
         .blurb {
           // https://css-tricks.com/snippets/css/prevent-long-urls-from-breaking-out-of-container/
@@ -97,6 +99,25 @@
         }
       }
 
+      .search-result-group {
+        .search-link {
+          color: $primary-high;
+
+          &:hover {
+            color: $primary;
+          }
+        }
+
+        .discourse-group {
+          display: inline-block;
+          word-break: break-all;
+
+          .d-icon {
+            margin-right: s(1);
+          }
+        }
+      }
+
       .search-result-user {
         .user-result {
           display: flex;
diff --git a/app/serializers/grouped_search_result_serializer.rb b/app/serializers/grouped_search_result_serializer.rb
index b9dcb5b..b6dac30 100644
--- a/app/serializers/grouped_search_result_serializer.rb
+++ b/app/serializers/grouped_search_result_serializer.rb
@@ -3,6 +3,7 @@ class GroupedSearchResultSerializer < ApplicationSerializer
   has_many :users, serializer: SearchResultUserSerializer
   has_many :categories, serializer: BasicCategorySerializer
   has_many :tags, serializer: TagSerializer
+  has_many :groups, serializer: BasicGroupSerializer
   attributes :more_posts, :more_users, :more_categories, :term, :search_log_id, :more_full_page_results, :can_create_topic
 
   def search_log_id
diff --git a/lib/search.rb b/lib/search.rb
index 9ec3006..56ebc31 100644
--- a/lib/search.rb
+++ b/lib/search.rb
@@ -598,6 +598,7 @@ class Search
         user_search if @term.present?
         category_search if @term.present?
         tags_search if @term.present?
+        groups_search if @term.present?
       end
       topic_search
     end
@@ -683,6 +684,14 @@ class Search
     end
   end
 
+  def groups_search
+    groups = Group
+      .visible_groups(@guardian.user, "name ASC", include_everyone: false)
+      .where("groups.name ILIKE ?", "%#{@term}%")
+
+    groups.each { |group| @results.add(group) }
+  end
+
   def tags_search
     return unless SiteSetting.tagging_enabled
 
diff --git a/lib/search/grouped_search_results.rb b/lib/search/grouped_search_results.rb
index 1f81e43..68c257f 100644
--- a/lib/search/grouped_search_results.rb
+++ b/lib/search/grouped_search_results.rb
@@ -15,6 +15,7 @@ class Search
       :categories,
       :users,
       :tags,
+      :groups,
       :more_posts,
       :more_categories,
       :more_users,
@@ -36,6 +37,7 @@ class Search
       @categories = []
       @users = []
       @tags = []
+      @groups = []
     end
 
     def find_user_data(guardian)
diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb
index 159ba50..993a259 100644
--- a/spec/components/search_spec.rb
+++ b/spec/components/search_spec.rb
@@ -430,6 +430,38 @@ describe Search do
 
   end
 
+  context 'groups' do
+    def search(user = Fabricate(:user))
+      Search.execute(group.name, guardian: Guardian.new(user))
+    end
+
+    let!(:group) { Group[:trust_level_0] }
+
+    it 'shows group' do
+      expect(search.groups.map(&:name)).to eq([group.name])
+    end
+
+    context 'group visibility' do
+      let!(:group) { Fabricate(:group) }
+
+      before do
+        group.update!(visibility_level: 3)
+      end
+
+      context 'staff logged in' do
+        it 'shows group' do
+          expect(search(Fabricate(:admin)).groups.map(&:name)).to eq([group.name])
+        end
+      end
+
+      context 'non staff logged in' do
+        it 'shows doesn’t show group' do
+          expect(search.groups.map(&:name)).to be_empty
+        end
+      end
+    end
+  end
+
   context 'tags' do
     def search
       Search.execute(tag.name)

GitHub sha: dc400137

This commit has been mentioned on Discourse Meta. There might be relevant details there: