FEATURE: Show prompt for required tag groups (#16458)

This commit is contained in:
David Taylor 2022-04-21 13:13:52 +01:00 committed by GitHub
parent 42bb629817
commit e5fb884695
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 105 additions and 5 deletions

View File

@ -133,13 +133,26 @@ export function applyDefaultHandlers(pretender) {
pretender.delete("/bookmarks/:id", () => response({}));
pretender.get("/tags/filter/search", () => {
return response({
pretender.get("/tags/filter/search", (request) => {
const responseBody = {
results: [
{ id: "monkey", name: "monkey", count: 1 },
{ id: "gazelle", name: "gazelle", count: 2 },
],
});
};
if (
request.queryParams.categoryId === "1" &&
request.queryParams.q === "" &&
!request.queryParams.selected_tags.includes("monkey")
) {
responseBody["required_tag_group"] = {
name: "monkey group",
min_count: 1,
};
}
return response(responseBody);
});
pretender.get(`/u/:username/emails.json`, (request) => {

View File

@ -3,6 +3,7 @@ import componentTest, {
} from "discourse/tests/helpers/component-test";
import {
discourseModule,
query,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import I18n from "I18n";
@ -81,5 +82,34 @@ discourseModule(
);
},
});
componentTest("required_tag_group", {
template: hbs`{{mini-tag-chooser value=value options=(hash categoryId=1)}}`,
beforeEach() {
this.set("value", ["foo", "bar"]);
},
async test(assert) {
assert.strictEqual(this.subject.header().value(), "foo,bar");
await this.subject.expand();
assert.strictEqual(
query("input[name=filter-input-search]").placeholder,
I18n.t("tagging.choose_for_topic_required_group", {
count: 1,
name: "monkey group",
})
);
await this.subject.selectRowByValue("monkey");
assert.strictEqual(
query("input[name=filter-input-search]").placeholder,
I18n.t("select_kit.filter_placeholder")
);
},
});
}
);

View File

@ -96,6 +96,18 @@ export default MultiSelectComponent.extend(TagsMixin, {
results = results.sort((a, b) => a.text.localeCompare(b.text));
}
if (json.required_tag_group) {
context.set(
"selectKit.options.translatedFilterPlaceholder",
I18n.t("tagging.choose_for_topic_required_group", {
count: json.required_tag_group.min_count,
name: json.required_tag_group.name,
})
);
} else {
context.set("selectKit.options.translatedFilterPlaceholder", null);
}
return results.filter((r) => !makeArray(context.tags).includes(r.id));
},
});

View File

@ -246,9 +246,10 @@ class TagsController < ::ApplicationController
filter_params[:order_popularity] = true
end
tags_with_counts = DiscourseTagging.filter_allowed_tags(
tags_with_counts, filter_result_context = DiscourseTagging.filter_allowed_tags(
guardian,
filter_params
**filter_params,
with_context: true
)
tags = self.class.tag_counts_json(tags_with_counts, show_pm_tags: guardian.can_tag_pms?)
@ -281,6 +282,10 @@ class TagsController < ::ApplicationController
end
end
if required_tag_group = filter_result_context[:required_tag_group]
json_response[:required_tag_group] = required_tag_group
end
render json: json_response
end

View File

@ -3836,6 +3836,9 @@ en:
choose_for_topic_required:
one: "select at least %{count} tag..."
other: "select at least %{count} tags..."
choose_for_topic_required_group:
one: "select %{count} tag from '%{name}'..."
other: "select %{count} tags from '%{name}'..."
info: "Info"
default_info: "This tag isn't restricted to any categories, and has no synonyms."
staff_info: "To add restrictions, put this tag in a <a href=%{basePath}/tag_groups>tag group</a>."

View File

@ -367,11 +367,13 @@ module DiscourseTagging
# - there are more available tags than the query limit
# - and no search term has been included
required_tag_ids = nil
required_category_tag_group = nil
if opts[:for_input] && category&.category_required_tag_groups.present? && (filter_for_non_staff || term.blank?)
category.category_required_tag_groups.each do |crtg|
group_tags = crtg.tag_group.tags.pluck(:id)
next if (group_tags & selected_tag_ids).size >= crtg.min_count
if filter_for_non_staff || group_tags.size >= opts[:limit].to_i
required_category_tag_group = crtg
required_tag_ids = group_tags
builder.where("id IN (?)", required_tag_ids)
end
@ -441,6 +443,19 @@ module DiscourseTagging
end
result = builder.query(builder_params).uniq { |t| t.id }
if opts[:with_context]
context = {}
if required_category_tag_group
context[:required_tag_group] = {
name: required_category_tag_group.tag_group.name,
min_count: required_category_tag_group.min_count
}
end
[result, context]
else
result
end
end
def self.filter_visible(query, guardian = nil)

View File

@ -877,6 +877,28 @@ describe TagsController do
expect(response.status).to eq(400)
expect(response.parsed_body['errors'].first).to eq(I18n.t('invalid_params', message: 'limit'))
end
it 'includes required tag group information' do
tag1 = Fabricate(:tag)
tag2 = Fabricate(:tag)
tag_group = Fabricate(:tag_group, tags: [tag1, tag2])
crtg = CategoryRequiredTagGroup.new(tag_group: tag_group, min_count: 1)
category = Fabricate(:category, category_required_tag_groups: [ crtg ])
get "/tags/filter/search.json", params: { q: '', categoryId: category.id, filterForInput: true }
expect(response.status).to eq(200)
expect(response.parsed_body["results"].map { |t| t["name"] }).to contain_exactly(tag1.name, tag2.name)
expect(response.parsed_body["required_tag_group"]).to eq({
"name" => tag_group.name,
"min_count" => crtg.min_count
})
get "/tags/filter/search.json", params: { q: '', categoryId: category.id, filterForInput: true, selected_tags: [tag1.name] }
expect(response.status).to eq(200)
expect(response.parsed_body["results"].map { |t| t["name"] }).to contain_exactly(tag2.name)
expect(response.parsed_body["required_tag_group"]).to eq(nil)
end
end
end