FEATURE: Scope search to PMs when in that context (#16528)

This commit is contained in:
Penar Musaraj 2022-04-26 14:43:09 -04:00 committed by GitHub
parent 11c5ff5f8e
commit 07f975848d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 219 additions and 23 deletions

View File

@ -118,7 +118,9 @@ function translateGroupedSearchResults(results, opts) {
const name = pair[1]; const name = pair[1];
if (results[name].length > 0) { if (results[name].length > 0) {
const componentName = const componentName =
opts.searchContext && type === "topic" ? "post" : type; opts.searchContext?.type === "topic" && type === "topic"
? "post"
: type;
const result = { const result = {
results: results[name], results: results[name],

View File

@ -292,7 +292,7 @@ createWidget("search-menu-results", {
return h("div.no-results", I18n.t("search.no_results")); return h("div.no-results", I18n.t("search.no_results"));
} }
if (!term) { if (!term && !attrs.inPMInboxContext) {
return this.attach("search-menu-initial-options", { term }); return this.attach("search-menu-initial-options", { term });
} }
@ -364,7 +364,9 @@ createWidget("search-menu-results", {
const content = []; const content = [];
if (!searchTopics) { if (!searchTopics) {
content.push(this.attach("search-menu-initial-options", { term })); if (!attrs.inPMInboxContext) {
content.push(this.attach("search-menu-initial-options", { term }));
}
} else { } else {
if (mainResultsContent.length) { if (mainResultsContent.length) {
content.push(mainResultsContent); content.push(mainResultsContent);

View File

@ -198,6 +198,7 @@ export default createWidget("search-menu", {
defaultState(attrs) { defaultState(attrs) {
return { return {
inTopicContext: attrs.inTopicContext, inTopicContext: attrs.inTopicContext,
inPMInboxContext: this.search?.searchContext?.type === "private_messages",
_lastEnterTimestamp: null, _lastEnterTimestamp: null,
_debouncer: null, _debouncer: null,
}; };
@ -216,6 +217,8 @@ export default createWidget("search-menu", {
if (searchContext?.type === "topic") { if (searchContext?.type === "topic") {
query += encodeURIComponent(` topic:${searchContext.id}`); query += encodeURIComponent(` topic:${searchContext.id}`);
} else if (searchContext?.type === "private_messages") {
query += encodeURIComponent(` in:personal`);
} }
if (query) { if (query) {
@ -236,7 +239,6 @@ export default createWidget("search-menu", {
panelContents() { panelContents() {
let searchInput = []; let searchInput = [];
if (this.state.inTopicContext) { if (this.state.inTopicContext) {
searchInput.push( searchInput.push(
this.attach("button", { this.attach("button", {
@ -248,6 +250,17 @@ export default createWidget("search-menu", {
iconRight: true, iconRight: true,
}) })
); );
} else if (this.state.inPMInboxContext) {
searchInput.push(
this.attach("button", {
icon: "times",
label: "search.in_messages",
title: "search.in_messages_tooltip",
className: "btn btn-small search-context",
action: "clearPMInboxContext",
iconRight: true,
})
);
} }
searchInput.push(this.attach("search-term", { value: searchData.term })); searchInput.push(this.attach("search-term", { value: searchData.term }));
@ -302,6 +315,7 @@ export default createWidget("search-menu", {
suggestionKeyword: searchData.suggestionKeyword, suggestionKeyword: searchData.suggestionKeyword,
suggestionResults: searchData.suggestionResults, suggestionResults: searchData.suggestionResults,
searchTopics: SearchHelper.includesTopics(), searchTopics: SearchHelper.includesTopics(),
inPMInboxContext: this.state.inPMInboxContext,
}) })
); );
} }
@ -336,6 +350,11 @@ export default createWidget("search-menu", {
this.sendWidgetAction("clearContext"); this.sendWidgetAction("clearContext");
}, },
clearPMInboxContext() {
this.state.inPMInboxContext = false;
this.sendWidgetAction("focusSearchInput");
},
keyDown(e) { keyDown(e) {
if (e.which === 27 /* escape */) { if (e.which === 27 /* escape */) {
this.sendWidgetAction("toggleSearchMenu"); this.sendWidgetAction("toggleSearchMenu");
@ -446,6 +465,7 @@ export default createWidget("search-menu", {
if (e.target === searchInput && e.which === 8 /* backspace */) { if (e.target === searchInput && e.which === 8 /* backspace */) {
if (!searchInput.value) { if (!searchInput.value) {
this.clearTopicContext(); this.clearTopicContext();
this.clearPMInboxContext();
} }
} }
}, },
@ -506,7 +526,7 @@ export default createWidget("search-menu", {
}, },
searchContext() { searchContext() {
if (this.state.inTopicContext) { if (this.state.inTopicContext || this.state.inPMInboxContext) {
return this.search.searchContext; return this.search.searchContext;
} }

View File

@ -247,12 +247,9 @@ acceptance("Group - Authenticated", function (needs) {
await click("#search-button"); await click("#search-button");
await fillIn("#search-term", "smth"); await fillIn("#search-term", "smth");
assert.strictEqual( assert.ok(
query( query(".search-menu .btn.search-context"),
".search-menu .results .search-menu-assistant-item:first-child" "'in messages' toggle is active by default"
).innerText.trim(),
"smth in:personal",
"contextual search is available as first option"
); );
}); });

View File

@ -105,7 +105,7 @@ acceptance("Search - Full Page", function (needs) {
}); });
}); });
needs.hooks.afterEach(function () { needs.hooks.afterEach(() => {
searchResultClickTracked = false; searchResultClickTracked = false;
}); });

View File

@ -11,6 +11,13 @@ import selectKit from "discourse/tests/helpers/select-kit-helper";
import { test } from "qunit"; import { test } from "qunit";
import { DEFAULT_TYPE_FILTER } from "discourse/widgets/search-menu"; import { DEFAULT_TYPE_FILTER } from "discourse/widgets/search-menu";
const keyEnter = 13;
const keyArrowDown = 40;
const keyArrowUp = 38;
const keyEsc = 27;
const keyA = 65;
const keyBackSpace = 8;
acceptance("Search - Anonymous", function (needs) { acceptance("Search - Anonymous", function (needs) {
needs.pretender((server, helper) => { needs.pretender((server, helper) => {
server.get("/search/query", (request) => { server.get("/search/query", (request) => {
@ -81,7 +88,7 @@ acceptance("Search - Anonymous", function (needs) {
"shows matching user results" "shows matching user results"
); );
await triggerKeyEvent(".search-menu", "keydown", 40); await triggerKeyEvent(".search-menu", "keydown", keyArrowDown);
await click(document.activeElement); await click(document.activeElement);
assert.ok( assert.ok(
@ -195,7 +202,7 @@ acceptance("Search - Anonymous", function (needs) {
await fillIn("#search-term", "a proper"); await fillIn("#search-term", "a proper");
await query("input#search-term").focus(); await query("input#search-term").focus();
await triggerKeyEvent(".search-menu", "keydown", 40); await triggerKeyEvent(".search-menu", "keydown", keyArrowDown);
await click(document.activeElement); await click(document.activeElement);
assert.ok( assert.ok(
@ -225,7 +232,7 @@ acceptance("Search - Anonymous", function (needs) {
await fillIn("#search-term", "dev"); await fillIn("#search-term", "dev");
await query("input#search-term").focus(); await query("input#search-term").focus();
await triggerKeyEvent(".search-menu", "keydown", 40); await triggerKeyEvent(".search-menu", "keydown", keyArrowDown);
await click(document.activeElement); await click(document.activeElement);
assert.ok( assert.ok(
@ -235,7 +242,7 @@ acceptance("Search - Anonymous", function (needs) {
await fillIn("#search-term", ""); await fillIn("#search-term", "");
await query("input#search-term").focus(); await query("input#search-term").focus();
await triggerKeyEvent("input#search-term", "keydown", 8); // backspace await triggerKeyEvent("input#search-term", "keydown", keyBackSpace);
assert.ok( assert.ok(
!exists(".search-menu .search-context"), !exists(".search-menu .search-context"),
@ -259,7 +266,7 @@ acceptance("Search - Anonymous", function (needs) {
await fillIn("#search-term", "proper"); await fillIn("#search-term", "proper");
await query("input#search-term").focus(); await query("input#search-term").focus();
await triggerKeyEvent(".search-menu", "keydown", 40); await triggerKeyEvent(".search-menu", "keydown", keyArrowDown);
await click(document.activeElement); await click(document.activeElement);
assert.ok( assert.ok(
@ -394,7 +401,7 @@ acceptance("Search - Authenticated", function (needs) {
await click("#search-button"); await click("#search-button");
await fillIn("#search-term", "plans"); await fillIn("#search-term", "plans");
await query("input#search-term").focus(); await query("input#search-term").focus();
await triggerKeyEvent(".search-menu", "keydown", 40); await triggerKeyEvent(".search-menu", "keydown", keyArrowDown);
await click(document.activeElement); await click(document.activeElement);
assert.notStrictEqual(count(".search-menu .results .item"), 0); assert.notStrictEqual(count(".search-menu .results .item"), 0);
@ -407,11 +414,6 @@ acceptance("Search - Authenticated", function (needs) {
}); });
test("search dropdown keyboard navigation", async function (assert) { test("search dropdown keyboard navigation", async function (assert) {
const keyEnter = 13;
const keyArrowDown = 40;
const keyArrowUp = 38;
const keyEsc = 27;
const keyA = 65;
const container = ".search-menu .results"; const container = ".search-menu .results";
await visit("/"); await visit("/");
@ -570,6 +572,147 @@ acceptance("Search - assistant", function (needs) {
needs.user(); needs.user();
needs.pretender((server, helper) => { needs.pretender((server, helper) => {
server.get("/search/query", (request) => {
if (request.queryParams["search_context[type]"] === "private_messages") {
// return only one result for PM search
return helper.response({
posts: [
{
id: 3833,
name: "Bill Dudney",
username: "bdudney",
avatar_template:
"/user_avatar/meta.discourse.org/bdudney/{size}/8343_1.png",
uploaded_avatar_id: 8343,
created_at: "2013-02-07T17:46:57.469Z",
cooked:
"<p>I've gotten vagrant up and running with a development environment but it's taking forever to load.</p>\n\n<p>For example <a href=\"http://192.168.10.200:3000/\" rel=\"nofollow\">http://192.168.10.200:3000/</a> takes tens of seconds to load.</p>\n\n<p>I'm running the whole stack on a new rMBP with OS X 10.8.2.</p>\n\n<p>Any ideas of what I've done wrong? Or is this just a function of being on the bleeding edge?</p>\n\n<p>Thanks,</p>\n\n<p>-bd</p>",
post_number: 1,
post_type: 1,
updated_at: "2013-02-07T17:46:57.469Z",
like_count: 0,
reply_count: 1,
reply_to_post_number: null,
quote_count: 0,
incoming_link_count: 4422,
reads: 327,
score: 21978.4,
yours: false,
topic_id: 2179,
topic_slug: "development-mode-super-slow",
display_username: "Bill Dudney",
primary_group_name: null,
version: 2,
can_edit: false,
can_delete: false,
can_recover: false,
user_title: null,
actions_summary: [
{
id: 2,
count: 0,
hidden: false,
can_act: false,
},
{
id: 3,
count: 0,
hidden: false,
can_act: false,
},
{
id: 4,
count: 0,
hidden: false,
can_act: false,
},
{
id: 5,
count: 0,
hidden: true,
can_act: false,
},
{
id: 6,
count: 0,
hidden: false,
can_act: false,
},
{
id: 7,
count: 0,
hidden: false,
can_act: false,
},
{
id: 8,
count: 0,
hidden: false,
can_act: false,
},
],
moderator: false,
admin: false,
staff: false,
user_id: 1828,
hidden: false,
hidden_reason_id: null,
trust_level: 1,
deleted_at: null,
user_deleted: false,
edit_reason: null,
can_view_edit_history: true,
wiki: false,
blurb:
"I've gotten vagrant up and running with a development environment but it's taking forever to load. For example http://192.168.10.200:3000/ takes...",
},
],
topics: [
{
id: 2179,
title: "Development mode super slow",
fancy_title: "Development mode super slow",
slug: "development-mode-super-slow",
posts_count: 72,
reply_count: 53,
highest_post_number: 73,
image_url: null,
created_at: "2013-02-07T17:46:57.262Z",
last_posted_at: "2015-04-17T08:08:26.671Z",
bumped: true,
bumped_at: "2015-04-17T08:08:26.671Z",
unseen: false,
pinned: false,
unpinned: null,
visible: true,
closed: false,
archived: false,
bookmarked: null,
liked: null,
views: 9538,
like_count: 45,
has_summary: true,
archetype: "regular",
last_poster_username: null,
category_id: 7,
pinned_globally: false,
posters: [],
tags: ["dev", "slow"],
tags_descriptions: {
dev: "dev description",
slow: "slow description",
},
},
],
grouped_search_result: {
term: "emoji",
post_ids: [3833],
},
});
}
return helper.response(searchFixtures["search/query"]);
});
server.get("/u/search/users", () => { server.get("/u/search/users", () => {
return helper.response({ return helper.response({
users: [ users: [
@ -666,4 +809,34 @@ acceptance("Search - assistant", function (needs) {
await click(query(firstUser)); await click(query(firstUser));
assert.strictEqual(query("#search-term").value, `@${firstUsername}`); assert.strictEqual(query("#search-term").value, `@${firstUsername}`);
}); });
test("shows 'in messages' button when in an inbox", async function (assert) {
await visit("/u/charlie/messages");
await click("#search-button");
assert.ok(exists(".btn.search-context"), "it shows the button");
await fillIn("#search-term", "");
await query("input#search-term").focus();
await triggerKeyEvent("input#search-term", "keydown", keyBackSpace);
assert.notOk(exists(".btn.search-context"), "it removes the button");
await click(".d-header");
await click("#search-button");
assert.ok(
exists(".btn.search-context"),
"it shows the button when reinvoking search"
);
await fillIn("#search-term", "emoji");
await query("input#search-term").focus();
await triggerKeyEvent("#search-term", "keydown", keyEnter);
assert.strictEqual(
count(".search-menu .search-result-topic"),
1,
"it passes the PM search context to the search query"
);
});
}); });

View File

@ -2425,6 +2425,8 @@ en:
in: "in" in: "in"
in_this_topic: "in this topic" in_this_topic: "in this topic"
in_this_topic_tooltip: "switch to searching all topics" in_this_topic_tooltip: "switch to searching all topics"
in_messages: "in messages"
in_messages_tooltip: "switch to searching regular topics"
in_topics_posts: "in all topics and posts" in_topics_posts: "in all topics and posts"
enter_hint: "or press Enter" enter_hint: "or press Enter"
in_posts_by: "in posts by %{username}" in_posts_by: "in posts by %{username}"