diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs
index 39c02c1d..f51b9fbb 100644
--- a/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs
+++ b/assets/javascripts/discourse/templates/components/wizard-custom-field.hbs
@@ -208,6 +208,20 @@
{{/if}}
+{{#if isTag}}
+
+
+
+
+
+
+ {{tag-group-chooser
+ tagGroups=field.tag_groups
+ }}
+
+
+{{/if}}
+
{{#if showAdvanced}}
{{wizard-advanced-toggle showAdvanced=field.showAdvanced}}
diff --git a/assets/javascripts/wizard/components/wizard-tag-chooser.js.es6 b/assets/javascripts/wizard/components/wizard-tag-chooser.js.es6
new file mode 100644
index 00000000..32a1fd6a
--- /dev/null
+++ b/assets/javascripts/wizard/components/wizard-tag-chooser.js.es6
@@ -0,0 +1,12 @@
+import TagChooser from "select-kit/components/tag-chooser";
+
+export default TagChooser.extend({
+ searchTags(url, data, callback) {
+ if (this.tagGroups) {
+ let tagGroupsString = this.tagGroups.join(",");
+ data.tag_groups = tagGroupsString;
+ }
+
+ return this._super(url, data, callback);
+ },
+});
diff --git a/assets/javascripts/wizard/templates/components/wizard-field-tag.hbs b/assets/javascripts/wizard/templates/components/wizard-field-tag.hbs
index 8ebc56eb..1916f3d1 100644
--- a/assets/javascripts/wizard/templates/components/wizard-field-tag.hbs
+++ b/assets/javascripts/wizard/templates/components/wizard-field-tag.hbs
@@ -1 +1,7 @@
-{{tag-chooser tags=field.value maximum=field.limit tabindex=field.tabindex everyTag=true}}
+{{wizard-tag-chooser
+ tags=field.value
+ maximum=field.limit
+ tabindex=field.tabindex
+ tagGroups=field.tag_groups
+ everyTag=true
+}}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index ff500ee2..b51421a7 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -188,6 +188,7 @@ en:
property: "Property"
prefill: "Prefill"
content: "Content"
+ tag_groups: "Tag Groups"
date_time_format:
label: "Format"
instructions: "Moment.js format"
diff --git a/controllers/custom_wizard/admin/wizard.rb b/controllers/custom_wizard/admin/wizard.rb
index 09471680..0a59e02b 100644
--- a/controllers/custom_wizard/admin/wizard.rb
+++ b/controllers/custom_wizard/admin/wizard.rb
@@ -117,6 +117,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
condition: mapped_params,
index: mapped_params,
validations: {},
+ tag_groups: [],
]
],
actions: [
diff --git a/extensions/discourse_tagging.rb b/extensions/discourse_tagging.rb
new file mode 100644
index 00000000..6c4d6040
--- /dev/null
+++ b/extensions/discourse_tagging.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module CustomWizardDiscourseTagging
+ def filter_allowed_tags(guardian, opts = {})
+ if tag_groups = RequestStore.store[:tag_groups]
+ tag_group_array = tag_groups.split(",")
+ filtered_tags = TagGroup.includes(:tags).where(name: tag_group_array).map do |tag_group|
+ tag_group.tags.pluck(:name)
+ end.flatten
+
+ opts[:only_tag_names] ||= []
+ opts[:only_tag_names].push(*filtered_tags)
+ end
+
+ super
+ end
+end
diff --git a/extensions/tags_controller.rb b/extensions/tags_controller.rb
new file mode 100644
index 00000000..e9618733
--- /dev/null
+++ b/extensions/tags_controller.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module CustomWizardTagsController
+ def search
+ RequestStore.store[:tag_groups] = params[:tag_groups] if params[:tag_groups].present?
+ super
+ end
+end
diff --git a/lib/custom_wizard/builder.rb b/lib/custom_wizard/builder.rb
index aede16a2..681bc459 100644
--- a/lib/custom_wizard/builder.rb
+++ b/lib/custom_wizard/builder.rb
@@ -86,7 +86,7 @@ class CustomWizard::Builder
required: field_template['required']
}
- %w(label description image key validations min_length max_length char_counter).each do |key|
+ %w(label description image key validations min_length max_length char_counter tag_groups).each do |key|
params[key.to_sym] = field_template[key] if field_template[key]
end
diff --git a/lib/custom_wizard/field.rb b/lib/custom_wizard/field.rb
index eb4af65d..65f29504 100644
--- a/lib/custom_wizard/field.rb
+++ b/lib/custom_wizard/field.rb
@@ -21,6 +21,7 @@ class CustomWizard::Field
:limit,
:property,
:content,
+ :tag_groups,
:preview_template,
:placeholder
@@ -46,6 +47,7 @@ class CustomWizard::Field
@limit = attrs[:limit]
@property = attrs[:property]
@content = attrs[:content]
+ @tag_groups = attrs[:tag_groups]
@preview_template = attrs[:preview_template]
@placeholder = attrs[:placeholder]
end
@@ -111,7 +113,8 @@ class CustomWizard::Field
tag: {
limit: nil,
prefill: nil,
- content: nil
+ content: nil,
+ tag_groups: nil
},
category: {
limit: 1,
diff --git a/plugin.rb b/plugin.rb
index 49745617..ba042e71 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -1,12 +1,14 @@
# frozen_string_literal: true
# name: discourse-custom-wizard
# about: Create custom wizards
-# version: 1.17.2.stable
+# version: 1.18.0.stable
# authors: Angus McLeod
# url: https://github.com/paviliondev/discourse-custom-wizard
# contact emails: angus@thepavilion.io
gem 'liquid', '5.0.1', require: true
+## ensure compatibility with category lockdown plugin
+gem 'request_store', '1.5.0', require: true
register_asset 'stylesheets/common/wizard-admin.scss'
register_asset 'stylesheets/common/wizard-mapper.scss'
@@ -110,9 +112,11 @@ after_initialize do
../extensions/invites_controller.rb
../extensions/guardian.rb
../extensions/users_controller.rb
+ ../extensions/tags_controller.rb
../extensions/custom_field/preloader.rb
../extensions/custom_field/serializer.rb
../extensions/custom_field/extension.rb
+ ../extensions/discourse_tagging.rb
].each do |path|
load File.expand_path(path, __FILE__)
end
@@ -249,5 +253,10 @@ after_initialize do
"#{serializer_klass}_serializer".classify.constantize.prepend CustomWizardCustomFieldSerializer
end
+ reloadable_patch do |plugin|
+ ::TagsController.prepend CustomWizardTagsController
+ ::DiscourseTagging.singleton_class.prepend CustomWizardDiscourseTagging
+ end
+
DiscourseEvent.trigger(:custom_wizard_ready)
end
diff --git a/serializers/custom_wizard/wizard_field_serializer.rb b/serializers/custom_wizard/wizard_field_serializer.rb
index 37f7a80f..9aa750e5 100644
--- a/serializers/custom_wizard/wizard_field_serializer.rb
+++ b/serializers/custom_wizard/wizard_field_serializer.rb
@@ -16,6 +16,7 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
:limit,
:property,
:content,
+ :tag_groups,
:validations,
:max_length,
:char_counter,
@@ -100,6 +101,10 @@ class CustomWizard::FieldSerializer < ::ApplicationSerializer
object.content
end
+ def content
+ object.tag_groups
+ end
+
def validations
validations = {}
object.validations&.each do |type, props|
diff --git a/spec/extensions/tags_controller_spec.rb b/spec/extensions/tags_controller_spec.rb
new file mode 100644
index 00000000..455990c6
--- /dev/null
+++ b/spec/extensions/tags_controller_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require_relative '../plugin_helper'
+
+describe ::TagsController, type: :request do
+ fab!(:tag_1) { Fabricate(:tag, name: "Angus") }
+ fab!(:tag_2) { Fabricate(:tag, name: "Faizaan") }
+ fab!(:tag_3) { Fabricate(:tag, name: "Robert") }
+ fab!(:tag_4) { Fabricate(:tag, name: "Eli") }
+ fab!(:tag_5) { Fabricate(:tag, name: "Jeff") }
+
+ fab!(:tag_group_1) { Fabricate(:tag_group, tags: [tag_1, tag_2]) }
+ fab!(:tag_group_2) { Fabricate(:tag_group, tags: [tag_3, tag_4]) }
+
+ describe "#search" do
+ context "tag group param present" do
+ it "returns tags only only in the tag group" do
+ get "/tags/filter/search.json", params: { q: '', tag_groups: [tag_group_1.name, tag_group_2.name] }
+ expect(response.status).to eq(200)
+ results = response.parsed_body['results']
+ names = results.map { |result| result['name'] }
+
+ expected_tag_names = TagGroup
+ .includes(:tags)
+ .where(id: [tag_group_1.id, tag_group_2.id])
+ .map { |tag_group| tag_group.tags.pluck(:name) }.flatten
+ expect(names).to contain_exactly(*expected_tag_names)
+ end
+ end
+
+ context "tag group param not present" do
+ it "returns all tags" do
+ get "/tags/filter/search.json", params: { q: '' }
+ expect(response.status).to eq(200)
+ results = response.parsed_body['results']
+ names = results.map { |result| result['name'] }
+
+ all_tag_names = Tag.all.pluck(:name)
+ expect(names).to contain_exactly(*all_tag_names)
+ end
+ end
+ end
+end