From 666b4a7e6be96ebbd4775b697eecb5f790f182b9 Mon Sep 17 00:00:00 2001 From: Keegan George Date: Wed, 1 Mar 2023 11:07:13 -0800 Subject: [PATCH] DEV: Define form template field inputs (#20430) --- .../addon/components/form-template/form.hbs | 44 ++++--- .../addon/components/form-template/form.js | 73 +++++++---- .../components/form-template/row-item.js | 3 +- .../admin-form-template-validation-options.js | 35 ++++++ .../admin/addon/lib/template-form-fields.js | 77 ++++++------ .../admin/addon/models/form-template.js | 15 +++ .../customize-form-templates-index.hbs | 2 +- ...admin-form-template-validation-options.hbs | 23 ++++ .../form-template-field/checkbox.hbs | 6 + .../form-template-field/dropdown.hbs | 15 +++ .../components/form-template-field/input.hbs | 10 ++ .../form-template-field/multi-select.hbs | 15 +++ .../form-template-field/textarea.hbs | 9 ++ .../components/form-template-field/upload.hbs | 11 ++ .../form-template-field/wrapper.hbs | 14 +++ .../components/form-template-field/wrapper.js | 17 +++ .../customize-form-template-view.js} | 7 ++ .../controllers/form-template-form-preview.js | 6 + .../modal/customize-form-template-view.hbs} | 15 ++- .../modal/form-template-form-preview.hbs | 6 + .../form-template-field/checkbox-test.js | 43 +++++++ .../form-template-field/dropdown-test.js | 88 ++++++++++++++ .../form-template-field/input-test.js | 61 ++++++++++ .../form-template-field/multi-select-test.js | 88 ++++++++++++++ .../form-template-field/textarea-test.js | 57 +++++++++ .../form-template-field/wrapper-test.js | 49 ++++++++ .../stylesheets/common/admin/customize.scss | 26 +++- .../admin/form_templates_controller.rb | 19 +++ config/locales/client.en.yml | 37 ++++++ config/locales/server.en.yml | 2 + config/routes.rb | 4 +- .../form_template_yaml_validator.rb | 28 +++++ spec/fabricators/form_template_fabricator.rb | 2 +- spec/models/form_template_spec.rb | 20 +++- .../admin/form_templates_controller_spec.rb | 6 +- .../admin_customize_form_templates_spec.rb | 113 +++++++++++++----- .../page_objects/pages/form_template.rb | 47 ++++++-- 37 files changed, 963 insertions(+), 130 deletions(-) create mode 100644 app/assets/javascripts/admin/addon/controllers/modals/admin-form-template-validation-options.js create mode 100644 app/assets/javascripts/admin/addon/templates/modal/admin-form-template-validation-options.hbs create mode 100644 app/assets/javascripts/discourse/app/components/form-template-field/checkbox.hbs create mode 100644 app/assets/javascripts/discourse/app/components/form-template-field/dropdown.hbs create mode 100644 app/assets/javascripts/discourse/app/components/form-template-field/input.hbs create mode 100644 app/assets/javascripts/discourse/app/components/form-template-field/multi-select.hbs create mode 100644 app/assets/javascripts/discourse/app/components/form-template-field/textarea.hbs create mode 100644 app/assets/javascripts/discourse/app/components/form-template-field/upload.hbs create mode 100644 app/assets/javascripts/discourse/app/components/form-template-field/wrapper.hbs create mode 100644 app/assets/javascripts/discourse/app/components/form-template-field/wrapper.js rename app/assets/javascripts/{admin/addon/controllers/modals/admin-customize-form-template-view.js => discourse/app/controllers/customize-form-template-view.js} (87%) create mode 100644 app/assets/javascripts/discourse/app/controllers/form-template-form-preview.js rename app/assets/javascripts/{admin/addon/templates/modal/admin-customize-form-template-view.hbs => discourse/app/templates/modal/customize-form-template-view.hbs} (53%) create mode 100644 app/assets/javascripts/discourse/app/templates/modal/form-template-form-preview.hbs create mode 100644 app/assets/javascripts/discourse/tests/integration/components/form-template-field/checkbox-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/form-template-field/dropdown-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/form-template-field/input-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/form-template-field/multi-select-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/form-template-field/textarea-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/form-template-field/wrapper-test.js diff --git a/app/assets/javascripts/admin/addon/components/form-template/form.hbs b/app/assets/javascripts/admin/addon/components/form-template/form.hbs index fe94fdc6bd2..907310123d4 100644 --- a/app/assets/javascripts/admin/addon/components/form-template/form.hbs +++ b/app/assets/javascripts/admin/addon/components/form-template/form.hbs @@ -1,4 +1,4 @@ -
+
- -
- - {{I18n "admin.form_templates.quick_insert_fields.add_new_field"}} - - {{#each this.quickInsertFields as |field|}} +
+
+ + {{I18n "admin.form_templates.quick_insert_fields.add_new_field"}} + + {{#each this.quickInsertFields as |field|}} + + {{/each}} - {{/each}} +
+
@@ -36,7 +50,7 @@ @label="admin.form_templates.new_template_form.submit" @icon="check" @action={{this.onSubmit}} - @disabled={{this.formSubmitted}} + @disabled={{this.disableSubmitButton}} /> { - this.formSubmitted = false; - this.router.transitionTo("adminCustomizeFormTemplates.index"); - }) - .catch((e) => { - popupAjaxError(e); - this.formSubmitted = false; - }); - } else { - FormTemplate.createTemplate(postData) - .then(() => { - this.formSubmitted = false; - this.router.transitionTo("adminCustomizeFormTemplates.index"); - }) - .catch((e) => { - popupAjaxError(e); - this.formSubmitted = false; - }); } + + FormTemplate.createOrUpdateTemplate(postData) + .then(() => { + this.formSubmitted = false; + this.router.transitionTo("adminCustomizeFormTemplates.index"); + }) + .catch((e) => { + popupAjaxError(e); + this.formSubmitted = false; + }); } @action @@ -106,4 +108,33 @@ export default class FormTemplateForm extends Component { this.templateContent += `\n${structure}`; } } + + @action + showValidationOptionsModal() { + return showModal("admin-form-template-validation-options", { + admin: true, + }); + } + + @action + showPreview() { + const data = { + name: this.templateName, + template: this.templateContent, + }; + + if (this.isEditing) { + data["id"] = this.args.model.id; + } + + FormTemplate.validateTemplate(data) + .then(() => { + return showModal("form-template-form-preview", { + model: { + content: this.templateContent, + }, + }); + }) + .catch(popupAjaxError); + } } diff --git a/app/assets/javascripts/admin/addon/components/form-template/row-item.js b/app/assets/javascripts/admin/addon/components/form-template/row-item.js index ef94e04a37e..823c17847cb 100644 --- a/app/assets/javascripts/admin/addon/components/form-template/row-item.js +++ b/app/assets/javascripts/admin/addon/components/form-template/row-item.js @@ -12,8 +12,7 @@ export default class FormTemplateRowItem extends Component { @action viewTemplate() { - showModal("admin-customize-form-template-view", { - admin: true, + showModal("customize-form-template-view", { model: this.args.template, refreshModel: this.args.refreshModel, }); diff --git a/app/assets/javascripts/admin/addon/controllers/modals/admin-form-template-validation-options.js b/app/assets/javascripts/admin/addon/controllers/modals/admin-form-template-validation-options.js new file mode 100644 index 00000000000..a9300f8f6d6 --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/modals/admin-form-template-validation-options.js @@ -0,0 +1,35 @@ +import Controller from "@ember/controller"; +import ModalFunctionality from "discourse/mixins/modal-functionality"; +import I18n from "I18n"; + +export default class AdminFormTemplateValidationOptions extends Controller.extend( + ModalFunctionality +) { + TABLE_HEADER_KEYS = ["key", "type", "description"]; + VALIDATION_KEYS = ["required", "minimum", "maximum", "pattern"]; + + get tableHeaders() { + const translatedHeaders = []; + this.TABLE_HEADER_KEYS.forEach((header) => { + translatedHeaders.push( + I18n.t(`admin.form_templates.validations_modal.table_headers.${header}`) + ); + }); + + return translatedHeaders; + } + + get validations() { + const translatedValidations = []; + const prefix = "admin.form_templates.validations_modal.validations"; + this.VALIDATION_KEYS.forEach((validation) => { + translatedValidations.push({ + key: I18n.t(`${prefix}.${validation}.key`), + type: I18n.t(`${prefix}.${validation}.type`), + description: I18n.t(`${prefix}.${validation}.description`), + }); + }); + + return translatedValidations; + } +} diff --git a/app/assets/javascripts/admin/addon/lib/template-form-fields.js b/app/assets/javascripts/admin/addon/lib/template-form-fields.js index c69cb0f711a..6a27b5c1d05 100644 --- a/app/assets/javascripts/admin/addon/lib/template-form-fields.js +++ b/app/assets/javascripts/admin/addon/lib/template-form-fields.js @@ -1,70 +1,75 @@ -// TODO(@keegan): Add translations for template strings +import I18n from "I18n"; + export const templateFormFields = [ { type: "checkbox", structure: `- type: checkbox - choices: - - "Option 1" - - "Option 2" - - "Option 3" attributes: - label: "Enter question here" - description: "Enter description here" - validations: - required: true`, + label: "${I18n.t("admin.form_templates.field_placeholders.label")}" + validations: + # ${I18n.t("admin.form_templates.field_placeholders.validations")}`, }, { type: "input", structure: `- type: input attributes: - label: "Enter input label here" - description: "Enter input description here" - placeholder: "Enter input placeholder here" - validations: - required: true`, + label: "${I18n.t("admin.form_templates.field_placeholders.label")}" + placeholder: "${I18n.t( + "admin.form_templates.field_placeholders.placeholder" + )}" + validations: + # ${I18n.t("admin.form_templates.field_placeholders.validations")}`, }, { type: "textarea", structure: `- type: textarea attributes: - label: "Enter textarea label here" - description: "Enter textarea description here" - placeholder: "Enter textarea placeholder here" - validations: - required: true`, + label: "${I18n.t("admin.form_templates.field_placeholders.label")}" + placeholder: "${I18n.t( + "admin.form_templates.field_placeholders.placeholder" + )}" + validations: + # ${I18n.t("admin.form_templates.field_placeholders.validations")}`, }, { type: "dropdown", structure: `- type: dropdown choices: - - "Option 1" - - "Option 2" - - "Option 3" + - "${I18n.t("admin.form_templates.field_placeholders.choices.first")}" + - "${I18n.t("admin.form_templates.field_placeholders.choices.second")}" + - "${I18n.t("admin.form_templates.field_placeholders.choices.third")}" attributes: - label: "Enter dropdown label here" - description: "Enter dropdown description here" - validations: - required: true`, + none_label: "${I18n.t( + "admin.form_templates.field_placeholders.none_label" + )}" + label: "${I18n.t("admin.form_templates.field_placeholders.label")}" + filterable: false + validations: + # ${I18n.t("admin.form_templates.field_placeholders.validations")}`, }, { type: "upload", structure: `- type: upload attributes: file_types: "jpg, png, gif" - label: "Enter upload label here" - description: "Enter upload description here"`, + allow_multiple: false + label: "${I18n.t("admin.form_templates.field_placeholders.label")}" + validations: + # ${I18n.t("admin.form_templates.field_placeholders.validations")}`, }, { type: "multiselect", - structure: `- type: multiple_choice + structure: `- type: multi-select choices: - - "Option 1" - - "Option 2" - - "Option 3" + - "${I18n.t("admin.form_templates.field_placeholders.choices.first")}" + - "${I18n.t("admin.form_templates.field_placeholders.choices.second")}" + - "${I18n.t("admin.form_templates.field_placeholders.choices.third")}" attributes: - label: "Enter multiple choice label here" - description: "Enter multiple choice description here" - validations: - required: true`, + none_label: "${I18n.t( + "admin.form_templates.field_placeholders.none_label" + )}" + label: "${I18n.t("admin.form_templates.field_placeholders.label")}" + validations: + # ${I18n.t("admin.form_templates.field_placeholders.validations")}`, }, ]; diff --git a/app/assets/javascripts/admin/addon/models/form-template.js b/app/assets/javascripts/admin/addon/models/form-template.js index 9893d9244a9..782b6a8c317 100644 --- a/app/assets/javascripts/admin/addon/models/form-template.js +++ b/app/assets/javascripts/admin/addon/models/form-template.js @@ -18,6 +18,14 @@ FormTemplate.reopenClass({ }); }, + createOrUpdateTemplate(data) { + if (data.id) { + return this.updateTemplate(data.id, data); + } else { + return this.createTemplate(data); + } + }, + deleteTemplate(id) { return ajax(`/admin/customize/form-templates/${id}.json`, { type: "DELETE", @@ -35,4 +43,11 @@ FormTemplate.reopenClass({ return model.form_template; }); }, + + validateTemplate(data) { + return ajax(`/admin/customize/form-templates/preview.json`, { + type: "GET", + data, + }); + }, }); diff --git a/app/assets/javascripts/admin/addon/templates/customize-form-templates-index.hbs b/app/assets/javascripts/admin/addon/templates/customize-form-templates-index.hbs index e7f1fc3adc6..b9a61cc44b4 100644 --- a/app/assets/javascripts/admin/addon/templates/customize-form-templates-index.hbs +++ b/app/assets/javascripts/admin/addon/templates/customize-form-templates-index.hbs @@ -2,7 +2,7 @@ {{#if this.model}} - +
{{i18n "admin.form_templates.list_table.headings.name"}} diff --git a/app/assets/javascripts/admin/addon/templates/modal/admin-form-template-validation-options.hbs b/app/assets/javascripts/admin/addon/templates/modal/admin-form-template-validation-options.hbs new file mode 100644 index 00000000000..330dd1cebdc --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/modal/admin-form-template-validation-options.hbs @@ -0,0 +1,23 @@ + + + + + {{#each this.tableHeaders as |header|}} + + {{/each}} + + + + {{#each this.validations as |item|}} + + + + + + {{/each}} + +
{{header}}
{{item.key}}
{{item.type}}{{item.description}}
+
\ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/form-template-field/checkbox.hbs b/app/assets/javascripts/discourse/app/components/form-template-field/checkbox.hbs new file mode 100644 index 00000000000..e4f4c10a239 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/form-template-field/checkbox.hbs @@ -0,0 +1,6 @@ +
+ +
\ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/form-template-field/dropdown.hbs b/app/assets/javascripts/discourse/app/components/form-template-field/dropdown.hbs new file mode 100644 index 00000000000..c4f17167935 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/form-template-field/dropdown.hbs @@ -0,0 +1,15 @@ +
+ {{#if @attributes.label}} + + {{/if}} + +
\ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/form-template-field/input.hbs b/app/assets/javascripts/discourse/app/components/form-template-field/input.hbs new file mode 100644 index 00000000000..4a08a25960b --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/form-template-field/input.hbs @@ -0,0 +1,10 @@ +
+ {{#if @attributes.label}} + + {{/if}} + +
\ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/form-template-field/multi-select.hbs b/app/assets/javascripts/discourse/app/components/form-template-field/multi-select.hbs new file mode 100644 index 00000000000..06721b3cd86 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/form-template-field/multi-select.hbs @@ -0,0 +1,15 @@ +
+ {{#if @attributes.label}} + + {{/if}} + +
\ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/form-template-field/textarea.hbs b/app/assets/javascripts/discourse/app/components/form-template-field/textarea.hbs new file mode 100644 index 00000000000..3029d15a318 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/form-template-field/textarea.hbs @@ -0,0 +1,9 @@ +
+ {{#if @attributes.label}} + + {{/if}} +