mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
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 { replaceTagRenderer } from "discourse/lib/render-tag";
|
||||||
import { setNewCategoryDefaultColors } from "discourse/routes/new-category";
|
import { setNewCategoryDefaultColors } from "discourse/routes/new-category";
|
||||||
import { addSearchResultsCallback } from "discourse/lib/search";
|
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
|
// 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 {
|
class PluginApi {
|
||||||
constructor(version, container) {
|
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) {
|
addSearchSuggestion(value) {
|
||||||
addInSearchShortcut(value);
|
addSearchSuggestion(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,30 +10,22 @@ import highlightSearch from "discourse/lib/highlight-search";
|
|||||||
import { iconNode } from "discourse-common/lib/icon-library";
|
import { iconNode } from "discourse-common/lib/icon-library";
|
||||||
import renderTag from "discourse/lib/render-tag";
|
import renderTag from "discourse/lib/render-tag";
|
||||||
|
|
||||||
const inSearchShortcuts = [
|
const suggestionShortcuts = [
|
||||||
"in:title",
|
"in:title",
|
||||||
"in:personal",
|
"in:pinned",
|
||||||
"in:seen",
|
|
||||||
"in:likes",
|
|
||||||
"in:bookmarks",
|
|
||||||
"in:created",
|
|
||||||
];
|
|
||||||
const statusSearchShortcuts = [
|
|
||||||
"status:open",
|
"status:open",
|
||||||
"status:closed",
|
"status:closed",
|
||||||
"status:public",
|
"status:public",
|
||||||
"status:noreplies",
|
"status:noreplies",
|
||||||
];
|
|
||||||
const orderSearchShortcuts = [
|
|
||||||
"order:latest",
|
"order:latest",
|
||||||
"order:views",
|
"order:views",
|
||||||
"order:likes",
|
"order:likes",
|
||||||
"order:latest_topic",
|
"order:latest_topic",
|
||||||
];
|
];
|
||||||
|
|
||||||
export function addInSearchShortcut(value) {
|
export function addSearchSuggestion(value) {
|
||||||
if (inSearchShortcuts.indexOf(value) === -1) {
|
if (suggestionShortcuts.indexOf(value) === -1) {
|
||||||
inSearchShortcuts.push(value);
|
suggestionShortcuts.push(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,8 +352,19 @@ createWidget("search-menu-assistant", {
|
|||||||
tagName: "ul.search-menu-assistant",
|
tagName: "ul.search-menu-assistant",
|
||||||
|
|
||||||
html(attrs) {
|
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) {
|
if (this.siteSettings.tagging_enabled) {
|
||||||
addInSearchShortcut("in:tagged");
|
addSearchSuggestion("in:tagged");
|
||||||
|
addSearchSuggestion("in:untagged");
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = [];
|
const content = [];
|
||||||
@ -370,7 +373,7 @@ createWidget("search-menu-assistant", {
|
|||||||
|
|
||||||
switch (suggestionKeyword) {
|
switch (suggestionKeyword) {
|
||||||
case "#":
|
case "#":
|
||||||
attrs.results.map((category) => {
|
attrs.results.forEach((category) => {
|
||||||
const slug = prefix
|
const slug = prefix
|
||||||
? `${prefix} #${category.slug} `
|
? `${prefix} #${category.slug} `
|
||||||
: `#${category.slug} `;
|
: `#${category.slug} `;
|
||||||
@ -385,7 +388,7 @@ createWidget("search-menu-assistant", {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "@":
|
case "@":
|
||||||
attrs.results.map((user) => {
|
attrs.results.forEach((user) => {
|
||||||
const slug = prefix
|
const slug = prefix
|
||||||
? `${prefix} @${user.username} `
|
? `${prefix} @${user.username} `
|
||||||
: `@${user.username} `;
|
: `@${user.username} `;
|
||||||
@ -399,27 +402,17 @@ createWidget("search-menu-assistant", {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "in:":
|
default:
|
||||||
inSearchShortcuts.map((item) => {
|
suggestionShortcuts.forEach((item) => {
|
||||||
const slug = prefix ? `${prefix} ${item} ` : item;
|
if (item.includes(suggestionKeyword)) {
|
||||||
content.push(this.attach("search-menu-assistant-item", { slug }));
|
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 }));
|
|
||||||
});
|
});
|
||||||
break;
|
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 CATEGORY_SLUG_REGEXP = /(\#[a-zA-Z0-9\-:]*)$/gi;
|
||||||
const USERNAME_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 searchData = {};
|
||||||
const suggestionTriggers = ["in:", "status:", "order:"];
|
|
||||||
|
|
||||||
export function initSearchData() {
|
export function initSearchData() {
|
||||||
searchData.loading = false;
|
searchData.loading = false;
|
||||||
@ -53,47 +53,42 @@ const SearchHelper = {
|
|||||||
searchData.results = [];
|
searchData.results = [];
|
||||||
searchData.loading = false;
|
searchData.loading = false;
|
||||||
|
|
||||||
if (typeof matchSuggestions === "string") {
|
if (matchSuggestions.type === "category") {
|
||||||
searchData.suggestionKeyword = matchSuggestions;
|
const categorySearchTerm = matchSuggestions.categoriesMatch[0].replace(
|
||||||
|
"#",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
|
searchData.suggestionResults = Category.search(categorySearchTerm);
|
||||||
|
searchData.suggestionKeyword = "#";
|
||||||
widget.scheduleRerender();
|
widget.scheduleRerender();
|
||||||
return;
|
} else if (matchSuggestions.type === "username") {
|
||||||
} else {
|
const userSearchTerm = matchSuggestions.usernamesMatch[0].replace(
|
||||||
if (matchSuggestions.type === "category") {
|
"@",
|
||||||
const categorySearchTerm = matchSuggestions.categoriesMatch[0].replace(
|
""
|
||||||
"#",
|
);
|
||||||
""
|
const opts = { includeGroups: true, limit: 6 };
|
||||||
);
|
if (userSearchTerm.length > 0) {
|
||||||
|
opts.term = userSearchTerm;
|
||||||
searchData.suggestionResults = Category.search(categorySearchTerm);
|
} else {
|
||||||
searchData.suggestionKeyword = "#";
|
opts.lastSeenUsers = true;
|
||||||
widget.scheduleRerender();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (matchSuggestions.type === "username") {
|
|
||||||
const userSearchTerm = matchSuggestions.usernamesMatch[0].replace(
|
userSearch(opts).then((result) => {
|
||||||
"@",
|
if (result?.users?.length > 0) {
|
||||||
""
|
searchData.suggestionResults = result.users;
|
||||||
);
|
searchData.suggestionKeyword = "@";
|
||||||
const opts = { includeGroups: true, limit: 6 };
|
|
||||||
if (userSearchTerm.length > 0) {
|
|
||||||
opts.term = userSearchTerm;
|
|
||||||
} else {
|
} else {
|
||||||
opts.lastSeenUsers = true;
|
searchData.noResults = true;
|
||||||
|
searchData.suggestionKeyword = false;
|
||||||
}
|
}
|
||||||
|
widget.scheduleRerender();
|
||||||
userSearch(opts).then((result) => {
|
});
|
||||||
if (result?.users?.length > 0) {
|
} else {
|
||||||
searchData.suggestionResults = result.users;
|
searchData.suggestionKeyword = matchSuggestions[0];
|
||||||
searchData.suggestionKeyword = "@";
|
widget.scheduleRerender();
|
||||||
} else {
|
|
||||||
searchData.noResults = true;
|
|
||||||
searchData.suggestionKeyword = false;
|
|
||||||
}
|
|
||||||
widget.scheduleRerender();
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
searchData.suggestionKeyword = false;
|
searchData.suggestionKeyword = false;
|
||||||
@ -142,14 +137,6 @@ const SearchHelper = {
|
|||||||
return false;
|
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);
|
const categoriesMatch = searchData.term.match(CATEGORY_SLUG_REGEXP);
|
||||||
|
|
||||||
if (categoriesMatch) {
|
if (categoriesMatch) {
|
||||||
@ -161,6 +148,11 @@ const SearchHelper = {
|
|||||||
return { type: "username", usernamesMatch };
|
return { type: "username", usernamesMatch };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const suggestionsMatch = searchData.term.match(SUGGESTIONS_REGEXP);
|
||||||
|
if (suggestionsMatch) {
|
||||||
|
return suggestionsMatch;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -343,6 +343,10 @@ acceptance("Search - assistant", function (needs) {
|
|||||||
await fillIn("#search-term", "sam in:");
|
await fillIn("#search-term", "sam in:");
|
||||||
await triggerKeyEvent("#search-term", "keyup", 51);
|
await triggerKeyEvent("#search-term", "keyup", 51);
|
||||||
assert.equal(query(firstTarget).innerText, "sam in:title");
|
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) {
|
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
|
posts.where("posts.user_id = #{@guardian.user.id}") if @guardian.user
|
||||||
end
|
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
|
posts.where(user_id: @guardian.user.id, post_number: 1) if @guardian.user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user