UX: Improve quick search suggestions (#13813)
This commit is contained in:
parent
4f328089d6
commit
8a470e508e
|
@ -73,10 +73,10 @@ import { replaceFormatter } from "discourse/lib/utilities";
|
|||
import { replaceTagRenderer } from "discourse/lib/render-tag";
|
||||
import { setNewCategoryDefaultColors } from "discourse/routes/new-category";
|
||||
import { addSearchResultsCallback } from "discourse/lib/search";
|
||||
import { addInSearchShortcut } from "discourse/widgets/search-menu-results";
|
||||
import { addSearchSuggestion } from "discourse/widgets/search-menu-results";
|
||||
|
||||
// If you add any methods to the API ensure you bump up this number
|
||||
const PLUGIN_API_VERSION = "0.11.6";
|
||||
const PLUGIN_API_VERSION = "0.11.7";
|
||||
|
||||
class PluginApi {
|
||||
constructor(version, container) {
|
||||
|
@ -1298,15 +1298,15 @@ class PluginApi {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a in: shortcut to search menu panel.
|
||||
* Add a suggestion shortcut to search menu panel.
|
||||
*
|
||||
* ```
|
||||
* addInSearchShortcut("in:assigned");
|
||||
* addSearchSuggestion("in:assigned");
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
addInSearchShortcut(value) {
|
||||
addInSearchShortcut(value);
|
||||
addSearchSuggestion(value) {
|
||||
addSearchSuggestion(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,30 +10,22 @@ import highlightSearch from "discourse/lib/highlight-search";
|
|||
import { iconNode } from "discourse-common/lib/icon-library";
|
||||
import renderTag from "discourse/lib/render-tag";
|
||||
|
||||
const inSearchShortcuts = [
|
||||
const suggestionShortcuts = [
|
||||
"in:title",
|
||||
"in:personal",
|
||||
"in:seen",
|
||||
"in:likes",
|
||||
"in:bookmarks",
|
||||
"in:created",
|
||||
];
|
||||
const statusSearchShortcuts = [
|
||||
"in:pinned",
|
||||
"status:open",
|
||||
"status:closed",
|
||||
"status:public",
|
||||
"status:noreplies",
|
||||
];
|
||||
const orderSearchShortcuts = [
|
||||
"order:latest",
|
||||
"order:views",
|
||||
"order:likes",
|
||||
"order:latest_topic",
|
||||
];
|
||||
|
||||
export function addInSearchShortcut(value) {
|
||||
if (inSearchShortcuts.indexOf(value) === -1) {
|
||||
inSearchShortcuts.push(value);
|
||||
export function addSearchSuggestion(value) {
|
||||
if (suggestionShortcuts.indexOf(value) === -1) {
|
||||
suggestionShortcuts.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,8 +352,19 @@ createWidget("search-menu-assistant", {
|
|||
tagName: "ul.search-menu-assistant",
|
||||
|
||||
html(attrs) {
|
||||
if (this.currentUser) {
|
||||
addSearchSuggestion("in:likes");
|
||||
addSearchSuggestion("in:bookmarks");
|
||||
addSearchSuggestion("in:mine");
|
||||
addSearchSuggestion("in:personal");
|
||||
addSearchSuggestion("in:seen");
|
||||
addSearchSuggestion("in:tracking");
|
||||
addSearchSuggestion("in:unseen");
|
||||
addSearchSuggestion("in:watching");
|
||||
}
|
||||
if (this.siteSettings.tagging_enabled) {
|
||||
addInSearchShortcut("in:tagged");
|
||||
addSearchSuggestion("in:tagged");
|
||||
addSearchSuggestion("in:untagged");
|
||||
}
|
||||
|
||||
const content = [];
|
||||
|
@ -370,7 +373,7 @@ createWidget("search-menu-assistant", {
|
|||
|
||||
switch (suggestionKeyword) {
|
||||
case "#":
|
||||
attrs.results.map((category) => {
|
||||
attrs.results.forEach((category) => {
|
||||
const slug = prefix
|
||||
? `${prefix} #${category.slug} `
|
||||
: `#${category.slug} `;
|
||||
|
@ -385,7 +388,7 @@ createWidget("search-menu-assistant", {
|
|||
});
|
||||
break;
|
||||
case "@":
|
||||
attrs.results.map((user) => {
|
||||
attrs.results.forEach((user) => {
|
||||
const slug = prefix
|
||||
? `${prefix} @${user.username} `
|
||||
: `@${user.username} `;
|
||||
|
@ -399,27 +402,17 @@ createWidget("search-menu-assistant", {
|
|||
);
|
||||
});
|
||||
break;
|
||||
case "in:":
|
||||
inSearchShortcuts.map((item) => {
|
||||
const slug = prefix ? `${prefix} ${item} ` : item;
|
||||
content.push(this.attach("search-menu-assistant-item", { slug }));
|
||||
});
|
||||
break;
|
||||
case "status:":
|
||||
statusSearchShortcuts.map((item) => {
|
||||
const slug = prefix ? `${prefix} ${item} ` : item;
|
||||
content.push(this.attach("search-menu-assistant-item", { slug }));
|
||||
});
|
||||
break;
|
||||
case "order:":
|
||||
orderSearchShortcuts.map((item) => {
|
||||
const slug = prefix ? `${prefix} ${item} ` : item;
|
||||
content.push(this.attach("search-menu-assistant-item", { slug }));
|
||||
default:
|
||||
suggestionShortcuts.forEach((item) => {
|
||||
if (item.includes(suggestionKeyword)) {
|
||||
const slug = prefix ? `${prefix} ${item} ` : `${item} `;
|
||||
content.push(this.attach("search-menu-assistant-item", { slug }));
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return content;
|
||||
return content.filter((c, i) => i <= 8);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@ import userSearch from "discourse/lib/user-search";
|
|||
|
||||
const CATEGORY_SLUG_REGEXP = /(\#[a-zA-Z0-9\-:]*)$/gi;
|
||||
const USERNAME_REGEXP = /(\@[a-zA-Z0-9\-\_]*)$/gi;
|
||||
const SUGGESTIONS_REGEXP = /(in:|status:|order:|:)([a-zA-Z]*)$/gi;
|
||||
|
||||
const searchData = {};
|
||||
const suggestionTriggers = ["in:", "status:", "order:"];
|
||||
|
||||
export function initSearchData() {
|
||||
searchData.loading = false;
|
||||
|
@ -53,47 +53,42 @@ const SearchHelper = {
|
|||
searchData.results = [];
|
||||
searchData.loading = false;
|
||||
|
||||
if (typeof matchSuggestions === "string") {
|
||||
searchData.suggestionKeyword = matchSuggestions;
|
||||
if (matchSuggestions.type === "category") {
|
||||
const categorySearchTerm = matchSuggestions.categoriesMatch[0].replace(
|
||||
"#",
|
||||
""
|
||||
);
|
||||
|
||||
searchData.suggestionResults = Category.search(categorySearchTerm);
|
||||
searchData.suggestionKeyword = "#";
|
||||
widget.scheduleRerender();
|
||||
return;
|
||||
} else {
|
||||
if (matchSuggestions.type === "category") {
|
||||
const categorySearchTerm = matchSuggestions.categoriesMatch[0].replace(
|
||||
"#",
|
||||
""
|
||||
);
|
||||
|
||||
searchData.suggestionResults = Category.search(categorySearchTerm);
|
||||
searchData.suggestionKeyword = "#";
|
||||
widget.scheduleRerender();
|
||||
return;
|
||||
} else if (matchSuggestions.type === "username") {
|
||||
const userSearchTerm = matchSuggestions.usernamesMatch[0].replace(
|
||||
"@",
|
||||
""
|
||||
);
|
||||
const opts = { includeGroups: true, limit: 6 };
|
||||
if (userSearchTerm.length > 0) {
|
||||
opts.term = userSearchTerm;
|
||||
} else {
|
||||
opts.lastSeenUsers = true;
|
||||
}
|
||||
if (matchSuggestions.type === "username") {
|
||||
const userSearchTerm = matchSuggestions.usernamesMatch[0].replace(
|
||||
"@",
|
||||
""
|
||||
);
|
||||
const opts = { includeGroups: true, limit: 6 };
|
||||
if (userSearchTerm.length > 0) {
|
||||
opts.term = userSearchTerm;
|
||||
|
||||
userSearch(opts).then((result) => {
|
||||
if (result?.users?.length > 0) {
|
||||
searchData.suggestionResults = result.users;
|
||||
searchData.suggestionKeyword = "@";
|
||||
} else {
|
||||
opts.lastSeenUsers = true;
|
||||
searchData.noResults = true;
|
||||
searchData.suggestionKeyword = false;
|
||||
}
|
||||
|
||||
userSearch(opts).then((result) => {
|
||||
if (result?.users?.length > 0) {
|
||||
searchData.suggestionResults = result.users;
|
||||
searchData.suggestionKeyword = "@";
|
||||
} else {
|
||||
searchData.noResults = true;
|
||||
searchData.suggestionKeyword = false;
|
||||
}
|
||||
widget.scheduleRerender();
|
||||
});
|
||||
return;
|
||||
}
|
||||
widget.scheduleRerender();
|
||||
});
|
||||
} else {
|
||||
searchData.suggestionKeyword = matchSuggestions[0];
|
||||
widget.scheduleRerender();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
searchData.suggestionKeyword = false;
|
||||
|
@ -142,14 +137,6 @@ const SearchHelper = {
|
|||
return false;
|
||||
}
|
||||
|
||||
const simpleSuggestion = suggestionTriggers.find(
|
||||
(mod) => searchData.term === mod || searchData.term.endsWith(` ${mod}`)
|
||||
);
|
||||
|
||||
if (simpleSuggestion) {
|
||||
return simpleSuggestion;
|
||||
}
|
||||
|
||||
const categoriesMatch = searchData.term.match(CATEGORY_SLUG_REGEXP);
|
||||
|
||||
if (categoriesMatch) {
|
||||
|
@ -161,6 +148,11 @@ const SearchHelper = {
|
|||
return { type: "username", usernamesMatch };
|
||||
}
|
||||
|
||||
const suggestionsMatch = searchData.term.match(SUGGESTIONS_REGEXP);
|
||||
if (suggestionsMatch) {
|
||||
return suggestionsMatch;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -343,6 +343,10 @@ acceptance("Search - assistant", function (needs) {
|
|||
await fillIn("#search-term", "sam in:");
|
||||
await triggerKeyEvent("#search-term", "keyup", 51);
|
||||
assert.equal(query(firstTarget).innerText, "sam in:title");
|
||||
|
||||
await fillIn("#search-term", "in:pers");
|
||||
await triggerKeyEvent("#search-term", "keyup", 51);
|
||||
assert.equal(query(firstTarget).innerText, "in:personal");
|
||||
});
|
||||
|
||||
test("shows users when typing @", async function (assert) {
|
||||
|
|
|
@ -452,7 +452,7 @@ class Search
|
|||
posts.where("posts.user_id = #{@guardian.user.id}") if @guardian.user
|
||||
end
|
||||
|
||||
advanced_filter(/^in:created$/i) do |posts|
|
||||
advanced_filter(/^in:(created|mine)$/i) do |posts|
|
||||
posts.where(user_id: @guardian.user.id, post_number: 1) if @guardian.user
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue