From 052c78381be2cd4783dd1b9159ea6316768864b7 Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Wed, 18 Aug 2021 14:14:10 -0400 Subject: [PATCH] FIX: Include tags in quick search suggestions (#14080) Followup to https://github.com/discourse/discourse/commit/438a7629561397830fa9622f517ecec46e003e82 --- .../app/widgets/search-menu-results.js | 75 +++++++++++++------ .../discourse/app/widgets/search-menu.js | 15 +++- .../discourse/tests/acceptance/search-test.js | 16 ++++ .../stylesheets/common/base/search-menu.scss | 12 +++ 4 files changed, 90 insertions(+), 28 deletions(-) diff --git a/app/assets/javascripts/discourse/app/widgets/search-menu-results.js b/app/assets/javascripts/discourse/app/widgets/search-menu-results.js index 6da7139e51e..ca01d7e9ce8 100644 --- a/app/assets/javascripts/discourse/app/widgets/search-menu-results.js +++ b/app/assets/javascripts/discourse/app/widgets/search-menu-results.js @@ -5,6 +5,7 @@ import { avatarImg } from "discourse/widgets/post"; import { createWidget } from "discourse/widgets/widget"; import { dateNode } from "discourse/helpers/node"; import { emojiUnescape } from "discourse/lib/text"; +import getURL from "discourse-common/lib/get-url"; import { h } from "virtual-dom"; import highlightSearch from "discourse/lib/highlight-search"; import { iconNode } from "discourse-common/lib/icon-library"; @@ -369,37 +370,45 @@ createWidget("search-menu-assistant", { const content = []; const { fullTerm, suggestionKeyword } = attrs; - const prefix = fullTerm.split(suggestionKeyword)[0].trim() || null; + let prefix = fullTerm.split(suggestionKeyword)[0].trim() || ""; + + if (prefix.length) { + prefix = `${prefix} `; + } switch (suggestionKeyword) { case "#": - attrs.results.forEach((category) => { - const fullSlug = category.parentCategory - ? `#${category.parentCategory.slug}:${category.slug}` - : `#${category.slug}`; + attrs.results.forEach((item) => { + if (item.model) { + const fullSlug = item.model.parentCategory + ? `#${item.model.parentCategory.slug}:${item.model.slug}` + : `#${item.model.slug}`; - const slug = prefix ? `${prefix} ${fullSlug} ` : `${fullSlug} `; - - content.push( - this.attach("search-menu-assistant-item", { - prefix: prefix, - category, - slug, - }) - ); + content.push( + this.attach("search-menu-assistant-item", { + prefix, + category: item.model, + slug: `${prefix}${fullSlug} `, + }) + ); + } else { + content.push( + this.attach("search-menu-assistant-item", { + prefix, + tag: item.name, + slug: `${prefix}#${item.name} `, + }) + ); + } }); break; case "@": attrs.results.forEach((user) => { - const slug = prefix - ? `${prefix} @${user.username} ` - : `@${user.username} `; - content.push( this.attach("search-menu-assistant-item", { - prefix: prefix, + prefix, user, - slug, + slug: `${prefix}@${user.username} `, }) ); }); @@ -407,8 +416,11 @@ createWidget("search-menu-assistant", { default: suggestionShortcuts.forEach((item) => { if (item.includes(suggestionKeyword)) { - const slug = prefix ? `${prefix} ${item} ` : `${item} `; - content.push(this.attach("search-menu-assistant-item", { slug })); + content.push( + this.attach("search-menu-assistant-item", { + slug: `${prefix}${item} `, + }) + ); } }); break; @@ -422,6 +434,7 @@ createWidget("search-menu-assistant-item", { tagName: "li.search-menu-assistant-item", html(attrs) { + const prefix = attrs.prefix?.trim(); if (attrs.category) { return h( "a.widget-link.search-link", @@ -431,7 +444,7 @@ createWidget("search-menu-assistant-item", { }, }, [ - h("span.search-item-prefix", attrs.prefix), + h("span.search-item-prefix", prefix), this.attach("category-link", { category: attrs.category, allowUncategorized: true, @@ -439,6 +452,20 @@ createWidget("search-menu-assistant-item", { }), ] ); + } else if (attrs.tag) { + return h( + "a.widget-link.search-link", + { + attributes: { + href: getURL(`/tag/${attrs.tag}`), + }, + }, + [ + h("span.search-item-prefix", prefix), + iconNode("tag"), + h("span.search-item-tag", attrs.tag), + ] + ); } else if (attrs.user) { const userResult = [ avatarImg("small", { @@ -456,7 +483,7 @@ createWidget("search-menu-assistant-item", { }, }, [ - h("span.search-item-prefix", attrs.prefix), + h("span.search-item-prefix", prefix), h("span.search-item-user", userResult), ] ); diff --git a/app/assets/javascripts/discourse/app/widgets/search-menu.js b/app/assets/javascripts/discourse/app/widgets/search-menu.js index f34668e243b..4dee355cd60 100644 --- a/app/assets/javascripts/discourse/app/widgets/search-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/search-menu.js @@ -1,5 +1,4 @@ import { isValidSearchTerm, searchForTerm } from "discourse/lib/search"; -import Category from "discourse/models/category"; import DiscourseURL from "discourse/lib/url"; import { createWidget } from "discourse/widgets/widget"; import discourseDebounce from "discourse-common/lib/debounce"; @@ -7,6 +6,8 @@ import { get } from "@ember/object"; import getURL from "discourse-common/lib/get-url"; import { h } from "virtual-dom"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { Promise } from "rsvp"; +import { search as searchCategoryTag } from "discourse/lib/category-tag-search"; import userSearch from "discourse/lib/user-search"; const CATEGORY_SLUG_REGEXP = /(\#[a-zA-Z0-9\-:]*)$/gi; @@ -59,9 +60,15 @@ const SearchHelper = { "" ); - searchData.suggestionResults = Category.search(categorySearchTerm); - searchData.suggestionKeyword = "#"; - widget.scheduleRerender(); + const categoryTagSearch = searchCategoryTag( + categorySearchTerm, + widget.siteSettings + ); + Promise.resolve(categoryTagSearch).then((results) => { + searchData.suggestionResults = results; + searchData.suggestionKeyword = "#"; + widget.scheduleRerender(); + }); } else if (matchSuggestions.type === "username") { const userSearchTerm = matchSuggestions.usernamesMatch[0].replace( "@", diff --git a/app/assets/javascripts/discourse/tests/acceptance/search-test.js b/app/assets/javascripts/discourse/tests/acceptance/search-test.js index 982749a6c16..19b333b3551 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/search-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/search-test.js @@ -263,6 +263,22 @@ acceptance("Search - with tagging enabled", function (needs) { assert.equal(tags, "dev slow"); }); + + test("displays tag shortcuts", async function (assert) { + await visit("/"); + + await click("#search-button"); + + await fillIn("#search-term", "dude #monk"); + await triggerKeyEvent("#search-term", "keyup", 51); + + const firstItem = + ".search-menu .results ul.search-menu-assistant .search-link"; + assert.ok(exists(query(firstItem))); + + const firstTag = query(`${firstItem} .search-item-tag`).innerText.trim(); + assert.equal(firstTag, "monkey"); + }); }); acceptance("Search - assistant", function (needs) { diff --git a/app/assets/stylesheets/common/base/search-menu.scss b/app/assets/stylesheets/common/base/search-menu.scss index b6c6926f229..2c19163e164 100644 --- a/app/assets/stylesheets/common/base/search-menu.scss +++ b/app/assets/stylesheets/common/base/search-menu.scss @@ -267,6 +267,18 @@ .search-item-prefix { margin-right: 0.5em; } + + .search-item-tag { + color: var(--primary-high); + font-size: var(--font-down-1); + } + + .d-icon-tag { + // match category badge styling + // tag/category suggestions can be displayed simultaneously + font-size: var(--font-down-2); + margin-right: 4px; + } } }