FEATURE: advanced search option for max posts count (#10761)

This commit adds an option to search for max posts count and updates
the UI for posts count search to show a min/max range in single line.
This commit is contained in:
Arpit Jalan 2020-09-28 21:34:16 +05:30 committed by GitHub
parent 4d1b18f4c6
commit f7940b1d20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 101 additions and 20 deletions

View File

@ -12,6 +12,7 @@ const REGEXP_TAGS_PREFIX = /^(tags?:|#(?=[a-z0-9\-]+::tag))/gi;
const REGEXP_IN_PREFIX = /^(in|with):/gi;
const REGEXP_STATUS_PREFIX = /^status:/gi;
const REGEXP_MIN_POSTS_PREFIX = /^min_posts:/gi;
const REGEXP_MAX_POSTS_PREFIX = /^max_posts:/gi;
const REGEXP_MIN_VIEWS_PREFIX = /^min_views:/gi;
const REGEXP_MAX_VIEWS_PREFIX = /^max_views:/gi;
const REGEXP_POST_TIME_PREFIX = /^(before|after):/gi;
@ -95,6 +96,7 @@ export default Component.extend({
},
status: null,
min_posts: null,
max_posts: null,
min_views: null,
max_views: null,
time: {
@ -166,6 +168,11 @@ export default Component.extend({
REGEXP_MIN_POSTS_PREFIX
);
this.setSearchedTermValue(
"searchedTerms.max_posts",
REGEXP_MAX_POSTS_PREFIX
);
this.setSearchedTermValue(
"searchedTerms.min_views",
REGEXP_MIN_VIEWS_PREFIX
@ -359,6 +366,12 @@ export default Component.extend({
this._updateSearchTermForMinPostCount();
},
@action
onChangeSearchTermMaxPostCount(value) {
this.set("searchedTerms.max_posts", value.length ? value : null);
this._updateSearchTermForMaxPostCount();
},
@action
onChangeSearchTermMinViews(value) {
this.set("searchedTerms.min_views", value.length ? value : null);
@ -653,6 +666,28 @@ export default Component.extend({
}
},
_updateSearchTermForMaxPostCount() {
const match = this.filterBlocks(REGEXP_MAX_POSTS_PREFIX);
const postsCountFilter = this.get("searchedTerms.max_posts");
let searchTerm = this.searchTerm || "";
if (postsCountFilter) {
if (match.length !== 0) {
searchTerm = searchTerm.replace(
match[0],
`max_posts:${postsCountFilter}`
);
} else {
searchTerm += ` max_posts:${postsCountFilter}`;
}
this._updateSearchTerm(searchTerm);
} else if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], "");
this._updateSearchTerm(searchTerm);
}
},
_updateSearchTermForMinViews() {
const match = this.filterBlocks(REGEXP_MIN_VIEWS_PREFIX);
const viewsCountFilter = this.get("searchedTerms.min_views");

View File

@ -148,22 +148,39 @@
}}
</div>
</div>
<div class="control-group pull-left">
<div class="count-group control-group pull-left">
<label class="control-label" for="search-min-post-count">{{i18n "search.advanced.post.count.label"}}</label>
<div class="controls">
{{input
type="number"
value=(readonly searchedTerms.min_posts)
class="input-small"
id="search-min-post-count"
input=(action "onChangeSearchTermMinPostCount" value="target.value")
}}
<div class="count pull-left">
<div class="controls">
{{input
type="number"
value=(readonly searchedTerms.min_posts)
class="input-small"
id="search-min-post-count"
input=(action "onChangeSearchTermMinPostCount" value="target.value")
placeholder=(i18n "search.advanced.post.min.placeholder")
}}
</div>
</div>
<span class="count-dash">&mdash;</span>
<div class="count pull-right">
<div class="controls">
{{input
type="number"
value=(readonly searchedTerms.max_posts)
class="input-small"
id="search-max-post-count"
input=(action "onChangeSearchTermMaxPostCount" value="target.value")
placeholder=(i18n "search.advanced.post.max.placeholder")
}}
</div>
</div>
</div>
<div class="views control-group pull-left">
<div class="count-group control-group pull-left">
<label class="control-label">{{i18n "search.advanced.views.label"}}</label>
<div class="views-count pull-left">
<div class="count pull-left">
<div class="controls">
{{input
type="number"
@ -175,8 +192,8 @@
}}
</div>
</div>
<span class="views-count-dash"></span>
<div class="views-count pull-right">
<span class="count-dash">&mdash;</span>
<div class="count pull-right">
<div class="controls">
{{input
type="number"

View File

@ -164,13 +164,13 @@
}
}
.views {
.views-count {
.count-group {
.count {
margin-bottom: 15px;
width: 45%;
}
.views-count-dash {
padding-left: 10px;
.count-dash {
padding-left: 6px;
vertical-align: middle;
}
}

View File

@ -2119,7 +2119,11 @@ en:
single_user: contain a single user
post:
count:
label: Minimum Posts
label: Posts
min:
placeholder: minimum
max:
placeholder: maximum
time:
label: Posted
before: before

View File

@ -369,12 +369,16 @@ class Search
posts.where("topics.posts_count = ?", match.to_i)
end
advanced_filter(/^min_post_count:(\d+)$/i) do |posts, match|
posts.where("topics.posts_count >= ?", match.to_i)
end
advanced_filter(/^min_posts:(\d+)$/i) do |posts, match|
posts.where("topics.posts_count >= ?", match.to_i)
end
advanced_filter(/^min_post_count:(\d+)$/i) do |posts, match|
posts.where("topics.posts_count >= ?", match.to_i)
advanced_filter(/^max_posts:(\d+)$/i) do |posts, match|
posts.where("topics.posts_count <= ?", match.to_i)
end
advanced_filter(/^in:first|^f$/i) do |posts|

View File

@ -1279,6 +1279,7 @@ describe Search do
expect(Search.execute('test posts_count:1').posts.length).to eq(1)
expect(Search.execute('test min_post_count:1').posts.length).to eq(1)
expect(Search.execute('test min_posts:1').posts.length).to eq(1)
expect(Search.execute('test max_posts:2').posts.length).to eq(1)
topic.update(closed: true)
second_topic.update(category: public_category)

View File

@ -396,6 +396,26 @@ QUnit.test(
}
);
QUnit.test(
"update max post count through advanced search ui",
async (assert) => {
await visit("/search");
await fillIn(".search-query", "none");
await fillIn("#search-max-post-count", "5");
assert.equal(
find(".search-advanced-options #search-max-post-count").val(),
"5",
'has "5" populated'
);
assert.equal(
find(".search-query").val(),
"none max_posts:5",
'has updated search term to "none max_posts:5"'
);
}
);
QUnit.test("validate advanced search when initially empty", async (assert) => {
await visit("/search?expanded=true");
await click(".search-advanced-options .in-likes");