From 320196b1f04f89ce949a7d4f9f6a76fe18256e80 Mon Sep 17 00:00:00 2001 From: jumagura Date: Thu, 9 Mar 2023 22:34:40 -0400 Subject: [PATCH 01/52] FIX: Use discourse hyperlink modal in composer instead of custom --- .../custom-wizard-composer-editor.js.es6 | 31 ++++++++----------- .../custom-wizard-composer-hyperlink.js.es6 | 15 --------- .../custom-wizard-composer-hyperlink.hbs | 21 ------------- plugin.rb | 2 +- 4 files changed, 14 insertions(+), 55 deletions(-) delete mode 100644 assets/javascripts/discourse/components/custom-wizard-composer-hyperlink.js.es6 delete mode 100644 assets/javascripts/discourse/templates/components/custom-wizard-composer-hyperlink.hbs diff --git a/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 b/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 index 5e2ef424..816c2387 100644 --- a/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 @@ -12,6 +12,7 @@ import { alias } from "@ember/object/computed"; import Site from "discourse/models/site"; import { uploadIcon } from "discourse/lib/uploads"; import { dasherize } from "@ember/string"; +import showModal from "discourse/lib/show-modal"; const IMAGE_MARKDOWN_REGEX = /!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?(.*?)\]\((upload:\/\/.*?)\)(?!(.*`))/g; @@ -19,7 +20,6 @@ export default ComposerEditor.extend({ classNameBindings: ["fieldClass"], allowUpload: true, showLink: false, - showHyperlinkBox: false, topic: null, showToolbar: true, focusTarget: "reply", @@ -116,12 +116,6 @@ export default ComposerEditor.extend({ return uploadIcon(false, this.siteSettings); }, - click(e) { - if ($(e.target).hasClass("wizard-composer-hyperlink")) { - this.set("showHyperlinkBox", false); - } - }, - @bind _handleImageDeleteButtonClick(event) { if (!event.target.classList.contains("delete-image-button")) { @@ -165,7 +159,7 @@ export default ComposerEditor.extend({ shortcut: "K", trimLeading: true, unshift: true, - sendAction: () => component.set("showHyperlinkBox", true), + sendAction: (event) => component.send("showLinkModal", event), }); if (this.siteSettings.mentionables_enabled) { @@ -206,17 +200,18 @@ export default ComposerEditor.extend({ this._super(...arguments); }, - addLink(linkName, linkUrl) { - let link = `[${linkName}](${linkUrl})`; - this.appEvents.trigger("wizard-editor:insert-text", { - fieldId: this.field.id, - text: link, - }); - this.set("showHyperlinkBox", false); - }, + showLinkModal(toolbarEvent) { + let linkText = ""; + this._lastSel = toolbarEvent.selected; - hideBox() { - this.set("showHyperlinkBox", false); + if (this._lastSel) { + linkText = this._lastSel.value; + } + + showModal("insert-hyperlink").setProperties({ + linkText, + toolbarEvent, + }); }, showUploadModal() { diff --git a/assets/javascripts/discourse/components/custom-wizard-composer-hyperlink.js.es6 b/assets/javascripts/discourse/components/custom-wizard-composer-hyperlink.js.es6 deleted file mode 100644 index a56b7aff..00000000 --- a/assets/javascripts/discourse/components/custom-wizard-composer-hyperlink.js.es6 +++ /dev/null @@ -1,15 +0,0 @@ -import Component from "@ember/component"; - -export default Component.extend({ - classNames: ["wizard-composer-hyperlink"], - - actions: { - addLink() { - this.addLink(this.linkName, this.linkUrl); - }, - - hideBox() { - this.hideBox(); - }, - }, -}); diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-composer-hyperlink.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-composer-hyperlink.hbs deleted file mode 100644 index f430fb59..00000000 --- a/assets/javascripts/discourse/templates/components/custom-wizard-composer-hyperlink.hbs +++ /dev/null @@ -1,21 +0,0 @@ - diff --git a/plugin.rb b/plugin.rb index 7422345f..54f9eeca 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.4 +# version: 2.2.5 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From 092947f68b3ba1f526f03bc5a563d88e8f741d8c Mon Sep 17 00:00:00 2001 From: merefield Date: Fri, 10 Mar 2023 12:43:37 +0000 Subject: [PATCH 02/52] FIX: regular users can't access wizard with guest permissions --- lib/custom_wizard/wizard.rb | 1 + spec/components/custom_wizard/wizard_spec.rb | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/lib/custom_wizard/wizard.rb b/lib/custom_wizard/wizard.rb index c815c764..4ed4037d 100644 --- a/lib/custom_wizard/wizard.rb +++ b/lib/custom_wizard/wizard.rb @@ -230,6 +230,7 @@ class CustomWizard::Wizard m[:type] === 'assignment' && [*m[:result]].include?(GUEST_GROUP_ID) else if m[:type] === 'assignment' + [*m[:result]].include?(GUEST_GROUP_ID) || [*m[:result]].include?(Group::AUTO_GROUPS[:everyone]) || GroupUser.exists?(group_id: m[:result], user_id: user.id) elsif m[:type] === 'validation' diff --git a/spec/components/custom_wizard/wizard_spec.rb b/spec/components/custom_wizard/wizard_spec.rb index ed6ebbea..59c0c8c9 100644 --- a/spec/components/custom_wizard/wizard_spec.rb +++ b/spec/components/custom_wizard/wizard_spec.rb @@ -6,11 +6,14 @@ describe CustomWizard::Wizard do fab!(:admin_user) { Fabricate(:user, admin: true) } let(:template_json) { get_wizard_fixture("wizard") } let(:permitted_json) { get_wizard_fixture("wizard/permitted") } + let(:guests_permitted_json) { get_wizard_fixture("wizard/guests_permitted") } before do Group.refresh_automatic_group!(:trust_level_3) @permitted_template = template_json.dup @permitted_template["permitted"] = permitted_json["permitted"] + @guests_permitted_template = template_json.dup + @guests_permitted_template["permitted"] = guests_permitted_json["permitted"] @wizard = CustomWizard::Wizard.new(template_json, user) end @@ -128,6 +131,9 @@ describe CustomWizard::Wizard do expect( CustomWizard::Wizard.new(@permitted_template, trusted_user).permitted? ).to eq(true) + expect( + CustomWizard::Wizard.new(@guests_permitted_template, trusted_user).permitted? + ).to eq(true) end it "permits everyone if everyone is permitted" do From 9e59b73ebe0359adac376baf1c791f26e671f091 Mon Sep 17 00:00:00 2001 From: merefield Date: Fri, 10 Mar 2023 12:49:32 +0000 Subject: [PATCH 03/52] Bump patch --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index 1bbd8f8e..78c384da 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.1 +# version: 2.2.2 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From a3b665434c9831df56d746045d3588ec9dd73dec Mon Sep 17 00:00:00 2001 From: merefield Date: Fri, 10 Mar 2023 12:50:37 +0000 Subject: [PATCH 04/52] Bump patch --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index 78c384da..54f9eeca 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.2 +# version: 2.2.5 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From a84bf525429f5220009246ddf5c802bd85bc7b9e Mon Sep 17 00:00:00 2001 From: jumagura Date: Fri, 10 Mar 2023 10:39:40 -0400 Subject: [PATCH 05/52] DEV: Add front-end test for hyperlink modal in composer --- test/javascripts/acceptance/field-test.js | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/test/javascripts/acceptance/field-test.js b/test/javascripts/acceptance/field-test.js index 5eecce4f..f1d97130 100644 --- a/test/javascripts/acceptance/field-test.js +++ b/test/javascripts/acceptance/field-test.js @@ -54,6 +54,70 @@ acceptance("Field | Fields", function (needs) { "Input in composer" ); }); + test("Composer - Hyperlink", async function (assert) { + await visit("/w/wizard"); + assert.ok( + visible(".wizard-field.composer-field .wizard-field-composer textarea") + ); + assert.ok( + exists(".wizard-field.composer-field .d-editor-button-bar button") + ); + assert.ok(visible(".wizard-btn.toggle-preview")); + await fillIn( + ".wizard-field.composer-field .wizard-field-composer textarea", + "This is a link to " + ); + assert.ok( + !exists(".insert-link.modal-body"), + "no hyperlink modal by default" + ); + await click( + ".wizard-field.composer-field .wizard-field-composer .d-editor button.link" + ); + assert.ok(exists(".insert-link.modal-body"), "hyperlink modal visible"); + + await fillIn(".modal-body .link-url", "google.com"); + await fillIn(".modal-body .link-text", "Google"); + await click(".modal-footer button.btn-primary"); + + assert.strictEqual( + query(".wizard-field.composer-field .wizard-field-composer textarea") + .value, + "This is a link to [Google](https://google.com)", + "adds link with url and text, prepends 'https://'" + ); + + assert.ok( + !exists( + ".wizard-field.composer-field .wizard-field-composer .insert-link.modal-body" + ), + "modal dismissed after submitting link" + ); + + await fillIn( + ".wizard-field.composer-field .wizard-field-composer textarea", + "Reset textarea contents." + ); + + await click( + ".wizard-field.composer-field .wizard-field-composer .d-editor button.link" + ); + await fillIn(".modal-body .link-url", "google.com"); + await fillIn(".modal-body .link-text", "Google"); + await click(".modal-footer button.btn-danger"); + + assert.strictEqual( + query(".wizard-field.composer-field .wizard-field-composer textarea") + .value, + "Reset textarea contents.", + "does not insert anything after cancelling" + ); + + assert.ok( + !exists(".insert-link.modal-body"), + "modal dismissed after cancelling" + ); + }); test("Text Only", async function (assert) { await visit("/w/wizard"); From b73437299c80b5133eedde37bf020b0af48c699e Mon Sep 17 00:00:00 2001 From: merefield Date: Fri, 10 Mar 2023 14:42:42 +0000 Subject: [PATCH 06/52] IMPROVE: separate out new tests --- spec/components/custom_wizard/wizard_spec.rb | 27 +++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/spec/components/custom_wizard/wizard_spec.rb b/spec/components/custom_wizard/wizard_spec.rb index 59c0c8c9..591eee8c 100644 --- a/spec/components/custom_wizard/wizard_spec.rb +++ b/spec/components/custom_wizard/wizard_spec.rb @@ -131,9 +131,6 @@ describe CustomWizard::Wizard do expect( CustomWizard::Wizard.new(@permitted_template, trusted_user).permitted? ).to eq(true) - expect( - CustomWizard::Wizard.new(@guests_permitted_template, trusted_user).permitted? - ).to eq(true) end it "permits everyone if everyone is permitted" do @@ -206,6 +203,30 @@ describe CustomWizard::Wizard do end end + context "with subscription and guest wizard" do + before do + enable_subscription("standard") + end + + it "permits admins" do + expect( + CustomWizard::Wizard.new(@guests_permitted_template, admin_user).permitted? + ).to eq(true) + end + + it "permits regular users" do + expect( + CustomWizard::Wizard.new(@guests_permitted_template, user).permitted? + ).to eq(true) + end + + it "permits guests" do + expect( + CustomWizard::Wizard.new(@guests_permitted_template, nil, "guest123").permitted? + ).to eq(true) + end + end + context "submissions" do before do CustomWizard::Submission.new(@wizard, step_1_field_1: "I am a user submission").save From 091362cb003c6c96073621da66132bb5a76021e1 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 14 Mar 2023 16:34:58 +0100 Subject: [PATCH 07/52] Remove subscription requirement for field interpolation. --- lib/custom_wizard/mapper.rb | 2 +- spec/components/custom_wizard/mapper_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/custom_wizard/mapper.rb b/lib/custom_wizard/mapper.rb index 410a50e4..9d26c82e 100644 --- a/lib/custom_wizard/mapper.rb +++ b/lib/custom_wizard/mapper.rb @@ -255,7 +255,7 @@ class CustomWizard::Mapper end end - if opts[:template] && CustomWizard::Subscription.subscribed? + if opts[:template] #&& CustomWizard::Subscription.subscribed? template = Liquid::Template.parse(string) string = template.render(data) end diff --git a/spec/components/custom_wizard/mapper_spec.rb b/spec/components/custom_wizard/mapper_spec.rb index 56778a07..f460cc01 100644 --- a/spec/components/custom_wizard/mapper_spec.rb +++ b/spec/components/custom_wizard/mapper_spec.rb @@ -373,7 +373,7 @@ describe CustomWizard::Mapper do expect(result).to eq(template_params["step_1_field_1"]) end - it "requires a subscription" do + it "does not require a subscription" do template = '{{ "w{step_1_field_1}" | size }}' mapper = create_template_mapper(template_params, user1) result = mapper.interpolate( @@ -383,7 +383,7 @@ describe CustomWizard::Mapper do wizard: true, value: true ) - expect(result).to eq("{{ \"#{template_params["step_1_field_1"]}\" | size }}") + expect(result).to eq("5") end context "with a subscription" do From 3a5430c767c9f7fcefdf198a000c8897c46e7364 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 14 Mar 2023 16:35:23 +0100 Subject: [PATCH 08/52] Bump version --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index 54f9eeca..d7ffc7f4 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.5 +# version: 2.2.6 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From 0e70a5a2210e4dfe8d2817df142313da0711e090 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 15 Mar 2023 09:22:09 +0100 Subject: [PATCH 09/52] FIX: add observed cache to undo changes mixin Prevents observer add / remove race conditions which can cause exceptions. --- .../javascripts/discourse/mixins/undo-changes.js.es6 | 10 +++++++++- plugin.rb | 2 +- .../fixtures/sprockets/require_tree_discourse_empty.js | 2 +- .../sprockets/require_tree_discourse_non_existant.js | 2 +- spec/fixtures/sprockets/require_tree_discourse_test.js | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/assets/javascripts/discourse/mixins/undo-changes.js.es6 b/assets/javascripts/discourse/mixins/undo-changes.js.es6 index b2ab322d..91497eae 100644 --- a/assets/javascripts/discourse/mixins/undo-changes.js.es6 +++ b/assets/javascripts/discourse/mixins/undo-changes.js.es6 @@ -4,6 +4,8 @@ import { get, set } from "@ember/object"; import Mixin from "@ember/object/mixin"; import { deepEqual } from "discourse-common/lib/object"; +var observedCache = []; + export default Mixin.create({ didInsertElement() { this._super(...arguments); @@ -32,7 +34,10 @@ export default Mixin.create({ }; listProperties(componentType, opts).forEach((property) => { - obj.removeObserver(property, this, this.toggleUndo); + if (observedCache.includes(property)) { + obj.removeObserver(property, this, this.toggleUndo); + observedCache = observedCache.filter(p => p !== property); + } }); }, @@ -45,6 +50,9 @@ export default Mixin.create({ }; listProperties(componentType, opts).forEach((property) => { + if (observedCache.indexOf(property) === -1) { + observedCache.push(property); + } obj.addObserver(property, this, this.toggleUndo); }); }, diff --git a/plugin.rb b/plugin.rb index d7ffc7f4..7f6829eb 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.6 +# version: 2.2.7 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech diff --git a/spec/fixtures/sprockets/require_tree_discourse_empty.js b/spec/fixtures/sprockets/require_tree_discourse_empty.js index 953c5ec4..4f034d13 100644 --- a/spec/fixtures/sprockets/require_tree_discourse_empty.js +++ b/spec/fixtures/sprockets/require_tree_discourse_empty.js @@ -1 +1 @@ -//= require_tree_discourse \ No newline at end of file +//= require_tree_discourse diff --git a/spec/fixtures/sprockets/require_tree_discourse_non_existant.js b/spec/fixtures/sprockets/require_tree_discourse_non_existant.js index d9b2be76..fc4752e5 100644 --- a/spec/fixtures/sprockets/require_tree_discourse_non_existant.js +++ b/spec/fixtures/sprockets/require_tree_discourse_non_existant.js @@ -1 +1 @@ -//= require_tree_discourse dummy_path \ No newline at end of file +//= require_tree_discourse dummy_path diff --git a/spec/fixtures/sprockets/require_tree_discourse_test.js b/spec/fixtures/sprockets/require_tree_discourse_test.js index a86aa0d7..56451213 100644 --- a/spec/fixtures/sprockets/require_tree_discourse_test.js +++ b/spec/fixtures/sprockets/require_tree_discourse_test.js @@ -1 +1 @@ -//= require_tree_discourse sptest \ No newline at end of file +//= require_tree_discourse sptest From 6a4063951e79dd962e3b257fcd36a47ea702f369 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 15 Mar 2023 10:26:46 +0100 Subject: [PATCH 10/52] Move to new Uppy handling in discourse/discourse --- .../custom-wizard-composer-editor.js.es6 | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 b/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 index 816c2387..d9fec6cd 100644 --- a/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 @@ -29,6 +29,7 @@ export default ComposerEditor.extend({ draftStatus: "null", replyPlaceholder: alias("field.translatedPlaceholder"), wizardEventFieldId: null, + composerEventPrefix: "wizard-editor", @on("didInsertElement") _composerEditorInit() { @@ -77,24 +78,11 @@ export default ComposerEditor.extend({ $input.on("scroll", this._throttledSyncEditorAndPreviewScroll); this._bindUploadTarget(); - const wizardEventNames = ["insert-text", "replace-text"]; - const eventPrefix = this.eventPrefix; - this.appEvents.reopen({ - trigger(name, ...args) { - let eventParts = name.split(":"); - let currentEventPrefix = eventParts[0]; - let currentEventName = eventParts[1]; + const field = this.field; + this.editorInputClass = `.${dasherize(field.type)}-${dasherize(field.id)} .d-editor-input`; - if ( - currentEventPrefix !== "wizard-editor" && - wizardEventNames.some((wen) => wen === currentEventName) - ) { - let wizardEventName = name.replace(eventPrefix, "wizard-editor"); - return this._super(wizardEventName, ...args); - } else { - return this._super(name, ...args); - } - }, + this._uppyInstance.on('file-added', (file) => { + this.session.set("wizardEventFieldId", field.id); }); }, From e489845daf2632e937027d0e2c8e6e0314533b61 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 15 Mar 2023 10:28:51 +0100 Subject: [PATCH 11/52] Bump version --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index 7f6829eb..6b13632a 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.7 +# version: 2.2.8 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From 24ce4da6f29bba0d7822f0e4d9e25b7a564ebd4a Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 15 Mar 2023 10:30:24 +0100 Subject: [PATCH 12/52] Make linters happy --- .../components/custom-wizard-composer-editor.js.es6 | 6 ++++-- assets/javascripts/discourse/mixins/undo-changes.js.es6 | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 b/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 index d9fec6cd..5335da81 100644 --- a/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-composer-editor.js.es6 @@ -79,9 +79,11 @@ export default ComposerEditor.extend({ this._bindUploadTarget(); const field = this.field; - this.editorInputClass = `.${dasherize(field.type)}-${dasherize(field.id)} .d-editor-input`; + this.editorInputClass = `.${dasherize(field.type)}-${dasherize( + field.id + )} .d-editor-input`; - this._uppyInstance.on('file-added', (file) => { + this._uppyInstance.on("file-added", () => { this.session.set("wizardEventFieldId", field.id); }); }, diff --git a/assets/javascripts/discourse/mixins/undo-changes.js.es6 b/assets/javascripts/discourse/mixins/undo-changes.js.es6 index 91497eae..ce126bdd 100644 --- a/assets/javascripts/discourse/mixins/undo-changes.js.es6 +++ b/assets/javascripts/discourse/mixins/undo-changes.js.es6 @@ -4,7 +4,7 @@ import { get, set } from "@ember/object"; import Mixin from "@ember/object/mixin"; import { deepEqual } from "discourse-common/lib/object"; -var observedCache = []; +let observedCache = []; export default Mixin.create({ didInsertElement() { @@ -36,7 +36,7 @@ export default Mixin.create({ listProperties(componentType, opts).forEach((property) => { if (observedCache.includes(property)) { obj.removeObserver(property, this, this.toggleUndo); - observedCache = observedCache.filter(p => p !== property); + observedCache = observedCache.filter((p) => p !== property); } }); }, From 52fe5166cd37a0a4be3a9f467c4398c4c7fa1518 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 15 Mar 2023 10:38:26 +0100 Subject: [PATCH 13/52] Fix linting --- assets/javascripts/discourse/mixins/undo-changes.js.es6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/javascripts/discourse/mixins/undo-changes.js.es6 b/assets/javascripts/discourse/mixins/undo-changes.js.es6 index 91497eae..ce126bdd 100644 --- a/assets/javascripts/discourse/mixins/undo-changes.js.es6 +++ b/assets/javascripts/discourse/mixins/undo-changes.js.es6 @@ -4,7 +4,7 @@ import { get, set } from "@ember/object"; import Mixin from "@ember/object/mixin"; import { deepEqual } from "discourse-common/lib/object"; -var observedCache = []; +let observedCache = []; export default Mixin.create({ didInsertElement() { @@ -36,7 +36,7 @@ export default Mixin.create({ listProperties(componentType, opts).forEach((property) => { if (observedCache.includes(property)) { obj.removeObserver(property, this, this.toggleUndo); - observedCache = observedCache.filter(p => p !== property); + observedCache = observedCache.filter((p) => p !== property); } }); }, From 20e7b492eaa81c42502ab139628cb2e2c75c219e Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 15 Mar 2023 10:44:56 +0100 Subject: [PATCH 14/52] FIX: use const instead of let for observedCache --- assets/javascripts/discourse/mixins/undo-changes.js.es6 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/assets/javascripts/discourse/mixins/undo-changes.js.es6 b/assets/javascripts/discourse/mixins/undo-changes.js.es6 index ce126bdd..e98cfb0e 100644 --- a/assets/javascripts/discourse/mixins/undo-changes.js.es6 +++ b/assets/javascripts/discourse/mixins/undo-changes.js.es6 @@ -4,7 +4,7 @@ import { get, set } from "@ember/object"; import Mixin from "@ember/object/mixin"; import { deepEqual } from "discourse-common/lib/object"; -let observedCache = []; +const observedCache = []; export default Mixin.create({ didInsertElement() { @@ -36,7 +36,10 @@ export default Mixin.create({ listProperties(componentType, opts).forEach((property) => { if (observedCache.includes(property)) { obj.removeObserver(property, this, this.toggleUndo); - observedCache = observedCache.filter((p) => p !== property); + let index = observedCache.indexOf(property); + if (index !== -1) { + observedCache.splice(index, 1); + } } }); }, From a4e49e7bbce7efa5f2db62fa5b7a72a404ab5345 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 15 Mar 2023 13:33:07 +0100 Subject: [PATCH 15/52] Ensure submission users are serialized properly --- .../custom_wizard/submission_serializer.rb | 2 +- lib/custom_wizard/submission.rb | 8 +++++++- plugin.rb | 2 +- .../submission_serializer_spec.rb | 20 +++++++++++++------ 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/app/serializers/custom_wizard/submission_serializer.rb b/app/serializers/custom_wizard/submission_serializer.rb index 48892c21..ed9ad411 100644 --- a/app/serializers/custom_wizard/submission_serializer.rb +++ b/app/serializers/custom_wizard/submission_serializer.rb @@ -10,7 +10,7 @@ class CustomWizard::SubmissionSerializer < ApplicationSerializer end def user - ::BasicUserSerializer.new(object.wizard.user).as_json + ::BasicUserSerializer.new(object.wizard.user, root: false).as_json end def fields diff --git a/lib/custom_wizard/submission.rb b/lib/custom_wizard/submission.rb index fc10cf31..edd0e1c9 100644 --- a/lib/custom_wizard/submission.rb +++ b/lib/custom_wizard/submission.rb @@ -120,15 +120,21 @@ class CustomWizard::Submission end def self.list(wizard, order_by: nil, page: nil) + list_actor_id = wizard.actor_id + list_user = wizard.user if wizard.user.present? + params = { plugin_name: "#{wizard.id}_#{KEY}" } - params[:key] = wizard.actor_id if wizard.actor_id + params[:key] = list_actor_id if list_actor_id query = PluginStoreRow.where(params) result = OpenStruct.new(submissions: [], total: nil) query.each do |record| if (submission_data = ::JSON.parse(record.value)).any? + submission_user = list_user || User.find_by(id: record.key.to_i) + submission_data.each do |data| + wizard.user = submission_user if submission_user.present? result.submissions.push(new(wizard, data)) end end diff --git a/plugin.rb b/plugin.rb index 7f6829eb..6b13632a 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.7 +# version: 2.2.8 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech diff --git a/spec/serializers/custom_wizard/submission_serializer_spec.rb b/spec/serializers/custom_wizard/submission_serializer_spec.rb index 02d8be8a..7853f768 100644 --- a/spec/serializers/custom_wizard/submission_serializer_spec.rb +++ b/spec/serializers/custom_wizard/submission_serializer_spec.rb @@ -3,7 +3,8 @@ require_relative '../../plugin_helper' describe CustomWizard::SubmissionSerializer do - fab!(:user) { Fabricate(:user) } + fab!(:user1) { Fabricate(:user) } + fab!(:user2) { Fabricate(:user) } let(:template_json) { JSON.parse(File.open( @@ -13,29 +14,36 @@ describe CustomWizard::SubmissionSerializer do before do CustomWizard::Template.save(template_json, skip_jobs: true) - wizard = CustomWizard::Wizard.create(template_json["id"], user) + wizard = CustomWizard::Wizard.create(template_json["id"], user1) CustomWizard::Submission.new(wizard, step_1_field_1: "I am user submission", submitted_at: Time.now.iso8601 ).save - @list = CustomWizard::Submission.list(wizard, page: 0) end it 'should return submission attributes' do + wizard = CustomWizard::Wizard.create(template_json["id"]) + list = CustomWizard::Submission.list(wizard, page: 0) + json_array = ActiveModel::ArraySerializer.new( - @list.submissions, + list.submissions, each_serializer: described_class ).as_json expect(json_array.length).to eq(1) expect(json_array[0][:id].present?).to eq(true) - expect(json_array[0][:user].present?).to eq(true) + expect(json_array[0][:user]).to eq( + BasicUserSerializer.new(user1, root: false).as_json + ) expect(json_array[0][:submitted_at].present?).to eq(true) end it "should return field values, types and labels" do + wizard = CustomWizard::Wizard.create(template_json["id"]) + list = CustomWizard::Submission.list(wizard, page: 0) + json_array = ActiveModel::ArraySerializer.new( - @list.submissions, + list.submissions, each_serializer: described_class ).as_json From 59f00d62783d294e82ee6b1e380deabf082481de Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 15 Mar 2023 14:06:55 +0100 Subject: [PATCH 16/52] Move to standard plugin workflow --- .github/workflows/discourse-plugin.yml | 11 ++ .github/workflows/plugin-linting.yml | 54 ---------- .github/workflows/plugin-tests.yml | 136 ------------------------- 3 files changed, 11 insertions(+), 190 deletions(-) create mode 100644 .github/workflows/discourse-plugin.yml delete mode 100644 .github/workflows/plugin-linting.yml delete mode 100644 .github/workflows/plugin-tests.yml diff --git a/.github/workflows/discourse-plugin.yml b/.github/workflows/discourse-plugin.yml new file mode 100644 index 00000000..f5cf62e5 --- /dev/null +++ b/.github/workflows/discourse-plugin.yml @@ -0,0 +1,11 @@ +name: Discourse Plugin + +on: + push: + branches: + - main + pull_request: + +jobs: + ci: + uses: discourse/.github/.github/workflows/discourse-plugin.yml@v1 diff --git a/.github/workflows/plugin-linting.yml b/.github/workflows/plugin-linting.yml deleted file mode 100644 index acb85230..00000000 --- a/.github/workflows/plugin-linting.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Linting - -on: - push: - branches: - - main - - stable - pull_request: - -concurrency: - group: plugin-linting-${{ format('{0}-{1}', github.head_ref || github.run_number, github.job) }} - cancel-in-progress: true - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - node-version: 16 - cache: yarn - - - name: Yarn install - run: yarn install - - - name: Set up ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.7 - bundler-cache: true - - - name: ESLint - if: ${{ always() }} - run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern {test,assets}/javascripts - - - name: Prettier - if: ${{ always() }} - shell: bash - run: | - yarn prettier -v - if [ 0 -lt $(find assets -type f \( -name "*.scss" -or -name "*.js" -or -name "*.es6" \) 2> /dev/null | wc -l) ]; then - yarn prettier --list-different "assets/**/*.{scss,js,es6}" - fi - if [ 0 -lt $(find test -type f \( -name "*.js" -or -name "*.es6" \) 2> /dev/null | wc -l) ]; then - yarn prettier --list-different "test/**/*.{js,es6}" - fi - - - name: Rubocop - if: ${{ always() }} - run: bundle exec rubocop . diff --git a/.github/workflows/plugin-tests.yml b/.github/workflows/plugin-tests.yml deleted file mode 100644 index f58f1b64..00000000 --- a/.github/workflows/plugin-tests.yml +++ /dev/null @@ -1,136 +0,0 @@ -name: Plugin Tests - -on: - push: - branches: - - main - - stable - pull_request: - -concurrency: - group: tests-${{ format('{0}-{1}', github.head_ref || github.run_number, github.job) }} - cancel-in-progress: true - -jobs: - build: - name: ${{ matrix.build_type }} - runs-on: ubuntu-latest - container: discourse/discourse_test:slim${{ startsWith(matrix.build_type, 'frontend') && '-browsers' || '' }} - timeout-minutes: 30 - - env: - DISCOURSE_HOSTNAME: www.example.com - RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072 - RAILS_ENV: test - PGUSER: discourse - PGPASSWORD: discourse - - strategy: - fail-fast: false - - matrix: - build_type: ["backend", "frontend"] - - steps: - - uses: actions/checkout@v3 - with: - repository: discourse/discourse - fetch-depth: 1 - - - name: Install plugin - uses: actions/checkout@v3 - with: - path: plugins/${{ github.event.repository.name }} - fetch-depth: 1 - - - name: Setup Git - run: | - git config --global user.email "ci@ci.invalid" - git config --global user.name "Discourse CI" - - - name: Start redis - run: | - redis-server /etc/redis/redis.conf & - - - name: Start Postgres - run: | - chown -R postgres /var/run/postgresql - sudo -E -u postgres script/start_test_db.rb - sudo -u postgres psql -c "CREATE ROLE $PGUSER LOGIN SUPERUSER PASSWORD '$PGPASSWORD';" - - - name: Bundler cache - uses: actions/cache@v3 - with: - path: vendor/bundle - key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }} - restore-keys: | - ${{ runner.os }}-gem- - - - name: Setup gems - run: | - gem install bundler --conservative -v $(awk '/BUNDLED WITH/ { getline; gsub(/ /,""); print $0 }' Gemfile.lock) - bundle config --local path vendor/bundle - bundle config --local deployment true - bundle config --local without development - bundle install --jobs 4 - bundle clean - - - name: Lint English locale - if: matrix.build_type == 'backend' - run: bundle exec ruby script/i18n_lint.rb "plugins/${{ github.event.repository.name }}/locales/{client,server}.en.yml" - - - name: Get yarn cache directory - id: yarn-cache-dir - run: echo "::set-output name=dir::$(yarn cache dir)" - - - name: Yarn cache - uses: actions/cache@v3 - id: yarn-cache - with: - path: ${{ steps.yarn-cache-dir.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Yarn install - run: yarn install - - - name: Fetch app state cache - uses: actions/cache@v3 - id: app-cache - with: - path: tmp/app-cache - key: >- - ${{ hashFiles('.github/workflows/tests.yml') }}- - ${{ hashFiles('db/**/*', 'plugins/**/db/**/*') }}- - - - name: Restore database from cache - if: steps.app-cache.outputs.cache-hit == 'true' - run: psql -f tmp/app-cache/cache.sql postgres - - - name: Restore uploads from cache - if: steps.app-cache.outputs.cache-hit == 'true' - run: rm -rf public/uploads && cp -r tmp/app-cache/uploads public/uploads - - - name: Create and migrate database - if: steps.app-cache.outputs.cache-hit != 'true' - run: | - bin/rake db:create - bin/rake db:migrate - - - name: Dump database for cache - if: steps.app-cache.outputs.cache-hit != 'true' - run: mkdir -p tmp/app-cache && pg_dumpall > tmp/app-cache/cache.sql - - - name: Dump uploads for cache - if: steps.app-cache.outputs.cache-hit != 'true' - run: rm -rf tmp/app-cache/uploads && cp -r public/uploads tmp/app-cache/uploads - - - name: Plugin RSpec - if: matrix.build_type == 'backend' - run: bin/rake plugin:spec[${{ github.event.repository.name }}] - - - name: Plugin QUnit - if: matrix.build_type == 'frontend' - run: QUNIT_EMBER_CLI=1 bundle exec rake plugin:qunit['${{ github.event.repository.name }}','1200000'] - timeout-minutes: 10 From e6d7f3d9bcfc5b7fc2a97c03beaf857686715630 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 15 Mar 2023 14:07:25 +0100 Subject: [PATCH 17/52] Update plugin.rb --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index 6b13632a..93648363 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.8 +# version: 2.2.9 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From ef1a8d1457485b8076f04f826f0abf91f440e879 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Thu, 16 Mar 2023 17:44:10 +0100 Subject: [PATCH 18/52] Ensure each wizard has the right user --- lib/custom_wizard/submission.rb | 5 +++-- .../submission_serializer_spec.rb | 20 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/custom_wizard/submission.rb b/lib/custom_wizard/submission.rb index edd0e1c9..38cad982 100644 --- a/lib/custom_wizard/submission.rb +++ b/lib/custom_wizard/submission.rb @@ -134,8 +134,9 @@ class CustomWizard::Submission submission_user = list_user || User.find_by(id: record.key.to_i) submission_data.each do |data| - wizard.user = submission_user if submission_user.present? - result.submissions.push(new(wizard, data)) + _wizard = wizard.clone + _wizard.user = submission_user if submission_user.present? + result.submissions.push(new(_wizard, data)) end end end diff --git a/spec/serializers/custom_wizard/submission_serializer_spec.rb b/spec/serializers/custom_wizard/submission_serializer_spec.rb index 7853f768..2fa000e8 100644 --- a/spec/serializers/custom_wizard/submission_serializer_spec.rb +++ b/spec/serializers/custom_wizard/submission_serializer_spec.rb @@ -14,11 +14,12 @@ describe CustomWizard::SubmissionSerializer do before do CustomWizard::Template.save(template_json, skip_jobs: true) + wizard = CustomWizard::Wizard.create(template_json["id"], user1) - CustomWizard::Submission.new(wizard, - step_1_field_1: "I am user submission", - submitted_at: Time.now.iso8601 - ).save + CustomWizard::Submission.new(wizard, step_1_field_1: "I am user1 submission", submitted_at: Time.now.iso8601).save + + wizard = CustomWizard::Wizard.create(template_json["id"], user2) + CustomWizard::Submission.new(wizard, step_1_field_1: "I am user2 submission", submitted_at: Time.now.iso8601).save end it 'should return submission attributes' do @@ -30,12 +31,11 @@ describe CustomWizard::SubmissionSerializer do each_serializer: described_class ).as_json - expect(json_array.length).to eq(1) + expect(json_array.length).to eq(2) expect(json_array[0][:id].present?).to eq(true) - expect(json_array[0][:user]).to eq( - BasicUserSerializer.new(user1, root: false).as_json - ) expect(json_array[0][:submitted_at].present?).to eq(true) + expect(json_array[0][:user]).to eq(BasicUserSerializer.new(user2, root: false).as_json) + expect(json_array[1][:user]).to eq(BasicUserSerializer.new(user1, root: false).as_json) end it "should return field values, types and labels" do @@ -47,10 +47,10 @@ describe CustomWizard::SubmissionSerializer do each_serializer: described_class ).as_json - expect(json_array.length).to eq(1) + expect(json_array.length).to eq(2) expect(json_array[0][:fields].as_json).to eq({ "step_1_field_1": { - "value": "I am user submission", + "value": "I am user2 submission", "type": "text", "label": "Text" } From 33abececd4dc211158296ab28013b325eb4a83d7 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Thu, 16 Mar 2023 17:44:24 +0100 Subject: [PATCH 19/52] Bump version --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index 2b8d1bd5..0bb34914 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.10 +# version: 2.2.11 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From c6dc80f02ca1fb61cde842dcad09b1b667c3004d Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Fri, 17 Mar 2023 09:05:53 +0100 Subject: [PATCH 20/52] FIX: template guest validation not working with validation conditions --- lib/custom_wizard/validators/template.rb | 2 +- plugin.rb | 2 +- .../custom_wizard/template_validator_spec.rb | 8 ++++++++ .../condition/validation_condition.json | 17 +++++++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 spec/fixtures/condition/validation_condition.json diff --git a/lib/custom_wizard/validators/template.rb b/lib/custom_wizard/validators/template.rb index 60652322..f2a4feb0 100644 --- a/lib/custom_wizard/validators/template.rb +++ b/lib/custom_wizard/validators/template.rb @@ -84,7 +84,7 @@ class CustomWizard::TemplateValidator def validate_guests(object, type) guests_permitted = @data[:permitted] && @data[:permitted].any? do |m| - m["output"].include?(CustomWizard::Wizard::GUEST_GROUP_ID) + m["output"]&.include?(CustomWizard::Wizard::GUEST_GROUP_ID) end return unless guests_permitted diff --git a/plugin.rb b/plugin.rb index 0bb34914..5b5c7980 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.11 +# version: 2.2.12 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech diff --git a/spec/components/custom_wizard/template_validator_spec.rb b/spec/components/custom_wizard/template_validator_spec.rb index b9b257e3..fe61be91 100644 --- a/spec/components/custom_wizard/template_validator_spec.rb +++ b/spec/components/custom_wizard/template_validator_spec.rb @@ -9,6 +9,7 @@ describe CustomWizard::TemplateValidator do let(:composer_preview) { get_wizard_fixture("field/composer_preview") } let(:guests_permitted) { get_wizard_fixture("wizard/guests_permitted") } let(:upload_field) { get_wizard_fixture("field/upload") } + let(:validation_condition) { get_wizard_fixture("condition/validation_condition") } let(:valid_liquid_template) { <<-LIQUID.strip @@ -182,6 +183,13 @@ describe CustomWizard::TemplateValidator do CustomWizard::TemplateValidator.new(template).perform ).to eq(true) end + + it "validates settings with validation conditions" do + template[:permitted] = validation_condition["condition"] + expect( + CustomWizard::TemplateValidator.new(template).perform + ).to eq(true) + end end context "steps" do diff --git a/spec/fixtures/condition/validation_condition.json b/spec/fixtures/condition/validation_condition.json new file mode 100644 index 00000000..695c25c9 --- /dev/null +++ b/spec/fixtures/condition/validation_condition.json @@ -0,0 +1,17 @@ +{ + "condition": [ + { + "type": "validation", + "pairs": [ + { + "index": 0, + "key": "trust_level", + "key_type": "user_field", + "value": "2", + "value_type": "text", + "connector": "greater_or_equal" + } + ] + } + ] +} \ No newline at end of file From 83d3ca8eb36dfa79cfb00e7707e2350cee161697 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 21 Mar 2023 15:34:07 +0100 Subject: [PATCH 21/52] Add output text selection to category name --- .../discourse/templates/components/wizard-custom-action.hbs | 2 +- plugin.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs index 106c61ee..8763d3a5 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -716,7 +716,7 @@ property="name" onUpdate=(action "mappedFieldUpdated") options=(hash - textSelection="key,value" + textSelection="key,value,output" wizardFieldSelection=true userFieldSelection="key,value" context="action" diff --git a/plugin.rb b/plugin.rb index 5b5c7980..3ba2d9c2 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.12 +# version: 2.2.13 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From a146d57f0e77704bbb20e89a31f45ea0b8818fba Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 21 Mar 2023 17:20:58 +0100 Subject: [PATCH 22/52] Ensure we're not interpolating an object --- lib/custom_wizard/mapper.rb | 9 ++++- spec/components/custom_wizard/mapper_spec.rb | 39 ++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/lib/custom_wizard/mapper.rb b/lib/custom_wizard/mapper.rb index 9d26c82e..41519b07 100644 --- a/lib/custom_wizard/mapper.rb +++ b/lib/custom_wizard/mapper.rb @@ -44,7 +44,7 @@ class CustomWizard::Mapper def initialize(params) @inputs = params[:inputs] || {} - @data = params[:data] || {} + @data = params[:data].with_indifferent_access || {} @user = params[:user] @opts = params[:opts] || {} end @@ -267,7 +267,12 @@ class CustomWizard::Mapper return nil if data.nil? k = keys.shift result = data[k] - keys.empty? ? result : self.recurse(result, keys) + + if keys.empty? + result.is_a?(Object) ? "" : result + else + self.recurse(result, keys) + end end def bool(value) diff --git a/spec/components/custom_wizard/mapper_spec.rb b/spec/components/custom_wizard/mapper_spec.rb index f460cc01..510632a9 100644 --- a/spec/components/custom_wizard/mapper_spec.rb +++ b/spec/components/custom_wizard/mapper_spec.rb @@ -58,6 +58,11 @@ describe CustomWizard::Mapper do "step_1_field_3" => "Value" } } + let(:template_params_object) { + { + "step_1_field_1": get_wizard_fixture("field/upload") + } + } def create_template_mapper(data, user) CustomWizard::Mapper.new( @@ -448,6 +453,40 @@ describe CustomWizard::Mapper do expect(result).to eq(template) end + it "handles correct object variable references" do + template = <<-LIQUID.strip + {%- if "w{step_1_field_1.id}" == "step_2_field_7" -%} + Correct + {%- else -%} + Incorrect + {%-endif-%} + LIQUID + mapper = create_template_mapper(template_params_object, user1) + result = mapper.interpolate( + template.dup, + template: true, + wizard: true + ) + expect(result).to eq("Correct") + end + + it "handles incorrect object variable references" do + template = <<-LIQUID.strip + {%- if "w{step_1_field_1}" == "step_2_field_7" -%} + Correct + {%- else -%} + Incorrect + {%-endif-%} + LIQUID + mapper = create_template_mapper(template_params_object, user1) + result = mapper.interpolate( + template.dup, + template: true, + wizard: true + ) + expect(result).to eq("Incorrect") + end + context "custom filter: 'first_non_empty'" do it "gives first non empty element from list" do template = <<-LIQUID.strip From 076e1f4966ece5e36d7844cc9748bad89feb75fb Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 21 Mar 2023 17:22:15 +0100 Subject: [PATCH 23/52] Bump version --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index 3ba2d9c2..c9cb9201 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.13 +# version: 2.2.14 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From 8fdd21601bf9621eadad32d27f5b643ac9d80283 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 21 Mar 2023 17:38:53 +0100 Subject: [PATCH 24/52] Strings are Objects in ruby --- lib/custom_wizard/mapper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/custom_wizard/mapper.rb b/lib/custom_wizard/mapper.rb index 41519b07..4e18ad01 100644 --- a/lib/custom_wizard/mapper.rb +++ b/lib/custom_wizard/mapper.rb @@ -44,7 +44,7 @@ class CustomWizard::Mapper def initialize(params) @inputs = params[:inputs] || {} - @data = params[:data].with_indifferent_access || {} + @data = params[:data] ? params[:data].with_indifferent_access : {} @user = params[:user] @opts = params[:opts] || {} end @@ -269,7 +269,7 @@ class CustomWizard::Mapper result = data[k] if keys.empty? - result.is_a?(Object) ? "" : result + result.is_a?(Hash) ? "" : result else self.recurse(result, keys) end From e2797ced64e0559f47fae1fb8411b43bbce7f465 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 21 Mar 2023 17:41:49 +0100 Subject: [PATCH 25/52] Bump version --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index c9cb9201..788ba1da 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.2.14 +# version: 2.2.15 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From 392b6f3d58506106ce5c5df7942f047569411515 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 22 Mar 2023 10:11:48 +0100 Subject: [PATCH 26/52] Fix deprecations && invalid field handling --- .../custom-wizard-date-input.js.es6 | 1 + .../custom-wizard-date-time-input.js.es6 | 2 ++ .../custom-wizard-field-time.js.es6 | 2 ++ .../custom-wizard-field-upload.js.es6 | 2 +- .../custom-wizard-field-user-selector.js.es6 | 4 ++- .../components/custom-wizard-step.js.es6 | 28 ++++++++----------- .../models/custom-wizard-field.js.es6 | 2 +- .../components/custom-wizard-date-input.hbs | 14 +++++----- .../custom-wizard-field-category.hbs | 1 + .../custom-wizard-field-checkbox.hbs | 8 +++++- .../custom-wizard-field-composer.hbs | 1 + .../components/custom-wizard-field-group.hbs | 1 + .../components/custom-wizard-field-number.hbs | 10 ++++++- .../components/custom-wizard-field-tag.hbs | 1 + .../components/custom-wizard-field-text.hbs | 9 +++++- .../custom-wizard-field-textarea.hbs | 8 +++++- .../components/custom-wizard-field-url.hbs | 7 ++++- assets/stylesheets/common/wizard/field.scss | 9 ++---- 18 files changed, 72 insertions(+), 38 deletions(-) diff --git a/assets/javascripts/discourse/components/custom-wizard-date-input.js.es6 b/assets/javascripts/discourse/components/custom-wizard-date-input.js.es6 index 9c8e4bff..2805c370 100644 --- a/assets/javascripts/discourse/components/custom-wizard-date-input.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-date-input.js.es6 @@ -3,6 +3,7 @@ import discourseComputed from "discourse-common/utils/decorators"; export default DateInput.extend({ useNativePicker: false, + classNameBindings: ["fieldClass"], @discourseComputed() placeholder() { diff --git a/assets/javascripts/discourse/components/custom-wizard-date-time-input.js.es6 b/assets/javascripts/discourse/components/custom-wizard-date-time-input.js.es6 index 44b675b0..1fcb62f5 100644 --- a/assets/javascripts/discourse/components/custom-wizard-date-time-input.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-date-time-input.js.es6 @@ -2,6 +2,8 @@ import DateTimeInput from "discourse/components/date-time-input"; import discourseComputed from "discourse-common/utils/decorators"; export default DateTimeInput.extend({ + classNameBindings: ["fieldClass"], + @discourseComputed("timeFirst", "tabindex") timeTabindex(timeFirst, tabindex) { return timeFirst ? tabindex : tabindex + 1; diff --git a/assets/javascripts/discourse/components/custom-wizard-field-time.js.es6 b/assets/javascripts/discourse/components/custom-wizard-field-time.js.es6 index 82f9c68b..ead5e94f 100644 --- a/assets/javascripts/discourse/components/custom-wizard-field-time.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-field-time.js.es6 @@ -2,6 +2,8 @@ import Component from "@ember/component"; import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ + classNameBindings: ['fieldClass'], + @observes("time") setValue() { this.set("field.value", this.time.format(this.field.format)); diff --git a/assets/javascripts/discourse/components/custom-wizard-field-upload.js.es6 b/assets/javascripts/discourse/components/custom-wizard-field-upload.js.es6 index eb5d318b..990d7daa 100644 --- a/assets/javascripts/discourse/components/custom-wizard-field-upload.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-field-upload.js.es6 @@ -4,7 +4,7 @@ import { computed } from "@ember/object"; export default Component.extend(UppyUploadMixin, { classNames: ["wizard-field-upload"], - classNameBindings: ["isImage"], + classNameBindings: ["isImage", "fieldClass"], uploading: false, type: computed(function () { return `wizard_${this.field.id}`; diff --git a/assets/javascripts/discourse/components/custom-wizard-field-user-selector.js.es6 b/assets/javascripts/discourse/components/custom-wizard-field-user-selector.js.es6 index 87d5ddb0..7ffb6dff 100644 --- a/assets/javascripts/discourse/components/custom-wizard-field-user-selector.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-field-user-selector.js.es6 @@ -1,3 +1,5 @@ import Component from "@ember/component"; -export default Component.extend({}); +export default Component.extend({ + classNameBindings: ['fieldClass'] +}); diff --git a/assets/javascripts/discourse/components/custom-wizard-step.js.es6 b/assets/javascripts/discourse/components/custom-wizard-step.js.es6 index b98db1ab..ee318b60 100644 --- a/assets/javascripts/discourse/components/custom-wizard-step.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-step.js.es6 @@ -9,6 +9,7 @@ import CustomWizard, { updateCachedWizard, } from "discourse/plugins/discourse-custom-wizard/discourse/models/custom-wizard"; import { alias, not } from "@ember/object/computed"; +import discourseLater from "discourse-common/lib/later"; const alreadyWarned = {}; @@ -110,29 +111,24 @@ export default Component.extend({ }, autoFocus() { - schedule("afterRender", () => { - const $invalid = $( - ".wizard-field.invalid:nth-of-type(1) .wizard-focusable" - ); - - if ($invalid.length) { - return $invalid.focus(); - } - - $(".wizard-focusable:first").focus(); + discourseLater(() => { + schedule("afterRender", () => { + if ($(".invalid .wizard-focusable").length) { + this.animateInvalidFields(); + } else { + $(".wizard-focusable:first").focus(); + } + }); }); }, animateInvalidFields() { schedule("afterRender", () => { - let $element = $( - ".invalid input[type=text],.invalid textarea,.invalid input[type=checkbox],.invalid .select-kit" - ); - - if ($element.length) { + let $invalid = $(".invalid .wizard-focusable"); + if ($invalid.length) { $([document.documentElement, document.body]).animate( { - scrollTop: $element.offset().top - 200, + scrollTop: $invalid.offset().top - 200, }, 400 ); diff --git a/assets/javascripts/discourse/models/custom-wizard-field.js.es6 b/assets/javascripts/discourse/models/custom-wizard-field.js.es6 index a03c7c9e..2afe79d9 100644 --- a/assets/javascripts/discourse/models/custom-wizard-field.js.es6 +++ b/assets/javascripts/discourse/models/custom-wizard-field.js.es6 @@ -72,7 +72,7 @@ export default EmberObject.extend(ValidState, { valid = true; } - this.setValid(valid); + this.setValid(Boolean(valid)); return valid; }, diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-date-input.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-date-input.hbs index 3b776215..0f798714 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-date-input.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-date-input.hbs @@ -1,11 +1,11 @@ -{{input - type=inputType +
diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-category.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-category.hbs index 9cce87bc..79180dc4 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-field-category.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-category.hbs @@ -1,5 +1,6 @@ {{custom-wizard-category-selector categories=categories + class=fieldClass whitelist=field.content onChange=(action (mut categories)) tabindex=field.tabindex diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-checkbox.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-checkbox.hbs index 053e0218..0ceeb11b 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-field-checkbox.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-checkbox.hbs @@ -1 +1,7 @@ -{{input type="checkbox" id=field.id checked=field.value tabindex=field.tabindex}} + diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-composer.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-composer.hbs index 51964a1b..2c966d24 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-field-composer.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-composer.hbs @@ -2,6 +2,7 @@ field=field composer=composer wizard=wizard + fieldClass=fieldClass groupsMentioned=(action "groupsMentioned") cannotSeeMention=(action "cannotSeeMention") importQuote=(action "importQuote") diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-group.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-group.hbs index 6873f9bd..75a5b2b1 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-field-group.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-group.hbs @@ -1,5 +1,6 @@ {{custom-wizard-group-selector groups=site.groups + class=fieldClass field=field whitelist=field.content value=field.value diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-number.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-number.hbs index f5d6543c..3049ab08 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-field-number.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-number.hbs @@ -1 +1,9 @@ -{{input type="number" step="0.01" id=field.id value=field.value tabindex=field.tabindex}} + + diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-tag.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-tag.hbs index 90679ae7..17f68b92 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-field-tag.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-tag.hbs @@ -1,5 +1,6 @@ {{custom-wizard-tag-chooser tags=field.value + class=fieldClass tabindex=field.tabindex tagGroups=field.tag_groups everyTag=true diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-text.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-text.hbs index 08733d3f..76dbee2a 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-field-text.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-text.hbs @@ -1 +1,8 @@ -{{input id=field.id value=field.value class=fieldClass placeholder=field.translatedPlaceholder tabindex=field.tabindex autocomplete=autocomplete}} + \ No newline at end of file diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-field-textarea.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-field-textarea.hbs index dda299bc..5431538c 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-field-textarea.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-field-textarea.hbs @@ -1 +1,7 @@ -{{textarea id=field.id value=field.value class=fieldClass placeholder=field.translatedPlaceholder tabindex=field.tabindex}} +