mirror of
https://github.com/discourse/discourse.git
synced 2025-03-06 10:42:33 +08:00
DEV: Apply form template to categories (#20337)
This commit is contained in:
parent
a9f2c6db64
commit
6108eee31d
@ -1,4 +1,38 @@
|
||||
<DEditor
|
||||
@value={{this.category.topic_template}}
|
||||
@showLink={{this.showInsertLinkButton}}
|
||||
/>
|
||||
{{#if this.siteSettings.experimental_form_templates}}
|
||||
<div class="control-group">
|
||||
<DToggleSwitch
|
||||
class="toggle-template-type"
|
||||
@state={{this.showFormTemplate}}
|
||||
@label={{this.templateTypeToggleLabel}}
|
||||
{{on "click" this.toggleTemplateType}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{{#if this.showFormTemplate}}
|
||||
<div class="control-group">
|
||||
<FormTemplateChooser
|
||||
@class="select-category-template"
|
||||
@value={{this.category.form_template_ids}}
|
||||
@onChange={{action (mut this.category.form_template_ids)}}
|
||||
/>
|
||||
|
||||
<p class="select-category-template__info desc">
|
||||
{{#if this.currentUser.staff}}
|
||||
<LinkTo @route="adminCustomizeFormTemplates">
|
||||
{{i18n "admin.form_templates.edit_category.select_template_help"}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
{{else}}
|
||||
<DEditor
|
||||
@value={{this.category.topic_template}}
|
||||
@showLink={{this.showInsertLinkButton}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<DEditor
|
||||
@value={{this.category.topic_template}}
|
||||
@showLink={{this.showInsertLinkButton}}
|
||||
/>
|
||||
{{/if}}
|
@ -1,15 +1,40 @@
|
||||
import { buildCategoryPanel } from "discourse/components/edit-category-panel";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import { action, computed } from "@ember/object";
|
||||
|
||||
export default buildCategoryPanel("topic-template", {
|
||||
// Modals are defined using the singleton pattern.
|
||||
// Opening the insert link modal will destroy the edit category modal.
|
||||
showInsertLinkButton: false,
|
||||
showFormTemplate: computed("category.form_template_ids", {
|
||||
get() {
|
||||
return Boolean(this.category.form_template_ids.length);
|
||||
},
|
||||
set(key, value) {
|
||||
return value;
|
||||
},
|
||||
}),
|
||||
|
||||
@observes("activeTab")
|
||||
@discourseComputed("showFormTemplate")
|
||||
templateTypeToggleLabel(showFormTemplate) {
|
||||
if (showFormTemplate) {
|
||||
return "admin.form_templates.edit_category.toggle_form_template";
|
||||
}
|
||||
|
||||
return "admin.form_templates.edit_category.toggle_freeform";
|
||||
},
|
||||
|
||||
@action
|
||||
toggleTemplateType() {
|
||||
this.toggleProperty("showFormTemplate");
|
||||
|
||||
if (!this.showFormTemplate) {
|
||||
// Clear associated form templates if switching to freeform
|
||||
this.set("category.form_template_ids", []);
|
||||
}
|
||||
},
|
||||
|
||||
@observes("activeTab", "showFormTemplate")
|
||||
_activeTabChanged() {
|
||||
if (this.activeTab) {
|
||||
if (this.activeTab && !this.showFormTemplate) {
|
||||
schedule("afterRender", () =>
|
||||
this.element.querySelector(".d-editor-input").focus()
|
||||
);
|
||||
|
@ -221,6 +221,7 @@ const Category = RestModel.extend({
|
||||
allow_badges: this.allow_badges,
|
||||
custom_fields: this.custom_fields,
|
||||
topic_template: this.topic_template,
|
||||
form_template_ids: this.form_template_ids,
|
||||
all_topics_wiki: this.all_topics_wiki,
|
||||
allow_unlimited_owner_edits_on_first_post:
|
||||
this.allow_unlimited_owner_edits_on_first_post,
|
||||
|
@ -0,0 +1,51 @@
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { render } from "@ember/test-helpers";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
import pretender, { response } from "discourse/tests/helpers/create-pretender";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
|
||||
module(
|
||||
"Integration | Component | select-kit/form-template-chooser",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.set("subject", selectKit());
|
||||
pretender.get("/admin/customize/form-templates.json", () => {
|
||||
return response({
|
||||
form_templates: [
|
||||
{ id: 1, name: "template 1", template: "test: true" },
|
||||
{ id: 2, name: "template 2", template: "test: false" },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("displays form templates", async function (assert) {
|
||||
await render(hbs`<FormTemplateChooser />`);
|
||||
|
||||
await this.subject.expand();
|
||||
|
||||
assert.strictEqual(this.subject.rowByIndex(0).value(), "1");
|
||||
assert.strictEqual(this.subject.rowByIndex(1).value(), "2");
|
||||
});
|
||||
|
||||
test("displays selected value", async function (assert) {
|
||||
this.set("value", [1]);
|
||||
|
||||
await render(hbs`<FormTemplateChooser @value={{this.value}} />`);
|
||||
|
||||
assert.strictEqual(this.subject.header().name(), "template 1");
|
||||
});
|
||||
|
||||
test("when no templates are available, the select is disabled", async function (assert) {
|
||||
pretender.get("/admin/customize/form-templates.json", () => {
|
||||
return response({ form_templates: [] });
|
||||
});
|
||||
|
||||
await render(hbs`<FormTemplateChooser />`);
|
||||
assert.ok(this.subject.isDisabled());
|
||||
});
|
||||
}
|
||||
);
|
@ -0,0 +1,44 @@
|
||||
import MultiSelectComponent from "select-kit/components/multi-select";
|
||||
import FormTemplate from "admin/models/form-template";
|
||||
import { computed } from "@ember/object";
|
||||
|
||||
export default MultiSelectComponent.extend({
|
||||
pluginApiIdentifiers: ["form-template-chooser"],
|
||||
classNames: ["form-template-chooser"],
|
||||
selectKitOptions: {
|
||||
none: "admin.form_templates.edit_category.select_template",
|
||||
},
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (!this.templates) {
|
||||
this._fetchTemplates();
|
||||
}
|
||||
},
|
||||
|
||||
@computed("templates")
|
||||
get content() {
|
||||
if (!this.templates) {
|
||||
return this._fetchTemplates();
|
||||
}
|
||||
|
||||
return this.templates;
|
||||
},
|
||||
|
||||
_fetchTemplates() {
|
||||
FormTemplate.findAll().then((result) => {
|
||||
const sortedTemplates = this._sortTemplatesByName(result);
|
||||
if (sortedTemplates.length > 0) {
|
||||
return this.set("templates", sortedTemplates);
|
||||
} else {
|
||||
this.set("templates", sortedTemplates);
|
||||
this.set("selectKit.options.disabled", true);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_sortTemplatesByName(templates) {
|
||||
return templates.sort((a, b) => a.name.localeCompare(b.name));
|
||||
},
|
||||
});
|
@ -176,6 +176,13 @@ div.edit-category {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-category-tab-topic-template {
|
||||
.select-category-template__info {
|
||||
margin-block: 0.25rem;
|
||||
font-size: var(--font-down-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.category-permissions-table {
|
||||
|
@ -410,6 +410,7 @@ class CategoriesController < ApplicationController
|
||||
allowed_tags: [],
|
||||
allowed_tag_groups: [],
|
||||
required_tag_groups: %i[name min_count],
|
||||
form_template_ids: [],
|
||||
)
|
||||
|
||||
if result[:required_tag_groups] && !result[:required_tag_groups].is_a?(Array)
|
||||
|
@ -144,6 +144,9 @@ class Category < ActiveRecord::Base
|
||||
has_many :sidebar_section_links, as: :linkable, dependent: :delete_all
|
||||
has_many :embeddable_hosts, dependent: :destroy
|
||||
|
||||
has_many :category_form_templates, dependent: :destroy
|
||||
has_many :form_templates, through: :category_form_templates
|
||||
|
||||
belongs_to :reviewable_by_group, class_name: "Group"
|
||||
|
||||
scope :latest, -> { order("topic_count DESC") }
|
||||
|
22
app/models/category_form_template.rb
Normal file
22
app/models/category_form_template.rb
Normal file
@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CategoryFormTemplate < ActiveRecord::Base
|
||||
belongs_to :category
|
||||
belongs_to :form_template
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: category_form_templates
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# category_id :bigint not null
|
||||
# form_template_id :bigint not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_category_form_templates_on_category_id (category_id)
|
||||
# index_category_form_templates_on_form_template_id (form_template_id)
|
||||
#
|
@ -4,6 +4,9 @@ class FormTemplate < ActiveRecord::Base
|
||||
validates :name, presence: true, uniqueness: true, length: { maximum: 100 }
|
||||
validates :template, presence: true, length: { maximum: 2000 }
|
||||
validates_with FormTemplateYamlValidator
|
||||
|
||||
has_many :category_form_templates, dependent: :destroy
|
||||
has_many :categories, through: :category_form_templates
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
@ -19,6 +19,7 @@ class BasicCategorySerializer < ApplicationSerializer
|
||||
:notification_level,
|
||||
:can_edit,
|
||||
:topic_template,
|
||||
:form_template_ids,
|
||||
:has_children,
|
||||
:sort_order,
|
||||
:sort_ascending,
|
||||
@ -91,4 +92,8 @@ class BasicCategorySerializer < ApplicationSerializer
|
||||
def include_custom_fields?
|
||||
custom_fields.present?
|
||||
end
|
||||
|
||||
def include_form_template_ids?
|
||||
SiteSetting.experimental_form_templates
|
||||
end
|
||||
end
|
||||
|
@ -3632,7 +3632,7 @@ en:
|
||||
back: "Back to category"
|
||||
general: "General"
|
||||
settings: "Settings"
|
||||
topic_template: "Topic Template"
|
||||
topic_template: "Template"
|
||||
tags: "Tags"
|
||||
tags_allowed_tags: "Restrict these tags to this category:"
|
||||
tags_allowed_tag_groups: "Restrict these tag groups to this category:"
|
||||
@ -5565,6 +5565,12 @@ en:
|
||||
dropdown: "Dropdown"
|
||||
upload: "Upload a file"
|
||||
multiselect: "Multiple choice"
|
||||
edit_category:
|
||||
toggle_freeform: "form template disabled"
|
||||
toggle_form_template: "form template enabled"
|
||||
select_template: "Select form templates"
|
||||
select_template_help: "Add/Edit Form Templates"
|
||||
|
||||
impersonate:
|
||||
title: "Impersonate"
|
||||
help: "Use this tool to impersonate a user account for debugging purposes. You will have to log out once finished."
|
||||
|
12
db/migrate/20230213234415_create_category_form_templates.rb
Normal file
12
db/migrate/20230213234415_create_category_form_templates.rb
Normal file
@ -0,0 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateCategoryFormTemplates < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table :category_form_templates do |t|
|
||||
t.references :category, null: false
|
||||
t.references :form_template, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
@ -674,6 +674,8 @@ RSpec.describe CategoriesController do
|
||||
readonly = CategoryGroup.permission_types[:readonly]
|
||||
create_post = CategoryGroup.permission_types[:create_post]
|
||||
tag_group = Fabricate(:tag_group)
|
||||
form_template_1 = Fabricate(:form_template)
|
||||
form_template_2 = Fabricate(:form_template)
|
||||
|
||||
put "/categories/#{category.id}.json",
|
||||
params: {
|
||||
@ -693,6 +695,7 @@ RSpec.describe CategoriesController do
|
||||
minimum_required_tags: "",
|
||||
allow_global_tags: "true",
|
||||
required_tag_groups: [{ name: tag_group.name, min_count: 2 }],
|
||||
form_template_ids: [form_template_1.id, form_template_2.id],
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
@ -713,6 +716,7 @@ RSpec.describe CategoriesController do
|
||||
expect(category.category_required_tag_groups.count).to eq(1)
|
||||
expect(category.category_required_tag_groups.first.tag_group.id).to eq(tag_group.id)
|
||||
expect(category.category_required_tag_groups.first.min_count).to eq(2)
|
||||
expect(category.form_template_ids).to eq([form_template_1.id, form_template_2.id])
|
||||
end
|
||||
|
||||
it "logs the changes correctly" do
|
||||
@ -839,6 +843,7 @@ RSpec.describe CategoriesController do
|
||||
expect(category.tag_groups).to be_blank
|
||||
expect(category.category_required_tag_groups).to eq([])
|
||||
expect(category.custom_fields).to eq({ "field_1" => "hi" })
|
||||
expect(category.form_template_ids.count).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
65
spec/system/category_edit_spec.rb
Normal file
65
spec/system/category_edit_spec.rb
Normal file
@ -0,0 +1,65 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe "Edit Category", type: :system, js: true do
|
||||
fab!(:color_scheme) { Fabricate(:color_scheme) }
|
||||
fab!(:theme) { Fabricate(:theme) }
|
||||
fab!(:admin) { Fabricate(:admin) }
|
||||
fab!(:form_template) { Fabricate(:form_template) }
|
||||
fab!(:form_template_2) { Fabricate(:form_template) }
|
||||
fab!(:category) do
|
||||
Fabricate(:category, name: "Cool Category", slug: "cool-cat", topic_count: 3234)
|
||||
end
|
||||
let(:category_page) { PageObjects::Pages::Category.new }
|
||||
|
||||
before do
|
||||
SiteSetting.experimental_form_templates = true
|
||||
sign_in(admin)
|
||||
end
|
||||
|
||||
describe "when editing a category with no form templates set" do
|
||||
before { category.update(form_template_ids: []) }
|
||||
|
||||
it "should have form templates disabled and topic template enabled" do
|
||||
category_page.visit_edit_template(category)
|
||||
expect(category_page).not_to have_form_template_enabled
|
||||
expect(category_page).to have_d_editor
|
||||
end
|
||||
|
||||
it "should allow you to select and save a form template" do
|
||||
category_page.visit_edit_template(category)
|
||||
category_page.toggle_form_templates
|
||||
expect(category_page).not_to have_d_editor
|
||||
category_page.select_form_template(form_template.name)
|
||||
expect(category_page).to have_selected_template(form_template.name)
|
||||
category_page.save_settings
|
||||
try_until_success do
|
||||
expect(Category.find_by_id(category.id).form_template_ids).to eq([form_template.id])
|
||||
end
|
||||
end
|
||||
|
||||
it "should allow you to select and save multiple form templates" do
|
||||
category_page.visit_edit_template(category)
|
||||
category_page.toggle_form_templates
|
||||
category_page.select_form_template(form_template.name)
|
||||
category_page.select_form_template(form_template_2.name)
|
||||
category_page.save_settings
|
||||
try_until_success do
|
||||
expect(Category.find_by_id(category.id).form_template_ids).to eq(
|
||||
[form_template.id, form_template_2.id],
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "when editing a category with form templates set" do
|
||||
before { category.update(form_template_ids: [form_template.id, form_template_2.id]) }
|
||||
|
||||
it "should have form templates enabled and showing the selected templates" do
|
||||
category_page.visit_edit_template(category)
|
||||
expect(category_page).to have_form_template_enabled
|
||||
expect(category_page).not_to have_d_editor
|
||||
selected_templates = "#{form_template.name},#{form_template_2.name}"
|
||||
expect(category_page).to have_selected_template(selected_templates)
|
||||
end
|
||||
end
|
||||
end
|
@ -15,6 +15,11 @@ module PageObjects
|
||||
self
|
||||
end
|
||||
|
||||
def visit_edit_template(category)
|
||||
page.visit("/c/#{category.slug}/edit/topic-template")
|
||||
self
|
||||
end
|
||||
|
||||
def back_to_category
|
||||
find(".edit-category-title-bar span", text: "Back to category").click
|
||||
self
|
||||
@ -29,6 +34,30 @@ module PageObjects
|
||||
find(".edit-category-tab .#{setting} label.checkbox-label", text: text).click
|
||||
self
|
||||
end
|
||||
|
||||
# Edit Category Page
|
||||
def has_form_template_enabled?
|
||||
find(".d-toggle-switch .toggle-template-type", visible: false)["aria-checked"] == "true"
|
||||
end
|
||||
|
||||
def has_d_editor?
|
||||
page.has_selector?(".d-editor")
|
||||
end
|
||||
|
||||
def has_selected_template?(template_name)
|
||||
find(".select-category-template .select-kit-header")["data-name"] == template_name
|
||||
end
|
||||
|
||||
def toggle_form_templates
|
||||
find(".d-toggle-switch .d-toggle-switch__checkbox-slider").click
|
||||
self
|
||||
end
|
||||
|
||||
def select_form_template(template_name)
|
||||
find(".select-category-template").click
|
||||
find(".select-kit-collection .select-kit-row", text: template_name).click
|
||||
find(".select-category-template").click
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user