From b62aee8a48e48eb25ad89988e2732898feb6183b Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 15 Feb 2022 17:16:21 +1100 Subject: [PATCH 01/11] WIP --- test/javascripts/wizard/test_helper.js | 74 ++++++++++++++ test/javascripts/wizard/wizard-pretender.js | 106 ++++++++++++++++++++ test/javascripts/wizard/wizard-test.js | 78 ++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 test/javascripts/wizard/test_helper.js create mode 100644 test/javascripts/wizard/wizard-pretender.js create mode 100644 test/javascripts/wizard/wizard-test.js diff --git a/test/javascripts/wizard/test_helper.js b/test/javascripts/wizard/test_helper.js new file mode 100644 index 00000000..7d851f1b --- /dev/null +++ b/test/javascripts/wizard/test_helper.js @@ -0,0 +1,74 @@ +// discourse-skip-module +/*global document, Logster, QUnit */ + +window.Discourse = {}; +window.Wizard = {}; +Wizard.SiteSettings = {}; +Discourse.__widget_helpers = {}; +Discourse.SiteSettings = Wizard.SiteSettings; + +//= require env +//= require jquery.debug +//= require ember.debug +//= require locales/i18n +//= require locales/en +//= require route-recognizer +//= require fake_xml_http_request +//= require pretender +//= require qunit +//= require ember-qunit +//= require discourse-loader +//= require jquery.debug +//= require handlebars +//= require ember-template-compiler +//= require wizard-application +//= require wizard-vendor +//= require_tree ./helpers +//= require_tree ./acceptance +//= require_tree ./models +//= require_tree ./components +//= require ./wizard-pretender +//= require test-shims + +document.addEventListener("DOMContentLoaded", function () { + document.body.insertAdjacentHTML( + "afterbegin", + ` +
+ + ` + ); +}); + +if (window.Logster) { + Logster.enabled = false; +} else { + window.Logster = { enabled: false }; +} +Ember.Test.adapter = window.QUnitAdapter.create(); + +let createPretendServer = requirejs( + "wizard/test/wizard-pretender", + null, + null, + false +).default; + +let server; +QUnit.testStart(function () { + server = createPretendServer(); +}); + +QUnit.testDone(function () { + server.shutdown(); +}); + +let _testApp = requirejs("wizard/test/helpers/start-app").default(); +let _buildResolver = requirejs("discourse-common/resolver").buildResolver; +window.setResolver(_buildResolver("wizard").create({ namespace: _testApp })); + +Object.keys(requirejs.entries).forEach(function (entry) { + if (/\-test/.test(entry)) { + requirejs(entry, null, null, true); + } +}); diff --git a/test/javascripts/wizard/wizard-pretender.js b/test/javascripts/wizard/wizard-pretender.js new file mode 100644 index 00000000..e9dccfb3 --- /dev/null +++ b/test/javascripts/wizard/wizard-pretender.js @@ -0,0 +1,106 @@ +import Pretender from "pretender"; + +// TODO: This file has some copied and pasted functions from `create-pretender` - would be good +// to centralize that code at some point. + +function parsePostData(query) { + const result = {}; + query.split("&").forEach(function (part) { + const item = part.split("="); + const firstSeg = decodeURIComponent(item[0]); + const m = /^([^\[]+)\[([^\]]+)\]/.exec(firstSeg); + + const val = decodeURIComponent(item[1]).replace(/\+/g, " "); + if (m) { + result[m[1]] = result[m[1]] || {}; + result[m[1]][m[2]] = val; + } else { + result[firstSeg] = val; + } + }); + return result; +} + +function response(code, obj) { + if (typeof code === "object") { + obj = code; + code = 200; + } + return [code, { "Content-Type": "application/json" }, obj]; +} + +export default function () { + const server = new Pretender(function () { + this.get("/wizard.json", () => { + return response(200, { + wizard: { + start: "hello-world", + completed: true, + steps: [ + { + id: "hello-world", + title: "hello there", + index: 0, + description: "hello!", + fields: [ + { + id: "full_name", + type: "text", + required: true, + description: "Your name", + }, + ], + next: "second-step", + }, + { + id: "second-step", + title: "Second step", + index: 1, + fields: [{ id: "some-title", type: "text" }], + previous: "hello-world", + next: "last-step", + }, + { + id: "last-step", + index: 2, + fields: [ + { id: "snack", type: "dropdown", required: true }, + { id: "theme-preview", type: "component" }, + { id: "an-image", type: "image" }, + ], + previous: "second-step", + }, + ], + }, + }); + }); + + this.put("/wizard/steps/:id", (request) => { + const body = parsePostData(request.requestBody); + + if (body.fields.full_name === "Server Fail") { + return response(422, { + errors: [{ field: "full_name", description: "Invalid name" }], + }); + } else { + return response(200, { success: true }); + } + }); + }); + + server.prepareBody = function (body) { + if (body && typeof body === "object") { + return JSON.stringify(body); + } + return body; + }; + + server.unhandledRequest = function (verb, path) { + const error = + "Unhandled request in test environment: " + path + " (" + verb + ")"; + window.console.error(error); + throw error; + }; + + return server; +} diff --git a/test/javascripts/wizard/wizard-test.js b/test/javascripts/wizard/wizard-test.js new file mode 100644 index 00000000..ea550cf2 --- /dev/null +++ b/test/javascripts/wizard/wizard-test.js @@ -0,0 +1,78 @@ +import { click, currentRouteName, fillIn, visit } from "@ember/test-helpers"; +import { module, test } from "qunit"; +import { run } from "@ember/runloop"; +import startApp from "wizard/test/helpers/start-app"; + +let wizard; +module("Acceptance: wizard", { + beforeEach() { + wizard = startApp(); + }, + + afterEach() { + run(wizard, "destroy"); + }, +}); + +function exists(selector) { + return document.querySelector(selector) !== null; +} + +test("Wizard starts", async function (assert) { + await visit("/"); + assert.ok(exists(".wizard-column-contents")); + assert.strictEqual(currentRouteName(), "step"); +}); + +test("Going back and forth in steps", async function (assert) { + await visit("/steps/hello-world"); + assert.ok(exists(".wizard-step")); + assert.ok( + exists(".wizard-step-hello-world"), + "it adds a class for the step id" + ); + assert.ok(!exists(".wizard-btn.finish"), "can’t finish on first step"); + assert.ok(exists(".wizard-progress")); + assert.ok(exists(".wizard-step-title")); + assert.ok(exists(".wizard-step-description")); + assert.ok( + !exists(".invalid .field-full-name"), + "don't show it as invalid until the user does something" + ); + assert.ok(exists(".wizard-field .field-description")); + assert.ok(!exists(".wizard-btn.back")); + assert.ok(!exists(".wizard-field .field-error-description")); + + // invalid data + await click(".wizard-btn.next"); + assert.ok(exists(".invalid .field-full-name")); + + // server validation fail + await fillIn("input.field-full-name", "Server Fail"); + await click(".wizard-btn.next"); + assert.ok(exists(".invalid .field-full-name")); + assert.ok(exists(".wizard-field .field-error-description")); + + // server validation ok + await fillIn("input.field-full-name", "Evil Trout"); + await click(".wizard-btn.next"); + assert.ok(!exists(".wizard-field .field-error-description")); + assert.ok(!exists(".wizard-step-description")); + assert.ok( + exists(".wizard-btn.finish"), + "shows finish on an intermediate step" + ); + + await click(".wizard-btn.next"); + assert.ok(exists(".select-kit.field-snack"), "went to the next step"); + assert.ok(exists(".preview-area"), "renders the component field"); + assert.ok(exists(".wizard-btn.done"), "last step shows a done button"); + assert.ok(exists(".action-link.back"), "shows the back button"); + assert.ok(!exists(".wizard-step-title")); + assert.ok(!exists(".wizard-btn.finish"), "can’t finish on last step"); + + await click(".action-link.back"); + assert.ok(exists(".wizard-step-title")); + assert.ok(exists(".wizard-btn.next")); + assert.ok(!exists(".wizard-prev")); +}); From b20b8ce3335af792b38b7d6319783e688c4eea39 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Thu, 17 Feb 2022 17:08:14 +1100 Subject: [PATCH 02/11] WIP 2 --- .github/workflows/plugin-tests.yml | 2 +- .../javascripts/acceptance/wizard-test.js.es6 | 30 ++ test/javascripts/fixtures/wizard.js | 340 ++++++++++++++++++ test/javascripts/helpers/start-app.js | 23 ++ .../test_helper.js => plugin_helper.js} | 18 +- test/javascripts/wizard/wizard-test.js | 78 ---- .../wizard => views}/wizard-pretender.js | 45 +-- 7 files changed, 404 insertions(+), 132 deletions(-) create mode 100644 test/javascripts/acceptance/wizard-test.js.es6 create mode 100644 test/javascripts/fixtures/wizard.js create mode 100644 test/javascripts/helpers/start-app.js rename test/javascripts/{wizard/test_helper.js => plugin_helper.js} (86%) delete mode 100644 test/javascripts/wizard/wizard-test.js rename {test/javascripts/wizard => views}/wizard-pretender.js (57%) diff --git a/.github/workflows/plugin-tests.yml b/.github/workflows/plugin-tests.yml index 855bdfec..ef042fbc 100644 --- a/.github/workflows/plugin-tests.yml +++ b/.github/workflows/plugin-tests.yml @@ -31,7 +31,7 @@ jobs: build_type: ["backend", "frontend"] ruby: ["2.7"] postgres: ["12"] - redis: ["4.x"] + redis: ["6.x"] services: postgres: diff --git a/test/javascripts/acceptance/wizard-test.js.es6 b/test/javascripts/acceptance/wizard-test.js.es6 new file mode 100644 index 00000000..d7aa706a --- /dev/null +++ b/test/javascripts/acceptance/wizard-test.js.es6 @@ -0,0 +1,30 @@ +import { click, currentRouteName, fillIn, visit } from "@ember/test-helpers"; +import { module, test } from "qunit"; +import { run } from "@ember/runloop"; +import startApp from "../helpers/start-app"; +console.log("STARTING TEST"); +let wizard; +window.onerror = function (msg, url, lineNo, columnNo, error) { + console.log(error); + return false +} +module("Acceptance: Custom Wizard", { + beforeEach() { + console.log("BEFORE EACH") + wizard = startApp(); + }, + + afterEach() { + run(wizard, "destroy"); + }, +}); + +function exists(selector) { + return document.querySelector(selector) !== null; +} + +test("Wizard starts", async function (assert) { + console.log("TEST") + await visit("/w/wizard"); + assert.ok(exists(".wizard-column")); +}); diff --git a/test/javascripts/fixtures/wizard.js b/test/javascripts/fixtures/wizard.js new file mode 100644 index 00000000..0b3a219c --- /dev/null +++ b/test/javascripts/fixtures/wizard.js @@ -0,0 +1,340 @@ +export default { + "id": "super_mega_fun_wizard", + "name": "Super Mega Fun Wizard", + "background": "#333333", + "save_submissions": true, + "after_signup": false, + "prompt_completion": false, + "theme_id": 2, + "steps": [ + { + "id": "step_1", + "title": "Text", + "raw_description": "Text inputs!", + "fields": [ + { + "id": "step_1_field_1", + "label": "Text", + "description": "Text field description.", + "type": "text", + "min_length": "3", + "prefill": [ + { + "type": "assignment", + "output": "I am prefilled", + "output_type": "text", + "output_connector": "set" + } + ] + }, + { + "id": "step_1_field_2", + "label": "Textarea", + "type": "textarea", + "min_length": "" + }, + { + "id": "step_1_field_3", + "label": "Composer", + "type": "composer" + }, + { + "id": "step_1_field_4", + "label": "I'm only text", + "description": "", + "type": "text_only" + } + ], + "description": "Text inputs!" + }, + { + "id": "step_2", + "title": "Values", + "raw_description": "Because I couldn't think of another name for this step :)", + "fields": [ + { + "id": "step_2_field_1", + "label": "Date", + "type": "date", + "format": "YYYY-MM-DD" + }, + { + "id": "step_2_field_2", + "label": "Time", + "type": "time", + "format": "HH:mm" + }, + { + "id": "step_2_field_3", + "label": "Date & Time", + "type": "date_time", + "format": "" + }, + { + "id": "step_2_field_4", + "label": "Number", + "type": "number" + }, + { + "id": "step_2_field_5", + "label": "Checkbox", + "type": "checkbox" + }, + { + "id": "step_2_field_6", + "label": "Url", + "type": "url" + }, + { + "id": "step_2_field_7", + "label": "Upload", + "type": "upload", + "file_types": ".jpg,.jpeg,.png" + } + ], + "description": "Because I couldn't think of another name for this step :)" + }, + { + "id": "step_3", + "title": "Combo-boxes", + "raw_description": "Unfortunately not the edible type :sushi: ", + "fields": [ + { + "id": "step_3_field_1", + "label": "Custom Dropdown", + "type": "dropdown", + "content": [ + { + "type": "association", + "pairs": [ + { + "index": 0, + "key": "choice1", + "key_type": "text", + "value": "Choice 1", + "value_type": "text", + "connector": "equal" + }, + { + "index": 1, + "key": "choice2", + "key_type": "text", + "value": "Choice 2", + "value_type": "text", + "connector": "association" + }, + { + "index": 2, + "key": "choice3", + "key_type": "text", + "value": "Choice 3", + "value_type": "text", + "connector": "association" + } + ] + } + ] + }, + { + "id": "step_3_field_2", + "label": "Tag", + "type": "tag" + }, + { + "id": "step_3_field_3", + "label": "Category", + "type": "category", + "limit": 1, + "property": "id" + }, + { + "id": "step_3_field_4", + "label": "Group", + "type": "group" + }, + { + "id": "step_3_field_5", + "label": "User Selector", + "description": "", + "type": "user_selector" + }, + { + "id": "step_3_field_6", + "label": "Conditional User Selector", + "description": "Shown when checkbox in step_2_field_5 is true", + "type": "user_selector" + } + ], + "description": "Unfortunately not the edible type :sushi: " + } + ], + "actions": [ + { + "id": "action_1", + "run_after": "step_3", + "type": "create_topic", + "skip_redirect": true, + "post": "step_1_field_2", + "title": [ + { + "type": "assignment", + "output": "step_1_field_1", + "output_type": "wizard_field", + "output_connector": "set" + } + ], + "category": [ + { + "type": "assignment", + "output": "step_3_field_3", + "output_type": "wizard_field", + "output_connector": "set" + } + ], + "tags": [ + { + "type": "assignment", + "output": "step_3_field_2", + "output_type": "wizard_field", + "output_connector": "set" + } + ], + "custom_fields": [ + { + "type": "association", + "pairs": [ + { + "index": 0, + "key": "post_field", + "key_type": "text", + "value": "Post custom field value", + "value_type": "text", + "connector": "association" + }, + { + "index": 1, + "key": "topic.topic_field", + "key_type": "text", + "value": "Topic custom field value", + "value_type": "text", + "connector": "association" + }, + { + "index": 2, + "key": "topic.topic_json_field{}.key_1", + "key_type": "text", + "value": "Key 1 value", + "value_type": "text", + "connector": "association" + }, + { + "index": 3, + "key": "topic.topic_json_field{}.key_2", + "key_type": "text", + "value": "Key 2 value", + "value_type": "text", + "connector": "association" + } + ] + } + ], + "visible": [ + { + "type": "conditional", + "output": "true", + "output_type": "text", + "output_connector": "then", + "pairs": [ + { + "index": 0, + "key": "name", + "key_type": "user_field", + "value": "Angus", + "value_type": "text", + "connector": "equal" + } + ] + } + ] + }, + { + "id": "action_5", + "run_after": "step_1", + "type": "watch_categories", + "notification_level": "tracking", + "wizard_user": true, + "categories": [ + { + "type": "assignment", + "output": "action_8", + "output_type": "wizard_action", + "output_connector": "set" + } + ], + "mute_remainder": [ + { + "type": "assignment", + "output": "true", + "output_type": "text", + "output_connector": "set" + } + ] + }, + { + "id": "action_4", + "run_after": "step_2", + "type": "update_profile", + "profile_updates": [ + { + "type": "association", + "pairs": [ + { + "index": 0, + "key": "profile_background", + "key_type": "user_field", + "value": "step_2_field_7", + "value_type": "wizard_field", + "connector": "association" + } + ] + } + ] + }, + { + "id": "action_3", + "run_after": "step_2", + "type": "open_composer", + "post_builder": true, + "post_template": "I am interpolating some user fields u{name} u{username} u{email}", + "title": [ + { + "type": "assignment", + "output": "Title of the composer topic", + "output_type": "text", + "output_connector": "set" + } + ], + "tags": [ + { + "type": "assignment", + "output": "tag1", + "output_type": "text", + "output_connector": "set" + } + ] + }, + { + "id": "action_10", + "run_after": "step_3", + "type": "route_to", + "url": [ + { + "type": "assignment", + "output": "https://google.com", + "output_type": "text", + "output_connector": "set" + } + ] + } + ] +} diff --git a/test/javascripts/helpers/start-app.js b/test/javascripts/helpers/start-app.js new file mode 100644 index 00000000..6f5dbcc6 --- /dev/null +++ b/test/javascripts/helpers/start-app.js @@ -0,0 +1,23 @@ +import CustomWizard from "discourse/plugins/discourse-custom-wizard/wizard/custom-wizard"; +import wizardInitializer from "discourse/plugins/discourse-custom-wizard/wizard/initializers/custom-wizard"; +import stepInitializer from "discourse/plugins/discourse-custom-wizard/wizard/initializers/custom-wizard-step"; +import fieldInitializer from "discourse/plugins/discourse-custom-wizard/wizard/initializers/custom-wizard-field"; +import { run } from "@ember/runloop"; + +let app; +let started = false; + +export default function () { + run(() => (app = CustomWizard.create({ rootElement: "#ember-testing" }))); + + if (!started) { + wizardInitializer.initialize(app); + stepInitializer.initialize(app); + fieldInitializer.initialize(app); + app.start(); + started = true; + } + app.setupForTesting(); + app.injectTestHelpers(); + return app; +} diff --git a/test/javascripts/wizard/test_helper.js b/test/javascripts/plugin_helper.js similarity index 86% rename from test/javascripts/wizard/test_helper.js rename to test/javascripts/plugin_helper.js index 7d851f1b..9b1558cd 100644 --- a/test/javascripts/wizard/test_helper.js +++ b/test/javascripts/plugin_helper.js @@ -1,6 +1,6 @@ // discourse-skip-module /*global document, Logster, QUnit */ - +console.log('starting test_helper') window.Discourse = {}; window.Wizard = {}; Wizard.SiteSettings = {}; @@ -21,7 +21,7 @@ Discourse.SiteSettings = Wizard.SiteSettings; //= require jquery.debug //= require handlebars //= require ember-template-compiler -//= require wizard-application +//= require wizard-custom //= require wizard-vendor //= require_tree ./helpers //= require_tree ./acceptance @@ -29,7 +29,7 @@ Discourse.SiteSettings = Wizard.SiteSettings; //= require_tree ./components //= require ./wizard-pretender //= require test-shims - +console.log ("end of require") document.addEventListener("DOMContentLoaded", function () { document.body.insertAdjacentHTML( "afterbegin", @@ -47,12 +47,7 @@ if (window.Logster) { } Ember.Test.adapter = window.QUnitAdapter.create(); -let createPretendServer = requirejs( - "wizard/test/wizard-pretender", - null, - null, - false -).default; +/*let createPretendServer = requirejs("./wizard-pretender", null, null, false).default; let server; QUnit.testStart(function () { @@ -61,9 +56,9 @@ QUnit.testStart(function () { QUnit.testDone(function () { server.shutdown(); -}); +});*/ -let _testApp = requirejs("wizard/test/helpers/start-app").default(); +let _testApp = requirejs("./helpers/start-app").default(); let _buildResolver = requirejs("discourse-common/resolver").buildResolver; window.setResolver(_buildResolver("wizard").create({ namespace: _testApp })); @@ -72,3 +67,4 @@ Object.keys(requirejs.entries).forEach(function (entry) { requirejs(entry, null, null, true); } }); +console.log ("end of helper") diff --git a/test/javascripts/wizard/wizard-test.js b/test/javascripts/wizard/wizard-test.js deleted file mode 100644 index ea550cf2..00000000 --- a/test/javascripts/wizard/wizard-test.js +++ /dev/null @@ -1,78 +0,0 @@ -import { click, currentRouteName, fillIn, visit } from "@ember/test-helpers"; -import { module, test } from "qunit"; -import { run } from "@ember/runloop"; -import startApp from "wizard/test/helpers/start-app"; - -let wizard; -module("Acceptance: wizard", { - beforeEach() { - wizard = startApp(); - }, - - afterEach() { - run(wizard, "destroy"); - }, -}); - -function exists(selector) { - return document.querySelector(selector) !== null; -} - -test("Wizard starts", async function (assert) { - await visit("/"); - assert.ok(exists(".wizard-column-contents")); - assert.strictEqual(currentRouteName(), "step"); -}); - -test("Going back and forth in steps", async function (assert) { - await visit("/steps/hello-world"); - assert.ok(exists(".wizard-step")); - assert.ok( - exists(".wizard-step-hello-world"), - "it adds a class for the step id" - ); - assert.ok(!exists(".wizard-btn.finish"), "can’t finish on first step"); - assert.ok(exists(".wizard-progress")); - assert.ok(exists(".wizard-step-title")); - assert.ok(exists(".wizard-step-description")); - assert.ok( - !exists(".invalid .field-full-name"), - "don't show it as invalid until the user does something" - ); - assert.ok(exists(".wizard-field .field-description")); - assert.ok(!exists(".wizard-btn.back")); - assert.ok(!exists(".wizard-field .field-error-description")); - - // invalid data - await click(".wizard-btn.next"); - assert.ok(exists(".invalid .field-full-name")); - - // server validation fail - await fillIn("input.field-full-name", "Server Fail"); - await click(".wizard-btn.next"); - assert.ok(exists(".invalid .field-full-name")); - assert.ok(exists(".wizard-field .field-error-description")); - - // server validation ok - await fillIn("input.field-full-name", "Evil Trout"); - await click(".wizard-btn.next"); - assert.ok(!exists(".wizard-field .field-error-description")); - assert.ok(!exists(".wizard-step-description")); - assert.ok( - exists(".wizard-btn.finish"), - "shows finish on an intermediate step" - ); - - await click(".wizard-btn.next"); - assert.ok(exists(".select-kit.field-snack"), "went to the next step"); - assert.ok(exists(".preview-area"), "renders the component field"); - assert.ok(exists(".wizard-btn.done"), "last step shows a done button"); - assert.ok(exists(".action-link.back"), "shows the back button"); - assert.ok(!exists(".wizard-step-title")); - assert.ok(!exists(".wizard-btn.finish"), "can’t finish on last step"); - - await click(".action-link.back"); - assert.ok(exists(".wizard-step-title")); - assert.ok(exists(".wizard-btn.next")); - assert.ok(!exists(".wizard-prev")); -}); diff --git a/test/javascripts/wizard/wizard-pretender.js b/views/wizard-pretender.js similarity index 57% rename from test/javascripts/wizard/wizard-pretender.js rename to views/wizard-pretender.js index e9dccfb3..ac0ef1e8 100644 --- a/test/javascripts/wizard/wizard-pretender.js +++ b/views/wizard-pretender.js @@ -1,4 +1,5 @@ import Pretender from "pretender"; +import WizardJson from "./fixtures/wizard"; // TODO: This file has some copied and pasted functions from `create-pretender` - would be good // to centralize that code at some point. @@ -31,48 +32,8 @@ function response(code, obj) { export default function () { const server = new Pretender(function () { - this.get("/wizard.json", () => { - return response(200, { - wizard: { - start: "hello-world", - completed: true, - steps: [ - { - id: "hello-world", - title: "hello there", - index: 0, - description: "hello!", - fields: [ - { - id: "full_name", - type: "text", - required: true, - description: "Your name", - }, - ], - next: "second-step", - }, - { - id: "second-step", - title: "Second step", - index: 1, - fields: [{ id: "some-title", type: "text" }], - previous: "hello-world", - next: "last-step", - }, - { - id: "last-step", - index: 2, - fields: [ - { id: "snack", type: "dropdown", required: true }, - { id: "theme-preview", type: "component" }, - { id: "an-image", type: "image" }, - ], - previous: "second-step", - }, - ], - }, - }); + this.get("/w/wizard.json", () => { + return response(200, cloneJSON(WizardJson); }); this.put("/wizard/steps/:id", (request) => { From 8893e6caf1dc97c7351023451f7916a86fbd9c3d Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 16 Mar 2022 12:33:34 +0100 Subject: [PATCH 03/11] Refactor wizard client and add tests --- assets/javascripts/wizard-custom-globals.js | 6 - assets/javascripts/wizard-custom-start.js | 2 +- assets/javascripts/wizard-custom.js | 15 +- assets/javascripts/wizard-qunit.js | 16 + assets/javascripts/wizard/application.js.es6 | 19 + .../components/custom-user-selector.js.es6 | 9 +- .../wizard/components/field-validators.js.es6 | 3 + .../similar-topics-validator.js.es6 | 1 + .../wizard/components/validator.js.es6 | 3 +- .../components/wizard-composer-editor.js.es6 | 1 + .../wizard-composer-hyperlink.js.es6 | 1 + .../components/wizard-date-input.js.es6 | 1 + .../components/wizard-date-time-input.js.es6 | 2 + .../components/wizard-field-category.js.es6 | 2 + .../components/wizard-field-checkbox.js.es6 | 5 + .../wizard-field-composer-preview.js.es6 | 2 + .../components/wizard-field-composer.js.es6 | 2 + .../components/wizard-field-date-time.js.es6 | 2 + .../components/wizard-field-date.js.es6 | 2 + .../components/wizard-field-dropdown.js.es6 | 15 + .../components/wizard-field-group.js.es6 | 5 + .../components/wizard-field-number.js.es6 | 5 + .../wizard/components/wizard-field-tag.js.es6 | 5 + .../components/wizard-field-text.js.es6 | 9 + .../components/wizard-field-textarea.js.es6 | 9 + .../components/wizard-field-time.js.es6 | 2 + .../components/wizard-field-upload.js.es6 | 4 + .../wizard/components/wizard-field-url.js.es6 | 5 + .../wizard-field-user-selector.js.es6 | 5 + .../wizard/components/wizard-field.js.es6 | 34 ++ .../components/wizard-group-selector.js.es6 | 1 + .../wizard/components/wizard-no-access.js.es6 | 23 +- .../components/wizard-similar-topics.js.es6 | 1 + .../wizard/components/wizard-step-form.js.es6 | 9 + .../wizard/components/wizard-step.js.es6 | 247 +++++++++ .../components/wizard-text-field.js.es6 | 6 +- .../components/wizard-time-input.js.es6 | 4 +- .../wizard/controllers/custom.js.es6 | 3 - .../{custom-step.js.es6 => step.js.es6} | 11 +- .../wizard/controllers/wizard-index.js.es6 | 24 + .../wizard/controllers/wizard.js.es6 | 5 + .../javascripts/wizard/custom-wizard.js.es6 | 39 -- .../initializers/custom-wizard-step.js.es6 | 219 -------- .../wizard/initializers/custom-wizard.js.es6 | 126 ----- .../lib/initialize/create-contexts.js.es6 | 12 + .../lib/initialize/inject-objects.js.es6 | 49 ++ .../initialize/patch-components.js.es6} | 140 ++---- .../lib/initialize/register-files.js.es6 | 26 + .../wizard/lib/initialize/wizard.js.es6 | 49 ++ .../wizard/lib/utilities-lite.js.es6 | 71 --- assets/javascripts/wizard/models/field.js.es6 | 79 +++ assets/javascripts/wizard/models/site.js.es6 | 3 +- assets/javascripts/wizard/models/step.js.es6 | 114 +++++ .../models/{custom.js.es6 => wizard.js.es6} | 6 +- assets/javascripts/wizard/router.js.es6 | 17 + .../wizard/routes/application.js.es6 | 3 + .../wizard/routes/custom-steps.js.es6 | 5 - assets/javascripts/wizard/routes/index.js.es6 | 9 + .../{custom-step.js.es6 => step.js.es6} | 11 +- assets/javascripts/wizard/routes/steps.js.es6 | 7 + ...ustom-index.js.es6 => wizard-index.js.es6} | 26 +- .../routes/{custom.js.es6 => wizard.js.es6} | 59 ++- .../components/wizard-field-dropdown.hbs | 1 + .../wizard/templates/custom.index.hbs | 15 - assets/javascripts/wizard/templates/index.hbs | 1 + .../templates/{custom.step.hbs => step.hbs} | 0 .../wizard/templates/wizard-index.hbs | 3 + .../templates/{custom.hbs => wizard.hbs} | 4 - .../wizard/tests/acceptance/field-test.js.es6 | 135 +++++ .../wizard/tests/acceptance/step-test.js.es6 | 47 ++ .../tests/acceptance/wizard-test.js.es6 | 72 +++ .../javascripts/wizard/tests/bootstrap.js.es6 | 17 + .../wizard/tests/fixtures/categories.js.es6 | 209 ++++++++ .../wizard/tests/fixtures/groups.js.es6 | 313 ++++++++++++ .../tests/fixtures/site-settings.js.es6 | 283 +++++++++++ .../wizard/tests/fixtures/tags.js.es6 | 22 + .../wizard/tests/fixtures/update.js.es6 | 5 + .../wizard/tests/fixtures/user.js.es6 | 34 ++ .../wizard/tests/fixtures/users.js.es6 | 14 + .../wizard/tests/fixtures/wizard.js.es6 | 469 ++++++++++++++++++ .../wizard/tests/helpers/acceptance.js.es6 | 53 ++ .../wizard/tests/helpers/start-app.js.es6 | 19 + .../wizard/tests/helpers/step.js.es6 | 20 + .../wizard/tests/helpers/test.js.es6 | 7 + .../wizard/tests/helpers/wizard.js.es6 | 52 ++ .../javascripts/wizard/tests/pretender.js.es6 | 28 +- .../stylesheets/wizard/custom/composer.scss | 2 +- config/routes.rb | 1 + controllers/custom_wizard/wizard.rb | 112 +++-- extensions/extra_locales_controller.rb | 1 + lib/custom_wizard/validators/update.rb | 2 +- plugin.rb | 3 +- .../javascripts/acceptance/wizard-test.js.es6 | 30 -- test/javascripts/fixtures/wizard.js | 340 ------------- test/javascripts/helpers/start-app.js | 23 - test/javascripts/plugin_helper.js | 70 --- views/layouts/qunit.html.erb | 28 ++ views/layouts/wizard.html.erb | 6 +- 98 files changed, 2834 insertions(+), 1203 deletions(-) delete mode 100644 assets/javascripts/wizard-custom-globals.js create mode 100644 assets/javascripts/wizard-qunit.js create mode 100644 assets/javascripts/wizard/application.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field-checkbox.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field-dropdown.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field-group.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field-number.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field-tag.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field-text.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field-textarea.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field-url.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field-user-selector.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-field.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-step-form.js.es6 create mode 100644 assets/javascripts/wizard/components/wizard-step.js.es6 delete mode 100644 assets/javascripts/wizard/controllers/custom.js.es6 rename assets/javascripts/wizard/controllers/{custom-step.js.es6 => step.js.es6} (76%) create mode 100644 assets/javascripts/wizard/controllers/wizard-index.js.es6 create mode 100644 assets/javascripts/wizard/controllers/wizard.js.es6 delete mode 100644 assets/javascripts/wizard/custom-wizard.js.es6 delete mode 100644 assets/javascripts/wizard/initializers/custom-wizard-step.js.es6 delete mode 100644 assets/javascripts/wizard/initializers/custom-wizard.js.es6 create mode 100644 assets/javascripts/wizard/lib/initialize/create-contexts.js.es6 create mode 100644 assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 rename assets/javascripts/wizard/{initializers/custom-wizard-field.js.es6 => lib/initialize/patch-components.js.es6} (52%) create mode 100644 assets/javascripts/wizard/lib/initialize/register-files.js.es6 create mode 100644 assets/javascripts/wizard/lib/initialize/wizard.js.es6 delete mode 100644 assets/javascripts/wizard/lib/utilities-lite.js.es6 create mode 100644 assets/javascripts/wizard/models/field.js.es6 create mode 100644 assets/javascripts/wizard/models/step.js.es6 rename assets/javascripts/wizard/models/{custom.js.es6 => wizard.js.es6} (96%) create mode 100644 assets/javascripts/wizard/router.js.es6 create mode 100644 assets/javascripts/wizard/routes/application.js.es6 delete mode 100644 assets/javascripts/wizard/routes/custom-steps.js.es6 create mode 100644 assets/javascripts/wizard/routes/index.js.es6 rename assets/javascripts/wizard/routes/{custom-step.js.es6 => step.js.es6} (78%) create mode 100644 assets/javascripts/wizard/routes/steps.js.es6 rename assets/javascripts/wizard/routes/{custom-index.js.es6 => wizard-index.js.es6} (50%) rename assets/javascripts/wizard/routes/{custom.js.es6 => wizard.js.es6} (59%) delete mode 100644 assets/javascripts/wizard/templates/custom.index.hbs create mode 100644 assets/javascripts/wizard/templates/index.hbs rename assets/javascripts/wizard/templates/{custom.step.hbs => step.hbs} (100%) create mode 100644 assets/javascripts/wizard/templates/wizard-index.hbs rename assets/javascripts/wizard/templates/{custom.hbs => wizard.hbs} (86%) create mode 100644 assets/javascripts/wizard/tests/acceptance/field-test.js.es6 create mode 100644 assets/javascripts/wizard/tests/acceptance/step-test.js.es6 create mode 100644 assets/javascripts/wizard/tests/acceptance/wizard-test.js.es6 create mode 100644 assets/javascripts/wizard/tests/bootstrap.js.es6 create mode 100644 assets/javascripts/wizard/tests/fixtures/categories.js.es6 create mode 100644 assets/javascripts/wizard/tests/fixtures/groups.js.es6 create mode 100644 assets/javascripts/wizard/tests/fixtures/site-settings.js.es6 create mode 100644 assets/javascripts/wizard/tests/fixtures/tags.js.es6 create mode 100644 assets/javascripts/wizard/tests/fixtures/update.js.es6 create mode 100644 assets/javascripts/wizard/tests/fixtures/user.js.es6 create mode 100644 assets/javascripts/wizard/tests/fixtures/users.js.es6 create mode 100644 assets/javascripts/wizard/tests/fixtures/wizard.js.es6 create mode 100644 assets/javascripts/wizard/tests/helpers/acceptance.js.es6 create mode 100644 assets/javascripts/wizard/tests/helpers/start-app.js.es6 create mode 100644 assets/javascripts/wizard/tests/helpers/step.js.es6 create mode 100644 assets/javascripts/wizard/tests/helpers/test.js.es6 create mode 100644 assets/javascripts/wizard/tests/helpers/wizard.js.es6 rename views/wizard-pretender.js => assets/javascripts/wizard/tests/pretender.js.es6 (56%) delete mode 100644 test/javascripts/acceptance/wizard-test.js.es6 delete mode 100644 test/javascripts/fixtures/wizard.js delete mode 100644 test/javascripts/helpers/start-app.js delete mode 100644 test/javascripts/plugin_helper.js create mode 100644 views/layouts/qunit.html.erb diff --git a/assets/javascripts/wizard-custom-globals.js b/assets/javascripts/wizard-custom-globals.js deleted file mode 100644 index 83923cba..00000000 --- a/assets/javascripts/wizard-custom-globals.js +++ /dev/null @@ -1,6 +0,0 @@ -/* eslint no-undef: 0*/ -window.Discourse = {}; -window.Wizard = {}; -Wizard.SiteSettings = {}; -Discourse.__widget_helpers = {}; -Discourse.SiteSettings = Wizard.SiteSettings; diff --git a/assets/javascripts/wizard-custom-start.js b/assets/javascripts/wizard-custom-start.js index 3ffa9c5a..b92d2871 100644 --- a/assets/javascripts/wizard-custom-start.js +++ b/assets/javascripts/wizard-custom-start.js @@ -1,4 +1,4 @@ (function () { - let wizard = require("discourse/plugins/discourse-custom-wizard/wizard/custom-wizard").default.create(); + let wizard = require("discourse/plugins/discourse-custom-wizard/wizard/application").default.create(); wizard.start(); })(); diff --git a/assets/javascripts/wizard-custom.js b/assets/javascripts/wizard-custom.js index 826cdf2d..2a5eb97a 100644 --- a/assets/javascripts/wizard-custom.js +++ b/assets/javascripts/wizard-custom.js @@ -1,10 +1,13 @@ +//= require_tree_discourse truth-helpers/addon +//= require_tree_discourse discourse-common/addon +//= require_tree_discourse select-kit/addon +//= require_tree_discourse wizard/lib +//= require_tree_discourse wizard/mixins //= require_tree_discourse discourse/app/lib //= require_tree_discourse discourse/app/mixins //= require discourse/app/adapters/rest - //= require message-bus - //= require_tree_discourse discourse/app/models //= require discourse/app/helpers/category-link @@ -12,9 +15,6 @@ //= require discourse/app/helpers/format-username //= require discourse/app/helpers/share-url //= require discourse/app/helpers/decorate-username-selector -//= require discourse-common/addon/helpers/component-for-collection -//= require discourse-common/addon/helpers/component-for-row -//= require discourse-common/addon/lib/raw-templates //= require discourse/app/helpers/discourse-tag //= require discourse/app/services/app-events @@ -59,7 +59,6 @@ //= require polyfills //= require markdown-it-bundle -//= require lodash.js //= require template_include.js //= require itsatrap.js //= require caret_position.js @@ -69,11 +68,11 @@ //= require bootbox.js //= require discourse-shims -//= require ./wizard/custom-wizard +//= require ./wizard/application +//= require ./wizard/router //= require_tree ./wizard/components //= require_tree ./wizard/controllers //= require_tree ./wizard/helpers -//= require_tree ./wizard/initializers //= require_tree ./wizard/lib //= require_tree ./wizard/models //= require_tree ./wizard/routes diff --git a/assets/javascripts/wizard-qunit.js b/assets/javascripts/wizard-qunit.js new file mode 100644 index 00000000..2866cb5d --- /dev/null +++ b/assets/javascripts/wizard-qunit.js @@ -0,0 +1,16 @@ +//= require route-recognizer +//= require fake_xml_http_request +//= require pretender +//= require qunit +//= require ember-qunit +//= require test-shims +//= require jquery.debug +//= require ember.debug +//= require ember-template-compiler + +//= require_tree ./wizard/tests/fixtures +//= require ./wizard/tests/pretender +//= require_tree ./wizard/tests/helpers +//= require_tree ./wizard/tests/acceptance + +//= require ./wizard/tests/bootstrap diff --git a/assets/javascripts/wizard/application.js.es6 b/assets/javascripts/wizard/application.js.es6 new file mode 100644 index 00000000..012949b3 --- /dev/null +++ b/assets/javascripts/wizard/application.js.es6 @@ -0,0 +1,19 @@ +import { buildResolver } from "discourse-common/resolver"; +import Application from "@ember/application"; +import WizardInitializer from "./lib/initialize/wizard"; +import { isTesting } from "discourse-common/config/environment"; + +export default Application.extend({ + rootElement: "#custom-wizard-main", + Resolver: buildResolver("discourse/plugins/discourse-custom-wizard/wizard"), + + customEvents: { + paste: "paste", + }, + + start() { + if (!isTesting()) { + this.initializer(WizardInitializer); + } + }, +}); diff --git a/assets/javascripts/wizard/components/custom-user-selector.js.es6 b/assets/javascripts/wizard/components/custom-user-selector.js.es6 index b2f08ede..1698a008 100644 --- a/assets/javascripts/wizard/components/custom-user-selector.js.es6 +++ b/assets/javascripts/wizard/components/custom-user-selector.js.es6 @@ -1,6 +1,6 @@ import { default as computed, - observes, + observes } from "discourse-common/utils/decorators"; import { renderAvatar } from "discourse/helpers/user-avatar"; import userSearch from "../lib/user-search"; @@ -55,7 +55,6 @@ export default Ember.TextField.extend({ let self = this, selected = [], groups = [], - currentUser = this.currentUser, includeMentionableGroups = this.get("includeMentionableGroups") === "true", includeMessageableGroups = @@ -66,13 +65,8 @@ export default Ember.TextField.extend({ function excludedUsernames() { // hack works around some issues with allowAny eventing const usernames = self.get("single") ? [] : selected; - - if (currentUser && self.get("excludeCurrentUser")) { - return usernames.concat([currentUser.get("username")]); - } return usernames; } - $(this.element) .val(this.get("usernames")) .autocomplete({ @@ -84,7 +78,6 @@ export default Ember.TextField.extend({ dataSource(term) { const termRegex = /[^a-zA-Z0-9_\-\.@\+]/; - let results = userSearch({ term: term.replace(termRegex, ""), topicId: self.get("topicId"), diff --git a/assets/javascripts/wizard/components/field-validators.js.es6 b/assets/javascripts/wizard/components/field-validators.js.es6 index a315020d..15cfc181 100644 --- a/assets/javascripts/wizard/components/field-validators.js.es6 +++ b/assets/javascripts/wizard/components/field-validators.js.es6 @@ -1,5 +1,8 @@ import Component from "@ember/component"; + export default Component.extend({ + layoutName: 'wizard/templates/components/field-validators', + actions: { perform() { this.appEvents.trigger("custom-wizard:validate"); diff --git a/assets/javascripts/wizard/components/similar-topics-validator.js.es6 b/assets/javascripts/wizard/components/similar-topics-validator.js.es6 index 98ea9270..e5133d4f 100644 --- a/assets/javascripts/wizard/components/similar-topics-validator.js.es6 +++ b/assets/javascripts/wizard/components/similar-topics-validator.js.es6 @@ -10,6 +10,7 @@ import { dasherize } from "@ember/string"; export default WizardFieldValidator.extend({ classNames: ["similar-topics-validator"], + layoutName: 'wizard/templates/components/similar-topics-validator', similarTopics: null, hasInput: notEmpty("field.value"), hasSimilarTopics: notEmpty("similarTopics"), diff --git a/assets/javascripts/wizard/components/validator.js.es6 b/assets/javascripts/wizard/components/validator.js.es6 index 6227cc64..ab442d97 100644 --- a/assets/javascripts/wizard/components/validator.js.es6 +++ b/assets/javascripts/wizard/components/validator.js.es6 @@ -6,11 +6,12 @@ import { getToken } from "wizard/lib/ajax"; export default Component.extend({ classNames: ["validator"], classNameBindings: ["isValid", "isInvalid"], + layoutName: 'wizard/templates/components/validator', validMessageKey: null, invalidMessageKey: null, isValid: null, isInvalid: equal("isValid", false), - layoutName: "components/validator", // useful for sharing the template with extending components + layoutName: "wizard/templates/components/validator", init() { this._super(...arguments); diff --git a/assets/javascripts/wizard/components/wizard-composer-editor.js.es6 b/assets/javascripts/wizard/components/wizard-composer-editor.js.es6 index 5e1d1aac..0bd003f5 100644 --- a/assets/javascripts/wizard/components/wizard-composer-editor.js.es6 +++ b/assets/javascripts/wizard/components/wizard-composer-editor.js.es6 @@ -13,6 +13,7 @@ import { uploadIcon } from "discourse/lib/uploads"; import { dasherize } from "@ember/string"; export default ComposerEditor.extend({ + layoutName: 'wizard/templates/components/wizard-composer-editor', classNameBindings: ["fieldClass"], allowUpload: true, showLink: false, diff --git a/assets/javascripts/wizard/components/wizard-composer-hyperlink.js.es6 b/assets/javascripts/wizard/components/wizard-composer-hyperlink.js.es6 index a56b7aff..c700d3ce 100644 --- a/assets/javascripts/wizard/components/wizard-composer-hyperlink.js.es6 +++ b/assets/javascripts/wizard/components/wizard-composer-hyperlink.js.es6 @@ -2,6 +2,7 @@ import Component from "@ember/component"; export default Component.extend({ classNames: ["wizard-composer-hyperlink"], + layoutName: 'wizard/templates/components/wizard-composer-hyperlink', actions: { addLink() { diff --git a/assets/javascripts/wizard/components/wizard-date-input.js.es6 b/assets/javascripts/wizard/components/wizard-date-input.js.es6 index 9c8e4bff..375b7195 100644 --- a/assets/javascripts/wizard/components/wizard-date-input.js.es6 +++ b/assets/javascripts/wizard/components/wizard-date-input.js.es6 @@ -3,6 +3,7 @@ import discourseComputed from "discourse-common/utils/decorators"; export default DateInput.extend({ useNativePicker: false, + layoutName: 'wizard/templates/components/wizard-date-input', @discourseComputed() placeholder() { diff --git a/assets/javascripts/wizard/components/wizard-date-time-input.js.es6 b/assets/javascripts/wizard/components/wizard-date-time-input.js.es6 index 44b675b0..0fe1e68a 100644 --- a/assets/javascripts/wizard/components/wizard-date-time-input.js.es6 +++ b/assets/javascripts/wizard/components/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({ + layoutName: 'wizard/templates/components/wizard-date-time-input', + @discourseComputed("timeFirst", "tabindex") timeTabindex(timeFirst, tabindex) { return timeFirst ? tabindex : tabindex + 1; diff --git a/assets/javascripts/wizard/components/wizard-field-category.js.es6 b/assets/javascripts/wizard/components/wizard-field-category.js.es6 index a7452214..dc20538e 100644 --- a/assets/javascripts/wizard/components/wizard-field-category.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-category.js.es6 @@ -2,6 +2,8 @@ import { observes } from "discourse-common/utils/decorators"; import Category from "discourse/models/category"; export default Ember.Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-category', + didInsertElement() { const property = this.field.property || "id"; const value = this.field.value; diff --git a/assets/javascripts/wizard/components/wizard-field-checkbox.js.es6 b/assets/javascripts/wizard/components/wizard-field-checkbox.js.es6 new file mode 100644 index 00000000..f9653cd2 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-checkbox.js.es6 @@ -0,0 +1,5 @@ +import Component from "@ember/component"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-checkbox' +}); diff --git a/assets/javascripts/wizard/components/wizard-field-composer-preview.js.es6 b/assets/javascripts/wizard/components/wizard-field-composer-preview.js.es6 index b49233f2..0aee0d13 100644 --- a/assets/javascripts/wizard/components/wizard-field-composer-preview.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-composer-preview.js.es6 @@ -7,6 +7,8 @@ import { ajax } from "discourse/lib/ajax"; import { on } from "discourse-common/utils/decorators"; export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-composer-preview', + @on("init") updatePreview() { if (this.isDestroyed) { diff --git a/assets/javascripts/wizard/components/wizard-field-composer.js.es6 b/assets/javascripts/wizard/components/wizard-field-composer.js.es6 index 8b9ecb82..0ef5fe20 100644 --- a/assets/javascripts/wizard/components/wizard-field-composer.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-composer.js.es6 @@ -5,6 +5,8 @@ import { import EmberObject from "@ember/object"; export default Ember.Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-composer', + showPreview: false, classNameBindings: [ ":wizard-field-composer", diff --git a/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 b/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 index 2d918636..a916f18e 100644 --- a/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 @@ -2,6 +2,8 @@ import Component from "@ember/component"; import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-date-time', + @observes("dateTime") setValue() { this.set("field.value", this.dateTime.format(this.field.format)); diff --git a/assets/javascripts/wizard/components/wizard-field-date.js.es6 b/assets/javascripts/wizard/components/wizard-field-date.js.es6 index d5d0a830..a06d582a 100644 --- a/assets/javascripts/wizard/components/wizard-field-date.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-date.js.es6 @@ -2,6 +2,8 @@ import Component from "@ember/component"; import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-date', + @observes("date") setValue() { this.set("field.value", this.date.format(this.field.format)); diff --git a/assets/javascripts/wizard/components/wizard-field-dropdown.js.es6 b/assets/javascripts/wizard/components/wizard-field-dropdown.js.es6 new file mode 100644 index 00000000..4b8b7e63 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-dropdown.js.es6 @@ -0,0 +1,15 @@ +import Component from "@ember/component"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-dropdown', + + keyPress(e) { + e.stopPropagation(); + }, + + actions: { + onChangeValue(value) { + this.set("field.value", value); + }, + }, +}); diff --git a/assets/javascripts/wizard/components/wizard-field-group.js.es6 b/assets/javascripts/wizard/components/wizard-field-group.js.es6 new file mode 100644 index 00000000..93538071 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-group.js.es6 @@ -0,0 +1,5 @@ +import Component from "@ember/component"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-group' +}); diff --git a/assets/javascripts/wizard/components/wizard-field-number.js.es6 b/assets/javascripts/wizard/components/wizard-field-number.js.es6 new file mode 100644 index 00000000..e7c4d77f --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-number.js.es6 @@ -0,0 +1,5 @@ +import Component from "@ember/component"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-number' +}); diff --git a/assets/javascripts/wizard/components/wizard-field-tag.js.es6 b/assets/javascripts/wizard/components/wizard-field-tag.js.es6 new file mode 100644 index 00000000..45343522 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-tag.js.es6 @@ -0,0 +1,5 @@ +import Component from "@ember/component"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-tag' +}); diff --git a/assets/javascripts/wizard/components/wizard-field-text.js.es6 b/assets/javascripts/wizard/components/wizard-field-text.js.es6 new file mode 100644 index 00000000..f9d5b056 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-text.js.es6 @@ -0,0 +1,9 @@ +import Component from "@ember/component"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-text', + + keyPress(e) { + e.stopPropagation(); + }, +}); diff --git a/assets/javascripts/wizard/components/wizard-field-textarea.js.es6 b/assets/javascripts/wizard/components/wizard-field-textarea.js.es6 new file mode 100644 index 00000000..54865d3c --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-textarea.js.es6 @@ -0,0 +1,9 @@ +import Component from "@ember/component"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-textarea', + + keyPress(e) { + e.stopPropagation(); + }, +}); diff --git a/assets/javascripts/wizard/components/wizard-field-time.js.es6 b/assets/javascripts/wizard/components/wizard-field-time.js.es6 index 82f9c68b..bf954ec4 100644 --- a/assets/javascripts/wizard/components/wizard-field-time.js.es6 +++ b/assets/javascripts/wizard/components/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({ + layoutName: 'wizard/templates/components/wizard-field-time', + @observes("time") setValue() { this.set("field.value", this.time.format(this.field.format)); diff --git a/assets/javascripts/wizard/components/wizard-field-upload.js.es6 b/assets/javascripts/wizard/components/wizard-field-upload.js.es6 index 876cdf0e..edadb4f0 100644 --- a/assets/javascripts/wizard/components/wizard-field-upload.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-upload.js.es6 @@ -3,12 +3,16 @@ import Component from "@ember/component"; import { computed } from "@ember/object"; export default Component.extend(UppyUploadMixin, { + layoutName: 'wizard/templates/components/wizard-field-upload', classNames: ["wizard-field-upload"], classNameBindings: ["isImage"], uploading: false, type: computed(function () { return `wizard_${this.field.id}`; }), + id: computed(function () { + return `wizard_field_upload_${this.field.id}`; + }), isImage: computed("field.value.extension", function () { return ( this.field.value && diff --git a/assets/javascripts/wizard/components/wizard-field-url.js.es6 b/assets/javascripts/wizard/components/wizard-field-url.js.es6 new file mode 100644 index 00000000..411b5fe9 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-url.js.es6 @@ -0,0 +1,5 @@ +import Component from "@ember/component"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-url' +}); diff --git a/assets/javascripts/wizard/components/wizard-field-user-selector.js.es6 b/assets/javascripts/wizard/components/wizard-field-user-selector.js.es6 new file mode 100644 index 00000000..c2a32f44 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field-user-selector.js.es6 @@ -0,0 +1,5 @@ +import Component from "@ember/component"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field-user-selector' +}); diff --git a/assets/javascripts/wizard/components/wizard-field.js.es6 b/assets/javascripts/wizard/components/wizard-field.js.es6 new file mode 100644 index 00000000..372ee182 --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-field.js.es6 @@ -0,0 +1,34 @@ +import Component from "@ember/component"; +import { dasherize } from "@ember/string"; +import discourseComputed from "discourse-common/utils/decorators"; +import { cook } from "discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite"; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-field', + classNameBindings: [":wizard-field", "typeClasses", "field.invalid", "field.id"], + + @discourseComputed("field.type", "field.id") + typeClasses: (type, id) => + `${dasherize(type)}-field ${dasherize(type)}-${dasherize(id)}`, + + @discourseComputed("field.id") + fieldClass: (id) => `field-${dasherize(id)} wizard-focusable`, + + @discourseComputed("field.type", "field.id") + inputComponentName(type, id) { + if (["text_only"].includes(type)) { + return false; + } + return dasherize(type === "component" ? id : `wizard-field-${type}`); + }, + + @discourseComputed("field.translatedDescription") + cookedDescription(description) { + return cook(description); + }, + + @discourseComputed("field.type") + textType(fieldType) { + return ["text", "textarea"].includes(fieldType); + }, +}); diff --git a/assets/javascripts/wizard/components/wizard-group-selector.js.es6 b/assets/javascripts/wizard/components/wizard-group-selector.js.es6 index cb613107..b7523f9a 100644 --- a/assets/javascripts/wizard/components/wizard-group-selector.js.es6 +++ b/assets/javascripts/wizard/components/wizard-group-selector.js.es6 @@ -3,6 +3,7 @@ import { computed } from "@ember/object"; import { makeArray } from "discourse-common/lib/helpers"; export default ComboBox.extend({ + layoutName: 'wizard/templates/components/wizard-group-selector', content: computed("groups.[]", "field.content.[]", function () { const whitelist = makeArray(this.field.content); return this.groups diff --git a/assets/javascripts/wizard/components/wizard-no-access.js.es6 b/assets/javascripts/wizard/components/wizard-no-access.js.es6 index 57fe9111..78a23aa8 100644 --- a/assets/javascripts/wizard/components/wizard-no-access.js.es6 +++ b/assets/javascripts/wizard/components/wizard-no-access.js.es6 @@ -1,10 +1,21 @@ -import CustomWizard from "../models/custom"; +import CustomWizard from "../models/wizard"; +import discourseComputed from "discourse-common/utils/decorators"; +import Component from "@ember/component"; +import { dasherize } from "@ember/string"; -export default Ember.Component.extend({ - siteName: function () { - /*eslint no-undef:0*/ - return Wizard.SiteSettings.title; - }.property(), +export default Component.extend({ + classNameBindings: [':wizard-no-access', 'reasonClass'], + layoutName: 'wizard/templates/components/wizard-no-access', + + @discourseComputed('reason') + reasonClass(reason) { + return dasherize(reason); + }, + + @discourseComputed + siteName() { + return (this.siteSettings.title || ''); + }, actions: { skip() { diff --git a/assets/javascripts/wizard/components/wizard-similar-topics.js.es6 b/assets/javascripts/wizard/components/wizard-similar-topics.js.es6 index 687cfa86..c52bfeae 100644 --- a/assets/javascripts/wizard/components/wizard-similar-topics.js.es6 +++ b/assets/javascripts/wizard/components/wizard-similar-topics.js.es6 @@ -4,6 +4,7 @@ import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ classNames: ["wizard-similar-topics"], + layoutName: 'wizard/templates/components/wizard-similar-topics', showTopics: true, didInsertElement() { diff --git a/assets/javascripts/wizard/components/wizard-step-form.js.es6 b/assets/javascripts/wizard/components/wizard-step-form.js.es6 new file mode 100644 index 00000000..73406b4f --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-step-form.js.es6 @@ -0,0 +1,9 @@ +import Component from "@ember/component"; +import discourseComputed from "discourse-common/utils/decorators"; + +export default Component.extend({ + classNameBindings: [":wizard-step-form", "customStepClass"], + + @discourseComputed("step.id") + customStepClass: (stepId) => `wizard-step-${stepId}`, +}); diff --git a/assets/javascripts/wizard/components/wizard-step.js.es6 b/assets/javascripts/wizard/components/wizard-step.js.es6 new file mode 100644 index 00000000..4518afee --- /dev/null +++ b/assets/javascripts/wizard/components/wizard-step.js.es6 @@ -0,0 +1,247 @@ +import discourseComputed, { observes } from "discourse-common/utils/decorators"; +import Component from "@ember/component"; +import I18n from "I18n"; +import getUrl from "discourse-common/lib/get-url"; +import { htmlSafe } from "@ember/template"; +import { schedule } from "@ember/runloop"; +import { cook } from "discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite"; +import { updateCachedWizard } from "discourse/plugins/discourse-custom-wizard/wizard/models/wizard"; +import { alias, not } from "@ember/object/computed"; +import CustomWizard from "../models/wizard"; + +const alreadyWarned = {}; + +export default Component.extend({ + layoutName: 'wizard/templates/components/wizard-step', + classNameBindings: [":wizard-step", "step.id"], + saving: null, + + init() { + this._super(...arguments); + this.set("stylingDropdown", {}); + }, + + didInsertElement() { + this._super(...arguments); + this.autoFocus(); + }, + + @discourseComputed("step.index", "wizard.required") + showQuitButton: (index, required) => (index === 0 && !required), + + showNextButton: not("step.final"), + showDoneButton: alias("step.final"), + + @discourseComputed("step.translatedTitle") + cookedTitle(title) { + return cook(title); + }, + + @discourseComputed("step.translatedDescription") + cookedDescription(description) { + return cook(description); + }, + + @discourseComputed( + "step.index", + "step.displayIndex", + "wizard.totalSteps", + "wizard.completed" + ) + showFinishButton: (index, displayIndex, total, completed) => { + return index !== 0 && displayIndex !== total && completed; + }, + + @discourseComputed("step.index") + showBackButton: (index) => index > 0, + + @discourseComputed("step.banner") + bannerImage(src) { + if (!src) { + return; + } + return getUrl(src); + }, + + @discourseComputed("step.id") + bannerAndDescriptionClass(id) { + return `wizard-banner-and-description wizard-banner-and-description-${id}`; + }, + + @discourseComputed("step.fields.[]") + primaryButtonIndex(fields) { + return fields.length + 1; + }, + + @discourseComputed("step.fields.[]") + secondaryButtonIndex(fields) { + return fields.length + 2; + }, + + @observes("step.id") + _stepChanged() { + this.set("saving", false); + this.autoFocus(); + }, + + @observes("step.message") + _handleMessage: function () { + const message = this.get("step.message"); + this.sendAction("showMessage", message); + }, + + keyPress(event) { + if (event.key === "Enter") { + if (this.showDoneButton) { + this.send("quit"); + } else { + this.send("nextStep"); + } + } + }, + + @discourseComputed("step.index", "wizard.totalSteps") + barStyle(displayIndex, totalSteps) { + let ratio = parseFloat(displayIndex) / parseFloat(totalSteps - 1); + if (ratio < 0) { + ratio = 0; + } + if (ratio > 1) { + ratio = 1; + } + + return htmlSafe(`width: ${ratio * 200}px`); + }, + + @discourseComputed("step.fields") + includeSidebar(fields) { + return !!fields.findBy("show_in_sidebar"); + }, + + autoFocus() { + schedule("afterRender", () => { + const $invalid = $( + ".wizard-field.invalid:nth-of-type(1) .wizard-focusable" + ); + + if ($invalid.length) { + return $invalid.focus(); + } + + $(".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) { + $([document.documentElement, document.body]).animate( + { + scrollTop: $element.offset().top - 200, + }, + 400, + function () { + $element.wiggle(2, 100); + } + ); + } + }); + }, + + advance() { + this.set("saving", true); + this.get("step") + .save() + .then((response) => { + updateCachedWizard(CustomWizard.build(response["wizard"])); + + if (response["final"]) { + CustomWizard.finished(response); + } else { + this.sendAction("goNext", response); + } + }) + .catch(() => this.animateInvalidFields()) + .finally(() => this.set("saving", false)); + }, + + keyPress() {}, + + actions: { + quit() { + this.get("wizard").skip(); + }, + + done() { + this.send("nextStep"); + }, + + showMessage(message) { + this.sendAction("showMessage", message); + }, + + stylingDropdownChanged(id, value) { + this.set("stylingDropdown", { id, value }); + }, + + exitEarly() { + const step = this.step; + step.validate(); + + if (step.get("valid")) { + this.set("saving", true); + + step + .save() + .then(() => this.send("quit")) + .finally(() => this.set("saving", false)); + } else { + this.autoFocus(); + } + }, + + backStep() { + if (this.saving) { + return; + } + + this.goBack(); + }, + + nextStep() { + if (this.saving) { + return; + } + + const step = this.step; + const result = step.validate(); + + if (result.warnings.length) { + const unwarned = result.warnings.filter((w) => !alreadyWarned[w]); + if (unwarned.length) { + unwarned.forEach((w) => (alreadyWarned[w] = true)); + return window.bootbox.confirm( + unwarned.map((w) => I18n.t(`wizard.${w}`)).join("\n"), + I18n.t("no_value"), + I18n.t("yes_value"), + (confirmed) => { + if (confirmed) { + this.advance(); + } + } + ); + } + } + + if (step.get("valid")) { + this.advance(); + } else { + this.autoFocus(); + } + }, + }, +}); diff --git a/assets/javascripts/wizard/components/wizard-text-field.js.es6 b/assets/javascripts/wizard/components/wizard-text-field.js.es6 index c522eb2c..3d87be09 100644 --- a/assets/javascripts/wizard/components/wizard-text-field.js.es6 +++ b/assets/javascripts/wizard/components/wizard-text-field.js.es6 @@ -1,5 +1,3 @@ -/* eslint no-undef: 0*/ - import computed from "discourse-common/utils/decorators"; import { isLTR, isRTL, siteDir } from "discourse/lib/text-direction"; import WizardI18n from "../lib/wizard-i18n"; @@ -15,7 +13,7 @@ export default Ember.TextField.extend({ @computed dir() { - if (Wizard.SiteSettings.support_mixed_text_direction) { + if (this.siteSettings.support_mixed_text_direction) { let val = this.value; if (val) { return isRTL(val) ? "rtl" : "ltr"; @@ -26,7 +24,7 @@ export default Ember.TextField.extend({ }, keyUp() { - if (Wizard.SiteSettings.support_mixed_text_direction) { + if (this.siteSettings.support_mixed_text_direction) { let val = this.value; if (isRTL(val)) { this.set("dir", "rtl"); diff --git a/assets/javascripts/wizard/components/wizard-time-input.js.es6 b/assets/javascripts/wizard/components/wizard-time-input.js.es6 index 0bca244d..ec121002 100644 --- a/assets/javascripts/wizard/components/wizard-time-input.js.es6 +++ b/assets/javascripts/wizard/components/wizard-time-input.js.es6 @@ -1,3 +1,5 @@ import TimeInput from "discourse/components/time-input"; -export default TimeInput.extend(); +export default TimeInput.extend({ + layoutName: 'wizard/templates/components/wizard-time-input' +}); diff --git a/assets/javascripts/wizard/controllers/custom.js.es6 b/assets/javascripts/wizard/controllers/custom.js.es6 deleted file mode 100644 index 5f168f3a..00000000 --- a/assets/javascripts/wizard/controllers/custom.js.es6 +++ /dev/null @@ -1,3 +0,0 @@ -export default Ember.Controller.extend({ - queryParams: ["reset"], -}); diff --git a/assets/javascripts/wizard/controllers/custom-step.js.es6 b/assets/javascripts/wizard/controllers/step.js.es6 similarity index 76% rename from assets/javascripts/wizard/controllers/custom-step.js.es6 rename to assets/javascripts/wizard/controllers/step.js.es6 index b44c0fca..4b321173 100644 --- a/assets/javascripts/wizard/controllers/custom-step.js.es6 +++ b/assets/javascripts/wizard/controllers/step.js.es6 @@ -1,7 +1,10 @@ -import StepController from "wizard/controllers/step"; +import Controller from "@ember/controller"; import getUrl from "discourse-common/lib/get-url"; -export default StepController.extend({ +export default Controller.extend({ + wizard: null, + step: null, + actions: { goNext(response) { let nextStepId = response["next_step_id"]; @@ -12,12 +15,12 @@ export default StepController.extend({ const wizardId = this.get("wizard.id"); window.location.href = getUrl(`/w/${wizardId}/steps/${nextStepId}`); } else { - this.transitionToRoute("custom.step", nextStepId); + this.transitionToRoute("step", nextStepId); } }, goBack() { - this.transitionToRoute("custom.step", this.get("step.previous")); + this.transitionToRoute("step", this.get("step.previous")); }, showMessage(message) { diff --git a/assets/javascripts/wizard/controllers/wizard-index.js.es6 b/assets/javascripts/wizard/controllers/wizard-index.js.es6 new file mode 100644 index 00000000..2dfdee40 --- /dev/null +++ b/assets/javascripts/wizard/controllers/wizard-index.js.es6 @@ -0,0 +1,24 @@ +import Controller from "@ember/controller"; +import { or } from "@ember/object/computed"; +import discourseComputed from "discourse-common/utils/decorators"; + +const reasons = { + noWizard: "none", + requiresLogin: "requires_login", + notPermitted: "not_permitted", + completed: "completed" +} + +export default Controller.extend({ + noAccess: or('noWizard', 'requiresLogin', 'notPermitted', 'completed'), + + @discourseComputed('noAccessReason') + noAccessI18nKey(reason) { + return reason ? `wizard.${reasons[reason]}` : 'wizard.none'; + }, + + @discourseComputed + noAccessReason() { + return Object.keys(reasons).find(reason => this.get(reason)); + } +}); diff --git a/assets/javascripts/wizard/controllers/wizard.js.es6 b/assets/javascripts/wizard/controllers/wizard.js.es6 new file mode 100644 index 00000000..35f964e2 --- /dev/null +++ b/assets/javascripts/wizard/controllers/wizard.js.es6 @@ -0,0 +1,5 @@ +import Controller from "@ember/controller"; + +export default Controller.extend({ + queryParams: ["reset"], +}); diff --git a/assets/javascripts/wizard/custom-wizard.js.es6 b/assets/javascripts/wizard/custom-wizard.js.es6 deleted file mode 100644 index 8c0a473c..00000000 --- a/assets/javascripts/wizard/custom-wizard.js.es6 +++ /dev/null @@ -1,39 +0,0 @@ -import { buildResolver } from "discourse-common/resolver"; - -export default Ember.Application.extend({ - rootElement: "#custom-wizard-main", - Resolver: buildResolver("wizard"), - - customEvents: { - paste: "paste", - }, - - start() { - Object.keys(requirejs._eak_seen).forEach((key) => { - if (/\/pre\-initializers\//.test(key)) { - const module = requirejs(key, null, null, true); - if (!module) { - throw new Error(key + " must export an initializer."); - } - - const init = module.default; - const oldInitialize = init.initialize; - init.initialize = () => { - oldInitialize.call(this, this.__container__, this); - }; - - this.initializer(init); - } - }); - - Object.keys(requirejs._eak_seen).forEach((key) => { - if (/\/initializers\//.test(key)) { - const module = requirejs(key, null, null, true); - if (!module) { - throw new Error(key + " must export an initializer."); - } - this.initializer(module.default); - } - }); - }, -}); diff --git a/assets/javascripts/wizard/initializers/custom-wizard-step.js.es6 b/assets/javascripts/wizard/initializers/custom-wizard-step.js.es6 deleted file mode 100644 index 6a679796..00000000 --- a/assets/javascripts/wizard/initializers/custom-wizard-step.js.es6 +++ /dev/null @@ -1,219 +0,0 @@ -export default { - name: "custom-wizard-step", - initialize() { - if (window.location.pathname.indexOf("/w/") < 0) { - return; - } - - const CustomWizard = requirejs( - "discourse/plugins/discourse-custom-wizard/wizard/models/custom" - ).default; - const updateCachedWizard = requirejs( - "discourse/plugins/discourse-custom-wizard/wizard/models/custom" - ).updateCachedWizard; - const StepModel = requirejs("wizard/models/step").default; - const StepComponent = requirejs("wizard/components/wizard-step").default; - const ajax = requirejs("wizard/lib/ajax").ajax; - const getUrl = requirejs("discourse-common/lib/get-url").default; - const discourseComputed = requirejs("discourse-common/utils/decorators") - .default; - const cook = requirejs( - "discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite" - ).cook; - const { schedule } = requirejs("@ember/runloop"); - const { alias, not } = requirejs("@ember/object/computed"); - const { translatedText } = requirejs( - "discourse/plugins/discourse-custom-wizard/wizard/lib/wizard-i18n" - ); - - StepModel.reopen({ - @discourseComputed("wizardId", "id") - i18nKey(wizardId, stepId) { - return `${wizardId}.${stepId}`; - }, - - @discourseComputed("i18nKey", "title") - translatedTitle(i18nKey, title) { - return translatedText(`${i18nKey}.title`, title); - }, - - @discourseComputed("i18nKey", "description") - translatedDescription(i18nKey, description) { - return translatedText(`${i18nKey}.description`, description); - }, - - save() { - const wizardId = this.get("wizardId"); - const fields = {}; - - this.get("fields").forEach((f) => { - if (f.type !== "text_only") { - fields[f.id] = f.value; - } - }); - - return ajax({ - url: `/w/${wizardId}/steps/${this.get("id")}`, - type: "PUT", - data: { fields }, - }).catch((response) => { - if ( - response && - response.responseJSON && - response.responseJSON.errors - ) { - let wizardErrors = []; - response.responseJSON.errors.forEach((err) => { - if (err.field === wizardId) { - wizardErrors.push(err.description); - } else if (err.field) { - this.fieldError(err.field, err.description); - } else if (err) { - wizardErrors.push(err); - } - }); - if (wizardErrors.length) { - this.handleWizardError(wizardErrors.join("\n")); - } - this.animateInvalidFields(); - throw response; - } - - if (response && response.responseText) { - const responseText = response.responseText; - const start = responseText.indexOf(">") + 1; - const end = responseText.indexOf("plugins"); - const message = responseText.substring(start, end); - this.handleWizardError(message); - throw message; - } - }); - }, - - handleWizardError(message) { - this.set("message", { - state: "error", - text: message, - }); - Ember.run.later(() => this.set("message", null), 6000); - }, - }); - - StepComponent.reopen({ - classNameBindings: ["step.id"], - - autoFocus() { - schedule("afterRender", () => { - const $invalid = $( - ".wizard-field.invalid:nth-of-type(1) .wizard-focusable" - ); - - if ($invalid.length) { - return $invalid.focus(); - } - - $(".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) { - $([document.documentElement, document.body]).animate( - { - scrollTop: $element.offset().top - 200, - }, - 400, - function () { - $element.wiggle(2, 100); - } - ); - } - }); - }, - - ensureStartsAtTop: function () { - window.scrollTo(0, 0); - }.observes("step.id"), - - showQuitButton: function () { - const index = this.get("step.index"); - const required = this.get("wizard.required"); - return index === 0 && !required; - }.property("step.index", "wizard.required"), - - @discourseComputed("step.translatedTitle") - cookedTitle(title) { - return cook(title); - }, - - @discourseComputed("step.translatedDescription") - cookedDescription(description) { - return cook(description); - }, - - bannerImage: function () { - const src = this.get("step.banner"); - if (!src) { - return; - } - return getUrl(src); - }.property("step.banner"), - - @discourseComputed("step.fields.[]") - primaryButtonIndex(fields) { - return fields.length + 1; - }, - - @discourseComputed("step.fields.[]") - secondaryButtonIndex(fields) { - return fields.length + 2; - }, - - handleMessage: function () { - const message = this.get("step.message"); - this.sendAction("showMessage", message); - }.observes("step.message"), - - showNextButton: not("step.final"), - showDoneButton: alias("step.final"), - - advance() { - this.set("saving", true); - this.get("step") - .save() - .then((response) => { - updateCachedWizard(CustomWizard.build(response["wizard"])); - - if (response["final"]) { - CustomWizard.finished(response); - } else { - this.sendAction("goNext", response); - } - }) - .catch(() => this.animateInvalidFields()) - .finally(() => this.set("saving", false)); - }, - - keyPress() {}, - - actions: { - quit() { - this.get("wizard").skip(); - }, - - done() { - this.send("nextStep"); - }, - - showMessage(message) { - this.sendAction("showMessage", message); - }, - }, - }); - }, -}; diff --git a/assets/javascripts/wizard/initializers/custom-wizard.js.es6 b/assets/javascripts/wizard/initializers/custom-wizard.js.es6 deleted file mode 100644 index f2095827..00000000 --- a/assets/javascripts/wizard/initializers/custom-wizard.js.es6 +++ /dev/null @@ -1,126 +0,0 @@ -export default { - name: "custom-routes", - initialize(app) { - if (window.location.pathname.indexOf("/w/") < 0) { - return; - } - - const EmberObject = requirejs("@ember/object").default; - const Router = requirejs("wizard/router").default; - const ApplicationRoute = requirejs("wizard/routes/application").default; - const getUrl = requirejs("discourse-common/lib/get-url").default; - const Store = requirejs("discourse/services/store").default; - const registerRawHelpers = requirejs( - "discourse-common/lib/raw-handlebars-helpers" - ).registerRawHelpers; - const createHelperContext = requirejs("discourse-common/lib/helpers") - .createHelperContext; - const RawHandlebars = requirejs("discourse-common/lib/raw-handlebars") - .default; - const Handlebars = requirejs("handlebars").default; - const Site = requirejs( - "discourse/plugins/discourse-custom-wizard/wizard/models/site" - ).default; - const RestAdapter = requirejs("discourse/adapters/rest").default; - const Session = requirejs("discourse/models/session").default; - const setDefaultOwner = requirejs("discourse-common/lib/get-owner") - .setDefaultOwner; - const messageBus = requirejs("message-bus-client").default; - const getToken = requirejs("wizard/lib/ajax").getToken; - const setEnvironment = requirejs("discourse-common/config/environment") - .setEnvironment; - const container = app.__container__; - Discourse.Model = EmberObject.extend(); - Discourse.__container__ = container; - setDefaultOwner(container); - registerRawHelpers(RawHandlebars, Handlebars); - - // IE11 Polyfill - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries#Polyfill - if (!Object.entries) { - Object.entries = function (obj) { - let ownProps = Object.keys(obj), - i = ownProps.length, - resArray = new Array(i); // preallocate the Array - while (i--) { - resArray[i] = [ownProps[i], obj[ownProps[i]]]; - } - - return resArray; - }; - } - - Object.keys(Ember.TEMPLATES).forEach((k) => { - if (k.indexOf("select-kit") === 0) { - let template = Ember.TEMPLATES[k]; - define(k, () => template); - } - }); - - const targets = ["controller", "component", "route", "model", "adapter"]; - /*eslint no-undef: 0*/ - const siteSettings = Wizard.SiteSettings; - app.register("site-settings:main", siteSettings, { instantiate: false }); - createHelperContext({ siteSettings }); - targets.forEach((t) => app.inject(t, "siteSettings", "site-settings:main")); - - app.register("message-bus:main", messageBus, { instantiate: false }); - targets.forEach((t) => app.inject(t, "messageBus", "message-bus:main")); - - app.register("service:store", Store); - targets.forEach((t) => app.inject(t, "store", "service:store")); - targets.forEach((t) => app.inject(t, "appEvents", "service:app-events")); - - app.register("adapter:rest", RestAdapter); - - const site = Site.current(); - app.register("site:main", site, { instantiate: false }); - targets.forEach((t) => app.inject(t, "site", "site:main")); - - site.set("can_create_tag", false); - app.register("session:main", Session.current(), { instantiate: false }); - targets.forEach((t) => app.inject(t, "session", "session:main")); - - createHelperContext({ - siteSettings: container.lookup("site-settings:main"), - currentUser: container.lookup("current-user:main"), - site: container.lookup("site:main"), - session: container.lookup("session:main"), - capabilities: container.lookup("capabilities:main"), - }); - - const session = container.lookup("session:main"); - const setupData = document.getElementById("data-discourse-setup").dataset; - session.set("highlightJsPath", setupData.highlightJsPath); - setEnvironment(setupData.environment); - - Router.reopen({ - rootURL: getUrl("/w/"), - }); - - Router.map(function () { - this.route("custom", { path: "/:wizard_id" }, function () { - this.route("steps"); - this.route("step", { path: "/steps/:step_id" }); - }); - }); - - ApplicationRoute.reopen({ - redirect() { - this.transitionTo("custom"); - }, - model() {}, - }); - - // Add a CSRF token to all AJAX requests - let token = getToken(); - session.set("csrfToken", token); - let callbacks = $.Callbacks(); - $.ajaxPrefilter(callbacks.fire); - - callbacks.add(function (options, originalOptions, xhr) { - if (!options.crossDomain) { - xhr.setRequestHeader("X-CSRF-Token", session.get("csrfToken")); - } - }); - }, -}; diff --git a/assets/javascripts/wizard/lib/initialize/create-contexts.js.es6 b/assets/javascripts/wizard/lib/initialize/create-contexts.js.es6 new file mode 100644 index 00000000..022ac48e --- /dev/null +++ b/assets/javascripts/wizard/lib/initialize/create-contexts.js.es6 @@ -0,0 +1,12 @@ +export default { + run(app, container) { + const { createHelperContext } = requirejs("discourse-common/lib/helpers"); + + createHelperContext({ + siteSettings: container.lookup('site-settings:main'), + site: container.lookup("site:main"), + session: container.lookup("session:main"), + capabilities: container.lookup("capabilities:main"), + }); + } +} diff --git a/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 b/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 new file mode 100644 index 00000000..d31efb4d --- /dev/null +++ b/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 @@ -0,0 +1,49 @@ +export default { + run(app, container) { + const Store = requirejs("discourse/services/store").default; + const Site = requirejs( + "discourse/plugins/discourse-custom-wizard/wizard/models/site" + ).default; + const Session = requirejs("discourse/models/session").default; + const RestAdapter = requirejs("discourse/adapters/rest").default; + const messageBus = requirejs("message-bus-client").default; + const sniffCapabilites = requirejs("discourse/pre-initializers/sniff-capabilities").default; + const site = Site.current(); + const session = Session.current(); + + const registrations = [ + ["site-settings:main", app.SiteSettings, false], + ["message-bus:main", messageBus, false], + ["site:main", site, false], + ["session:main", session, false], + ["service:store", Store, true], + ["adapter:rest", RestAdapter, true] + ]; + + registrations.forEach(registration => { + if (!app.hasRegistration(registration[0])) { + app.register(registration[0], registration[1], { instantiate: registration[2] }); + } + }); + + const targets = ["controller", "component", "route", "model", "adapter", "mixin"]; + const injections = [ + ["siteSettings", "site-settings:main"], + ["messageBus", "message-bus:main"], + ["site", "site:main"], + ["session", "session:main"], + ["store", "service:store"], + ["appEvents", "service:app-events"] + ]; + + injections.forEach(injection => { + targets.forEach((t) => app.inject(t, injection[0], injection[1])); + }); + + if (!app.hasRegistration("capabilities:main")) { + sniffCapabilites.initialize(null, app); + } + + site.set("can_create_tag", false); + } +} diff --git a/assets/javascripts/wizard/initializers/custom-wizard-field.js.es6 b/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 similarity index 52% rename from assets/javascripts/wizard/initializers/custom-wizard-field.js.es6 rename to assets/javascripts/wizard/lib/initialize/patch-components.js.es6 index 6f2a80b7..65086e53 100644 --- a/assets/javascripts/wizard/initializers/custom-wizard-field.js.es6 +++ b/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 @@ -1,117 +1,25 @@ -import { dasherize } from "@ember/string"; -import discourseComputed from "discourse-common/utils/decorators"; - export default { - name: "custom-wizard-field", - initialize() { - if (window.location.pathname.indexOf("/w/") < 0) { - return; + run(app, container) { + const getToken = requirejs("wizard/lib/ajax").getToken; + const isTesting = requirejs("discourse-common/config/environment").isTesting; + + if (!isTesting) { + // Add a CSRF token to all AJAX requests + let token = getToken(); + session.set("csrfToken", token); + let callbacks = $.Callbacks(); + $.ajaxPrefilter(callbacks.fire); + + callbacks.add(function (options, originalOptions, xhr) { + if (!options.crossDomain) { + xhr.setRequestHeader("X-CSRF-Token", session.get("csrfToken")); + } + }); } - const FieldComponent = requirejs("wizard/components/wizard-field").default; - const FieldModel = requirejs("wizard/models/wizard-field").default; - const { cook } = requirejs( - "discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite" - ); const DEditor = requirejs("discourse/components/d-editor").default; const { clipboardHelpers } = requirejs("discourse/lib/utilities"); const toMarkdown = requirejs("discourse/lib/to-markdown").default; - const { translatedText } = requirejs( - "discourse/plugins/discourse-custom-wizard/wizard/lib/wizard-i18n" - ); - - FieldComponent.reopen({ - classNameBindings: ["field.id"], - - @discourseComputed("field.translatedDescription") - cookedDescription(description) { - return cook(description); - }, - - @discourseComputed("field.type") - textType(fieldType) { - return ["text", "textarea"].includes(fieldType); - }, - - inputComponentName: function () { - const type = this.get("field.type"); - const id = this.get("field.id"); - if (["text_only"].includes(type)) { - return false; - } - return dasherize(type === "component" ? id : `wizard-field-${type}`); - }.property("field.type", "field.id"), - }); - - const StandardFieldValidation = [ - "text", - "number", - "textarea", - "dropdown", - "tag", - "image", - "user_selector", - "text_only", - "composer", - "category", - "group", - "date", - "time", - "date_time", - ]; - - FieldModel.reopen({ - @discourseComputed("wizardId", "stepId", "id") - i18nKey(wizardId, stepId, id) { - return `${wizardId}.${stepId}.${id}`; - }, - - @discourseComputed("i18nKey", "label") - translatedLabel(i18nKey, label) { - return translatedText(`${i18nKey}.label`, label); - }, - - @discourseComputed("i18nKey", "placeholder") - translatedPlaceholder(i18nKey, placeholder) { - return translatedText(`${i18nKey}.placeholder`, placeholder); - }, - - @discourseComputed("i18nKey", "description") - translatedDescription(i18nKey, description) { - return translatedText(`${i18nKey}.description`, description); - }, - - check() { - if (this.customCheck) { - return this.customCheck(); - } - - let valid = this.valid; - - if (!this.required) { - this.setValid(true); - return true; - } - - const val = this.get("value"); - const type = this.get("type"); - - if (type === "checkbox") { - valid = val; - } else if (type === "upload") { - valid = val && val.id > 0; - } else if (StandardFieldValidation.indexOf(type) > -1) { - valid = val && val.toString().length > 0; - } else if (type === "url") { - valid = true; - } - - this.setValid(valid); - - return valid; - }, - }); - const isInside = (text, regex) => { const matches = text.match(regex); return matches && matches.length % 2; @@ -218,5 +126,19 @@ export default { } }, }); - }, + + // IE11 Polyfill - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries#Polyfill + if (!Object.entries) { + Object.entries = function (obj) { + let ownProps = Object.keys(obj), + i = ownProps.length, + resArray = new Array(i); // preallocate the Array + while (i--) { + resArray[i] = [ownProps[i], obj[ownProps[i]]]; + } + + return resArray; + }; + } + } }; diff --git a/assets/javascripts/wizard/lib/initialize/register-files.js.es6 b/assets/javascripts/wizard/lib/initialize/register-files.js.es6 new file mode 100644 index 00000000..8d4b850e --- /dev/null +++ b/assets/javascripts/wizard/lib/initialize/register-files.js.es6 @@ -0,0 +1,26 @@ +export default { + run(app, container) { + const RawHandlebars = requirejs("discourse-common/lib/raw-handlebars").default; + const Handlebars = requirejs("handlebars").default; + const registerRawHelpers = requirejs("discourse-common/lib/raw-handlebars-helpers").registerRawHelpers; + const { registerHelpers } = requirejs("discourse-common/lib/helpers"); + const jqueryPlugins = requirejs("discourse/initializers/jquery-plugins").default; + + Object.keys(Ember.TEMPLATES).forEach((k) => { + if (k.indexOf("select-kit") === 0) { + let template = Ember.TEMPLATES[k]; + define(k, () => template); + } + }); + + Object.keys(requirejs.entries).forEach((entry) => { + if (/\/helpers\//.test(entry)) { + requirejs(entry, null, null, true); + } + }); + + registerRawHelpers(RawHandlebars, Handlebars); + registerHelpers(app); + jqueryPlugins.initialize(container, app); + } +} diff --git a/assets/javascripts/wizard/lib/initialize/wizard.js.es6 b/assets/javascripts/wizard/lib/initialize/wizard.js.es6 new file mode 100644 index 00000000..134257a1 --- /dev/null +++ b/assets/javascripts/wizard/lib/initialize/wizard.js.es6 @@ -0,0 +1,49 @@ +export default { + name: "custom-wizard", + initialize(app) { + const isTesting = requirejs("discourse-common/config/environment").isTesting; + const isWizard = window.location.pathname.indexOf("/w/") > -1; + + if (!isWizard && !isTesting()) { + return; + } + + const container = app.__container__; + const setDefaultOwner = requirejs("discourse-common/lib/get-owner").setDefaultOwner; + setDefaultOwner(container); + + if (!isTesting()) { + const PreloadStore = requirejs("discourse/lib/preload-store").default; + + let preloaded; + const preloadedDataElement = document.getElementById("data-preloaded-wizard"); + if (preloadedDataElement) { + preloaded = JSON.parse(preloadedDataElement.dataset.preloadedWizard); + } + + Object.keys(preloaded).forEach(function (key) { + PreloadStore.store(key, JSON.parse(preloaded[key])); + }); + + app.SiteSettings = PreloadStore.get("siteSettings"); + } + + const setEnvironment = requirejs("discourse-common/config/environment").setEnvironment; + const setupData = document.getElementById("data-discourse-setup").dataset; + setEnvironment(setupData.environment); + + const Session = requirejs("discourse/models/session").default; + const session = Session.current(); + session.set("highlightJsPath", setupData.highlightJsPath); + + [ + 'register-files', + 'inject-objects', + 'create-contexts', + 'patch-components' + ].forEach(fileName => { + const initializer = requirejs(`discourse/plugins/discourse-custom-wizard/wizard/lib/initialize/${fileName}`).default; + initializer.run(app, container); + }); + } +}; diff --git a/assets/javascripts/wizard/lib/utilities-lite.js.es6 b/assets/javascripts/wizard/lib/utilities-lite.js.es6 deleted file mode 100644 index 19517b2b..00000000 --- a/assets/javascripts/wizard/lib/utilities-lite.js.es6 +++ /dev/null @@ -1,71 +0,0 @@ -// lite version of discourse/lib/utilities - -export function determinePostReplaceSelection({ - selection, - needle, - replacement, -}) { - const diff = - replacement.end - replacement.start - (needle.end - needle.start); - - if (selection.end <= needle.start) { - // Selection ends (and starts) before needle. - return { start: selection.start, end: selection.end }; - } else if (selection.start <= needle.start) { - // Selection starts before needle... - if (selection.end < needle.end) { - // ... and ends inside needle. - return { start: selection.start, end: needle.start }; - } else { - // ... and spans needle completely. - return { start: selection.start, end: selection.end + diff }; - } - } else if (selection.start < needle.end) { - // Selection starts inside needle... - if (selection.end <= needle.end) { - // ... and ends inside needle. - return { start: replacement.end, end: replacement.end }; - } else { - // ... and spans end of needle. - return { start: replacement.end, end: selection.end + diff }; - } - } else { - // Selection starts (and ends) behind needle. - return { start: selection.start + diff, end: selection.end + diff }; - } -} - -const toArray = (items) => { - items = items || []; - - if (!Array.isArray(items)) { - return Array.from(items); - } - - return items; -}; - -export function clipboardData(e, canUpload) { - const clipboard = - e.clipboardData || - e.originalEvent.clipboardData || - e.delegatedEvent.originalEvent.clipboardData; - - const types = toArray(clipboard.types); - let files = toArray(clipboard.files); - - if (types.includes("Files") && files.length === 0) { - // for IE - files = toArray(clipboard.items).filter((i) => i.kind === "file"); - } - - canUpload = files && canUpload && !types.includes("text/plain"); - const canUploadImage = - canUpload && files.filter((f) => f.type.match("^image/"))[0]; - const canPasteHtml = - Discourse.SiteSettings.enable_rich_text_paste && - types.includes("text/html") && - !canUploadImage; - - return { clipboard, types, canUpload, canPasteHtml }; -} diff --git a/assets/javascripts/wizard/models/field.js.es6 b/assets/javascripts/wizard/models/field.js.es6 new file mode 100644 index 00000000..5f76074e --- /dev/null +++ b/assets/javascripts/wizard/models/field.js.es6 @@ -0,0 +1,79 @@ +import EmberObject from "@ember/object"; +import ValidState from "wizard/mixins/valid-state"; +import discourseComputed from "discourse-common/utils/decorators"; +import { translatedText } from "discourse/plugins/discourse-custom-wizard/wizard/lib/wizard-i18n"; + +const StandardFieldValidation = [ + "text", + "number", + "textarea", + "dropdown", + "tag", + "image", + "user_selector", + "text_only", + "composer", + "category", + "group", + "date", + "time", + "date_time", +]; + +export default EmberObject.extend(ValidState, { + id: null, + type: null, + value: null, + required: null, + warning: null, + + @discourseComputed("wizardId", "stepId", "id") + i18nKey(wizardId, stepId, id) { + return `${wizardId}.${stepId}.${id}`; + }, + + @discourseComputed("i18nKey", "label") + translatedLabel(i18nKey, label) { + return translatedText(`${i18nKey}.label`, label); + }, + + @discourseComputed("i18nKey", "placeholder") + translatedPlaceholder(i18nKey, placeholder) { + return translatedText(`${i18nKey}.placeholder`, placeholder); + }, + + @discourseComputed("i18nKey", "description") + translatedDescription(i18nKey, description) { + return translatedText(`${i18nKey}.description`, description); + }, + + check() { + if (this.customCheck) { + return this.customCheck(); + } + + let valid = this.valid; + + if (!this.required) { + this.setValid(true); + return true; + } + + const val = this.get("value"); + const type = this.get("type"); + + if (type === "checkbox") { + valid = val; + } else if (type === "upload") { + valid = val && val.id > 0; + } else if (StandardFieldValidation.indexOf(type) > -1) { + valid = val && val.toString().length > 0; + } else if (type === "url") { + valid = true; + } + + this.setValid(valid); + + return valid; + } +}); diff --git a/assets/javascripts/wizard/models/site.js.es6 b/assets/javascripts/wizard/models/site.js.es6 index c15ce98f..96837ff2 100644 --- a/assets/javascripts/wizard/models/site.js.es6 +++ b/assets/javascripts/wizard/models/site.js.es6 @@ -1,10 +1,11 @@ import Site from "discourse/models/site"; +import { getOwner } from "discourse-common/lib/get-owner"; export default Site.reopenClass({ // There is no site data actually loaded by the CW yet. This placeholder is // needed by imported classes createCurrent() { - const store = Discourse.__container__.lookup("service:store"); + const store = getOwner(this).lookup("service:store"); return store.createRecord("site", {}); }, }); diff --git a/assets/javascripts/wizard/models/step.js.es6 b/assets/javascripts/wizard/models/step.js.es6 new file mode 100644 index 00000000..e18657b5 --- /dev/null +++ b/assets/javascripts/wizard/models/step.js.es6 @@ -0,0 +1,114 @@ +import EmberObject from "@ember/object"; +import ValidState from "wizard/mixins/valid-state"; +import { ajax } from "wizard/lib/ajax"; +import discourseComputed from "discourse-common/utils/decorators"; +import { translatedText } from "discourse/plugins/discourse-custom-wizard/wizard/lib/wizard-i18n"; + +export default EmberObject.extend(ValidState, { + id: null, + + @discourseComputed("wizardId", "id") + i18nKey(wizardId, stepId) { + return `${wizardId}.${stepId}`; + }, + + @discourseComputed("i18nKey", "title") + translatedTitle(i18nKey, title) { + return translatedText(`${i18nKey}.title`, title); + }, + + @discourseComputed("i18nKey", "description") + translatedDescription(i18nKey, description) { + return translatedText(`${i18nKey}.description`, description); + }, + + @discourseComputed("index") + displayIndex: (index) => index + 1, + + @discourseComputed("fields.[]") + fieldsById(fields) { + const lookup = {}; + fields.forEach((field) => (lookup[field.get("id")] = field)); + return lookup; + }, + + validate() { + let allValid = true; + const result = { warnings: [] }; + + this.fields.forEach((field) => { + allValid = allValid && field.check(); + const warning = field.get("warning"); + if (warning) { + result.warnings.push(warning); + } + }); + + this.setValid(allValid); + + return result; + }, + + fieldError(id, description) { + const field = this.fields.findBy("id", id); + if (field) { + field.setValid(false, description); + } + }, + + save() { + const wizardId = this.get("wizardId"); + const fields = {}; + + this.get("fields").forEach((f) => { + if (f.type !== "text_only") { + fields[f.id] = f.value; + } + }); + + return ajax({ + url: `/w/${wizardId}/steps/${this.get("id")}`, + type: "PUT", + data: { fields }, + }).catch((response) => { + if ( + response && + response.responseJSON && + response.responseJSON.errors + ) { + let wizardErrors = []; + response.responseJSON.errors.forEach((err) => { + if (err.field === wizardId) { + wizardErrors.push(err.description); + } else if (err.field) { + this.fieldError(err.field, err.description); + } else if (err) { + wizardErrors.push(err); + } + }); + if (wizardErrors.length) { + this.handleWizardError(wizardErrors.join("\n")); + } + this.animateInvalidFields(); + throw response; + } + + if (response && response.responseText) { + const responseText = response.responseText; + const start = responseText.indexOf(">") + 1; + const end = responseText.indexOf("plugins"); + const message = responseText.substring(start, end); + this.handleWizardError(message); + throw message; + } + }); + }, + + handleWizardError(message) { + this.set("message", { + state: "error", + text: message, + }); + Ember.run.later(() => this.set("message", null), 6000); + }, +}); diff --git a/assets/javascripts/wizard/models/custom.js.es6 b/assets/javascripts/wizard/models/wizard.js.es6 similarity index 96% rename from assets/javascripts/wizard/models/custom.js.es6 rename to assets/javascripts/wizard/models/wizard.js.es6 index 4cbd5706..b2e26b25 100644 --- a/assets/javascripts/wizard/models/custom.js.es6 +++ b/assets/javascripts/wizard/models/wizard.js.es6 @@ -1,9 +1,9 @@ import { default as computed } from "discourse-common/utils/decorators"; import getUrl from "discourse-common/lib/get-url"; -import WizardField from "wizard/models/wizard-field"; +import Field from "./field"; import { ajax } from "wizard/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; -import Step from "wizard/models/step"; +import Step from "./step"; import EmberObject from "@ember/object"; import Site from "./site"; @@ -77,7 +77,7 @@ CustomWizard.reopenClass({ stepObj.fields = stepObj.fields.map((f) => { f.wizardId = wizardJson.id; f.stepId = stepObj.id; - return WizardField.create(f); + return Field.create(f); }); return stepObj; diff --git a/assets/javascripts/wizard/router.js.es6 b/assets/javascripts/wizard/router.js.es6 new file mode 100644 index 00000000..5178c91f --- /dev/null +++ b/assets/javascripts/wizard/router.js.es6 @@ -0,0 +1,17 @@ +import EmberRouter from "@ember/routing/router"; +import getUrl from "discourse-common/lib/get-url"; +import { isTesting } from "discourse-common/config/environment"; + +const Router = EmberRouter.extend({ + rootURL: isTesting() ? getUrl("/") : getUrl("/w/"), + location: isTesting() ? "none" : "history", +}); + +Router.map(function () { + this.route("wizard", { path: "/:wizard_id" }, function () { + this.route("steps", { path: "/steps", resetNamespace: true }); + this.route("step", { path: "/steps/:step_id", resetNamespace: true }); + }); +}); + +export default Router; diff --git a/assets/javascripts/wizard/routes/application.js.es6 b/assets/javascripts/wizard/routes/application.js.es6 new file mode 100644 index 00000000..0051f5ce --- /dev/null +++ b/assets/javascripts/wizard/routes/application.js.es6 @@ -0,0 +1,3 @@ +import Route from "@ember/routing/route"; + +export default Route.extend(); diff --git a/assets/javascripts/wizard/routes/custom-steps.js.es6 b/assets/javascripts/wizard/routes/custom-steps.js.es6 deleted file mode 100644 index c58d1251..00000000 --- a/assets/javascripts/wizard/routes/custom-steps.js.es6 +++ /dev/null @@ -1,5 +0,0 @@ -export default Ember.Route.extend({ - redirect() { - this.transitionTo("custom.index"); - }, -}); diff --git a/assets/javascripts/wizard/routes/index.js.es6 b/assets/javascripts/wizard/routes/index.js.es6 new file mode 100644 index 00000000..b24b3631 --- /dev/null +++ b/assets/javascripts/wizard/routes/index.js.es6 @@ -0,0 +1,9 @@ +import Route from "@ember/routing/route"; + +export default Route.extend({ + beforeModel(transition) { + if (transition.intent.params) { + this.transitionTo("wizard"); + } + }, +}); diff --git a/assets/javascripts/wizard/routes/custom-step.js.es6 b/assets/javascripts/wizard/routes/step.js.es6 similarity index 78% rename from assets/javascripts/wizard/routes/custom-step.js.es6 rename to assets/javascripts/wizard/routes/step.js.es6 index 8088727a..2454fc95 100644 --- a/assets/javascripts/wizard/routes/custom-step.js.es6 +++ b/assets/javascripts/wizard/routes/step.js.es6 @@ -1,7 +1,8 @@ import WizardI18n from "../lib/wizard-i18n"; -import { getCachedWizard } from "../models/custom"; +import { getCachedWizard } from "../models/wizard"; +import Route from "@ember/routing/route"; -export default Ember.Route.extend({ +export default Route.extend({ beforeModel() { this.set("wizard", getCachedWizard()); }, @@ -19,11 +20,15 @@ export default Ember.Route.extend({ afterModel(model) { if (model.completed) { - return this.transitionTo("index"); + return this.transitionTo("wizard.index"); } return model.set("wizardId", this.wizard.id); }, + renderTemplate() { + this.render('wizard/templates/step'); + }, + setupController(controller, model) { let props = { step: model, diff --git a/assets/javascripts/wizard/routes/steps.js.es6 b/assets/javascripts/wizard/routes/steps.js.es6 new file mode 100644 index 00000000..6f35d152 --- /dev/null +++ b/assets/javascripts/wizard/routes/steps.js.es6 @@ -0,0 +1,7 @@ +import Route from "@ember/routing/route"; + +export default Route.extend({ + redirect() { + this.transitionTo("wizard.index"); + }, +}); diff --git a/assets/javascripts/wizard/routes/custom-index.js.es6 b/assets/javascripts/wizard/routes/wizard-index.js.es6 similarity index 50% rename from assets/javascripts/wizard/routes/custom-index.js.es6 rename to assets/javascripts/wizard/routes/wizard-index.js.es6 index a8abc152..16b1140a 100644 --- a/assets/javascripts/wizard/routes/custom-index.js.es6 +++ b/assets/javascripts/wizard/routes/wizard-index.js.es6 @@ -1,10 +1,11 @@ -import { getCachedWizard } from "../models/custom"; +import { getCachedWizard } from "../models/wizard"; +import Route from "@ember/routing/route"; -export default Ember.Route.extend({ +export default Route.extend({ beforeModel() { const wizard = getCachedWizard(); - if (wizard && wizard.permitted && !wizard.completed && wizard.start) { - this.replaceWith("custom.step", wizard.start); + if (wizard && wizard.user && wizard.permitted && !wizard.completed && wizard.start) { + this.replaceWith("step", wizard.start); } }, @@ -12,6 +13,10 @@ export default Ember.Route.extend({ return getCachedWizard(); }, + renderTemplate() { + this.render('wizard/templates/wizard-index'); + }, + setupController(controller, model) { if (model && model.id) { const completed = model.get("completed"); @@ -19,17 +24,20 @@ export default Ember.Route.extend({ const wizardId = model.get("id"); const user = model.get("user"); const name = model.get("name"); + const requiresLogin = !user; + const notPermitted = !permitted; - controller.setProperties({ - requiresLogin: !user, + const props = { + requiresLogin, user, name, completed, - notPermitted: !permitted, + notPermitted, wizardId, - }); + }; + controller.setProperties(props); } else { controller.set("noWizard", true); } - }, + } }); diff --git a/assets/javascripts/wizard/routes/custom.js.es6 b/assets/javascripts/wizard/routes/wizard.js.es6 similarity index 59% rename from assets/javascripts/wizard/routes/custom.js.es6 rename to assets/javascripts/wizard/routes/wizard.js.es6 index a312db3a..2910ee6d 100644 --- a/assets/javascripts/wizard/routes/custom.js.es6 +++ b/assets/javascripts/wizard/routes/wizard.js.es6 @@ -1,37 +1,26 @@ -/* eslint no-undef: 0*/ - -import { findCustomWizard, updateCachedWizard } from "../models/custom"; +import { findCustomWizard, updateCachedWizard } from "../models/wizard"; import { ajax } from "wizard/lib/ajax"; import WizardI18n from "../lib/wizard-i18n"; +import Route from "@ember/routing/route"; +import { scheduleOnce } from "@ember/runloop"; +import { getOwner } from "discourse-common/lib/get-owner"; -export default Ember.Route.extend({ +export default Route.extend({ beforeModel(transition) { - this.set("queryParams", transition.intent.queryParams); + if (transition.intent.queryParams) { + this.set("queryParams", transition.intent.queryParams); + } }, model(params) { return findCustomWizard(params.wizard_id, this.get("queryParams")); }, - renderTemplate() { - this.render("custom"); - const wizardModel = this.modelFor("custom"); - const stepModel = this.modelFor("custom.step"); - - if ( - wizardModel.resume_on_revisit && - wizardModel.submission_last_updated_at && - stepModel.index > 0 - ) { - this.showDialog(wizardModel); - } - }, - showDialog(wizardModel) { const title = WizardI18n("wizard.incomplete_submission.title", { date: moment(wizardModel.submission_last_updated_at).format( "MMMM Do YYYY" - ), + ) }); const buttons = [ @@ -57,28 +46,36 @@ export default Ember.Route.extend({ afterModel(model) { updateCachedWizard(model); + }, - return ajax({ - url: `/site/settings`, - type: "GET", - }).then((result) => { - $.extend(Wizard.SiteSettings, result); - }); + renderTemplate() { + this.render('wizard/templates/wizard'); }, setupController(controller, model) { - const background = model ? model.get("background") : "AliceBlue"; - Ember.run.scheduleOnce("afterRender", this, function () { - $("body.custom-wizard").css("background", background); + const background = model ? model.get("background") : ""; + + scheduleOnce("afterRender", this, function () { + $("body").css("background", background); if (model && model.id) { - $("#custom-wizard-main").addClass(model.id.dasherize()); + $(getOwner(this).rootElement).addClass(model.id.dasherize()); } }); + controller.setProperties({ customWizard: true, - logoUrl: Wizard.SiteSettings.logo_small, + logoUrl: this.siteSettings.logo_small, reset: null, }); + + const stepModel = this.modelFor("step"); + if ( + model.resume_on_revisit && + model.submission_last_updated_at && + stepModel.index > 0 + ) { + this.showDialog(model); + } }, }); diff --git a/assets/javascripts/wizard/templates/components/wizard-field-dropdown.hbs b/assets/javascripts/wizard/templates/components/wizard-field-dropdown.hbs index 7ce4c298..42fc63e8 100644 --- a/assets/javascripts/wizard/templates/components/wizard-field-dropdown.hbs +++ b/assets/javascripts/wizard/templates/components/wizard-field-dropdown.hbs @@ -3,6 +3,7 @@ value=field.value content=field.content tabindex=field.tabindex + onChange=(action "onChangeValue") options=(hash none="select_kit.default_header_text" )}} diff --git a/assets/javascripts/wizard/templates/custom.index.hbs b/assets/javascripts/wizard/templates/custom.index.hbs deleted file mode 100644 index 3cd02e05..00000000 --- a/assets/javascripts/wizard/templates/custom.index.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if noWizard}} - {{wizard-no-access text=(wizard-i18n "wizard.none") wizardId=wizardId}} -{{else}} - {{#if requiresLogin}} - {{wizard-no-access text=(wizard-i18n "wizard.requires_login") wizardId=wizardId}} - {{else}} - {{#if notPermitted}} - {{wizard-no-access text=(wizard-i18n "wizard.not_permitted") wizardId=wizardId}} - {{else}} - {{#if completed}} - {{wizard-no-access text=(wizard-i18n "wizard.completed") wizardId=wizardId}} - {{/if}} - {{/if}} - {{/if}} -{{/if}} diff --git a/assets/javascripts/wizard/templates/index.hbs b/assets/javascripts/wizard/templates/index.hbs new file mode 100644 index 00000000..c24cd689 --- /dev/null +++ b/assets/javascripts/wizard/templates/index.hbs @@ -0,0 +1 @@ +{{outlet}} diff --git a/assets/javascripts/wizard/templates/custom.step.hbs b/assets/javascripts/wizard/templates/step.hbs similarity index 100% rename from assets/javascripts/wizard/templates/custom.step.hbs rename to assets/javascripts/wizard/templates/step.hbs diff --git a/assets/javascripts/wizard/templates/wizard-index.hbs b/assets/javascripts/wizard/templates/wizard-index.hbs new file mode 100644 index 00000000..a8f1b9ba --- /dev/null +++ b/assets/javascripts/wizard/templates/wizard-index.hbs @@ -0,0 +1,3 @@ +{{#if noAccess}} + {{wizard-no-access text=(wizard-i18n noAccessI18nKey) wizardId=wizardId reason=noAccessReason}} +{{/if}} diff --git a/assets/javascripts/wizard/templates/custom.hbs b/assets/javascripts/wizard/templates/wizard.hbs similarity index 86% rename from assets/javascripts/wizard/templates/custom.hbs rename to assets/javascripts/wizard/templates/wizard.hbs index 4701fec2..f6d6127e 100644 --- a/assets/javascripts/wizard/templates/custom.hbs +++ b/assets/javascripts/wizard/templates/wizard.hbs @@ -1,7 +1,3 @@ -{{#if showCanvas}} - {{wizard-canvas}} -{{/if}} -
{{outlet}} diff --git a/assets/javascripts/wizard/tests/acceptance/field-test.js.es6 b/assets/javascripts/wizard/tests/acceptance/field-test.js.es6 new file mode 100644 index 00000000..f73d1ab7 --- /dev/null +++ b/assets/javascripts/wizard/tests/acceptance/field-test.js.es6 @@ -0,0 +1,135 @@ +import { + visit, + click, + fillIn, + triggerKeyEvent +} from "@ember/test-helpers"; +import { test } from "qunit"; +import { exists } from "../helpers/test"; +import acceptance, { + query, + count, + visible, + server +} from "../helpers/acceptance"; +import { + allFieldsWizard, + getWizard +} from "../helpers/wizard"; +import tagsJson from "../fixtures/tags"; +import usersJson from "../fixtures/users"; +import { response } from "../pretender"; + +acceptance("Field | Fields", [ getWizard(allFieldsWizard) ], + function(hooks) { + test("Text", async function (assert) { + await visit("/wizard"); + assert.ok(exists(".wizard-field.text-field input.wizard-focusable")); + }); + + test("Textarea", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.textarea-field textarea.wizard-focusable")); + }); + + test("Composer", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.composer-field .wizard-field-composer textarea")); + assert.strictEqual(count(".wizard-field.composer-field .d-editor-button-bar button"), 8); + assert.ok(visible(".wizard-btn.toggle-preview")); + + await fillIn(".wizard-field.composer-field .wizard-field-composer textarea", "Input in composer"); + await click(".wizard-btn.toggle-preview"); + assert.strictEqual(query('.wizard-field.composer-field .wizard-field-composer .d-editor-preview-wrapper p').textContent.trim(), "Input in composer"); + }); + + test("Text Only", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.text-only-field label.field-label")); + }); + + test("Date", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.date-field input.date-picker")); + await click(".wizard-field.date-field input.date-picker"); + assert.ok(visible(".wizard-field.date-field .pika-single")); + }); + + test("Time", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.time-field .d-time-input .select-kit")); + await click(".wizard-field.time-field .d-time-input .select-kit .select-kit-header"); + assert.ok(visible(".wizard-field.time-field .select-kit-collection")); + }); + + test("Date Time", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.date-time-field .d-date-time-input .select-kit")); + await click(".wizard-field.date-time-field .d-date-input input.date-picker"); + assert.ok(visible(".wizard-field.date-time-field .d-date-input .pika-single")); + await click(".wizard-field.date-time-field .d-time-input .select-kit .select-kit-header"); + assert.ok(visible(".wizard-field.date-time-field .select-kit-collection")); + }); + + test("Number", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.number-field input[type='number']")); + }); + + test("Checkbox", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.checkbox-field input[type='checkbox']")); + }); + + test("Url", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.url-field input[type='text']")); + }); + + test("Upload", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.upload-field label.wizard-btn-upload-file")); + assert.ok(exists(".wizard-field.upload-field input.hidden-upload-field")); + }); + + test("Dropdown", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.dropdown-field .single-select-header")); + await click(".wizard-field.dropdown-field .select-kit-header"); + assert.strictEqual(count(".wizard-field.dropdown-field .select-kit-collection li"), 3); + }); + + test("Tag", async function (assert) { + server.get("/tags/filter/search", () => (response(200, { results: tagsJson['tags']}))); + await visit("/wizard"); + assert.ok(visible(".wizard-field.tag-field .multi-select-header")); + await click(".wizard-field.tag-field .select-kit-header"); + assert.strictEqual(count(".wizard-field.tag-field .select-kit-collection li"), 2); + }); + + test("Category", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.category-field .multi-select-header")); + await click(".wizard-field.category-field .select-kit-header"); + assert.strictEqual(count(".wizard-field.category-field .select-kit-collection li"), 5); + }); + + test("Group", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.group-field .single-select-header")); + await click(".wizard-field.group-field .select-kit-header"); + assert.strictEqual(count(".wizard-field.group-field .select-kit-collection li"), 10); + }); + + test("User", async function (assert) { + server.get("/u/search/users", () => (response(200, usersJson))); + + await visit("/wizard"); + await fillIn(".wizard-field.user-selector-field input.ember-text-field", "a"); + await triggerKeyEvent(".wizard-field.user-selector-field input.ember-text-field", "keyup", "a".charCodeAt(0)); + + assert.ok(visible(".wizard-field.user-selector-field .ac-wrap")); + // TODO: add assertion for ac results. autocomplete does not appear in time. + }); + } +); diff --git a/assets/javascripts/wizard/tests/acceptance/step-test.js.es6 b/assets/javascripts/wizard/tests/acceptance/step-test.js.es6 new file mode 100644 index 00000000..731c9b76 --- /dev/null +++ b/assets/javascripts/wizard/tests/acceptance/step-test.js.es6 @@ -0,0 +1,47 @@ +import { visit, click } from "@ember/test-helpers"; +import { test } from "qunit"; +import { exists } from "../helpers/test"; +import acceptance, { + query, + count, + visible +} from "../helpers/acceptance"; +import { + stepNotPermitted, + wizard, + getWizard +} from "../helpers/wizard"; +import { + saveStep, + update +} from "../helpers/step"; + +acceptance("Step | Not permitted", [ getWizard(stepNotPermitted) ], + function(hooks) { + test("Shows not permitted message", async function (assert) { + await visit("/wizard"); + assert.ok(exists(".step-message.not-permitted")); + }); + } +); + +acceptance("Step | Step", [ getWizard(wizard), saveStep(update) ], + function(hooks) { + test("Renders the step", async function (assert) { + await visit("/wizard"); + assert.strictEqual(query('.wizard-step-title p').textContent.trim(), "Text"); + assert.strictEqual(query('.wizard-step-description p').textContent.trim(), "Text inputs!"); + assert.strictEqual(query('.wizard-step-description p').textContent.trim(), "Text inputs!"); + assert.strictEqual(count('.wizard-step-form .wizard-field'), 6); + assert.ok(visible('.wizard-step-footer .wizard-progress'), true); + assert.ok(visible('.wizard-step-footer .wizard-buttons'), true); + }); + + test("Goes to the next step", async function (assert) { + await visit("/wizard"); + assert.ok(visible('.wizard-step.step_1'), true); + await click('.wizard-btn.next'); + assert.ok(visible('.wizard-step.step_2'), true); + }); + } +); diff --git a/assets/javascripts/wizard/tests/acceptance/wizard-test.js.es6 b/assets/javascripts/wizard/tests/acceptance/wizard-test.js.es6 new file mode 100644 index 00000000..e68f59ae --- /dev/null +++ b/assets/javascripts/wizard/tests/acceptance/wizard-test.js.es6 @@ -0,0 +1,72 @@ +import { visit } from "@ember/test-helpers"; +import { test } from "qunit"; +import { exists } from "../helpers/test"; +import acceptance, { + query, + count, + visible +} from "../helpers/acceptance"; +import { + wizardNoUser, + wizardNotPermitted, + wizardCompleted, + wizard, + getWizard +} from "../helpers/wizard"; + +acceptance("Wizard | Not logged in", [ getWizard(wizardNoUser) ], + function(hooks) { + test("Wizard no access requires login", async function (assert) { + await visit("/wizard"); + assert.ok(exists(".wizard-no-access.requires-login")); + }); + } +); + +acceptance("Wizard | Not permitted", [ getWizard(wizardNotPermitted) ], + function(hooks) { + test("Wizard no access not permitted", async function (assert) { + await visit("/wizard"); + assert.ok(exists(".wizard-no-access.not-permitted")); + }); + } +); + +acceptance("Wizard | Completed", [ getWizard(wizardCompleted) ], + function(hooks) { + test("Wizard no access completed", async function (assert) { + await visit("/wizard"); + assert.ok(exists(".wizard-no-access.completed")); + }); + } +); + +acceptance("Wizard | Wizard", [ getWizard(wizard) ], + function(hooks) { + test("Starts", async function (assert) { + await visit("/wizard"); + assert.ok(query('.wizard-column'), true); + }); + + test("Applies the body background color", async function (assert) { + await visit("/wizard"); + assert.ok($("body")[0].style.background); + }); + + test("Renders the wizard form", async function (assert) { + await visit("/wizard"); + assert.ok(visible('.wizard-column-contents .wizard-step'), true); + assert.ok(visible('.wizard-footer img'), true); + }); + + test("Renders the first step", async function (assert) { + await visit("/wizard"); + assert.strictEqual(query('.wizard-step-title p').textContent.trim(), "Text"); + assert.strictEqual(query('.wizard-step-description p').textContent.trim(), "Text inputs!"); + assert.strictEqual(query('.wizard-step-description p').textContent.trim(), "Text inputs!"); + assert.strictEqual(count('.wizard-step-form .wizard-field'), 6); + assert.ok(visible('.wizard-step-footer .wizard-progress'), true); + assert.ok(visible('.wizard-step-footer .wizard-buttons'), true); + }); + } +); diff --git a/assets/javascripts/wizard/tests/bootstrap.js.es6 b/assets/javascripts/wizard/tests/bootstrap.js.es6 new file mode 100644 index 00000000..d2c503ad --- /dev/null +++ b/assets/javascripts/wizard/tests/bootstrap.js.es6 @@ -0,0 +1,17 @@ +// discourse-skip-module + +document.addEventListener("DOMContentLoaded", function () { + document.body.insertAdjacentHTML( + "afterbegin", + ` +
+ + ` + ); +}); + +Object.keys(requirejs.entries).forEach(function (entry) { + if (/\-test/.test(entry)) { + requirejs(entry); + } +}); diff --git a/assets/javascripts/wizard/tests/fixtures/categories.js.es6 b/assets/javascripts/wizard/tests/fixtures/categories.js.es6 new file mode 100644 index 00000000..e862f54a --- /dev/null +++ b/assets/javascripts/wizard/tests/fixtures/categories.js.es6 @@ -0,0 +1,209 @@ +export default { + "categories": [ + { + "id": 1, + "name": "Uncategorized", + "color": "0088CC", + "text_color": "FFFFFF", + "slug": "uncategorized", + "topic_count": 1, + "post_count": 1, + "position": 0, + "description": "Topics that don't need a category, or don't fit into any other existing category.", + "description_text": "Topics that don't need a category, or don't fit into any other existing category.", + "description_excerpt": "Topics that don't need a category, or don't fit into any other existing category.", + "topic_url": "/t/", + "read_restricted": false, + "permission": 1, + "notification_level": 0, + "topic_template": null, + "has_children": false, + "sort_order": null, + "sort_ascending": null, + "show_subcategory_list": false, + "num_featured_topics": 3, + "default_view": null, + "subcategory_list_style": "rows_with_featured_topics", + "default_top_period": "all", + "default_list_filter": "all", + "minimum_required_tags": 0, + "navigate_to_first_post_after_read": false, + "custom_fields": { + "create_topic_wizard": null + }, + "allowed_tags": [], + "allowed_tag_groups": [], + "allow_global_tags": false, + "min_tags_from_required_group": 1, + "required_tag_group_name": null, + "read_only_banner": null, + "uploaded_logo": null, + "uploaded_background": null, + "can_edit": true + }, + { + "id": 2, + "name": "Site Feedback", + "color": "808281", + "text_color": "FFFFFF", + "slug": "site-feedback", + "topic_count": 20, + "post_count": 21, + "position": 1, + "description": "

Discussion about this site, its organization, how it works, and how we can improve it.

", + "description_text": "Discussion about this site, its organization, how it works, and how we can improve it.", + "description_excerpt": "Discussion about this site, its organization, how it works, and how we can improve it.", + "topic_url": "/t/about-the-site-feedback-category/1", + "read_restricted": false, + "permission": 1, + "notification_level": 0, + "topic_template": null, + "has_children": false, + "sort_order": null, + "sort_ascending": null, + "show_subcategory_list": false, + "num_featured_topics": 3, + "default_view": null, + "subcategory_list_style": "rows_with_featured_topics", + "default_top_period": "all", + "default_list_filter": "all", + "minimum_required_tags": 0, + "navigate_to_first_post_after_read": false, + "custom_fields": { + "create_topic_wizard": null + }, + "allowed_tags": [], + "allowed_tag_groups": [], + "allow_global_tags": false, + "min_tags_from_required_group": 1, + "required_tag_group_name": null, + "read_only_banner": null, + "uploaded_logo": null, + "uploaded_background": null, + "can_edit": true + }, + { + "id": 3, + "name": "Staff", + "color": "E45735", + "text_color": "FFFFFF", + "slug": "staff", + "topic_count": 4, + "post_count": 7, + "position": 2, + "description": "

Private category for staff discussions. Topics are only visible to admins and moderators.

", + "description_text": "Private category for staff discussions. Topics are only visible to admins and moderators.", + "description_excerpt": "Private category for staff discussions. Topics are only visible to admins and moderators.", + "topic_url": "/t/about-the-staff-category/2", + "read_restricted": true, + "permission": 1, + "notification_level": 0, + "topic_template": null, + "has_children": false, + "sort_order": null, + "sort_ascending": null, + "show_subcategory_list": false, + "num_featured_topics": 3, + "default_view": null, + "subcategory_list_style": "rows_with_featured_topics", + "default_top_period": "all", + "default_list_filter": "all", + "minimum_required_tags": 0, + "navigate_to_first_post_after_read": false, + "custom_fields": { + "create_topic_wizard": null + }, + "allowed_tags": [], + "allowed_tag_groups": [], + "allow_global_tags": false, + "min_tags_from_required_group": 1, + "required_tag_group_name": null, + "read_only_banner": null, + "uploaded_logo": null, + "uploaded_background": null, + "can_edit": true + }, + { + "id": 4, + "name": "Lounge", + "color": "A461EF", + "text_color": "652D90", + "slug": "lounge", + "topic_count": 1, + "post_count": 1, + "position": 3, + "description": "

A category exclusive to members with trust level 3 and higher.

", + "description_text": "A category exclusive to members with trust level 3 and higher.", + "description_excerpt": "A category exclusive to members with trust level 3 and higher.", + "topic_url": "/t/about-the-lounge-category/3", + "read_restricted": true, + "permission": 1, + "notification_level": 0, + "topic_template": null, + "has_children": false, + "sort_order": null, + "sort_ascending": null, + "show_subcategory_list": false, + "num_featured_topics": 3, + "default_view": null, + "subcategory_list_style": "rows_with_featured_topics", + "default_top_period": "all", + "default_list_filter": "all", + "minimum_required_tags": 0, + "navigate_to_first_post_after_read": false, + "custom_fields": { + "create_topic_wizard": null + }, + "allowed_tags": [], + "allowed_tag_groups": [], + "allow_global_tags": false, + "min_tags_from_required_group": 1, + "required_tag_group_name": null, + "read_only_banner": null, + "uploaded_logo": null, + "uploaded_background": null, + "can_edit": true + }, + { + "id": 5, + "name": "Custom Categories", + "color": "0088CC", + "text_color": "FFFFFF", + "slug": "custom-category", + "topic_count": 0, + "post_count": 0, + "position": 10, + "description": "Description of custom category", + "description_text": "Description of custom category", + "description_excerpt": "Description of custom category", + "topic_url": "/t/about-the-custom-category/5", + "read_restricted": false, + "permission": 1, + "notification_level": 0, + "topic_template": null, + "has_children": false, + "sort_order": null, + "sort_ascending": null, + "show_subcategory_list": false, + "num_featured_topics": 3, + "default_view": null, + "subcategory_list_style": "rows_with_featured_topics", + "default_top_period": "all", + "default_list_filter": "all", + "minimum_required_tags": 0, + "navigate_to_first_post_after_read": false, + "custom_fields": { + "create_topic_wizard": null + }, + "allowed_tags": [], + "allowed_tag_groups": [], + "allow_global_tags": false, + "min_tags_from_required_group": 1, + "required_tag_group_name": null, + "read_only_banner": null, + "uploaded_logo": null, + "uploaded_background": null, + "can_edit": true + } + ] +} diff --git a/assets/javascripts/wizard/tests/fixtures/groups.js.es6 b/assets/javascripts/wizard/tests/fixtures/groups.js.es6 new file mode 100644 index 00000000..16f8150d --- /dev/null +++ b/assets/javascripts/wizard/tests/fixtures/groups.js.es6 @@ -0,0 +1,313 @@ +export default { + "groups": [ + { + "id": 1, + "automatic": true, + "name": "admins", + "display_name": "admins", + "user_count": 1, + "mentionable_level": 0, + "messageable_level": 0, + "visibility_level": 1, + "primary_group": false, + "title": null, + "grant_trust_level": null, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": null, + "default_notification_level": 3, + "membership_request_template": null, + "members_visibility_level": 0, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + }, + { + "id": 0, + "automatic": true, + "name": "everyone", + "display_name": "everyone", + "user_count": 0, + "mentionable_level": 0, + "messageable_level": 0, + "visibility_level": 3, + "primary_group": false, + "title": null, + "grant_trust_level": null, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": null, + "default_notification_level": 3, + "membership_request_template": null, + "members_visibility_level": 0, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + }, + { + "id": 15, + "automatic": false, + "name": "custom_group", + "user_count": 1, + "mentionable_level": 1, + "messageable_level": 2, + "visibility_level": 3, + "primary_group": false, + "title": "Custom Group", + "grant_trust_level": 3, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": "I am prefilled", + "default_notification_level": 3, + "membership_request_template": null, + "members_visibility_level": 99, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + }, + { + "id": 2, + "automatic": true, + "name": "moderators", + "display_name": "moderators", + "user_count": 0, + "mentionable_level": 0, + "messageable_level": 99, + "visibility_level": 1, + "primary_group": false, + "title": null, + "grant_trust_level": null, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": null, + "default_notification_level": 2, + "membership_request_template": null, + "members_visibility_level": 0, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + }, + { + "id": 3, + "automatic": true, + "name": "staff", + "display_name": "staff", + "user_count": 1, + "mentionable_level": 0, + "messageable_level": 0, + "visibility_level": 1, + "primary_group": false, + "title": null, + "grant_trust_level": null, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": null, + "default_notification_level": 3, + "membership_request_template": null, + "members_visibility_level": 0, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + }, + { + "id": 10, + "automatic": true, + "name": "trust_level_0", + "display_name": "trust_level_0", + "user_count": 2, + "mentionable_level": 0, + "messageable_level": 0, + "visibility_level": 1, + "primary_group": false, + "title": null, + "grant_trust_level": null, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": null, + "default_notification_level": 3, + "membership_request_template": null, + "members_visibility_level": 0, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + }, + { + "id": 11, + "automatic": true, + "name": "trust_level_1", + "display_name": "trust_level_1", + "user_count": 2, + "mentionable_level": 0, + "messageable_level": 0, + "visibility_level": 1, + "primary_group": false, + "title": null, + "grant_trust_level": null, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": null, + "default_notification_level": 3, + "membership_request_template": null, + "members_visibility_level": 0, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + }, + { + "id": 12, + "automatic": true, + "name": "trust_level_2", + "display_name": "trust_level_2", + "user_count": 1, + "mentionable_level": 0, + "messageable_level": 0, + "visibility_level": 1, + "primary_group": false, + "title": null, + "grant_trust_level": null, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": null, + "default_notification_level": 3, + "membership_request_template": null, + "members_visibility_level": 0, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + }, + { + "id": 13, + "automatic": true, + "name": "trust_level_3", + "display_name": "trust_level_3", + "user_count": 1, + "mentionable_level": 0, + "messageable_level": 0, + "visibility_level": 1, + "primary_group": false, + "title": null, + "grant_trust_level": null, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": null, + "default_notification_level": 3, + "membership_request_template": null, + "members_visibility_level": 0, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + }, + { + "id": 14, + "automatic": true, + "name": "trust_level_4", + "display_name": "trust_level_4", + "user_count": 0, + "mentionable_level": 0, + "messageable_level": 0, + "visibility_level": 1, + "primary_group": false, + "title": null, + "grant_trust_level": null, + "incoming_email": null, + "has_messages": false, + "flair_url": null, + "flair_bg_color": null, + "flair_color": null, + "bio_raw": null, + "bio_cooked": null, + "bio_excerpt": null, + "public_admission": false, + "public_exit": false, + "allow_membership_requests": false, + "full_name": null, + "default_notification_level": 3, + "membership_request_template": null, + "members_visibility_level": 0, + "can_see_members": true, + "can_admin_group": true, + "publish_read_state": false + } + ] +} diff --git a/assets/javascripts/wizard/tests/fixtures/site-settings.js.es6 b/assets/javascripts/wizard/tests/fixtures/site-settings.js.es6 new file mode 100644 index 00000000..f71ace8e --- /dev/null +++ b/assets/javascripts/wizard/tests/fixtures/site-settings.js.es6 @@ -0,0 +1,283 @@ +export default { + "default_locale": "en", + "title": "Discourse", + "short_site_description": "", + "exclude_rel_nofollow_domains": "", + "logo": "/images/discourse-logo-sketch.png", + "logo_small": "/images/discourse-logo-sketch-small.png", + "digest_logo": "", + "mobile_logo": "", + "logo_dark": "", + "logo_small_dark": "", + "mobile_logo_dark": "", + "large_icon": "", + "favicon": "", + "apple_touch_icon": "", + "display_local_time_in_user_card": false, + "allow_user_locale": false, + "set_locale_from_accept_language_header": false, + "support_mixed_text_direction": false, + "suggested_topics": 5, + "ga_universal_tracking_code": "", + "ga_universal_domain_name": "auto", + "gtm_container_id": "", + "top_menu": "categories|latest", + "post_menu": "read|like|share|flag|edit|bookmark|delete|admin|reply", + "post_menu_hidden_items": "flag|bookmark|edit|delete|admin", + "share_links": "twitter|facebook|email", + "share_quote_visibility": "anonymous", + "share_quote_buttons": "twitter|email", + "desktop_category_page_style": "categories_and_latest_topics", + "category_colors": "BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|E45735", + "category_style": "bullet", + "max_category_nesting": 2, + "enable_mobile_theme": true, + "enable_direct_s3_uploads": false, + "enable_upload_debug_mode": false, + "default_dark_mode_color_scheme_id": 1, + "relative_date_duration": 30, + "fixed_category_positions": false, + "fixed_category_positions_on_create": false, + "enable_badges": true, + "enable_badge_sql": true, + "max_favorite_badges": 2, + "enable_whispers": false, + "enable_bookmarks_with_reminders": true, + "push_notifications_prompt": true, + "vapid_public_key_bytes": "4|29|219|88|202|66|198|62|182|204|66|176|229|200|131|26|141|21|178|231|150|161|2|128|228|200|179|126|118|232|196|19|232|76|108|189|54|211|210|155|55|228|173|112|38|158|114|127|18|95|7|56|110|183|192|92|43|0|243|249|233|89|9|207|255", + "invite_only": false, + "login_required": false, + "must_approve_users": false, + "enable_local_logins": true, + "enable_local_logins_via_email": true, + "allow_new_registrations": true, + "enable_signup_cta": true, + "facebook_app_id": "", + "auth_skip_create_confirm": false, + "auth_overrides_email": false, + "enable_discourse_connect": true, + "discourse_connect_overrides_avatar": false, + "hide_email_address_taken": false, + "min_username_length": 3, + "max_username_length": 20, + "unicode_usernames": false, + "min_password_length": 10, + "min_admin_password_length": 15, + "email_editable": true, + "logout_redirect": "", + "full_name_required": false, + "enable_names": true, + "invite_expiry_days": 90, + "invites_per_page": 40, + "delete_user_max_post_age": 60, + "delete_all_posts_max": 15, + "prioritize_username_in_ux": true, + "enable_user_directory": true, + "allow_anonymous_posting": false, + "anonymous_posting_min_trust_level": 1, + "allow_users_to_hide_profile": true, + "hide_user_profiles_from_public": false, + "allow_featured_topic_on_user_profiles": true, + "hide_suspension_reasons": false, + "ignored_users_count_message_threshold": 5, + "ignored_users_message_gap_days": 365, + "user_selected_primary_groups": false, + "gravatar_name": "Gravatar", + "gravatar_base_url": "www.gravatar.com", + "gravatar_login_url": "/emails", + "enable_group_directory": true, + "enable_category_group_moderation": false, + "min_post_length": 20, + "min_first_post_length": 20, + "min_personal_message_post_length": 10, + "max_post_length": 32000, + "topic_featured_link_enabled": true, + "min_topic_views_for_delete_confirm": 5000, + "min_topic_title_length": 15, + "max_topic_title_length": 255, + "enable_filtered_replies_view": false, + "min_personal_message_title_length": 2, + "allow_uncategorized_topics": true, + "min_title_similar_length": 10, + "enable_personal_messages": true, + "edit_history_visible_to_public": true, + "delete_removed_posts_after": 24, + "traditional_markdown_linebreaks": false, + "enable_markdown_typographer": true, + "enable_markdown_linkify": true, + "markdown_linkify_tlds": "com|net|org|io|onion|co|tv|ru|cn|us|uk|me|de|fr|fi|gov", + "markdown_typographer_quotation_marks": "“|”|‘|’", + "enable_rich_text_paste": true, + "suppress_reply_directly_below": true, + "suppress_reply_directly_above": true, + "max_reply_history": 1, + "enable_mentions": true, + "here_mention": "here", + "newuser_max_embedded_media": 1, + "newuser_max_attachments": 0, + "show_pinned_excerpt_mobile": true, + "show_pinned_excerpt_desktop": true, + "display_name_on_posts": false, + "show_time_gap_days": 7, + "short_progress_text_threshold": 10000, + "default_code_lang": "auto", + "autohighlight_all_code": false, + "highlighted_languages": "apache|bash|cs|cpp|css|coffeescript|diff|xml|http|ini|json|java|javascript|makefile|markdown|nginx|objectivec|ruby|perl|php|python|sql|handlebars", + "show_copy_button_on_codeblocks": false, + "enable_emoji": true, + "enable_emoji_shortcuts": true, + "emoji_set": "twitter", + "emoji_autocomplete_min_chars": 0, + "enable_inline_emoji_translation": false, + "code_formatting_style": "code-fences", + "allowed_href_schemes": "", + "watched_words_regular_expressions": false, + "enable_diffhtml_preview": false, + "enable_fast_edit": true, + "old_post_notice_days": 14, + "blur_tl0_flagged_posts_media": true, + "email_time_window_mins": 10, + "disable_digest_emails": false, + "email_in": false, + "enable_imap": false, + "enable_smtp": false, + "disable_emails": "no", + "bounce_score_threshold": 4, + "enable_secondary_emails": true, + "max_image_size_kb": 4096, + "max_attachment_size_kb": 4096, + "authorized_extensions": "jpg|jpeg|png|gif|heic|heif|webp", + "authorized_extensions_for_staff": "", + "max_image_width": 690, + "max_image_height": 500, + "prevent_anons_from_downloading_files": false, + "secure_media": false, + "enable_s3_uploads": false, + "allow_profile_backgrounds": true, + "allow_uploaded_avatars": "0", + "default_avatars": "", + "external_system_avatars_enabled": true, + "external_system_avatars_url": "/letter_avatar_proxy/v4/letter/{first_letter}/{color}/{size}.png", + "external_emoji_url": "", + "selectable_avatars_mode": "disabled", + "selectable_avatars": "", + "allow_staff_to_upload_any_file_in_pm": true, + "simultaneous_uploads": 5, + "composer_media_optimization_image_enabled": true, + "composer_media_optimization_image_bytes_optimization_threshold": 524288, + "composer_media_optimization_image_resize_dimensions_threshold": 1920, + "composer_media_optimization_image_resize_width_target": 1920, + "composer_media_optimization_image_resize_pre_multiply": false, + "composer_media_optimization_image_resize_linear_rgb": false, + "composer_media_optimization_image_encode_quality": 75, + "composer_media_optimization_debug_mode": false, + "min_trust_level_to_allow_profile_background": 0, + "min_trust_level_to_allow_user_card_background": 0, + "min_trust_level_to_allow_ignore": 2, + "tl1_requires_read_posts": 30, + "tl3_links_no_follow": false, + "enforce_second_factor": "no", + "moderators_change_post_ownership": false, + "moderators_view_emails": false, + "use_admin_ip_allowlist": false, + "allowed_iframes": "https://www.google.com/maps/embed?|https://www.openstreetmap.org/export/embed.html?|https://calendar.google.com/calendar/embed?|https://codepen.io/|https://www.instagram.com|http://localhost:3000/discobot/certificate.svg", + "can_permanently_delete": false, + "max_oneboxes_per_post": 50, + "reviewable_claiming": "disabled", + "reviewable_default_topics": false, + "reviewable_default_visibility": "low", + "alert_admins_if_errors_per_minute": 0, + "alert_admins_if_errors_per_hour": 0, + "max_prints_per_hour_per_user": 5, + "invite_link_max_redemptions_limit": 5000, + "invite_link_max_redemptions_limit_users": 10, + "enable_long_polling": true, + "enable_chunked_encoding": true, + "long_polling_base_url": "/", + "background_polling_interval": 60000, + "polling_interval": 3000, + "anon_polling_interval": 25000, + "flush_timings_secs": 60, + "verbose_localization": false, + "max_new_topics": 500, + "enable_safe_mode": true, + "tos_url": "", + "privacy_policy_url": "", + "faq_url": "", + "enable_backups": true, + "backup_location": "local", + "maximum_backups": 5, + "use_pg_headlines_for_excerpt": false, + "min_search_term_length": 3, + "log_search_queries": true, + "version_checks": true, + "suppress_uncategorized_badge": true, + "header_dropdown_category_count": 8, + "slug_generation_method": "ascii", + "summary_timeline_button": false, + "topic_views_heat_low": 1000, + "topic_views_heat_medium": 2000, + "topic_views_heat_high": 3500, + "topic_post_like_heat_low": 0.5, + "topic_post_like_heat_medium": 1, + "topic_post_like_heat_high": 2, + "history_hours_low": 12, + "history_hours_medium": 24, + "history_hours_high": 48, + "cold_age_days_low": 14, + "cold_age_days_medium": 90, + "cold_age_days_high": 180, + "global_notice": "", + "show_create_topics_notice": true, + "bootstrap_mode_min_users": 50, + "bootstrap_mode_enabled": true, + "automatically_unpin_topics": true, + "read_time_word_count": 500, + "topic_page_title_includes_category": true, + "svg_icon_subset": "", + "allow_bulk_invite": true, + "disable_mailing_list_mode": true, + "default_topics_automatic_unpin": true, + "mute_all_categories_by_default": false, + "tagging_enabled": true, + "tag_style": "simple", + "max_tags_per_topic": 5, + "max_tag_length": 20, + "min_trust_level_to_tag_topics": "0", + "max_tag_search_results": 5, + "max_tags_in_filter_list": 30, + "tags_sort_alphabetically": false, + "tags_listed_by_group": false, + "suppress_overlapping_tags_in_list": false, + "remove_muted_tags_from_latest": "always", + "force_lowercase_tags": true, + "dashboard_hidden_reports": "", + "dashboard_visible_tabs": "moderation|security|reports", + "dashboard_general_tab_activity_metrics": "page_view_total_reqs|visits|time_to_first_response|likes|flags|user_to_user_private_messages_with_replies", + "discourse_narrative_bot_enabled": true, + "details_enabled": true, + "custom_wizard_enabled": true, + "wizard_redirect_exclude_paths": "admin", + "wizard_recognised_image_upload_formats": "jpg|jpeg|png|gif", + "wizard_important_notices_on_dashboard": true, + "discourse_local_dates_email_format": "YYYY-MM-DDTHH:mm:ss[Z]", + "discourse_local_dates_enabled": true, + "discourse_local_dates_default_formats": "LLL|LTS|LL|LLLL", + "discourse_local_dates_default_timezones": "Europe/Paris|America/Los_Angeles", + "poll_enabled": true, + "poll_maximum_options": 20, + "poll_minimum_trust_level_to_create": 1, + "poll_groupable_user_fields": "", + "poll_export_data_explorer_query_id": -16, + "presence_enabled": true, + "presence_max_users_shown": 5, + "available_locales": "[{\"name\":\"اللغة العربية\",\"value\":\"ar\"},{\"name\":\"беларуская мова\",\"value\":\"be\"},{\"name\":\"български език\",\"value\":\"bg\"},{\"name\":\"bosanski jezik\",\"value\":\"bs_BA\"},{\"name\":\"català\",\"value\":\"ca\"},{\"name\":\"čeština\",\"value\":\"cs\"},{\"name\":\"dansk\",\"value\":\"da\"},{\"name\":\"Deutsch\",\"value\":\"de\"},{\"name\":\"ελληνικά\",\"value\":\"el\"},{\"name\":\"English (US)\",\"value\":\"en\"},{\"name\":\"English (UK)\",\"value\":\"en_GB\"},{\"name\":\"Español\",\"value\":\"es\"},{\"name\":\"eesti\",\"value\":\"et\"},{\"name\":\"فارسی\",\"value\":\"fa_IR\"},{\"name\":\"suomi\",\"value\":\"fi\"},{\"name\":\"Français\",\"value\":\"fr\"},{\"name\":\"galego\",\"value\":\"gl\"},{\"name\":\"עברית\",\"value\":\"he\"},{\"name\":\"magyar\",\"value\":\"hu\"},{\"name\":\"Հայերեն\",\"value\":\"hy\"},{\"name\":\"Indonesian\",\"value\":\"id\"},{\"name\":\"Italiano\",\"value\":\"it\"},{\"name\":\"日本語\",\"value\":\"ja\"},{\"name\":\"한국어\",\"value\":\"ko\"},{\"name\":\"lietuvių kalba\",\"value\":\"lt\"},{\"name\":\"latviešu valoda\",\"value\":\"lv\"},{\"name\":\"Norsk bokmål\",\"value\":\"nb_NO\"},{\"name\":\"Nederlands\",\"value\":\"nl\"},{\"name\":\"polski\",\"value\":\"pl_PL\"},{\"name\":\"Português\",\"value\":\"pt\"},{\"name\":\"Português (BR)\",\"value\":\"pt_BR\"},{\"name\":\"limba română\",\"value\":\"ro\"},{\"name\":\"Русский\",\"value\":\"ru\"},{\"name\":\"slovenčina\",\"value\":\"sk\"},{\"name\":\"slovenščina\",\"value\":\"sl\"},{\"name\":\"Shqip\",\"value\":\"sq\"},{\"name\":\"српски језик\",\"value\":\"sr\"},{\"name\":\"svenska\",\"value\":\"sv\"},{\"name\":\"Kiswahili\",\"value\":\"sw\"},{\"name\":\"తెలుగు\",\"value\":\"te\"},{\"name\":\"ไทย\",\"value\":\"th\"},{\"name\":\"Türkçe\",\"value\":\"tr_TR\"},{\"name\":\"українська мова\",\"value\":\"uk\"},{\"name\":\"اردو\",\"value\":\"ur\"},{\"name\":\"Việt Nam\",\"value\":\"vi\"},{\"name\":\"简体中文\",\"value\":\"zh_CN\"},{\"name\":\"繁體中文\",\"value\":\"zh_TW\"}]", + "require_invite_code": false, + "site_logo_url": "http://localhost:3000/images/discourse-logo-sketch.png", + "site_logo_small_url": "http://localhost:3000/images/discourse-logo-sketch-small.png", + "site_mobile_logo_url": "http://localhost:3000/images/discourse-logo-sketch.png", + "site_favicon_url": "http://localhost:3000/uploads/default/optimized/1X/_129430568242d1b7f853bb13ebea28b3f6af4e7_2_32x32.png", + "site_logo_dark_url": "", + "site_logo_small_dark_url": "", + "site_mobile_logo_dark_url": "" +} diff --git a/assets/javascripts/wizard/tests/fixtures/tags.js.es6 b/assets/javascripts/wizard/tests/fixtures/tags.js.es6 new file mode 100644 index 00000000..a072772e --- /dev/null +++ b/assets/javascripts/wizard/tests/fixtures/tags.js.es6 @@ -0,0 +1,22 @@ +export default { + "tags": [ + { + "id": "tag1", + "text": "tag1", + "name": "tag1", + "description": null, + "count": 1, + "pm_count": 0, + "target_tag": null + }, + { + "id": "tag2", + "text": "tag2", + "name": "tag2", + "description": null, + "count": 1, + "pm_count": 0, + "target_tag": null + } + ] +} diff --git a/assets/javascripts/wizard/tests/fixtures/update.js.es6 b/assets/javascripts/wizard/tests/fixtures/update.js.es6 new file mode 100644 index 00000000..3908525c --- /dev/null +++ b/assets/javascripts/wizard/tests/fixtures/update.js.es6 @@ -0,0 +1,5 @@ +export default { + "final": false, + "next_step_id": "step_2", + "wizard": {} +} diff --git a/assets/javascripts/wizard/tests/fixtures/user.js.es6 b/assets/javascripts/wizard/tests/fixtures/user.js.es6 new file mode 100644 index 00000000..8acd7392 --- /dev/null +++ b/assets/javascripts/wizard/tests/fixtures/user.js.es6 @@ -0,0 +1,34 @@ +export default { + id: 19, + username: "angus", + uploaded_avatar_id: 5275, + avatar_template: "/user_avatar/localhost/angus/{size}/5275.png", + name: "Angus McLeod", + unread_notifications: 0, + unread_private_messages: 0, + unread_high_priority_notifications: 0, + admin: true, + notification_channel_position: null, + site_flagged_posts_count: 1, + moderator: true, + staff: true, + can_create_group: true, + title: "", + reply_count: 859, + topic_count: 36, + enable_quoting: true, + external_links_in_new_tab: false, + dynamic_favicon: true, + trust_level: 4, + can_edit: true, + can_invite_to_forum: true, + should_be_redirected_to_top: false, + custom_fields: {}, + muted_category_ids: [], + dismissed_banner_key: null, + akismet_review_count: 0, + title_count_mode: "notifications", + timezone: "Australia/Perth", + skip_new_user_tips: false, + can_review: true +} diff --git a/assets/javascripts/wizard/tests/fixtures/users.js.es6 b/assets/javascripts/wizard/tests/fixtures/users.js.es6 new file mode 100644 index 00000000..267d4909 --- /dev/null +++ b/assets/javascripts/wizard/tests/fixtures/users.js.es6 @@ -0,0 +1,14 @@ +export default { + "users": [ + { + "username": "angus", + "name": "Angus", + "avatar_template": "/user_avatar/localhost/angus/{size}/12_2.png" + }, + { + "username": "angus_2", + "name": "Angus 2", + "avatar_template": "/letter_avatar_proxy/v4/letter/a/e9a140/{size}.png" + } + ] +} diff --git a/assets/javascripts/wizard/tests/fixtures/wizard.js.es6 b/assets/javascripts/wizard/tests/fixtures/wizard.js.es6 new file mode 100644 index 00000000..be4fa8b2 --- /dev/null +++ b/assets/javascripts/wizard/tests/fixtures/wizard.js.es6 @@ -0,0 +1,469 @@ +export default { + "id": "wizard", + "name": "Wizard", + "start": "step_1", + "background": "#333333", + "submission_last_updated_at": "2022-03-15T21:11:01+01:00", + "theme_id": 2, + "required": false, + "permitted": true, + "uncategorized_category_id": 1, + "categories": [], + "subscribed": false, + "resume_on_revisit": false, + "steps": [ + { + "id": "step_1", + "index": 0, + "next": "step_2", + "description": "

Text inputs!

", + "title": "Text", + "permitted": true, + "permitted_message": null, + "final": false, + "fields": [ + { + "id": "step_1_field_1", + "index": 0, + "type": "text", + "required": false, + "value": "I am prefilled", + "label": "

Text

", + "description": "Text field description.", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 1, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_1", + "_validState": 0 + }, + { + "id": "step_1_field_2", + "index": 0, + "type": "textarea", + "required": false, + "value": "", + "label": "

Textarea

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 2, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_1", + "_validState": 0 + }, + { + "id": "step_1_field_3", + "index": 2, + "type": "composer", + "required": false, + "value": "", + "label": "

Composer

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 3, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_1", + "_validState": 0 + }, + { + "id": "step_1_field_4", + "index": 3, + "type": "text_only", + "required": false, + "value": null, + "label": "

I’m only text

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 4, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_1", + "_validState": 0 + }, + { + "id": "step_1_field_5", + "index": 4, + "type": "composer_preview", + "required": false, + "value": "", + "label": "

I’m a preview

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": "

I am prefilled

", + "tabindex": 5, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_1", + "_validState": 0 + }, + { + "id": "step_1_field_6", + "index": 5, + "type": "composer_preview", + "required": false, + "value": "", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": "

This is the preview of the composer

", + "tabindex": 6, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_1", + "_validState": 0 + } + ], + "_validState": 0, + "wizardId": "super_mega_fun_wizard" + }, + { + "id": "step_2", + "index": 1, + "next": "step_3", + "previous": "step_1", + "description": "

Because I couldn’t think of another name for this step \":slight_smile:\"

", + "title": "Values", + "permitted": true, + "permitted_message": null, + "final": false, + "fields": [ + { + "id": "step_2_field_1", + "index": 0, + "type": "date", + "required": false, + "value": "", + "label": "

Date

", + "file_types": null, + "format": "YYYY-MM-DD", + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 1, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_2", + "_validState": 0 + }, + { + "id": "step_2_field_2", + "index": 0, + "type": "time", + "required": false, + "value": "", + "label": "

Time

", + "file_types": null, + "format": "HH:mm", + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 2, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_2", + "_validState": 0 + }, + { + "id": "step_2_field_3", + "index": 2, + "type": "date_time", + "required": false, + "value": "", + "label": "

Date & Time

", + "file_types": null, + "format": "", + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 3, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_2", + "_validState": 0 + }, + { + "id": "step_2_field_4", + "index": 3, + "type": "number", + "required": false, + "value": "", + "label": "

Number

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 5, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_2", + "_validState": 0 + }, + { + "id": "step_2_field_5", + "index": 4, + "type": "checkbox", + "required": false, + "value": false, + "label": "

Checkbox

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 6, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_2", + "_validState": 0 + }, + { + "id": "step_2_field_6", + "index": 5, + "type": "url", + "required": false, + "value": "", + "label": "

Url

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 7, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_2", + "_validState": 0 + }, + { + "id": "step_2_field_7", + "index": 6, + "type": "upload", + "required": false, + "value": "", + "label": "

Upload

", + "file_types": ".jpg,.jpeg,.png", + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 8, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_2", + "_validState": 0 + } + ], + "_validState": 0, + "wizardId": "super_mega_fun_wizard" + }, + { + "id": "step_3", + "index": 2, + "previous": "step_2", + "description": "

Unfortunately not the edible type \":sushi:\"

", + "title": "Combo-boxes", + "permitted": true, + "permitted_message": null, + "final": true, + "fields": [ + { + "id": "step_3_field_1", + "index": 0, + "type": "dropdown", + "required": false, + "value": "choice1", + "label": "

Custom Dropdown

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": [ + { + "id": "one", + "name": "One" + }, + { + "id": "two", + "name": "Two" + } + ], + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 1, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_3", + "_validState": 0 + }, + { + "id": "step_3_field_2", + "index": 0, + "type": "tag", + "required": false, + "value": null, + "label": "

Tag

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 2, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_3", + "_validState": 0 + }, + { + "id": "step_3_field_3", + "index": 2, + "type": "category", + "required": false, + "value": null, + "label": "

Category

", + "file_types": null, + "format": null, + "limit": 1, + "property": "id", + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 3, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_3", + "_validState": 0 + }, + { + "id": "step_3_field_4", + "index": 3, + "type": "group", + "required": false, + "value": null, + "label": "

Group

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 4, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_3", + "_validState": 0 + }, + { + "id": "step_3_field_5", + "index": 4, + "type": "user_selector", + "required": false, + "value": null, + "label": "

User Selector

", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 5, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_3", + "_validState": 0 + }, + { + "id": "step_3_field_6", + "index": 5, + "type": "user_selector", + "required": false, + "value": null, + "label": "

Conditional User Selector

", + "description": "Shown when checkbox in step_2_field_5 is true", + "file_types": null, + "format": null, + "limit": null, + "property": null, + "content": null, + "validations": {}, + "max_length": null, + "char_counter": null, + "preview_template": null, + "tabindex": 6, + "wizardId": "super_mega_fun_wizard", + "stepId": "step_3", + "_validState": 0 + } + ], + "_validState": 0, + "wizardId": "super_mega_fun_wizard" + } + ], + "groups": [] +} diff --git a/assets/javascripts/wizard/tests/helpers/acceptance.js.es6 b/assets/javascripts/wizard/tests/helpers/acceptance.js.es6 new file mode 100644 index 00000000..f5c1175f --- /dev/null +++ b/assets/javascripts/wizard/tests/helpers/acceptance.js.es6 @@ -0,0 +1,53 @@ +import { module } from "qunit"; +import setupPretender, { response } from "../pretender"; +import startApp from "../helpers/start-app"; + +let server; +let app; + +function acceptance(name, requests, cb) { + module(`Acceptance: ${name}`, function(hooks) { + hooks.beforeEach(function() { + server = setupPretender(function(pretender) { + requests.forEach(req => { + pretender[req.verb](req.path, () => (response(req.status, req.response))); + }); + return pretender; + }); + app = startApp(); + }); + + hooks.afterEach(function() { + app.destroy(); + server.shutdown(); + }); + + cb(hooks); + }); +} + +export default acceptance; + +export { + server +}; + +// The discourse/test/helpers/qunit-helpers file has many functions and imports +// we don't need, so there will be some duplciation here. + +export function queryAll(selector, context) { + context = context || "#ember-testing"; + return $(selector, context); +} + +export function query() { + return document.querySelector("#ember-testing").querySelector(...arguments); +} + +export function visible(selector) { + return queryAll(selector + ":visible").length > 0; +} + +export function count(selector) { + return queryAll(selector).length; +} diff --git a/assets/javascripts/wizard/tests/helpers/start-app.js.es6 b/assets/javascripts/wizard/tests/helpers/start-app.js.es6 new file mode 100644 index 00000000..6afe6eb9 --- /dev/null +++ b/assets/javascripts/wizard/tests/helpers/start-app.js.es6 @@ -0,0 +1,19 @@ +const CustomWizard = requirejs("discourse/plugins/discourse-custom-wizard/wizard/application").default; +const initializer = requirejs("discourse/plugins/discourse-custom-wizard/wizard/lib/initialize/wizard").default; +const siteSettings = requirejs("discourse/plugins/discourse-custom-wizard/wizard/tests/fixtures/site-settings").default; +const { cloneJSON } = requirejs("discourse-common/lib/object").default; + +let app; + +export default function () { + app = CustomWizard.create({ rootElement: "#ember-testing" }); + app.start(); + + app.SiteSettings = cloneJSON(siteSettings); + initializer.initialize(app); + + app.setupForTesting(); + app.injectTestHelpers(); + + return app; +} diff --git a/assets/javascripts/wizard/tests/helpers/step.js.es6 b/assets/javascripts/wizard/tests/helpers/step.js.es6 new file mode 100644 index 00000000..a24e04e1 --- /dev/null +++ b/assets/javascripts/wizard/tests/helpers/step.js.es6 @@ -0,0 +1,20 @@ +import updateJson from "../fixtures/update"; +import { cloneJSON } from "discourse-common/lib/object"; +import wizardJson from "../fixtures/wizard"; + +const update = cloneJSON(updateJson); +update.wizard = cloneJSON(wizardJson); + +const saveStep = function(response) { + return { + verb: "put", + path: '/w/wizard/steps/:step_id', + status: 200, + response + } +} + +export { + saveStep, + update +} diff --git a/assets/javascripts/wizard/tests/helpers/test.js.es6 b/assets/javascripts/wizard/tests/helpers/test.js.es6 new file mode 100644 index 00000000..c7401fd5 --- /dev/null +++ b/assets/javascripts/wizard/tests/helpers/test.js.es6 @@ -0,0 +1,7 @@ +function exists(selector) { + return document.querySelector(selector) !== null; +} + +export { + exists +} diff --git a/assets/javascripts/wizard/tests/helpers/wizard.js.es6 b/assets/javascripts/wizard/tests/helpers/wizard.js.es6 new file mode 100644 index 00000000..997f6c36 --- /dev/null +++ b/assets/javascripts/wizard/tests/helpers/wizard.js.es6 @@ -0,0 +1,52 @@ +import wizardJson from "../fixtures/wizard"; +import userJson from "../fixtures/user"; +import categoriesJson from "../fixtures/categories"; +import groupsJson from "../fixtures/groups"; +import { cloneJSON } from "discourse-common/lib/object"; + +const wizardNoUser = cloneJSON(wizardJson); +const wizard = cloneJSON(wizardJson); +wizard.user = cloneJSON(userJson); + +const wizardNotPermitted = cloneJSON(wizard); +wizardNotPermitted.permitted = false; + +const wizardCompleted = cloneJSON(wizard); +wizardCompleted.completed = true; + +wizard.start = "step_1"; +wizard.resume_on_revisit = false; +wizard.submission_last_updated_at = "2022-03-11T20:00:18+01:00"; +wizard.subscribed = false; + +const stepNotPermitted = cloneJSON(wizard); +stepNotPermitted.steps[0].permitted = false; + +const allFieldsWizard = cloneJSON(wizard); +allFieldsWizard.steps[0].fields = [ + ...allFieldsWizard.steps[0].fields, + ...allFieldsWizard.steps[1].fields, + ...allFieldsWizard.steps[2].fields +]; +allFieldsWizard.steps = [cloneJSON(allFieldsWizard.steps[0])]; +allFieldsWizard.categories = cloneJSON(categoriesJson['categories']); +allFieldsWizard.groups = cloneJSON(groupsJson['groups']); + +const getWizard = function(response) { + return { + verb: "get", + path: "/w/wizard", + status: 200, + response + } +} + +export { + getWizard, + wizardNoUser, + wizardNotPermitted, + wizardCompleted, + stepNotPermitted, + allFieldsWizard, + wizard +} diff --git a/views/wizard-pretender.js b/assets/javascripts/wizard/tests/pretender.js.es6 similarity index 56% rename from views/wizard-pretender.js rename to assets/javascripts/wizard/tests/pretender.js.es6 index ac0ef1e8..88eae666 100644 --- a/views/wizard-pretender.js +++ b/assets/javascripts/wizard/tests/pretender.js.es6 @@ -1,8 +1,4 @@ import Pretender from "pretender"; -import WizardJson from "./fixtures/wizard"; - -// TODO: This file has some copied and pasted functions from `create-pretender` - would be good -// to centralize that code at some point. function parsePostData(query) { const result = {}; @@ -30,24 +26,14 @@ function response(code, obj) { return [code, { "Content-Type": "application/json" }, obj]; } -export default function () { - const server = new Pretender(function () { - this.get("/w/wizard.json", () => { - return response(200, cloneJSON(WizardJson); - }); +export { response }; - this.put("/wizard/steps/:id", (request) => { - const body = parsePostData(request.requestBody); +export default function (cb) { + let server = new Pretender(); - if (body.fields.full_name === "Server Fail") { - return response(422, { - errors: [{ field: "full_name", description: "Invalid name" }], - }); - } else { - return response(200, { success: true }); - } - }); - }); + if (cb) { + server = cb(server); + } server.prepareBody = function (body) { if (body && typeof body === "object") { @@ -56,7 +42,7 @@ export default function () { return body; }; - server.unhandledRequest = function (verb, path) { + server.unhandledRequest = function (verb, path, request) { const error = "Unhandled request in test environment: " + path + " (" + verb + ")"; window.console.error(error); diff --git a/assets/stylesheets/wizard/custom/composer.scss b/assets/stylesheets/wizard/custom/composer.scss index be866b8a..aea17d63 100644 --- a/assets/stylesheets/wizard/custom/composer.scss +++ b/assets/stylesheets/wizard/custom/composer.scss @@ -46,7 +46,7 @@ position: relative; } -.wizard-field-composer.show-preview .d-editor-textarea-wrapper { +.wizard-field-composer.show-preview .d-editor-textarea-column { display: none; } diff --git a/config/routes.rb b/config/routes.rb index 3b5f8ca6..514605de 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true CustomWizard::Engine.routes.draw do + get 'qunit' => 'wizard#qunit' get ':wizard_id' => 'wizard#index' put ':wizard_id/skip' => 'wizard#skip' get ':wizard_id/steps' => 'wizard#index' diff --git a/controllers/custom_wizard/wizard.rb b/controllers/custom_wizard/wizard.rb index 1e20adf9..d877f035 100644 --- a/controllers/custom_wizard/wizard.rb +++ b/controllers/custom_wizard/wizard.rb @@ -1,55 +1,40 @@ # frozen_string_literal: true -class CustomWizard::WizardController < ::ApplicationController - include ApplicationHelper - prepend_view_path(Rails.root.join('plugins', 'discourse-custom-wizard', 'views')) - layout 'wizard' +class CustomWizard::WizardController < ::ActionController::Base + helper ApplicationHelper + include CurrentUser + include CanonicalURL::ControllerExtensions + include GlobalPath + + prepend_view_path(Rails.root.join('plugins', 'discourse-custom-wizard', 'views')) + layout :set_wizard_layout + + before_action :preload_wizard_json before_action :ensure_plugin_enabled before_action :update_subscription, only: [:index] before_action :ensure_logged_in, only: [:skip] + helper_method :wizard_page_title helper_method :wizard_theme_id helper_method :wizard_theme_lookup helper_method :wizard_theme_translations_lookup - def wizard - @builder = CustomWizard::Builder.new(params[:wizard_id].underscore, current_user) - @wizard ||= @builder.build - @wizard - end - - def wizard_page_title - wizard ? (wizard.name || wizard.id) : I18n.t('wizard.custom_title') - end - - def wizard_theme_id - wizard ? wizard.theme_id : nil - end - - def wizard_theme_lookup(name) - Theme.lookup_field(wizard_theme_id, mobile_view? ? :mobile : :desktop, name) - end - - def wizard_theme_translations_lookup - Theme.lookup_field(wizard_theme_id, :translations, I18n.locale) + def set_wizard_layout + action_name === 'qunit' ? 'qunit' : 'wizard' end def index respond_to do |format| format.json do - builder = CustomWizard::Builder.new(params[:wizard_id].underscore, current_user) - - if builder.wizard.present? - builder_opts = {} - builder_opts[:reset] = params[:reset] - built_wizard = builder.build(builder_opts, params) - - render_serialized(built_wizard, ::CustomWizard::WizardSerializer, root: false) + if wizard.present? + render json: CustomWizard::WizardSerializer.new(wizard, scope: guardian, root: false).as_json, status: 200 else render json: { error: I18n.t('wizard.none') } end end - format.html {} + format.html do + render "default/empty" + end end end @@ -61,9 +46,8 @@ class CustomWizard::WizardController < ::ApplicationController end result = success_json - user = current_user - if user && wizard.can_access? + if current_user && wizard.can_access? submission = wizard.current_submission if submission.present? && submission.redirect_to @@ -77,6 +61,64 @@ class CustomWizard::WizardController < ::ApplicationController render json: result end + def qunit + raise Discourse::InvalidAccess.new if Rails.env.production? + + respond_to do |format| + format.html do + render "default/empty" + end + end + end + + protected + + def ensure_logged_in + raise Discourse::NotLoggedIn.new unless current_user.present? + end + + def guardian + @guardian ||= Guardian.new(current_user, request) + end + + def wizard + @wizard ||= begin + builder = CustomWizard::Builder.new(params[:wizard_id].underscore, current_user) + return nil unless builder.present? + opts = {} + opts[:reset] = params[:reset] + builder.build(opts, params) + end + end + + def wizard_page_title + wizard ? (wizard.name || wizard.id) : I18n.t('wizard.custom_title') + end + + def wizard_theme_id + wizard ? wizard.theme_id : nil + end + + def wizard_theme_lookup(name) + Theme.lookup_field(wizard_theme_id, view_context.mobile_view? ? :mobile : :desktop, name) + end + + def wizard_theme_translations_lookup + Theme.lookup_field(wizard_theme_id, :translations, I18n.locale) + end + + def preload_wizard_json + return if request.xhr? || request.format.json? + return if request.method != "GET" + + store_preloaded("siteSettings", SiteSetting.client_settings_json) + end + + def store_preloaded(key, json) + @preloaded ||= {} + @preloaded[key] = json.gsub(" (app = CustomWizard.create({ rootElement: "#ember-testing" }))); - - if (!started) { - wizardInitializer.initialize(app); - stepInitializer.initialize(app); - fieldInitializer.initialize(app); - app.start(); - started = true; - } - app.setupForTesting(); - app.injectTestHelpers(); - return app; -} diff --git a/test/javascripts/plugin_helper.js b/test/javascripts/plugin_helper.js deleted file mode 100644 index 9b1558cd..00000000 --- a/test/javascripts/plugin_helper.js +++ /dev/null @@ -1,70 +0,0 @@ -// discourse-skip-module -/*global document, Logster, QUnit */ -console.log('starting test_helper') -window.Discourse = {}; -window.Wizard = {}; -Wizard.SiteSettings = {}; -Discourse.__widget_helpers = {}; -Discourse.SiteSettings = Wizard.SiteSettings; - -//= require env -//= require jquery.debug -//= require ember.debug -//= require locales/i18n -//= require locales/en -//= require route-recognizer -//= require fake_xml_http_request -//= require pretender -//= require qunit -//= require ember-qunit -//= require discourse-loader -//= require jquery.debug -//= require handlebars -//= require ember-template-compiler -//= require wizard-custom -//= require wizard-vendor -//= require_tree ./helpers -//= require_tree ./acceptance -//= require_tree ./models -//= require_tree ./components -//= require ./wizard-pretender -//= require test-shims -console.log ("end of require") -document.addEventListener("DOMContentLoaded", function () { - document.body.insertAdjacentHTML( - "afterbegin", - ` -
- - ` - ); -}); - -if (window.Logster) { - Logster.enabled = false; -} else { - window.Logster = { enabled: false }; -} -Ember.Test.adapter = window.QUnitAdapter.create(); - -/*let createPretendServer = requirejs("./wizard-pretender", null, null, false).default; - -let server; -QUnit.testStart(function () { - server = createPretendServer(); -}); - -QUnit.testDone(function () { - server.shutdown(); -});*/ - -let _testApp = requirejs("./helpers/start-app").default(); -let _buildResolver = requirejs("discourse-common/resolver").buildResolver; -window.setResolver(_buildResolver("wizard").create({ namespace: _testApp })); - -Object.keys(requirejs.entries).forEach(function (entry) { - if (/\-test/.test(entry)) { - requirejs(entry, null, null, true); - } -}); -console.log ("end of helper") diff --git a/views/layouts/qunit.html.erb b/views/layouts/qunit.html.erb new file mode 100644 index 00000000..c2f5fb5e --- /dev/null +++ b/views/layouts/qunit.html.erb @@ -0,0 +1,28 @@ + + + + Custom Wizard QUnit Test Runner + <%= discourse_stylesheet_link_tag(:test_helper, theme_id: nil) %> + <%= discourse_stylesheet_link_tag :wizard, theme_id: nil %> + <%= discourse_stylesheet_link_tag :wizard_custom %> + <%= preload_script "locales/en" %> + <%= preload_script "ember_jquery" %> + <%= preload_script "wizard-vendor" %> + <%= preload_script "wizard-custom" %> + <%= preload_script "wizard-raw-templates" %> + <%= preload_script "wizard-plugin" %> + <%= preload_script "pretty-text-bundle" %> + <%= preload_script "wizard-qunit" %> + <%= csrf_meta_tags %> + + + + <%= tag.meta id: 'data-discourse-setup', data: client_side_setup_data %> + + + + +
+
+ + diff --git a/views/layouts/wizard.html.erb b/views/layouts/wizard.html.erb index 16d119b7..f909ae84 100644 --- a/views/layouts/wizard.html.erb +++ b/views/layouts/wizard.html.erb @@ -11,10 +11,8 @@ <%= preload_script "locales/#{I18n.locale}" %> <%= preload_script "ember_jquery" %> <%= preload_script "wizard-vendor" %> - <%= preload_script "wizard-application" %> - <%= preload_script "wizard-custom-globals" %> - <%= preload_script "wizard-raw-templates" %> <%= preload_script "wizard-custom" %> + <%= preload_script "wizard-raw-templates" %> <%= preload_script "wizard-plugin" %> <%= preload_script "pretty-text-bundle" %> @@ -58,5 +56,7 @@ <%= raw SvgSprite.bundle %>
+ + From 835600c05498eed68a8f80b33c282aeaee4c8644 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 16 Mar 2022 12:46:16 +0100 Subject: [PATCH 04/11] Fix linting --- .../initializers/custom-wizard-edits.js.es6 | 2 +- .../components/custom-user-selector.js.es6 | 2 +- .../wizard/components/field-validators.js.es6 | 2 +- .../similar-topics-validator.js.es6 | 2 +- .../wizard/components/validator.js.es6 | 2 +- .../components/wizard-composer-editor.js.es6 | 2 +- .../wizard-composer-hyperlink.js.es6 | 2 +- .../components/wizard-date-input.js.es6 | 2 +- .../components/wizard-date-time-input.js.es6 | 2 +- .../components/wizard-field-category.js.es6 | 2 +- .../components/wizard-field-checkbox.js.es6 | 2 +- .../wizard-field-composer-preview.js.es6 | 2 +- .../components/wizard-field-composer.js.es6 | 2 +- .../components/wizard-field-date-time.js.es6 | 2 +- .../components/wizard-field-date.js.es6 | 2 +- .../components/wizard-field-dropdown.js.es6 | 2 +- .../components/wizard-field-group.js.es6 | 2 +- .../components/wizard-field-number.js.es6 | 2 +- .../wizard/components/wizard-field-tag.js.es6 | 2 +- .../components/wizard-field-text.js.es6 | 2 +- .../components/wizard-field-textarea.js.es6 | 2 +- .../components/wizard-field-time.js.es6 | 2 +- .../components/wizard-field-upload.js.es6 | 2 +- .../wizard/components/wizard-field-url.js.es6 | 2 +- .../wizard-field-user-selector.js.es6 | 2 +- .../wizard/components/wizard-field.js.es6 | 9 +- .../components/wizard-group-selector.js.es6 | 2 +- .../wizard/components/wizard-no-access.js.es6 | 8 +- .../components/wizard-similar-topics.js.es6 | 2 +- .../wizard/components/wizard-step.js.es6 | 4 +- .../components/wizard-time-input.js.es6 | 2 +- .../wizard/controllers/wizard-index.js.es6 | 14 +- .../lib/initialize/create-contexts.js.es6 | 6 +- .../lib/initialize/inject-objects.js.es6 | 31 +- .../lib/initialize/patch-components.js.es6 | 8 +- .../lib/initialize/register-files.js.es6 | 14 +- .../wizard/lib/initialize/wizard.js.es6 | 29 +- assets/javascripts/wizard/models/field.js.es6 | 2 +- assets/javascripts/wizard/models/step.js.es6 | 6 +- assets/javascripts/wizard/routes/step.js.es6 | 2 +- .../wizard/routes/wizard-index.js.es6 | 12 +- .../javascripts/wizard/routes/wizard.js.es6 | 5 +- .../wizard/tests/acceptance/field-test.js.es6 | 252 +++--- .../wizard/tests/acceptance/step-test.js.es6 | 78 +- .../tests/acceptance/wizard-test.js.es6 | 105 +-- .../wizard/tests/fixtures/categories.js.es6 | 400 +++++---- .../wizard/tests/fixtures/groups.js.es6 | 586 ++++++------ .../tests/fixtures/site-settings.js.es6 | 575 ++++++------ .../wizard/tests/fixtures/tags.js.es6 | 36 +- .../wizard/tests/fixtures/update.js.es6 | 8 +- .../wizard/tests/fixtures/user.js.es6 | 4 +- .../wizard/tests/fixtures/users.js.es6 | 20 +- .../wizard/tests/fixtures/wizard.js.es6 | 842 +++++++++--------- .../wizard/tests/helpers/acceptance.js.es6 | 18 +- .../wizard/tests/helpers/start-app.js.es6 | 12 +- .../wizard/tests/helpers/step.js.es6 | 15 +- .../wizard/tests/helpers/test.js.es6 | 4 +- .../wizard/tests/helpers/wizard.js.es6 | 18 +- .../javascripts/wizard/tests/pretender.js.es6 | 20 +- 59 files changed, 1635 insertions(+), 1564 deletions(-) diff --git a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 index 035fa6f2..6a027dee 100644 --- a/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 +++ b/assets/javascripts/discourse/initializers/custom-wizard-edits.js.es6 @@ -64,7 +64,7 @@ export default { this.set("customWizardCriticalNotices", criticalNotices); } }); - } + }, }); api.modifyClass("component:d-navigation", { diff --git a/assets/javascripts/wizard/components/custom-user-selector.js.es6 b/assets/javascripts/wizard/components/custom-user-selector.js.es6 index 1698a008..c53c3bf4 100644 --- a/assets/javascripts/wizard/components/custom-user-selector.js.es6 +++ b/assets/javascripts/wizard/components/custom-user-selector.js.es6 @@ -1,6 +1,6 @@ import { default as computed, - observes + observes, } from "discourse-common/utils/decorators"; import { renderAvatar } from "discourse/helpers/user-avatar"; import userSearch from "../lib/user-search"; diff --git a/assets/javascripts/wizard/components/field-validators.js.es6 b/assets/javascripts/wizard/components/field-validators.js.es6 index 15cfc181..7284241c 100644 --- a/assets/javascripts/wizard/components/field-validators.js.es6 +++ b/assets/javascripts/wizard/components/field-validators.js.es6 @@ -1,7 +1,7 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/field-validators', + layoutName: "wizard/templates/components/field-validators", actions: { perform() { diff --git a/assets/javascripts/wizard/components/similar-topics-validator.js.es6 b/assets/javascripts/wizard/components/similar-topics-validator.js.es6 index e5133d4f..4f722123 100644 --- a/assets/javascripts/wizard/components/similar-topics-validator.js.es6 +++ b/assets/javascripts/wizard/components/similar-topics-validator.js.es6 @@ -10,7 +10,7 @@ import { dasherize } from "@ember/string"; export default WizardFieldValidator.extend({ classNames: ["similar-topics-validator"], - layoutName: 'wizard/templates/components/similar-topics-validator', + layoutName: "wizard/templates/components/similar-topics-validator", similarTopics: null, hasInput: notEmpty("field.value"), hasSimilarTopics: notEmpty("similarTopics"), diff --git a/assets/javascripts/wizard/components/validator.js.es6 b/assets/javascripts/wizard/components/validator.js.es6 index ab442d97..dafbf8c0 100644 --- a/assets/javascripts/wizard/components/validator.js.es6 +++ b/assets/javascripts/wizard/components/validator.js.es6 @@ -6,7 +6,7 @@ import { getToken } from "wizard/lib/ajax"; export default Component.extend({ classNames: ["validator"], classNameBindings: ["isValid", "isInvalid"], - layoutName: 'wizard/templates/components/validator', + layoutName: "wizard/templates/components/validator", validMessageKey: null, invalidMessageKey: null, isValid: null, diff --git a/assets/javascripts/wizard/components/wizard-composer-editor.js.es6 b/assets/javascripts/wizard/components/wizard-composer-editor.js.es6 index 0bd003f5..4f44d439 100644 --- a/assets/javascripts/wizard/components/wizard-composer-editor.js.es6 +++ b/assets/javascripts/wizard/components/wizard-composer-editor.js.es6 @@ -13,7 +13,7 @@ import { uploadIcon } from "discourse/lib/uploads"; import { dasherize } from "@ember/string"; export default ComposerEditor.extend({ - layoutName: 'wizard/templates/components/wizard-composer-editor', + layoutName: "wizard/templates/components/wizard-composer-editor", classNameBindings: ["fieldClass"], allowUpload: true, showLink: false, diff --git a/assets/javascripts/wizard/components/wizard-composer-hyperlink.js.es6 b/assets/javascripts/wizard/components/wizard-composer-hyperlink.js.es6 index c700d3ce..0eeeb176 100644 --- a/assets/javascripts/wizard/components/wizard-composer-hyperlink.js.es6 +++ b/assets/javascripts/wizard/components/wizard-composer-hyperlink.js.es6 @@ -2,7 +2,7 @@ import Component from "@ember/component"; export default Component.extend({ classNames: ["wizard-composer-hyperlink"], - layoutName: 'wizard/templates/components/wizard-composer-hyperlink', + layoutName: "wizard/templates/components/wizard-composer-hyperlink", actions: { addLink() { diff --git a/assets/javascripts/wizard/components/wizard-date-input.js.es6 b/assets/javascripts/wizard/components/wizard-date-input.js.es6 index 375b7195..da2711c7 100644 --- a/assets/javascripts/wizard/components/wizard-date-input.js.es6 +++ b/assets/javascripts/wizard/components/wizard-date-input.js.es6 @@ -3,7 +3,7 @@ import discourseComputed from "discourse-common/utils/decorators"; export default DateInput.extend({ useNativePicker: false, - layoutName: 'wizard/templates/components/wizard-date-input', + layoutName: "wizard/templates/components/wizard-date-input", @discourseComputed() placeholder() { diff --git a/assets/javascripts/wizard/components/wizard-date-time-input.js.es6 b/assets/javascripts/wizard/components/wizard-date-time-input.js.es6 index 0fe1e68a..84a2b03e 100644 --- a/assets/javascripts/wizard/components/wizard-date-time-input.js.es6 +++ b/assets/javascripts/wizard/components/wizard-date-time-input.js.es6 @@ -2,7 +2,7 @@ import DateTimeInput from "discourse/components/date-time-input"; import discourseComputed from "discourse-common/utils/decorators"; export default DateTimeInput.extend({ - layoutName: 'wizard/templates/components/wizard-date-time-input', + layoutName: "wizard/templates/components/wizard-date-time-input", @discourseComputed("timeFirst", "tabindex") timeTabindex(timeFirst, tabindex) { diff --git a/assets/javascripts/wizard/components/wizard-field-category.js.es6 b/assets/javascripts/wizard/components/wizard-field-category.js.es6 index dc20538e..9f4b65ba 100644 --- a/assets/javascripts/wizard/components/wizard-field-category.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-category.js.es6 @@ -2,7 +2,7 @@ import { observes } from "discourse-common/utils/decorators"; import Category from "discourse/models/category"; export default Ember.Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-category', + layoutName: "wizard/templates/components/wizard-field-category", didInsertElement() { const property = this.field.property || "id"; diff --git a/assets/javascripts/wizard/components/wizard-field-checkbox.js.es6 b/assets/javascripts/wizard/components/wizard-field-checkbox.js.es6 index f9653cd2..6f9daba2 100644 --- a/assets/javascripts/wizard/components/wizard-field-checkbox.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-checkbox.js.es6 @@ -1,5 +1,5 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-checkbox' + layoutName: "wizard/templates/components/wizard-field-checkbox", }); diff --git a/assets/javascripts/wizard/components/wizard-field-composer-preview.js.es6 b/assets/javascripts/wizard/components/wizard-field-composer-preview.js.es6 index 0aee0d13..a2056a86 100644 --- a/assets/javascripts/wizard/components/wizard-field-composer-preview.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-composer-preview.js.es6 @@ -7,7 +7,7 @@ import { ajax } from "discourse/lib/ajax"; import { on } from "discourse-common/utils/decorators"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-composer-preview', + layoutName: "wizard/templates/components/wizard-field-composer-preview", @on("init") updatePreview() { diff --git a/assets/javascripts/wizard/components/wizard-field-composer.js.es6 b/assets/javascripts/wizard/components/wizard-field-composer.js.es6 index 0ef5fe20..07829e8a 100644 --- a/assets/javascripts/wizard/components/wizard-field-composer.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-composer.js.es6 @@ -5,7 +5,7 @@ import { import EmberObject from "@ember/object"; export default Ember.Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-composer', + layoutName: "wizard/templates/components/wizard-field-composer", showPreview: false, classNameBindings: [ diff --git a/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 b/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 index a916f18e..eee98892 100644 --- a/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-date-time.js.es6 @@ -2,7 +2,7 @@ import Component from "@ember/component"; import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-date-time', + layoutName: "wizard/templates/components/wizard-field-date-time", @observes("dateTime") setValue() { diff --git a/assets/javascripts/wizard/components/wizard-field-date.js.es6 b/assets/javascripts/wizard/components/wizard-field-date.js.es6 index a06d582a..df35638c 100644 --- a/assets/javascripts/wizard/components/wizard-field-date.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-date.js.es6 @@ -2,7 +2,7 @@ import Component from "@ember/component"; import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-date', + layoutName: "wizard/templates/components/wizard-field-date", @observes("date") setValue() { diff --git a/assets/javascripts/wizard/components/wizard-field-dropdown.js.es6 b/assets/javascripts/wizard/components/wizard-field-dropdown.js.es6 index 4b8b7e63..e6b08102 100644 --- a/assets/javascripts/wizard/components/wizard-field-dropdown.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-dropdown.js.es6 @@ -1,7 +1,7 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-dropdown', + layoutName: "wizard/templates/components/wizard-field-dropdown", keyPress(e) { e.stopPropagation(); diff --git a/assets/javascripts/wizard/components/wizard-field-group.js.es6 b/assets/javascripts/wizard/components/wizard-field-group.js.es6 index 93538071..65a19719 100644 --- a/assets/javascripts/wizard/components/wizard-field-group.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-group.js.es6 @@ -1,5 +1,5 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-group' + layoutName: "wizard/templates/components/wizard-field-group", }); diff --git a/assets/javascripts/wizard/components/wizard-field-number.js.es6 b/assets/javascripts/wizard/components/wizard-field-number.js.es6 index e7c4d77f..14e1bfcd 100644 --- a/assets/javascripts/wizard/components/wizard-field-number.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-number.js.es6 @@ -1,5 +1,5 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-number' + layoutName: "wizard/templates/components/wizard-field-number", }); diff --git a/assets/javascripts/wizard/components/wizard-field-tag.js.es6 b/assets/javascripts/wizard/components/wizard-field-tag.js.es6 index 45343522..473bba08 100644 --- a/assets/javascripts/wizard/components/wizard-field-tag.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-tag.js.es6 @@ -1,5 +1,5 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-tag' + layoutName: "wizard/templates/components/wizard-field-tag", }); diff --git a/assets/javascripts/wizard/components/wizard-field-text.js.es6 b/assets/javascripts/wizard/components/wizard-field-text.js.es6 index f9d5b056..d9e7cca8 100644 --- a/assets/javascripts/wizard/components/wizard-field-text.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-text.js.es6 @@ -1,7 +1,7 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-text', + layoutName: "wizard/templates/components/wizard-field-text", keyPress(e) { e.stopPropagation(); diff --git a/assets/javascripts/wizard/components/wizard-field-textarea.js.es6 b/assets/javascripts/wizard/components/wizard-field-textarea.js.es6 index 54865d3c..e59a1707 100644 --- a/assets/javascripts/wizard/components/wizard-field-textarea.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-textarea.js.es6 @@ -1,7 +1,7 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-textarea', + layoutName: "wizard/templates/components/wizard-field-textarea", keyPress(e) { e.stopPropagation(); diff --git a/assets/javascripts/wizard/components/wizard-field-time.js.es6 b/assets/javascripts/wizard/components/wizard-field-time.js.es6 index bf954ec4..a2f2a10d 100644 --- a/assets/javascripts/wizard/components/wizard-field-time.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-time.js.es6 @@ -2,7 +2,7 @@ import Component from "@ember/component"; import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-time', + layoutName: "wizard/templates/components/wizard-field-time", @observes("time") setValue() { diff --git a/assets/javascripts/wizard/components/wizard-field-upload.js.es6 b/assets/javascripts/wizard/components/wizard-field-upload.js.es6 index edadb4f0..4774e942 100644 --- a/assets/javascripts/wizard/components/wizard-field-upload.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-upload.js.es6 @@ -3,7 +3,7 @@ import Component from "@ember/component"; import { computed } from "@ember/object"; export default Component.extend(UppyUploadMixin, { - layoutName: 'wizard/templates/components/wizard-field-upload', + layoutName: "wizard/templates/components/wizard-field-upload", classNames: ["wizard-field-upload"], classNameBindings: ["isImage"], uploading: false, diff --git a/assets/javascripts/wizard/components/wizard-field-url.js.es6 b/assets/javascripts/wizard/components/wizard-field-url.js.es6 index 411b5fe9..96c10cc2 100644 --- a/assets/javascripts/wizard/components/wizard-field-url.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-url.js.es6 @@ -1,5 +1,5 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-url' + layoutName: "wizard/templates/components/wizard-field-url", }); diff --git a/assets/javascripts/wizard/components/wizard-field-user-selector.js.es6 b/assets/javascripts/wizard/components/wizard-field-user-selector.js.es6 index c2a32f44..7cf5b446 100644 --- a/assets/javascripts/wizard/components/wizard-field-user-selector.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-user-selector.js.es6 @@ -1,5 +1,5 @@ import Component from "@ember/component"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field-user-selector' + layoutName: "wizard/templates/components/wizard-field-user-selector", }); diff --git a/assets/javascripts/wizard/components/wizard-field.js.es6 b/assets/javascripts/wizard/components/wizard-field.js.es6 index 372ee182..493d7676 100644 --- a/assets/javascripts/wizard/components/wizard-field.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field.js.es6 @@ -4,8 +4,13 @@ import discourseComputed from "discourse-common/utils/decorators"; import { cook } from "discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite"; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-field', - classNameBindings: [":wizard-field", "typeClasses", "field.invalid", "field.id"], + layoutName: "wizard/templates/components/wizard-field", + classNameBindings: [ + ":wizard-field", + "typeClasses", + "field.invalid", + "field.id", + ], @discourseComputed("field.type", "field.id") typeClasses: (type, id) => diff --git a/assets/javascripts/wizard/components/wizard-group-selector.js.es6 b/assets/javascripts/wizard/components/wizard-group-selector.js.es6 index b7523f9a..4ff56ec9 100644 --- a/assets/javascripts/wizard/components/wizard-group-selector.js.es6 +++ b/assets/javascripts/wizard/components/wizard-group-selector.js.es6 @@ -3,7 +3,7 @@ import { computed } from "@ember/object"; import { makeArray } from "discourse-common/lib/helpers"; export default ComboBox.extend({ - layoutName: 'wizard/templates/components/wizard-group-selector', + layoutName: "wizard/templates/components/wizard-group-selector", content: computed("groups.[]", "field.content.[]", function () { const whitelist = makeArray(this.field.content); return this.groups diff --git a/assets/javascripts/wizard/components/wizard-no-access.js.es6 b/assets/javascripts/wizard/components/wizard-no-access.js.es6 index 78a23aa8..492a41dc 100644 --- a/assets/javascripts/wizard/components/wizard-no-access.js.es6 +++ b/assets/javascripts/wizard/components/wizard-no-access.js.es6 @@ -4,17 +4,17 @@ import Component from "@ember/component"; import { dasherize } from "@ember/string"; export default Component.extend({ - classNameBindings: [':wizard-no-access', 'reasonClass'], - layoutName: 'wizard/templates/components/wizard-no-access', + classNameBindings: [":wizard-no-access", "reasonClass"], + layoutName: "wizard/templates/components/wizard-no-access", - @discourseComputed('reason') + @discourseComputed("reason") reasonClass(reason) { return dasherize(reason); }, @discourseComputed siteName() { - return (this.siteSettings.title || ''); + return this.siteSettings.title || ""; }, actions: { diff --git a/assets/javascripts/wizard/components/wizard-similar-topics.js.es6 b/assets/javascripts/wizard/components/wizard-similar-topics.js.es6 index c52bfeae..6a56873e 100644 --- a/assets/javascripts/wizard/components/wizard-similar-topics.js.es6 +++ b/assets/javascripts/wizard/components/wizard-similar-topics.js.es6 @@ -4,7 +4,7 @@ import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ classNames: ["wizard-similar-topics"], - layoutName: 'wizard/templates/components/wizard-similar-topics', + layoutName: "wizard/templates/components/wizard-similar-topics", showTopics: true, didInsertElement() { diff --git a/assets/javascripts/wizard/components/wizard-step.js.es6 b/assets/javascripts/wizard/components/wizard-step.js.es6 index 4518afee..18b1a255 100644 --- a/assets/javascripts/wizard/components/wizard-step.js.es6 +++ b/assets/javascripts/wizard/components/wizard-step.js.es6 @@ -12,7 +12,7 @@ import CustomWizard from "../models/wizard"; const alreadyWarned = {}; export default Component.extend({ - layoutName: 'wizard/templates/components/wizard-step', + layoutName: "wizard/templates/components/wizard-step", classNameBindings: [":wizard-step", "step.id"], saving: null, @@ -27,7 +27,7 @@ export default Component.extend({ }, @discourseComputed("step.index", "wizard.required") - showQuitButton: (index, required) => (index === 0 && !required), + showQuitButton: (index, required) => index === 0 && !required, showNextButton: not("step.final"), showDoneButton: alias("step.final"), diff --git a/assets/javascripts/wizard/components/wizard-time-input.js.es6 b/assets/javascripts/wizard/components/wizard-time-input.js.es6 index ec121002..14b08288 100644 --- a/assets/javascripts/wizard/components/wizard-time-input.js.es6 +++ b/assets/javascripts/wizard/components/wizard-time-input.js.es6 @@ -1,5 +1,5 @@ import TimeInput from "discourse/components/time-input"; export default TimeInput.extend({ - layoutName: 'wizard/templates/components/wizard-time-input' + layoutName: "wizard/templates/components/wizard-time-input", }); diff --git a/assets/javascripts/wizard/controllers/wizard-index.js.es6 b/assets/javascripts/wizard/controllers/wizard-index.js.es6 index 2dfdee40..f56db02d 100644 --- a/assets/javascripts/wizard/controllers/wizard-index.js.es6 +++ b/assets/javascripts/wizard/controllers/wizard-index.js.es6 @@ -6,19 +6,19 @@ const reasons = { noWizard: "none", requiresLogin: "requires_login", notPermitted: "not_permitted", - completed: "completed" -} + completed: "completed", +}; export default Controller.extend({ - noAccess: or('noWizard', 'requiresLogin', 'notPermitted', 'completed'), + noAccess: or("noWizard", "requiresLogin", "notPermitted", "completed"), - @discourseComputed('noAccessReason') + @discourseComputed("noAccessReason") noAccessI18nKey(reason) { - return reason ? `wizard.${reasons[reason]}` : 'wizard.none'; + return reason ? `wizard.${reasons[reason]}` : "wizard.none"; }, @discourseComputed noAccessReason() { - return Object.keys(reasons).find(reason => this.get(reason)); - } + return Object.keys(reasons).find((reason) => this.get(reason)); + }, }); diff --git a/assets/javascripts/wizard/lib/initialize/create-contexts.js.es6 b/assets/javascripts/wizard/lib/initialize/create-contexts.js.es6 index 022ac48e..0e637f6c 100644 --- a/assets/javascripts/wizard/lib/initialize/create-contexts.js.es6 +++ b/assets/javascripts/wizard/lib/initialize/create-contexts.js.es6 @@ -3,10 +3,10 @@ export default { const { createHelperContext } = requirejs("discourse-common/lib/helpers"); createHelperContext({ - siteSettings: container.lookup('site-settings:main'), + siteSettings: container.lookup("site-settings:main"), site: container.lookup("site:main"), session: container.lookup("session:main"), capabilities: container.lookup("capabilities:main"), }); - } -} + }, +}; diff --git a/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 b/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 index d31efb4d..fb11c9e7 100644 --- a/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 +++ b/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 @@ -1,5 +1,5 @@ export default { - run(app, container) { + run(app) { const Store = requirejs("discourse/services/store").default; const Site = requirejs( "discourse/plugins/discourse-custom-wizard/wizard/models/site" @@ -7,7 +7,9 @@ export default { const Session = requirejs("discourse/models/session").default; const RestAdapter = requirejs("discourse/adapters/rest").default; const messageBus = requirejs("message-bus-client").default; - const sniffCapabilites = requirejs("discourse/pre-initializers/sniff-capabilities").default; + const sniffCapabilites = requirejs( + "discourse/pre-initializers/sniff-capabilities" + ).default; const site = Site.current(); const session = Session.current(); @@ -17,26 +19,35 @@ export default { ["site:main", site, false], ["session:main", session, false], ["service:store", Store, true], - ["adapter:rest", RestAdapter, true] + ["adapter:rest", RestAdapter, true], ]; - registrations.forEach(registration => { + registrations.forEach((registration) => { if (!app.hasRegistration(registration[0])) { - app.register(registration[0], registration[1], { instantiate: registration[2] }); + app.register(registration[0], registration[1], { + instantiate: registration[2], + }); } }); - const targets = ["controller", "component", "route", "model", "adapter", "mixin"]; + const targets = [ + "controller", + "component", + "route", + "model", + "adapter", + "mixin", + ]; const injections = [ ["siteSettings", "site-settings:main"], ["messageBus", "message-bus:main"], ["site", "site:main"], ["session", "session:main"], ["store", "service:store"], - ["appEvents", "service:app-events"] + ["appEvents", "service:app-events"], ]; - injections.forEach(injection => { + injections.forEach((injection) => { targets.forEach((t) => app.inject(t, injection[0], injection[1])); }); @@ -45,5 +56,5 @@ export default { } site.set("can_create_tag", false); - } -} + }, +}; diff --git a/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 b/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 index 65086e53..75cc63f1 100644 --- a/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 +++ b/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 @@ -1,11 +1,13 @@ export default { run(app, container) { const getToken = requirejs("wizard/lib/ajax").getToken; - const isTesting = requirejs("discourse-common/config/environment").isTesting; + const isTesting = requirejs("discourse-common/config/environment") + .isTesting; - if (!isTesting) { + if (!isTesting()) { // Add a CSRF token to all AJAX requests let token = getToken(); + const session = container.lookup("session:main"); session.set("csrfToken", token); let callbacks = $.Callbacks(); $.ajaxPrefilter(callbacks.fire); @@ -140,5 +142,5 @@ export default { return resArray; }; } - } + }, }; diff --git a/assets/javascripts/wizard/lib/initialize/register-files.js.es6 b/assets/javascripts/wizard/lib/initialize/register-files.js.es6 index 8d4b850e..85079270 100644 --- a/assets/javascripts/wizard/lib/initialize/register-files.js.es6 +++ b/assets/javascripts/wizard/lib/initialize/register-files.js.es6 @@ -1,10 +1,14 @@ export default { run(app, container) { - const RawHandlebars = requirejs("discourse-common/lib/raw-handlebars").default; + const RawHandlebars = requirejs("discourse-common/lib/raw-handlebars") + .default; const Handlebars = requirejs("handlebars").default; - const registerRawHelpers = requirejs("discourse-common/lib/raw-handlebars-helpers").registerRawHelpers; + const registerRawHelpers = requirejs( + "discourse-common/lib/raw-handlebars-helpers" + ).registerRawHelpers; const { registerHelpers } = requirejs("discourse-common/lib/helpers"); - const jqueryPlugins = requirejs("discourse/initializers/jquery-plugins").default; + const jqueryPlugins = requirejs("discourse/initializers/jquery-plugins") + .default; Object.keys(Ember.TEMPLATES).forEach((k) => { if (k.indexOf("select-kit") === 0) { @@ -22,5 +26,5 @@ export default { registerRawHelpers(RawHandlebars, Handlebars); registerHelpers(app); jqueryPlugins.initialize(container, app); - } -} + }, +}; diff --git a/assets/javascripts/wizard/lib/initialize/wizard.js.es6 b/assets/javascripts/wizard/lib/initialize/wizard.js.es6 index 134257a1..0020f7a8 100644 --- a/assets/javascripts/wizard/lib/initialize/wizard.js.es6 +++ b/assets/javascripts/wizard/lib/initialize/wizard.js.es6 @@ -1,7 +1,8 @@ export default { name: "custom-wizard", initialize(app) { - const isTesting = requirejs("discourse-common/config/environment").isTesting; + const isTesting = requirejs("discourse-common/config/environment") + .isTesting; const isWizard = window.location.pathname.indexOf("/w/") > -1; if (!isWizard && !isTesting()) { @@ -9,14 +10,17 @@ export default { } const container = app.__container__; - const setDefaultOwner = requirejs("discourse-common/lib/get-owner").setDefaultOwner; + const setDefaultOwner = requirejs("discourse-common/lib/get-owner") + .setDefaultOwner; setDefaultOwner(container); if (!isTesting()) { const PreloadStore = requirejs("discourse/lib/preload-store").default; let preloaded; - const preloadedDataElement = document.getElementById("data-preloaded-wizard"); + const preloadedDataElement = document.getElementById( + "data-preloaded-wizard" + ); if (preloadedDataElement) { preloaded = JSON.parse(preloadedDataElement.dataset.preloadedWizard); } @@ -28,7 +32,8 @@ export default { app.SiteSettings = PreloadStore.get("siteSettings"); } - const setEnvironment = requirejs("discourse-common/config/environment").setEnvironment; + const setEnvironment = requirejs("discourse-common/config/environment") + .setEnvironment; const setupData = document.getElementById("data-discourse-setup").dataset; setEnvironment(setupData.environment); @@ -37,13 +42,15 @@ export default { session.set("highlightJsPath", setupData.highlightJsPath); [ - 'register-files', - 'inject-objects', - 'create-contexts', - 'patch-components' - ].forEach(fileName => { - const initializer = requirejs(`discourse/plugins/discourse-custom-wizard/wizard/lib/initialize/${fileName}`).default; + "register-files", + "inject-objects", + "create-contexts", + "patch-components", + ].forEach((fileName) => { + const initializer = requirejs( + `discourse/plugins/discourse-custom-wizard/wizard/lib/initialize/${fileName}` + ).default; initializer.run(app, container); }); - } + }, }; diff --git a/assets/javascripts/wizard/models/field.js.es6 b/assets/javascripts/wizard/models/field.js.es6 index 5f76074e..2b88140e 100644 --- a/assets/javascripts/wizard/models/field.js.es6 +++ b/assets/javascripts/wizard/models/field.js.es6 @@ -75,5 +75,5 @@ export default EmberObject.extend(ValidState, { this.setValid(valid); return valid; - } + }, }); diff --git a/assets/javascripts/wizard/models/step.js.es6 b/assets/javascripts/wizard/models/step.js.es6 index e18657b5..2729e993 100644 --- a/assets/javascripts/wizard/models/step.js.es6 +++ b/assets/javascripts/wizard/models/step.js.es6 @@ -71,11 +71,7 @@ export default EmberObject.extend(ValidState, { type: "PUT", data: { fields }, }).catch((response) => { - if ( - response && - response.responseJSON && - response.responseJSON.errors - ) { + if (response && response.responseJSON && response.responseJSON.errors) { let wizardErrors = []; response.responseJSON.errors.forEach((err) => { if (err.field === wizardId) { diff --git a/assets/javascripts/wizard/routes/step.js.es6 b/assets/javascripts/wizard/routes/step.js.es6 index 2454fc95..a076951f 100644 --- a/assets/javascripts/wizard/routes/step.js.es6 +++ b/assets/javascripts/wizard/routes/step.js.es6 @@ -26,7 +26,7 @@ export default Route.extend({ }, renderTemplate() { - this.render('wizard/templates/step'); + this.render("wizard/templates/step"); }, setupController(controller, model) { diff --git a/assets/javascripts/wizard/routes/wizard-index.js.es6 b/assets/javascripts/wizard/routes/wizard-index.js.es6 index 16b1140a..264cb0a2 100644 --- a/assets/javascripts/wizard/routes/wizard-index.js.es6 +++ b/assets/javascripts/wizard/routes/wizard-index.js.es6 @@ -4,7 +4,13 @@ import Route from "@ember/routing/route"; export default Route.extend({ beforeModel() { const wizard = getCachedWizard(); - if (wizard && wizard.user && wizard.permitted && !wizard.completed && wizard.start) { + if ( + wizard && + wizard.user && + wizard.permitted && + !wizard.completed && + wizard.start + ) { this.replaceWith("step", wizard.start); } }, @@ -14,7 +20,7 @@ export default Route.extend({ }, renderTemplate() { - this.render('wizard/templates/wizard-index'); + this.render("wizard/templates/wizard-index"); }, setupController(controller, model) { @@ -39,5 +45,5 @@ export default Route.extend({ } else { controller.set("noWizard", true); } - } + }, }); diff --git a/assets/javascripts/wizard/routes/wizard.js.es6 b/assets/javascripts/wizard/routes/wizard.js.es6 index 2910ee6d..a2c34f13 100644 --- a/assets/javascripts/wizard/routes/wizard.js.es6 +++ b/assets/javascripts/wizard/routes/wizard.js.es6 @@ -1,5 +1,4 @@ import { findCustomWizard, updateCachedWizard } from "../models/wizard"; -import { ajax } from "wizard/lib/ajax"; import WizardI18n from "../lib/wizard-i18n"; import Route from "@ember/routing/route"; import { scheduleOnce } from "@ember/runloop"; @@ -20,7 +19,7 @@ export default Route.extend({ const title = WizardI18n("wizard.incomplete_submission.title", { date: moment(wizardModel.submission_last_updated_at).format( "MMMM Do YYYY" - ) + ), }); const buttons = [ @@ -49,7 +48,7 @@ export default Route.extend({ }, renderTemplate() { - this.render('wizard/templates/wizard'); + this.render("wizard/templates/wizard"); }, setupController(controller, model) { diff --git a/assets/javascripts/wizard/tests/acceptance/field-test.js.es6 b/assets/javascripts/wizard/tests/acceptance/field-test.js.es6 index f73d1ab7..9300fc09 100644 --- a/assets/javascripts/wizard/tests/acceptance/field-test.js.es6 +++ b/assets/javascripts/wizard/tests/acceptance/field-test.js.es6 @@ -1,135 +1,173 @@ -import { - visit, - click, - fillIn, - triggerKeyEvent -} from "@ember/test-helpers"; +import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers"; import { test } from "qunit"; import { exists } from "../helpers/test"; import acceptance, { - query, count, + query, + server, visible, - server } from "../helpers/acceptance"; -import { - allFieldsWizard, - getWizard -} from "../helpers/wizard"; +import { allFieldsWizard, getWizard } from "../helpers/wizard"; import tagsJson from "../fixtures/tags"; import usersJson from "../fixtures/users"; import { response } from "../pretender"; -acceptance("Field | Fields", [ getWizard(allFieldsWizard) ], - function(hooks) { - test("Text", async function (assert) { - await visit("/wizard"); - assert.ok(exists(".wizard-field.text-field input.wizard-focusable")); - }); +acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () { + test("Text", async function (assert) { + await visit("/wizard"); + assert.ok(exists(".wizard-field.text-field input.wizard-focusable")); + }); - test("Textarea", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.textarea-field textarea.wizard-focusable")); - }); + test("Textarea", async function (assert) { + await visit("/wizard"); + assert.ok( + visible(".wizard-field.textarea-field textarea.wizard-focusable") + ); + }); - test("Composer", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.composer-field .wizard-field-composer textarea")); - assert.strictEqual(count(".wizard-field.composer-field .d-editor-button-bar button"), 8); - assert.ok(visible(".wizard-btn.toggle-preview")); + test("Composer", async function (assert) { + await visit("/wizard"); + assert.ok( + visible(".wizard-field.composer-field .wizard-field-composer textarea") + ); + assert.strictEqual( + count(".wizard-field.composer-field .d-editor-button-bar button"), + 8 + ); + assert.ok(visible(".wizard-btn.toggle-preview")); - await fillIn(".wizard-field.composer-field .wizard-field-composer textarea", "Input in composer"); - await click(".wizard-btn.toggle-preview"); - assert.strictEqual(query('.wizard-field.composer-field .wizard-field-composer .d-editor-preview-wrapper p').textContent.trim(), "Input in composer"); - }); + await fillIn( + ".wizard-field.composer-field .wizard-field-composer textarea", + "Input in composer" + ); + await click(".wizard-btn.toggle-preview"); + assert.strictEqual( + query( + ".wizard-field.composer-field .wizard-field-composer .d-editor-preview-wrapper p" + ).textContent.trim(), + "Input in composer" + ); + }); - test("Text Only", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.text-only-field label.field-label")); - }); + test("Text Only", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.text-only-field label.field-label")); + }); - test("Date", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.date-field input.date-picker")); - await click(".wizard-field.date-field input.date-picker"); - assert.ok(visible(".wizard-field.date-field .pika-single")); - }); + test("Date", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.date-field input.date-picker")); + await click(".wizard-field.date-field input.date-picker"); + assert.ok(visible(".wizard-field.date-field .pika-single")); + }); - test("Time", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.time-field .d-time-input .select-kit")); - await click(".wizard-field.time-field .d-time-input .select-kit .select-kit-header"); - assert.ok(visible(".wizard-field.time-field .select-kit-collection")); - }); + test("Time", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.time-field .d-time-input .select-kit")); + await click( + ".wizard-field.time-field .d-time-input .select-kit .select-kit-header" + ); + assert.ok(visible(".wizard-field.time-field .select-kit-collection")); + }); - test("Date Time", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.date-time-field .d-date-time-input .select-kit")); - await click(".wizard-field.date-time-field .d-date-input input.date-picker"); - assert.ok(visible(".wizard-field.date-time-field .d-date-input .pika-single")); - await click(".wizard-field.date-time-field .d-time-input .select-kit .select-kit-header"); - assert.ok(visible(".wizard-field.date-time-field .select-kit-collection")); - }); + test("Date Time", async function (assert) { + await visit("/wizard"); + assert.ok( + visible(".wizard-field.date-time-field .d-date-time-input .select-kit") + ); + await click( + ".wizard-field.date-time-field .d-date-input input.date-picker" + ); + assert.ok( + visible(".wizard-field.date-time-field .d-date-input .pika-single") + ); + await click( + ".wizard-field.date-time-field .d-time-input .select-kit .select-kit-header" + ); + assert.ok(visible(".wizard-field.date-time-field .select-kit-collection")); + }); - test("Number", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.number-field input[type='number']")); - }); + test("Number", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.number-field input[type='number']")); + }); - test("Checkbox", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.checkbox-field input[type='checkbox']")); - }); + test("Checkbox", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.checkbox-field input[type='checkbox']")); + }); - test("Url", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.url-field input[type='text']")); - }); + test("Url", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.url-field input[type='text']")); + }); - test("Upload", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.upload-field label.wizard-btn-upload-file")); - assert.ok(exists(".wizard-field.upload-field input.hidden-upload-field")); - }); + test("Upload", async function (assert) { + await visit("/wizard"); + assert.ok( + visible(".wizard-field.upload-field label.wizard-btn-upload-file") + ); + assert.ok(exists(".wizard-field.upload-field input.hidden-upload-field")); + }); - test("Dropdown", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.dropdown-field .single-select-header")); - await click(".wizard-field.dropdown-field .select-kit-header"); - assert.strictEqual(count(".wizard-field.dropdown-field .select-kit-collection li"), 3); - }); + test("Dropdown", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.dropdown-field .single-select-header")); + await click(".wizard-field.dropdown-field .select-kit-header"); + assert.strictEqual( + count(".wizard-field.dropdown-field .select-kit-collection li"), + 3 + ); + }); - test("Tag", async function (assert) { - server.get("/tags/filter/search", () => (response(200, { results: tagsJson['tags']}))); - await visit("/wizard"); - assert.ok(visible(".wizard-field.tag-field .multi-select-header")); - await click(".wizard-field.tag-field .select-kit-header"); - assert.strictEqual(count(".wizard-field.tag-field .select-kit-collection li"), 2); - }); + test("Tag", async function (assert) { + server.get("/tags/filter/search", () => + response(200, { results: tagsJson["tags"] }) + ); + await visit("/wizard"); + assert.ok(visible(".wizard-field.tag-field .multi-select-header")); + await click(".wizard-field.tag-field .select-kit-header"); + assert.strictEqual( + count(".wizard-field.tag-field .select-kit-collection li"), + 2 + ); + }); - test("Category", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.category-field .multi-select-header")); - await click(".wizard-field.category-field .select-kit-header"); - assert.strictEqual(count(".wizard-field.category-field .select-kit-collection li"), 5); - }); + test("Category", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.category-field .multi-select-header")); + await click(".wizard-field.category-field .select-kit-header"); + assert.strictEqual( + count(".wizard-field.category-field .select-kit-collection li"), + 5 + ); + }); - test("Group", async function (assert) { - await visit("/wizard"); - assert.ok(visible(".wizard-field.group-field .single-select-header")); - await click(".wizard-field.group-field .select-kit-header"); - assert.strictEqual(count(".wizard-field.group-field .select-kit-collection li"), 10); - }); + test("Group", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-field.group-field .single-select-header")); + await click(".wizard-field.group-field .select-kit-header"); + assert.strictEqual( + count(".wizard-field.group-field .select-kit-collection li"), + 10 + ); + }); - test("User", async function (assert) { - server.get("/u/search/users", () => (response(200, usersJson))); + test("User", async function (assert) { + server.get("/u/search/users", () => response(200, usersJson)); - await visit("/wizard"); - await fillIn(".wizard-field.user-selector-field input.ember-text-field", "a"); - await triggerKeyEvent(".wizard-field.user-selector-field input.ember-text-field", "keyup", "a".charCodeAt(0)); + await visit("/wizard"); + await fillIn( + ".wizard-field.user-selector-field input.ember-text-field", + "a" + ); + await triggerKeyEvent( + ".wizard-field.user-selector-field input.ember-text-field", + "keyup", + "a".charCodeAt(0) + ); - assert.ok(visible(".wizard-field.user-selector-field .ac-wrap")); - // TODO: add assertion for ac results. autocomplete does not appear in time. - }); - } -); + assert.ok(visible(".wizard-field.user-selector-field .ac-wrap")); + // TODO: add assertion for ac results. autocomplete does not appear in time. + }); +}); diff --git a/assets/javascripts/wizard/tests/acceptance/step-test.js.es6 b/assets/javascripts/wizard/tests/acceptance/step-test.js.es6 index 731c9b76..1537f1c7 100644 --- a/assets/javascripts/wizard/tests/acceptance/step-test.js.es6 +++ b/assets/javascripts/wizard/tests/acceptance/step-test.js.es6 @@ -1,47 +1,41 @@ -import { visit, click } from "@ember/test-helpers"; +import { click, visit } from "@ember/test-helpers"; import { test } from "qunit"; import { exists } from "../helpers/test"; -import acceptance, { - query, - count, - visible -} from "../helpers/acceptance"; -import { - stepNotPermitted, - wizard, - getWizard -} from "../helpers/wizard"; -import { - saveStep, - update -} from "../helpers/step"; +import acceptance, { count, query, visible } from "../helpers/acceptance"; +import { getWizard, stepNotPermitted, wizard } from "../helpers/wizard"; +import { saveStep, update } from "../helpers/step"; -acceptance("Step | Not permitted", [ getWizard(stepNotPermitted) ], - function(hooks) { - test("Shows not permitted message", async function (assert) { - await visit("/wizard"); - assert.ok(exists(".step-message.not-permitted")); - }); - } -); +acceptance("Step | Not permitted", [getWizard(stepNotPermitted)], function () { + test("Shows not permitted message", async function (assert) { + await visit("/wizard"); + assert.ok(exists(".step-message.not-permitted")); + }); +}); -acceptance("Step | Step", [ getWizard(wizard), saveStep(update) ], - function(hooks) { - test("Renders the step", async function (assert) { - await visit("/wizard"); - assert.strictEqual(query('.wizard-step-title p').textContent.trim(), "Text"); - assert.strictEqual(query('.wizard-step-description p').textContent.trim(), "Text inputs!"); - assert.strictEqual(query('.wizard-step-description p').textContent.trim(), "Text inputs!"); - assert.strictEqual(count('.wizard-step-form .wizard-field'), 6); - assert.ok(visible('.wizard-step-footer .wizard-progress'), true); - assert.ok(visible('.wizard-step-footer .wizard-buttons'), true); - }); +acceptance("Step | Step", [getWizard(wizard), saveStep(update)], function () { + test("Renders the step", async function (assert) { + await visit("/wizard"); + assert.strictEqual( + query(".wizard-step-title p").textContent.trim(), + "Text" + ); + assert.strictEqual( + query(".wizard-step-description p").textContent.trim(), + "Text inputs!" + ); + assert.strictEqual( + query(".wizard-step-description p").textContent.trim(), + "Text inputs!" + ); + assert.strictEqual(count(".wizard-step-form .wizard-field"), 6); + assert.ok(visible(".wizard-step-footer .wizard-progress"), true); + assert.ok(visible(".wizard-step-footer .wizard-buttons"), true); + }); - test("Goes to the next step", async function (assert) { - await visit("/wizard"); - assert.ok(visible('.wizard-step.step_1'), true); - await click('.wizard-btn.next'); - assert.ok(visible('.wizard-step.step_2'), true); - }); - } -); + test("Goes to the next step", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-step.step_1"), true); + await click(".wizard-btn.next"); + assert.ok(visible(".wizard-step.step_2"), true); + }); +}); diff --git a/assets/javascripts/wizard/tests/acceptance/wizard-test.js.es6 b/assets/javascripts/wizard/tests/acceptance/wizard-test.js.es6 index e68f59ae..8fd82d11 100644 --- a/assets/javascripts/wizard/tests/acceptance/wizard-test.js.es6 +++ b/assets/javascripts/wizard/tests/acceptance/wizard-test.js.es6 @@ -1,30 +1,26 @@ import { visit } from "@ember/test-helpers"; import { test } from "qunit"; import { exists } from "../helpers/test"; -import acceptance, { - query, - count, - visible -} from "../helpers/acceptance"; +import acceptance, { count, query, visible } from "../helpers/acceptance"; import { + getWizard, + wizard, + wizardCompleted, wizardNoUser, wizardNotPermitted, - wizardCompleted, - wizard, - getWizard } from "../helpers/wizard"; -acceptance("Wizard | Not logged in", [ getWizard(wizardNoUser) ], - function(hooks) { - test("Wizard no access requires login", async function (assert) { - await visit("/wizard"); - assert.ok(exists(".wizard-no-access.requires-login")); - }); - } -); +acceptance("Wizard | Not logged in", [getWizard(wizardNoUser)], function () { + test("Wizard no access requires login", async function (assert) { + await visit("/wizard"); + assert.ok(exists(".wizard-no-access.requires-login")); + }); +}); -acceptance("Wizard | Not permitted", [ getWizard(wizardNotPermitted) ], - function(hooks) { +acceptance( + "Wizard | Not permitted", + [getWizard(wizardNotPermitted)], + function () { test("Wizard no access not permitted", async function (assert) { await visit("/wizard"); assert.ok(exists(".wizard-no-access.not-permitted")); @@ -32,41 +28,46 @@ acceptance("Wizard | Not permitted", [ getWizard(wizardNotPermitted) ], } ); -acceptance("Wizard | Completed", [ getWizard(wizardCompleted) ], - function(hooks) { - test("Wizard no access completed", async function (assert) { - await visit("/wizard"); - assert.ok(exists(".wizard-no-access.completed")); - }); - } -); +acceptance("Wizard | Completed", [getWizard(wizardCompleted)], function () { + test("Wizard no access completed", async function (assert) { + await visit("/wizard"); + assert.ok(exists(".wizard-no-access.completed")); + }); +}); -acceptance("Wizard | Wizard", [ getWizard(wizard) ], - function(hooks) { - test("Starts", async function (assert) { - await visit("/wizard"); - assert.ok(query('.wizard-column'), true); - }); +acceptance("Wizard | Wizard", [getWizard(wizard)], function () { + test("Starts", async function (assert) { + await visit("/wizard"); + assert.ok(query(".wizard-column"), true); + }); - test("Applies the body background color", async function (assert) { - await visit("/wizard"); - assert.ok($("body")[0].style.background); - }); + test("Applies the body background color", async function (assert) { + await visit("/wizard"); + assert.ok($("body")[0].style.background); + }); - test("Renders the wizard form", async function (assert) { - await visit("/wizard"); - assert.ok(visible('.wizard-column-contents .wizard-step'), true); - assert.ok(visible('.wizard-footer img'), true); - }); + test("Renders the wizard form", async function (assert) { + await visit("/wizard"); + assert.ok(visible(".wizard-column-contents .wizard-step"), true); + assert.ok(visible(".wizard-footer img"), true); + }); - test("Renders the first step", async function (assert) { - await visit("/wizard"); - assert.strictEqual(query('.wizard-step-title p').textContent.trim(), "Text"); - assert.strictEqual(query('.wizard-step-description p').textContent.trim(), "Text inputs!"); - assert.strictEqual(query('.wizard-step-description p').textContent.trim(), "Text inputs!"); - assert.strictEqual(count('.wizard-step-form .wizard-field'), 6); - assert.ok(visible('.wizard-step-footer .wizard-progress'), true); - assert.ok(visible('.wizard-step-footer .wizard-buttons'), true); - }); - } -); + test("Renders the first step", async function (assert) { + await visit("/wizard"); + assert.strictEqual( + query(".wizard-step-title p").textContent.trim(), + "Text" + ); + assert.strictEqual( + query(".wizard-step-description p").textContent.trim(), + "Text inputs!" + ); + assert.strictEqual( + query(".wizard-step-description p").textContent.trim(), + "Text inputs!" + ); + assert.strictEqual(count(".wizard-step-form .wizard-field"), 6); + assert.ok(visible(".wizard-step-footer .wizard-progress"), true); + assert.ok(visible(".wizard-step-footer .wizard-buttons"), true); + }); +}); diff --git a/assets/javascripts/wizard/tests/fixtures/categories.js.es6 b/assets/javascripts/wizard/tests/fixtures/categories.js.es6 index e862f54a..e553f860 100644 --- a/assets/javascripts/wizard/tests/fixtures/categories.js.es6 +++ b/assets/javascripts/wizard/tests/fixtures/categories.js.es6 @@ -1,209 +1,221 @@ export default { - "categories": [ + categories: [ { - "id": 1, - "name": "Uncategorized", - "color": "0088CC", - "text_color": "FFFFFF", - "slug": "uncategorized", - "topic_count": 1, - "post_count": 1, - "position": 0, - "description": "Topics that don't need a category, or don't fit into any other existing category.", - "description_text": "Topics that don't need a category, or don't fit into any other existing category.", - "description_excerpt": "Topics that don't need a category, or don't fit into any other existing category.", - "topic_url": "/t/", - "read_restricted": false, - "permission": 1, - "notification_level": 0, - "topic_template": null, - "has_children": false, - "sort_order": null, - "sort_ascending": null, - "show_subcategory_list": false, - "num_featured_topics": 3, - "default_view": null, - "subcategory_list_style": "rows_with_featured_topics", - "default_top_period": "all", - "default_list_filter": "all", - "minimum_required_tags": 0, - "navigate_to_first_post_after_read": false, - "custom_fields": { - "create_topic_wizard": null + id: 1, + name: "Uncategorized", + color: "0088CC", + text_color: "FFFFFF", + slug: "uncategorized", + topic_count: 1, + post_count: 1, + position: 0, + description: + "Topics that don't need a category, or don't fit into any other existing category.", + description_text: + "Topics that don't need a category, or don't fit into any other existing category.", + description_excerpt: + "Topics that don't need a category, or don't fit into any other existing category.", + topic_url: "/t/", + read_restricted: false, + permission: 1, + notification_level: 0, + topic_template: null, + has_children: false, + sort_order: null, + sort_ascending: null, + show_subcategory_list: false, + num_featured_topics: 3, + default_view: null, + subcategory_list_style: "rows_with_featured_topics", + default_top_period: "all", + default_list_filter: "all", + minimum_required_tags: 0, + navigate_to_first_post_after_read: false, + custom_fields: { + create_topic_wizard: null, }, - "allowed_tags": [], - "allowed_tag_groups": [], - "allow_global_tags": false, - "min_tags_from_required_group": 1, - "required_tag_group_name": null, - "read_only_banner": null, - "uploaded_logo": null, - "uploaded_background": null, - "can_edit": true + allowed_tags: [], + allowed_tag_groups: [], + allow_global_tags: false, + min_tags_from_required_group: 1, + required_tag_group_name: null, + read_only_banner: null, + uploaded_logo: null, + uploaded_background: null, + can_edit: true, }, { - "id": 2, - "name": "Site Feedback", - "color": "808281", - "text_color": "FFFFFF", - "slug": "site-feedback", - "topic_count": 20, - "post_count": 21, - "position": 1, - "description": "

Discussion about this site, its organization, how it works, and how we can improve it.

", - "description_text": "Discussion about this site, its organization, how it works, and how we can improve it.", - "description_excerpt": "Discussion about this site, its organization, how it works, and how we can improve it.", - "topic_url": "/t/about-the-site-feedback-category/1", - "read_restricted": false, - "permission": 1, - "notification_level": 0, - "topic_template": null, - "has_children": false, - "sort_order": null, - "sort_ascending": null, - "show_subcategory_list": false, - "num_featured_topics": 3, - "default_view": null, - "subcategory_list_style": "rows_with_featured_topics", - "default_top_period": "all", - "default_list_filter": "all", - "minimum_required_tags": 0, - "navigate_to_first_post_after_read": false, - "custom_fields": { - "create_topic_wizard": null + id: 2, + name: "Site Feedback", + color: "808281", + text_color: "FFFFFF", + slug: "site-feedback", + topic_count: 20, + post_count: 21, + position: 1, + description: + "

Discussion about this site, its organization, how it works, and how we can improve it.

", + description_text: + "Discussion about this site, its organization, how it works, and how we can improve it.", + description_excerpt: + "Discussion about this site, its organization, how it works, and how we can improve it.", + topic_url: "/t/about-the-site-feedback-category/1", + read_restricted: false, + permission: 1, + notification_level: 0, + topic_template: null, + has_children: false, + sort_order: null, + sort_ascending: null, + show_subcategory_list: false, + num_featured_topics: 3, + default_view: null, + subcategory_list_style: "rows_with_featured_topics", + default_top_period: "all", + default_list_filter: "all", + minimum_required_tags: 0, + navigate_to_first_post_after_read: false, + custom_fields: { + create_topic_wizard: null, }, - "allowed_tags": [], - "allowed_tag_groups": [], - "allow_global_tags": false, - "min_tags_from_required_group": 1, - "required_tag_group_name": null, - "read_only_banner": null, - "uploaded_logo": null, - "uploaded_background": null, - "can_edit": true + allowed_tags: [], + allowed_tag_groups: [], + allow_global_tags: false, + min_tags_from_required_group: 1, + required_tag_group_name: null, + read_only_banner: null, + uploaded_logo: null, + uploaded_background: null, + can_edit: true, }, { - "id": 3, - "name": "Staff", - "color": "E45735", - "text_color": "FFFFFF", - "slug": "staff", - "topic_count": 4, - "post_count": 7, - "position": 2, - "description": "

Private category for staff discussions. Topics are only visible to admins and moderators.

", - "description_text": "Private category for staff discussions. Topics are only visible to admins and moderators.", - "description_excerpt": "Private category for staff discussions. Topics are only visible to admins and moderators.", - "topic_url": "/t/about-the-staff-category/2", - "read_restricted": true, - "permission": 1, - "notification_level": 0, - "topic_template": null, - "has_children": false, - "sort_order": null, - "sort_ascending": null, - "show_subcategory_list": false, - "num_featured_topics": 3, - "default_view": null, - "subcategory_list_style": "rows_with_featured_topics", - "default_top_period": "all", - "default_list_filter": "all", - "minimum_required_tags": 0, - "navigate_to_first_post_after_read": false, - "custom_fields": { - "create_topic_wizard": null + id: 3, + name: "Staff", + color: "E45735", + text_color: "FFFFFF", + slug: "staff", + topic_count: 4, + post_count: 7, + position: 2, + description: + "

Private category for staff discussions. Topics are only visible to admins and moderators.

", + description_text: + "Private category for staff discussions. Topics are only visible to admins and moderators.", + description_excerpt: + "Private category for staff discussions. Topics are only visible to admins and moderators.", + topic_url: "/t/about-the-staff-category/2", + read_restricted: true, + permission: 1, + notification_level: 0, + topic_template: null, + has_children: false, + sort_order: null, + sort_ascending: null, + show_subcategory_list: false, + num_featured_topics: 3, + default_view: null, + subcategory_list_style: "rows_with_featured_topics", + default_top_period: "all", + default_list_filter: "all", + minimum_required_tags: 0, + navigate_to_first_post_after_read: false, + custom_fields: { + create_topic_wizard: null, }, - "allowed_tags": [], - "allowed_tag_groups": [], - "allow_global_tags": false, - "min_tags_from_required_group": 1, - "required_tag_group_name": null, - "read_only_banner": null, - "uploaded_logo": null, - "uploaded_background": null, - "can_edit": true + allowed_tags: [], + allowed_tag_groups: [], + allow_global_tags: false, + min_tags_from_required_group: 1, + required_tag_group_name: null, + read_only_banner: null, + uploaded_logo: null, + uploaded_background: null, + can_edit: true, }, { - "id": 4, - "name": "Lounge", - "color": "A461EF", - "text_color": "652D90", - "slug": "lounge", - "topic_count": 1, - "post_count": 1, - "position": 3, - "description": "

A category exclusive to members with trust level 3 and higher.

", - "description_text": "A category exclusive to members with trust level 3 and higher.", - "description_excerpt": "A category exclusive to members with trust level 3 and higher.", - "topic_url": "/t/about-the-lounge-category/3", - "read_restricted": true, - "permission": 1, - "notification_level": 0, - "topic_template": null, - "has_children": false, - "sort_order": null, - "sort_ascending": null, - "show_subcategory_list": false, - "num_featured_topics": 3, - "default_view": null, - "subcategory_list_style": "rows_with_featured_topics", - "default_top_period": "all", - "default_list_filter": "all", - "minimum_required_tags": 0, - "navigate_to_first_post_after_read": false, - "custom_fields": { - "create_topic_wizard": null + id: 4, + name: "Lounge", + color: "A461EF", + text_color: "652D90", + slug: "lounge", + topic_count: 1, + post_count: 1, + position: 3, + description: + "

A category exclusive to members with trust level 3 and higher.

", + description_text: + "A category exclusive to members with trust level 3 and higher.", + description_excerpt: + "A category exclusive to members with trust level 3 and higher.", + topic_url: "/t/about-the-lounge-category/3", + read_restricted: true, + permission: 1, + notification_level: 0, + topic_template: null, + has_children: false, + sort_order: null, + sort_ascending: null, + show_subcategory_list: false, + num_featured_topics: 3, + default_view: null, + subcategory_list_style: "rows_with_featured_topics", + default_top_period: "all", + default_list_filter: "all", + minimum_required_tags: 0, + navigate_to_first_post_after_read: false, + custom_fields: { + create_topic_wizard: null, }, - "allowed_tags": [], - "allowed_tag_groups": [], - "allow_global_tags": false, - "min_tags_from_required_group": 1, - "required_tag_group_name": null, - "read_only_banner": null, - "uploaded_logo": null, - "uploaded_background": null, - "can_edit": true + allowed_tags: [], + allowed_tag_groups: [], + allow_global_tags: false, + min_tags_from_required_group: 1, + required_tag_group_name: null, + read_only_banner: null, + uploaded_logo: null, + uploaded_background: null, + can_edit: true, }, { - "id": 5, - "name": "Custom Categories", - "color": "0088CC", - "text_color": "FFFFFF", - "slug": "custom-category", - "topic_count": 0, - "post_count": 0, - "position": 10, - "description": "Description of custom category", - "description_text": "Description of custom category", - "description_excerpt": "Description of custom category", - "topic_url": "/t/about-the-custom-category/5", - "read_restricted": false, - "permission": 1, - "notification_level": 0, - "topic_template": null, - "has_children": false, - "sort_order": null, - "sort_ascending": null, - "show_subcategory_list": false, - "num_featured_topics": 3, - "default_view": null, - "subcategory_list_style": "rows_with_featured_topics", - "default_top_period": "all", - "default_list_filter": "all", - "minimum_required_tags": 0, - "navigate_to_first_post_after_read": false, - "custom_fields": { - "create_topic_wizard": null + id: 5, + name: "Custom Categories", + color: "0088CC", + text_color: "FFFFFF", + slug: "custom-category", + topic_count: 0, + post_count: 0, + position: 10, + description: "Description of custom category", + description_text: "Description of custom category", + description_excerpt: "Description of custom category", + topic_url: "/t/about-the-custom-category/5", + read_restricted: false, + permission: 1, + notification_level: 0, + topic_template: null, + has_children: false, + sort_order: null, + sort_ascending: null, + show_subcategory_list: false, + num_featured_topics: 3, + default_view: null, + subcategory_list_style: "rows_with_featured_topics", + default_top_period: "all", + default_list_filter: "all", + minimum_required_tags: 0, + navigate_to_first_post_after_read: false, + custom_fields: { + create_topic_wizard: null, }, - "allowed_tags": [], - "allowed_tag_groups": [], - "allow_global_tags": false, - "min_tags_from_required_group": 1, - "required_tag_group_name": null, - "read_only_banner": null, - "uploaded_logo": null, - "uploaded_background": null, - "can_edit": true - } - ] -} + allowed_tags: [], + allowed_tag_groups: [], + allow_global_tags: false, + min_tags_from_required_group: 1, + required_tag_group_name: null, + read_only_banner: null, + uploaded_logo: null, + uploaded_background: null, + can_edit: true, + }, + ], +}; diff --git a/assets/javascripts/wizard/tests/fixtures/groups.js.es6 b/assets/javascripts/wizard/tests/fixtures/groups.js.es6 index 16f8150d..a770cf58 100644 --- a/assets/javascripts/wizard/tests/fixtures/groups.js.es6 +++ b/assets/javascripts/wizard/tests/fixtures/groups.js.es6 @@ -1,313 +1,313 @@ export default { - "groups": [ + groups: [ { - "id": 1, - "automatic": true, - "name": "admins", - "display_name": "admins", - "user_count": 1, - "mentionable_level": 0, - "messageable_level": 0, - "visibility_level": 1, - "primary_group": false, - "title": null, - "grant_trust_level": null, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": null, - "default_notification_level": 3, - "membership_request_template": null, - "members_visibility_level": 0, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false + id: 1, + automatic: true, + name: "admins", + display_name: "admins", + user_count: 1, + mentionable_level: 0, + messageable_level: 0, + visibility_level: 1, + primary_group: false, + title: null, + grant_trust_level: null, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: null, + default_notification_level: 3, + membership_request_template: null, + members_visibility_level: 0, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, }, { - "id": 0, - "automatic": true, - "name": "everyone", - "display_name": "everyone", - "user_count": 0, - "mentionable_level": 0, - "messageable_level": 0, - "visibility_level": 3, - "primary_group": false, - "title": null, - "grant_trust_level": null, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": null, - "default_notification_level": 3, - "membership_request_template": null, - "members_visibility_level": 0, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false + id: 0, + automatic: true, + name: "everyone", + display_name: "everyone", + user_count: 0, + mentionable_level: 0, + messageable_level: 0, + visibility_level: 3, + primary_group: false, + title: null, + grant_trust_level: null, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: null, + default_notification_level: 3, + membership_request_template: null, + members_visibility_level: 0, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, }, { - "id": 15, - "automatic": false, - "name": "custom_group", - "user_count": 1, - "mentionable_level": 1, - "messageable_level": 2, - "visibility_level": 3, - "primary_group": false, - "title": "Custom Group", - "grant_trust_level": 3, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": "I am prefilled", - "default_notification_level": 3, - "membership_request_template": null, - "members_visibility_level": 99, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false + id: 15, + automatic: false, + name: "custom_group", + user_count: 1, + mentionable_level: 1, + messageable_level: 2, + visibility_level: 3, + primary_group: false, + title: "Custom Group", + grant_trust_level: 3, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: "I am prefilled", + default_notification_level: 3, + membership_request_template: null, + members_visibility_level: 99, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, }, { - "id": 2, - "automatic": true, - "name": "moderators", - "display_name": "moderators", - "user_count": 0, - "mentionable_level": 0, - "messageable_level": 99, - "visibility_level": 1, - "primary_group": false, - "title": null, - "grant_trust_level": null, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": null, - "default_notification_level": 2, - "membership_request_template": null, - "members_visibility_level": 0, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false + id: 2, + automatic: true, + name: "moderators", + display_name: "moderators", + user_count: 0, + mentionable_level: 0, + messageable_level: 99, + visibility_level: 1, + primary_group: false, + title: null, + grant_trust_level: null, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: null, + default_notification_level: 2, + membership_request_template: null, + members_visibility_level: 0, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, }, { - "id": 3, - "automatic": true, - "name": "staff", - "display_name": "staff", - "user_count": 1, - "mentionable_level": 0, - "messageable_level": 0, - "visibility_level": 1, - "primary_group": false, - "title": null, - "grant_trust_level": null, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": null, - "default_notification_level": 3, - "membership_request_template": null, - "members_visibility_level": 0, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false + id: 3, + automatic: true, + name: "staff", + display_name: "staff", + user_count: 1, + mentionable_level: 0, + messageable_level: 0, + visibility_level: 1, + primary_group: false, + title: null, + grant_trust_level: null, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: null, + default_notification_level: 3, + membership_request_template: null, + members_visibility_level: 0, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, }, { - "id": 10, - "automatic": true, - "name": "trust_level_0", - "display_name": "trust_level_0", - "user_count": 2, - "mentionable_level": 0, - "messageable_level": 0, - "visibility_level": 1, - "primary_group": false, - "title": null, - "grant_trust_level": null, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": null, - "default_notification_level": 3, - "membership_request_template": null, - "members_visibility_level": 0, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false + id: 10, + automatic: true, + name: "trust_level_0", + display_name: "trust_level_0", + user_count: 2, + mentionable_level: 0, + messageable_level: 0, + visibility_level: 1, + primary_group: false, + title: null, + grant_trust_level: null, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: null, + default_notification_level: 3, + membership_request_template: null, + members_visibility_level: 0, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, }, { - "id": 11, - "automatic": true, - "name": "trust_level_1", - "display_name": "trust_level_1", - "user_count": 2, - "mentionable_level": 0, - "messageable_level": 0, - "visibility_level": 1, - "primary_group": false, - "title": null, - "grant_trust_level": null, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": null, - "default_notification_level": 3, - "membership_request_template": null, - "members_visibility_level": 0, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false + id: 11, + automatic: true, + name: "trust_level_1", + display_name: "trust_level_1", + user_count: 2, + mentionable_level: 0, + messageable_level: 0, + visibility_level: 1, + primary_group: false, + title: null, + grant_trust_level: null, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: null, + default_notification_level: 3, + membership_request_template: null, + members_visibility_level: 0, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, }, { - "id": 12, - "automatic": true, - "name": "trust_level_2", - "display_name": "trust_level_2", - "user_count": 1, - "mentionable_level": 0, - "messageable_level": 0, - "visibility_level": 1, - "primary_group": false, - "title": null, - "grant_trust_level": null, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": null, - "default_notification_level": 3, - "membership_request_template": null, - "members_visibility_level": 0, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false + id: 12, + automatic: true, + name: "trust_level_2", + display_name: "trust_level_2", + user_count: 1, + mentionable_level: 0, + messageable_level: 0, + visibility_level: 1, + primary_group: false, + title: null, + grant_trust_level: null, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: null, + default_notification_level: 3, + membership_request_template: null, + members_visibility_level: 0, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, }, { - "id": 13, - "automatic": true, - "name": "trust_level_3", - "display_name": "trust_level_3", - "user_count": 1, - "mentionable_level": 0, - "messageable_level": 0, - "visibility_level": 1, - "primary_group": false, - "title": null, - "grant_trust_level": null, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": null, - "default_notification_level": 3, - "membership_request_template": null, - "members_visibility_level": 0, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false + id: 13, + automatic: true, + name: "trust_level_3", + display_name: "trust_level_3", + user_count: 1, + mentionable_level: 0, + messageable_level: 0, + visibility_level: 1, + primary_group: false, + title: null, + grant_trust_level: null, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: null, + default_notification_level: 3, + membership_request_template: null, + members_visibility_level: 0, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, }, { - "id": 14, - "automatic": true, - "name": "trust_level_4", - "display_name": "trust_level_4", - "user_count": 0, - "mentionable_level": 0, - "messageable_level": 0, - "visibility_level": 1, - "primary_group": false, - "title": null, - "grant_trust_level": null, - "incoming_email": null, - "has_messages": false, - "flair_url": null, - "flair_bg_color": null, - "flair_color": null, - "bio_raw": null, - "bio_cooked": null, - "bio_excerpt": null, - "public_admission": false, - "public_exit": false, - "allow_membership_requests": false, - "full_name": null, - "default_notification_level": 3, - "membership_request_template": null, - "members_visibility_level": 0, - "can_see_members": true, - "can_admin_group": true, - "publish_read_state": false - } - ] -} + id: 14, + automatic: true, + name: "trust_level_4", + display_name: "trust_level_4", + user_count: 0, + mentionable_level: 0, + messageable_level: 0, + visibility_level: 1, + primary_group: false, + title: null, + grant_trust_level: null, + incoming_email: null, + has_messages: false, + flair_url: null, + flair_bg_color: null, + flair_color: null, + bio_raw: null, + bio_cooked: null, + bio_excerpt: null, + public_admission: false, + public_exit: false, + allow_membership_requests: false, + full_name: null, + default_notification_level: 3, + membership_request_template: null, + members_visibility_level: 0, + can_see_members: true, + can_admin_group: true, + publish_read_state: false, + }, + ], +}; diff --git a/assets/javascripts/wizard/tests/fixtures/site-settings.js.es6 b/assets/javascripts/wizard/tests/fixtures/site-settings.js.es6 index f71ace8e..7568cd49 100644 --- a/assets/javascripts/wizard/tests/fixtures/site-settings.js.es6 +++ b/assets/javascripts/wizard/tests/fixtures/site-settings.js.es6 @@ -1,283 +1,294 @@ export default { - "default_locale": "en", - "title": "Discourse", - "short_site_description": "", - "exclude_rel_nofollow_domains": "", - "logo": "/images/discourse-logo-sketch.png", - "logo_small": "/images/discourse-logo-sketch-small.png", - "digest_logo": "", - "mobile_logo": "", - "logo_dark": "", - "logo_small_dark": "", - "mobile_logo_dark": "", - "large_icon": "", - "favicon": "", - "apple_touch_icon": "", - "display_local_time_in_user_card": false, - "allow_user_locale": false, - "set_locale_from_accept_language_header": false, - "support_mixed_text_direction": false, - "suggested_topics": 5, - "ga_universal_tracking_code": "", - "ga_universal_domain_name": "auto", - "gtm_container_id": "", - "top_menu": "categories|latest", - "post_menu": "read|like|share|flag|edit|bookmark|delete|admin|reply", - "post_menu_hidden_items": "flag|bookmark|edit|delete|admin", - "share_links": "twitter|facebook|email", - "share_quote_visibility": "anonymous", - "share_quote_buttons": "twitter|email", - "desktop_category_page_style": "categories_and_latest_topics", - "category_colors": "BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|E45735", - "category_style": "bullet", - "max_category_nesting": 2, - "enable_mobile_theme": true, - "enable_direct_s3_uploads": false, - "enable_upload_debug_mode": false, - "default_dark_mode_color_scheme_id": 1, - "relative_date_duration": 30, - "fixed_category_positions": false, - "fixed_category_positions_on_create": false, - "enable_badges": true, - "enable_badge_sql": true, - "max_favorite_badges": 2, - "enable_whispers": false, - "enable_bookmarks_with_reminders": true, - "push_notifications_prompt": true, - "vapid_public_key_bytes": "4|29|219|88|202|66|198|62|182|204|66|176|229|200|131|26|141|21|178|231|150|161|2|128|228|200|179|126|118|232|196|19|232|76|108|189|54|211|210|155|55|228|173|112|38|158|114|127|18|95|7|56|110|183|192|92|43|0|243|249|233|89|9|207|255", - "invite_only": false, - "login_required": false, - "must_approve_users": false, - "enable_local_logins": true, - "enable_local_logins_via_email": true, - "allow_new_registrations": true, - "enable_signup_cta": true, - "facebook_app_id": "", - "auth_skip_create_confirm": false, - "auth_overrides_email": false, - "enable_discourse_connect": true, - "discourse_connect_overrides_avatar": false, - "hide_email_address_taken": false, - "min_username_length": 3, - "max_username_length": 20, - "unicode_usernames": false, - "min_password_length": 10, - "min_admin_password_length": 15, - "email_editable": true, - "logout_redirect": "", - "full_name_required": false, - "enable_names": true, - "invite_expiry_days": 90, - "invites_per_page": 40, - "delete_user_max_post_age": 60, - "delete_all_posts_max": 15, - "prioritize_username_in_ux": true, - "enable_user_directory": true, - "allow_anonymous_posting": false, - "anonymous_posting_min_trust_level": 1, - "allow_users_to_hide_profile": true, - "hide_user_profiles_from_public": false, - "allow_featured_topic_on_user_profiles": true, - "hide_suspension_reasons": false, - "ignored_users_count_message_threshold": 5, - "ignored_users_message_gap_days": 365, - "user_selected_primary_groups": false, - "gravatar_name": "Gravatar", - "gravatar_base_url": "www.gravatar.com", - "gravatar_login_url": "/emails", - "enable_group_directory": true, - "enable_category_group_moderation": false, - "min_post_length": 20, - "min_first_post_length": 20, - "min_personal_message_post_length": 10, - "max_post_length": 32000, - "topic_featured_link_enabled": true, - "min_topic_views_for_delete_confirm": 5000, - "min_topic_title_length": 15, - "max_topic_title_length": 255, - "enable_filtered_replies_view": false, - "min_personal_message_title_length": 2, - "allow_uncategorized_topics": true, - "min_title_similar_length": 10, - "enable_personal_messages": true, - "edit_history_visible_to_public": true, - "delete_removed_posts_after": 24, - "traditional_markdown_linebreaks": false, - "enable_markdown_typographer": true, - "enable_markdown_linkify": true, - "markdown_linkify_tlds": "com|net|org|io|onion|co|tv|ru|cn|us|uk|me|de|fr|fi|gov", - "markdown_typographer_quotation_marks": "“|”|‘|’", - "enable_rich_text_paste": true, - "suppress_reply_directly_below": true, - "suppress_reply_directly_above": true, - "max_reply_history": 1, - "enable_mentions": true, - "here_mention": "here", - "newuser_max_embedded_media": 1, - "newuser_max_attachments": 0, - "show_pinned_excerpt_mobile": true, - "show_pinned_excerpt_desktop": true, - "display_name_on_posts": false, - "show_time_gap_days": 7, - "short_progress_text_threshold": 10000, - "default_code_lang": "auto", - "autohighlight_all_code": false, - "highlighted_languages": "apache|bash|cs|cpp|css|coffeescript|diff|xml|http|ini|json|java|javascript|makefile|markdown|nginx|objectivec|ruby|perl|php|python|sql|handlebars", - "show_copy_button_on_codeblocks": false, - "enable_emoji": true, - "enable_emoji_shortcuts": true, - "emoji_set": "twitter", - "emoji_autocomplete_min_chars": 0, - "enable_inline_emoji_translation": false, - "code_formatting_style": "code-fences", - "allowed_href_schemes": "", - "watched_words_regular_expressions": false, - "enable_diffhtml_preview": false, - "enable_fast_edit": true, - "old_post_notice_days": 14, - "blur_tl0_flagged_posts_media": true, - "email_time_window_mins": 10, - "disable_digest_emails": false, - "email_in": false, - "enable_imap": false, - "enable_smtp": false, - "disable_emails": "no", - "bounce_score_threshold": 4, - "enable_secondary_emails": true, - "max_image_size_kb": 4096, - "max_attachment_size_kb": 4096, - "authorized_extensions": "jpg|jpeg|png|gif|heic|heif|webp", - "authorized_extensions_for_staff": "", - "max_image_width": 690, - "max_image_height": 500, - "prevent_anons_from_downloading_files": false, - "secure_media": false, - "enable_s3_uploads": false, - "allow_profile_backgrounds": true, - "allow_uploaded_avatars": "0", - "default_avatars": "", - "external_system_avatars_enabled": true, - "external_system_avatars_url": "/letter_avatar_proxy/v4/letter/{first_letter}/{color}/{size}.png", - "external_emoji_url": "", - "selectable_avatars_mode": "disabled", - "selectable_avatars": "", - "allow_staff_to_upload_any_file_in_pm": true, - "simultaneous_uploads": 5, - "composer_media_optimization_image_enabled": true, - "composer_media_optimization_image_bytes_optimization_threshold": 524288, - "composer_media_optimization_image_resize_dimensions_threshold": 1920, - "composer_media_optimization_image_resize_width_target": 1920, - "composer_media_optimization_image_resize_pre_multiply": false, - "composer_media_optimization_image_resize_linear_rgb": false, - "composer_media_optimization_image_encode_quality": 75, - "composer_media_optimization_debug_mode": false, - "min_trust_level_to_allow_profile_background": 0, - "min_trust_level_to_allow_user_card_background": 0, - "min_trust_level_to_allow_ignore": 2, - "tl1_requires_read_posts": 30, - "tl3_links_no_follow": false, - "enforce_second_factor": "no", - "moderators_change_post_ownership": false, - "moderators_view_emails": false, - "use_admin_ip_allowlist": false, - "allowed_iframes": "https://www.google.com/maps/embed?|https://www.openstreetmap.org/export/embed.html?|https://calendar.google.com/calendar/embed?|https://codepen.io/|https://www.instagram.com|http://localhost:3000/discobot/certificate.svg", - "can_permanently_delete": false, - "max_oneboxes_per_post": 50, - "reviewable_claiming": "disabled", - "reviewable_default_topics": false, - "reviewable_default_visibility": "low", - "alert_admins_if_errors_per_minute": 0, - "alert_admins_if_errors_per_hour": 0, - "max_prints_per_hour_per_user": 5, - "invite_link_max_redemptions_limit": 5000, - "invite_link_max_redemptions_limit_users": 10, - "enable_long_polling": true, - "enable_chunked_encoding": true, - "long_polling_base_url": "/", - "background_polling_interval": 60000, - "polling_interval": 3000, - "anon_polling_interval": 25000, - "flush_timings_secs": 60, - "verbose_localization": false, - "max_new_topics": 500, - "enable_safe_mode": true, - "tos_url": "", - "privacy_policy_url": "", - "faq_url": "", - "enable_backups": true, - "backup_location": "local", - "maximum_backups": 5, - "use_pg_headlines_for_excerpt": false, - "min_search_term_length": 3, - "log_search_queries": true, - "version_checks": true, - "suppress_uncategorized_badge": true, - "header_dropdown_category_count": 8, - "slug_generation_method": "ascii", - "summary_timeline_button": false, - "topic_views_heat_low": 1000, - "topic_views_heat_medium": 2000, - "topic_views_heat_high": 3500, - "topic_post_like_heat_low": 0.5, - "topic_post_like_heat_medium": 1, - "topic_post_like_heat_high": 2, - "history_hours_low": 12, - "history_hours_medium": 24, - "history_hours_high": 48, - "cold_age_days_low": 14, - "cold_age_days_medium": 90, - "cold_age_days_high": 180, - "global_notice": "", - "show_create_topics_notice": true, - "bootstrap_mode_min_users": 50, - "bootstrap_mode_enabled": true, - "automatically_unpin_topics": true, - "read_time_word_count": 500, - "topic_page_title_includes_category": true, - "svg_icon_subset": "", - "allow_bulk_invite": true, - "disable_mailing_list_mode": true, - "default_topics_automatic_unpin": true, - "mute_all_categories_by_default": false, - "tagging_enabled": true, - "tag_style": "simple", - "max_tags_per_topic": 5, - "max_tag_length": 20, - "min_trust_level_to_tag_topics": "0", - "max_tag_search_results": 5, - "max_tags_in_filter_list": 30, - "tags_sort_alphabetically": false, - "tags_listed_by_group": false, - "suppress_overlapping_tags_in_list": false, - "remove_muted_tags_from_latest": "always", - "force_lowercase_tags": true, - "dashboard_hidden_reports": "", - "dashboard_visible_tabs": "moderation|security|reports", - "dashboard_general_tab_activity_metrics": "page_view_total_reqs|visits|time_to_first_response|likes|flags|user_to_user_private_messages_with_replies", - "discourse_narrative_bot_enabled": true, - "details_enabled": true, - "custom_wizard_enabled": true, - "wizard_redirect_exclude_paths": "admin", - "wizard_recognised_image_upload_formats": "jpg|jpeg|png|gif", - "wizard_important_notices_on_dashboard": true, - "discourse_local_dates_email_format": "YYYY-MM-DDTHH:mm:ss[Z]", - "discourse_local_dates_enabled": true, - "discourse_local_dates_default_formats": "LLL|LTS|LL|LLLL", - "discourse_local_dates_default_timezones": "Europe/Paris|America/Los_Angeles", - "poll_enabled": true, - "poll_maximum_options": 20, - "poll_minimum_trust_level_to_create": 1, - "poll_groupable_user_fields": "", - "poll_export_data_explorer_query_id": -16, - "presence_enabled": true, - "presence_max_users_shown": 5, - "available_locales": "[{\"name\":\"اللغة العربية\",\"value\":\"ar\"},{\"name\":\"беларуская мова\",\"value\":\"be\"},{\"name\":\"български език\",\"value\":\"bg\"},{\"name\":\"bosanski jezik\",\"value\":\"bs_BA\"},{\"name\":\"català\",\"value\":\"ca\"},{\"name\":\"čeština\",\"value\":\"cs\"},{\"name\":\"dansk\",\"value\":\"da\"},{\"name\":\"Deutsch\",\"value\":\"de\"},{\"name\":\"ελληνικά\",\"value\":\"el\"},{\"name\":\"English (US)\",\"value\":\"en\"},{\"name\":\"English (UK)\",\"value\":\"en_GB\"},{\"name\":\"Español\",\"value\":\"es\"},{\"name\":\"eesti\",\"value\":\"et\"},{\"name\":\"فارسی\",\"value\":\"fa_IR\"},{\"name\":\"suomi\",\"value\":\"fi\"},{\"name\":\"Français\",\"value\":\"fr\"},{\"name\":\"galego\",\"value\":\"gl\"},{\"name\":\"עברית\",\"value\":\"he\"},{\"name\":\"magyar\",\"value\":\"hu\"},{\"name\":\"Հայերեն\",\"value\":\"hy\"},{\"name\":\"Indonesian\",\"value\":\"id\"},{\"name\":\"Italiano\",\"value\":\"it\"},{\"name\":\"日本語\",\"value\":\"ja\"},{\"name\":\"한국어\",\"value\":\"ko\"},{\"name\":\"lietuvių kalba\",\"value\":\"lt\"},{\"name\":\"latviešu valoda\",\"value\":\"lv\"},{\"name\":\"Norsk bokmål\",\"value\":\"nb_NO\"},{\"name\":\"Nederlands\",\"value\":\"nl\"},{\"name\":\"polski\",\"value\":\"pl_PL\"},{\"name\":\"Português\",\"value\":\"pt\"},{\"name\":\"Português (BR)\",\"value\":\"pt_BR\"},{\"name\":\"limba română\",\"value\":\"ro\"},{\"name\":\"Русский\",\"value\":\"ru\"},{\"name\":\"slovenčina\",\"value\":\"sk\"},{\"name\":\"slovenščina\",\"value\":\"sl\"},{\"name\":\"Shqip\",\"value\":\"sq\"},{\"name\":\"српски језик\",\"value\":\"sr\"},{\"name\":\"svenska\",\"value\":\"sv\"},{\"name\":\"Kiswahili\",\"value\":\"sw\"},{\"name\":\"తెలుగు\",\"value\":\"te\"},{\"name\":\"ไทย\",\"value\":\"th\"},{\"name\":\"Türkçe\",\"value\":\"tr_TR\"},{\"name\":\"українська мова\",\"value\":\"uk\"},{\"name\":\"اردو\",\"value\":\"ur\"},{\"name\":\"Việt Nam\",\"value\":\"vi\"},{\"name\":\"简体中文\",\"value\":\"zh_CN\"},{\"name\":\"繁體中文\",\"value\":\"zh_TW\"}]", - "require_invite_code": false, - "site_logo_url": "http://localhost:3000/images/discourse-logo-sketch.png", - "site_logo_small_url": "http://localhost:3000/images/discourse-logo-sketch-small.png", - "site_mobile_logo_url": "http://localhost:3000/images/discourse-logo-sketch.png", - "site_favicon_url": "http://localhost:3000/uploads/default/optimized/1X/_129430568242d1b7f853bb13ebea28b3f6af4e7_2_32x32.png", - "site_logo_dark_url": "", - "site_logo_small_dark_url": "", - "site_mobile_logo_dark_url": "" -} + default_locale: "en", + title: "Discourse", + short_site_description: "", + exclude_rel_nofollow_domains: "", + logo: "/images/discourse-logo-sketch.png", + logo_small: "/images/discourse-logo-sketch-small.png", + digest_logo: "", + mobile_logo: "", + logo_dark: "", + logo_small_dark: "", + mobile_logo_dark: "", + large_icon: "", + favicon: "", + apple_touch_icon: "", + display_local_time_in_user_card: false, + allow_user_locale: false, + set_locale_from_accept_language_header: false, + support_mixed_text_direction: false, + suggested_topics: 5, + ga_universal_tracking_code: "", + ga_universal_domain_name: "auto", + gtm_container_id: "", + top_menu: "categories|latest", + post_menu: "read|like|share|flag|edit|bookmark|delete|admin|reply", + post_menu_hidden_items: "flag|bookmark|edit|delete|admin", + share_links: "twitter|facebook|email", + share_quote_visibility: "anonymous", + share_quote_buttons: "twitter|email", + desktop_category_page_style: "categories_and_latest_topics", + category_colors: + "BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|E45735", + category_style: "bullet", + max_category_nesting: 2, + enable_mobile_theme: true, + enable_direct_s3_uploads: false, + enable_upload_debug_mode: false, + default_dark_mode_color_scheme_id: 1, + relative_date_duration: 30, + fixed_category_positions: false, + fixed_category_positions_on_create: false, + enable_badges: true, + enable_badge_sql: true, + max_favorite_badges: 2, + enable_whispers: false, + enable_bookmarks_with_reminders: true, + push_notifications_prompt: true, + vapid_public_key_bytes: + "4|29|219|88|202|66|198|62|182|204|66|176|229|200|131|26|141|21|178|231|150|161|2|128|228|200|179|126|118|232|196|19|232|76|108|189|54|211|210|155|55|228|173|112|38|158|114|127|18|95|7|56|110|183|192|92|43|0|243|249|233|89|9|207|255", + invite_only: false, + login_required: false, + must_approve_users: false, + enable_local_logins: true, + enable_local_logins_via_email: true, + allow_new_registrations: true, + enable_signup_cta: true, + facebook_app_id: "", + auth_skip_create_confirm: false, + auth_overrides_email: false, + enable_discourse_connect: true, + discourse_connect_overrides_avatar: false, + hide_email_address_taken: false, + min_username_length: 3, + max_username_length: 20, + unicode_usernames: false, + min_password_length: 10, + min_admin_password_length: 15, + email_editable: true, + logout_redirect: "", + full_name_required: false, + enable_names: true, + invite_expiry_days: 90, + invites_per_page: 40, + delete_user_max_post_age: 60, + delete_all_posts_max: 15, + prioritize_username_in_ux: true, + enable_user_directory: true, + allow_anonymous_posting: false, + anonymous_posting_min_trust_level: 1, + allow_users_to_hide_profile: true, + hide_user_profiles_from_public: false, + allow_featured_topic_on_user_profiles: true, + hide_suspension_reasons: false, + ignored_users_count_message_threshold: 5, + ignored_users_message_gap_days: 365, + user_selected_primary_groups: false, + gravatar_name: "Gravatar", + gravatar_base_url: "www.gravatar.com", + gravatar_login_url: "/emails", + enable_group_directory: true, + enable_category_group_moderation: false, + min_post_length: 20, + min_first_post_length: 20, + min_personal_message_post_length: 10, + max_post_length: 32000, + topic_featured_link_enabled: true, + min_topic_views_for_delete_confirm: 5000, + min_topic_title_length: 15, + max_topic_title_length: 255, + enable_filtered_replies_view: false, + min_personal_message_title_length: 2, + allow_uncategorized_topics: true, + min_title_similar_length: 10, + enable_personal_messages: true, + edit_history_visible_to_public: true, + delete_removed_posts_after: 24, + traditional_markdown_linebreaks: false, + enable_markdown_typographer: true, + enable_markdown_linkify: true, + markdown_linkify_tlds: + "com|net|org|io|onion|co|tv|ru|cn|us|uk|me|de|fr|fi|gov", + markdown_typographer_quotation_marks: "“|”|‘|’", + enable_rich_text_paste: true, + suppress_reply_directly_below: true, + suppress_reply_directly_above: true, + max_reply_history: 1, + enable_mentions: true, + here_mention: "here", + newuser_max_embedded_media: 1, + newuser_max_attachments: 0, + show_pinned_excerpt_mobile: true, + show_pinned_excerpt_desktop: true, + display_name_on_posts: false, + show_time_gap_days: 7, + short_progress_text_threshold: 10000, + default_code_lang: "auto", + autohighlight_all_code: false, + highlighted_languages: + "apache|bash|cs|cpp|css|coffeescript|diff|xml|http|ini|json|java|javascript|makefile|markdown|nginx|objectivec|ruby|perl|php|python|sql|handlebars", + show_copy_button_on_codeblocks: false, + enable_emoji: true, + enable_emoji_shortcuts: true, + emoji_set: "twitter", + emoji_autocomplete_min_chars: 0, + enable_inline_emoji_translation: false, + code_formatting_style: "code-fences", + allowed_href_schemes: "", + watched_words_regular_expressions: false, + enable_diffhtml_preview: false, + enable_fast_edit: true, + old_post_notice_days: 14, + blur_tl0_flagged_posts_media: true, + email_time_window_mins: 10, + disable_digest_emails: false, + email_in: false, + enable_imap: false, + enable_smtp: false, + disable_emails: "no", + bounce_score_threshold: 4, + enable_secondary_emails: true, + max_image_size_kb: 4096, + max_attachment_size_kb: 4096, + authorized_extensions: "jpg|jpeg|png|gif|heic|heif|webp", + authorized_extensions_for_staff: "", + max_image_width: 690, + max_image_height: 500, + prevent_anons_from_downloading_files: false, + secure_media: false, + enable_s3_uploads: false, + allow_profile_backgrounds: true, + allow_uploaded_avatars: "0", + default_avatars: "", + external_system_avatars_enabled: true, + external_system_avatars_url: + "/letter_avatar_proxy/v4/letter/{first_letter}/{color}/{size}.png", + external_emoji_url: "", + selectable_avatars_mode: "disabled", + selectable_avatars: "", + allow_staff_to_upload_any_file_in_pm: true, + simultaneous_uploads: 5, + composer_media_optimization_image_enabled: true, + composer_media_optimization_image_bytes_optimization_threshold: 524288, + composer_media_optimization_image_resize_dimensions_threshold: 1920, + composer_media_optimization_image_resize_width_target: 1920, + composer_media_optimization_image_resize_pre_multiply: false, + composer_media_optimization_image_resize_linear_rgb: false, + composer_media_optimization_image_encode_quality: 75, + composer_media_optimization_debug_mode: false, + min_trust_level_to_allow_profile_background: 0, + min_trust_level_to_allow_user_card_background: 0, + min_trust_level_to_allow_ignore: 2, + tl1_requires_read_posts: 30, + tl3_links_no_follow: false, + enforce_second_factor: "no", + moderators_change_post_ownership: false, + moderators_view_emails: false, + use_admin_ip_allowlist: false, + allowed_iframes: + "https://www.google.com/maps/embed?|https://www.openstreetmap.org/export/embed.html?|https://calendar.google.com/calendar/embed?|https://codepen.io/|https://www.instagram.com|http://localhost:3000/discobot/certificate.svg", + can_permanently_delete: false, + max_oneboxes_per_post: 50, + reviewable_claiming: "disabled", + reviewable_default_topics: false, + reviewable_default_visibility: "low", + alert_admins_if_errors_per_minute: 0, + alert_admins_if_errors_per_hour: 0, + max_prints_per_hour_per_user: 5, + invite_link_max_redemptions_limit: 5000, + invite_link_max_redemptions_limit_users: 10, + enable_long_polling: true, + enable_chunked_encoding: true, + long_polling_base_url: "/", + background_polling_interval: 60000, + polling_interval: 3000, + anon_polling_interval: 25000, + flush_timings_secs: 60, + verbose_localization: false, + max_new_topics: 500, + enable_safe_mode: true, + tos_url: "", + privacy_policy_url: "", + faq_url: "", + enable_backups: true, + backup_location: "local", + maximum_backups: 5, + use_pg_headlines_for_excerpt: false, + min_search_term_length: 3, + log_search_queries: true, + version_checks: true, + suppress_uncategorized_badge: true, + header_dropdown_category_count: 8, + slug_generation_method: "ascii", + summary_timeline_button: false, + topic_views_heat_low: 1000, + topic_views_heat_medium: 2000, + topic_views_heat_high: 3500, + topic_post_like_heat_low: 0.5, + topic_post_like_heat_medium: 1, + topic_post_like_heat_high: 2, + history_hours_low: 12, + history_hours_medium: 24, + history_hours_high: 48, + cold_age_days_low: 14, + cold_age_days_medium: 90, + cold_age_days_high: 180, + global_notice: "", + show_create_topics_notice: true, + bootstrap_mode_min_users: 50, + bootstrap_mode_enabled: true, + automatically_unpin_topics: true, + read_time_word_count: 500, + topic_page_title_includes_category: true, + svg_icon_subset: "", + allow_bulk_invite: true, + disable_mailing_list_mode: true, + default_topics_automatic_unpin: true, + mute_all_categories_by_default: false, + tagging_enabled: true, + tag_style: "simple", + max_tags_per_topic: 5, + max_tag_length: 20, + min_trust_level_to_tag_topics: "0", + max_tag_search_results: 5, + max_tags_in_filter_list: 30, + tags_sort_alphabetically: false, + tags_listed_by_group: false, + suppress_overlapping_tags_in_list: false, + remove_muted_tags_from_latest: "always", + force_lowercase_tags: true, + dashboard_hidden_reports: "", + dashboard_visible_tabs: "moderation|security|reports", + dashboard_general_tab_activity_metrics: + "page_view_total_reqs|visits|time_to_first_response|likes|flags|user_to_user_private_messages_with_replies", + discourse_narrative_bot_enabled: true, + details_enabled: true, + custom_wizard_enabled: true, + wizard_redirect_exclude_paths: "admin", + wizard_recognised_image_upload_formats: "jpg|jpeg|png|gif", + wizard_important_notices_on_dashboard: true, + discourse_local_dates_email_format: "YYYY-MM-DDTHH:mm:ss[Z]", + discourse_local_dates_enabled: true, + discourse_local_dates_default_formats: "LLL|LTS|LL|LLLL", + discourse_local_dates_default_timezones: "Europe/Paris|America/Los_Angeles", + poll_enabled: true, + poll_maximum_options: 20, + poll_minimum_trust_level_to_create: 1, + poll_groupable_user_fields: "", + poll_export_data_explorer_query_id: -16, + presence_enabled: true, + presence_max_users_shown: 5, + available_locales: + '[{"name":"اللغة العربية","value":"ar"},{"name":"беларуская мова","value":"be"},{"name":"български език","value":"bg"},{"name":"bosanski jezik","value":"bs_BA"},{"name":"català","value":"ca"},{"name":"čeština","value":"cs"},{"name":"dansk","value":"da"},{"name":"Deutsch","value":"de"},{"name":"ελληνικά","value":"el"},{"name":"English (US)","value":"en"},{"name":"English (UK)","value":"en_GB"},{"name":"Español","value":"es"},{"name":"eesti","value":"et"},{"name":"فارسی","value":"fa_IR"},{"name":"suomi","value":"fi"},{"name":"Français","value":"fr"},{"name":"galego","value":"gl"},{"name":"עברית","value":"he"},{"name":"magyar","value":"hu"},{"name":"Հայերեն","value":"hy"},{"name":"Indonesian","value":"id"},{"name":"Italiano","value":"it"},{"name":"日本語","value":"ja"},{"name":"한국어","value":"ko"},{"name":"lietuvių kalba","value":"lt"},{"name":"latviešu valoda","value":"lv"},{"name":"Norsk bokmål","value":"nb_NO"},{"name":"Nederlands","value":"nl"},{"name":"polski","value":"pl_PL"},{"name":"Português","value":"pt"},{"name":"Português (BR)","value":"pt_BR"},{"name":"limba română","value":"ro"},{"name":"Русский","value":"ru"},{"name":"slovenčina","value":"sk"},{"name":"slovenščina","value":"sl"},{"name":"Shqip","value":"sq"},{"name":"српски језик","value":"sr"},{"name":"svenska","value":"sv"},{"name":"Kiswahili","value":"sw"},{"name":"తెలుగు","value":"te"},{"name":"ไทย","value":"th"},{"name":"Türkçe","value":"tr_TR"},{"name":"українська мова","value":"uk"},{"name":"اردو","value":"ur"},{"name":"Việt Nam","value":"vi"},{"name":"简体中文","value":"zh_CN"},{"name":"繁體中文","value":"zh_TW"}]', + require_invite_code: false, + site_logo_url: "http://localhost:3000/images/discourse-logo-sketch.png", + site_logo_small_url: + "http://localhost:3000/images/discourse-logo-sketch-small.png", + site_mobile_logo_url: + "http://localhost:3000/images/discourse-logo-sketch.png", + site_favicon_url: + "http://localhost:3000/uploads/default/optimized/1X/_129430568242d1b7f853bb13ebea28b3f6af4e7_2_32x32.png", + site_logo_dark_url: "", + site_logo_small_dark_url: "", + site_mobile_logo_dark_url: "", +}; diff --git a/assets/javascripts/wizard/tests/fixtures/tags.js.es6 b/assets/javascripts/wizard/tests/fixtures/tags.js.es6 index a072772e..61e51994 100644 --- a/assets/javascripts/wizard/tests/fixtures/tags.js.es6 +++ b/assets/javascripts/wizard/tests/fixtures/tags.js.es6 @@ -1,22 +1,22 @@ export default { - "tags": [ + tags: [ { - "id": "tag1", - "text": "tag1", - "name": "tag1", - "description": null, - "count": 1, - "pm_count": 0, - "target_tag": null + id: "tag1", + text: "tag1", + name: "tag1", + description: null, + count: 1, + pm_count: 0, + target_tag: null, }, { - "id": "tag2", - "text": "tag2", - "name": "tag2", - "description": null, - "count": 1, - "pm_count": 0, - "target_tag": null - } - ] -} + id: "tag2", + text: "tag2", + name: "tag2", + description: null, + count: 1, + pm_count: 0, + target_tag: null, + }, + ], +}; diff --git a/assets/javascripts/wizard/tests/fixtures/update.js.es6 b/assets/javascripts/wizard/tests/fixtures/update.js.es6 index 3908525c..5b20788c 100644 --- a/assets/javascripts/wizard/tests/fixtures/update.js.es6 +++ b/assets/javascripts/wizard/tests/fixtures/update.js.es6 @@ -1,5 +1,5 @@ export default { - "final": false, - "next_step_id": "step_2", - "wizard": {} -} + final: false, + next_step_id: "step_2", + wizard: {}, +}; diff --git a/assets/javascripts/wizard/tests/fixtures/user.js.es6 b/assets/javascripts/wizard/tests/fixtures/user.js.es6 index 8acd7392..d954905c 100644 --- a/assets/javascripts/wizard/tests/fixtures/user.js.es6 +++ b/assets/javascripts/wizard/tests/fixtures/user.js.es6 @@ -30,5 +30,5 @@ export default { title_count_mode: "notifications", timezone: "Australia/Perth", skip_new_user_tips: false, - can_review: true -} + can_review: true, +}; diff --git a/assets/javascripts/wizard/tests/fixtures/users.js.es6 b/assets/javascripts/wizard/tests/fixtures/users.js.es6 index 267d4909..437631a2 100644 --- a/assets/javascripts/wizard/tests/fixtures/users.js.es6 +++ b/assets/javascripts/wizard/tests/fixtures/users.js.es6 @@ -1,14 +1,14 @@ export default { - "users": [ + users: [ { - "username": "angus", - "name": "Angus", - "avatar_template": "/user_avatar/localhost/angus/{size}/12_2.png" + username: "angus", + name: "Angus", + avatar_template: "/user_avatar/localhost/angus/{size}/12_2.png", }, { - "username": "angus_2", - "name": "Angus 2", - "avatar_template": "/letter_avatar_proxy/v4/letter/a/e9a140/{size}.png" - } - ] -} + username: "angus_2", + name: "Angus 2", + avatar_template: "/letter_avatar_proxy/v4/letter/a/e9a140/{size}.png", + }, + ], +}; diff --git a/assets/javascripts/wizard/tests/fixtures/wizard.js.es6 b/assets/javascripts/wizard/tests/fixtures/wizard.js.es6 index be4fa8b2..73fe45c1 100644 --- a/assets/javascripts/wizard/tests/fixtures/wizard.js.es6 +++ b/assets/javascripts/wizard/tests/fixtures/wizard.js.es6 @@ -1,469 +1,471 @@ export default { - "id": "wizard", - "name": "Wizard", - "start": "step_1", - "background": "#333333", - "submission_last_updated_at": "2022-03-15T21:11:01+01:00", - "theme_id": 2, - "required": false, - "permitted": true, - "uncategorized_category_id": 1, - "categories": [], - "subscribed": false, - "resume_on_revisit": false, - "steps": [ + id: "wizard", + name: "Wizard", + start: "step_1", + background: "#333333", + submission_last_updated_at: "2022-03-15T21:11:01+01:00", + theme_id: 2, + required: false, + permitted: true, + uncategorized_category_id: 1, + categories: [], + subscribed: false, + resume_on_revisit: false, + steps: [ { - "id": "step_1", - "index": 0, - "next": "step_2", - "description": "

Text inputs!

", - "title": "Text", - "permitted": true, - "permitted_message": null, - "final": false, - "fields": [ + id: "step_1", + index: 0, + next: "step_2", + description: "

Text inputs!

", + title: "Text", + permitted: true, + permitted_message: null, + final: false, + fields: [ { - "id": "step_1_field_1", - "index": 0, - "type": "text", - "required": false, - "value": "I am prefilled", - "label": "

Text

", - "description": "Text field description.", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 1, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_1", - "_validState": 0 + id: "step_1_field_1", + index: 0, + type: "text", + required: false, + value: "I am prefilled", + label: "

Text

", + description: "Text field description.", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 1, + wizardId: "super_mega_fun_wizard", + stepId: "step_1", + _validState: 0, }, { - "id": "step_1_field_2", - "index": 0, - "type": "textarea", - "required": false, - "value": "", - "label": "

Textarea

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 2, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_1", - "_validState": 0 + id: "step_1_field_2", + index: 0, + type: "textarea", + required: false, + value: "", + label: "

Textarea

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 2, + wizardId: "super_mega_fun_wizard", + stepId: "step_1", + _validState: 0, }, { - "id": "step_1_field_3", - "index": 2, - "type": "composer", - "required": false, - "value": "", - "label": "

Composer

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 3, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_1", - "_validState": 0 + id: "step_1_field_3", + index: 2, + type: "composer", + required: false, + value: "", + label: "

Composer

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 3, + wizardId: "super_mega_fun_wizard", + stepId: "step_1", + _validState: 0, }, { - "id": "step_1_field_4", - "index": 3, - "type": "text_only", - "required": false, - "value": null, - "label": "

I’m only text

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 4, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_1", - "_validState": 0 + id: "step_1_field_4", + index: 3, + type: "text_only", + required: false, + value: null, + label: "

I’m only text

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 4, + wizardId: "super_mega_fun_wizard", + stepId: "step_1", + _validState: 0, }, { - "id": "step_1_field_5", - "index": 4, - "type": "composer_preview", - "required": false, - "value": "", - "label": "

I’m a preview

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": "

I am prefilled

", - "tabindex": 5, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_1", - "_validState": 0 + id: "step_1_field_5", + index: 4, + type: "composer_preview", + required: false, + value: "", + label: "

I’m a preview

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: "

I am prefilled

", + tabindex: 5, + wizardId: "super_mega_fun_wizard", + stepId: "step_1", + _validState: 0, }, { - "id": "step_1_field_6", - "index": 5, - "type": "composer_preview", - "required": false, - "value": "", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": "

This is the preview of the composer

", - "tabindex": 6, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_1", - "_validState": 0 - } + id: "step_1_field_6", + index: 5, + type: "composer_preview", + required: false, + value: "", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: "

This is the preview of the composer

", + tabindex: 6, + wizardId: "super_mega_fun_wizard", + stepId: "step_1", + _validState: 0, + }, ], - "_validState": 0, - "wizardId": "super_mega_fun_wizard" + _validState: 0, + wizardId: "super_mega_fun_wizard", }, { - "id": "step_2", - "index": 1, - "next": "step_3", - "previous": "step_1", - "description": "

Because I couldn’t think of another name for this step \":slight_smile:\"

", - "title": "Values", - "permitted": true, - "permitted_message": null, - "final": false, - "fields": [ + id: "step_2", + index: 1, + next: "step_3", + previous: "step_1", + description: + '

Because I couldn’t think of another name for this step :slight_smile:

', + title: "Values", + permitted: true, + permitted_message: null, + final: false, + fields: [ { - "id": "step_2_field_1", - "index": 0, - "type": "date", - "required": false, - "value": "", - "label": "

Date

", - "file_types": null, - "format": "YYYY-MM-DD", - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 1, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_2", - "_validState": 0 + id: "step_2_field_1", + index: 0, + type: "date", + required: false, + value: "", + label: "

Date

", + file_types: null, + format: "YYYY-MM-DD", + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 1, + wizardId: "super_mega_fun_wizard", + stepId: "step_2", + _validState: 0, }, { - "id": "step_2_field_2", - "index": 0, - "type": "time", - "required": false, - "value": "", - "label": "

Time

", - "file_types": null, - "format": "HH:mm", - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 2, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_2", - "_validState": 0 + id: "step_2_field_2", + index: 0, + type: "time", + required: false, + value: "", + label: "

Time

", + file_types: null, + format: "HH:mm", + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 2, + wizardId: "super_mega_fun_wizard", + stepId: "step_2", + _validState: 0, }, { - "id": "step_2_field_3", - "index": 2, - "type": "date_time", - "required": false, - "value": "", - "label": "

Date & Time

", - "file_types": null, - "format": "", - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 3, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_2", - "_validState": 0 + id: "step_2_field_3", + index: 2, + type: "date_time", + required: false, + value: "", + label: "

Date & Time

", + file_types: null, + format: "", + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 3, + wizardId: "super_mega_fun_wizard", + stepId: "step_2", + _validState: 0, }, { - "id": "step_2_field_4", - "index": 3, - "type": "number", - "required": false, - "value": "", - "label": "

Number

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 5, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_2", - "_validState": 0 + id: "step_2_field_4", + index: 3, + type: "number", + required: false, + value: "", + label: "

Number

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 5, + wizardId: "super_mega_fun_wizard", + stepId: "step_2", + _validState: 0, }, { - "id": "step_2_field_5", - "index": 4, - "type": "checkbox", - "required": false, - "value": false, - "label": "

Checkbox

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 6, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_2", - "_validState": 0 + id: "step_2_field_5", + index: 4, + type: "checkbox", + required: false, + value: false, + label: "

Checkbox

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 6, + wizardId: "super_mega_fun_wizard", + stepId: "step_2", + _validState: 0, }, { - "id": "step_2_field_6", - "index": 5, - "type": "url", - "required": false, - "value": "", - "label": "

Url

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 7, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_2", - "_validState": 0 + id: "step_2_field_6", + index: 5, + type: "url", + required: false, + value: "", + label: "

Url

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 7, + wizardId: "super_mega_fun_wizard", + stepId: "step_2", + _validState: 0, }, { - "id": "step_2_field_7", - "index": 6, - "type": "upload", - "required": false, - "value": "", - "label": "

Upload

", - "file_types": ".jpg,.jpeg,.png", - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 8, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_2", - "_validState": 0 - } + id: "step_2_field_7", + index: 6, + type: "upload", + required: false, + value: "", + label: "

Upload

", + file_types: ".jpg,.jpeg,.png", + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 8, + wizardId: "super_mega_fun_wizard", + stepId: "step_2", + _validState: 0, + }, ], - "_validState": 0, - "wizardId": "super_mega_fun_wizard" + _validState: 0, + wizardId: "super_mega_fun_wizard", }, { - "id": "step_3", - "index": 2, - "previous": "step_2", - "description": "

Unfortunately not the edible type \":sushi:\"

", - "title": "Combo-boxes", - "permitted": true, - "permitted_message": null, - "final": true, - "fields": [ + id: "step_3", + index: 2, + previous: "step_2", + description: + '

Unfortunately not the edible type :sushi:

', + title: "Combo-boxes", + permitted: true, + permitted_message: null, + final: true, + fields: [ { - "id": "step_3_field_1", - "index": 0, - "type": "dropdown", - "required": false, - "value": "choice1", - "label": "

Custom Dropdown

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": [ + id: "step_3_field_1", + index: 0, + type: "dropdown", + required: false, + value: "choice1", + label: "

Custom Dropdown

", + file_types: null, + format: null, + limit: null, + property: null, + content: [ { - "id": "one", - "name": "One" + id: "one", + name: "One", }, { - "id": "two", - "name": "Two" - } + id: "two", + name: "Two", + }, ], - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 1, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_3", - "_validState": 0 + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 1, + wizardId: "super_mega_fun_wizard", + stepId: "step_3", + _validState: 0, }, { - "id": "step_3_field_2", - "index": 0, - "type": "tag", - "required": false, - "value": null, - "label": "

Tag

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 2, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_3", - "_validState": 0 + id: "step_3_field_2", + index: 0, + type: "tag", + required: false, + value: null, + label: "

Tag

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 2, + wizardId: "super_mega_fun_wizard", + stepId: "step_3", + _validState: 0, }, { - "id": "step_3_field_3", - "index": 2, - "type": "category", - "required": false, - "value": null, - "label": "

Category

", - "file_types": null, - "format": null, - "limit": 1, - "property": "id", - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 3, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_3", - "_validState": 0 + id: "step_3_field_3", + index: 2, + type: "category", + required: false, + value: null, + label: "

Category

", + file_types: null, + format: null, + limit: 1, + property: "id", + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 3, + wizardId: "super_mega_fun_wizard", + stepId: "step_3", + _validState: 0, }, { - "id": "step_3_field_4", - "index": 3, - "type": "group", - "required": false, - "value": null, - "label": "

Group

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 4, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_3", - "_validState": 0 + id: "step_3_field_4", + index: 3, + type: "group", + required: false, + value: null, + label: "

Group

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 4, + wizardId: "super_mega_fun_wizard", + stepId: "step_3", + _validState: 0, }, { - "id": "step_3_field_5", - "index": 4, - "type": "user_selector", - "required": false, - "value": null, - "label": "

User Selector

", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 5, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_3", - "_validState": 0 + id: "step_3_field_5", + index: 4, + type: "user_selector", + required: false, + value: null, + label: "

User Selector

", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 5, + wizardId: "super_mega_fun_wizard", + stepId: "step_3", + _validState: 0, }, { - "id": "step_3_field_6", - "index": 5, - "type": "user_selector", - "required": false, - "value": null, - "label": "

Conditional User Selector

", - "description": "Shown when checkbox in step_2_field_5 is true", - "file_types": null, - "format": null, - "limit": null, - "property": null, - "content": null, - "validations": {}, - "max_length": null, - "char_counter": null, - "preview_template": null, - "tabindex": 6, - "wizardId": "super_mega_fun_wizard", - "stepId": "step_3", - "_validState": 0 - } + id: "step_3_field_6", + index: 5, + type: "user_selector", + required: false, + value: null, + label: "

Conditional User Selector

", + description: "Shown when checkbox in step_2_field_5 is true", + file_types: null, + format: null, + limit: null, + property: null, + content: null, + validations: {}, + max_length: null, + char_counter: null, + preview_template: null, + tabindex: 6, + wizardId: "super_mega_fun_wizard", + stepId: "step_3", + _validState: 0, + }, ], - "_validState": 0, - "wizardId": "super_mega_fun_wizard" - } + _validState: 0, + wizardId: "super_mega_fun_wizard", + }, ], - "groups": [] -} + groups: [], +}; diff --git a/assets/javascripts/wizard/tests/helpers/acceptance.js.es6 b/assets/javascripts/wizard/tests/helpers/acceptance.js.es6 index f5c1175f..913e8c7a 100644 --- a/assets/javascripts/wizard/tests/helpers/acceptance.js.es6 +++ b/assets/javascripts/wizard/tests/helpers/acceptance.js.es6 @@ -6,18 +6,20 @@ let server; let app; function acceptance(name, requests, cb) { - module(`Acceptance: ${name}`, function(hooks) { - hooks.beforeEach(function() { - server = setupPretender(function(pretender) { - requests.forEach(req => { - pretender[req.verb](req.path, () => (response(req.status, req.response))); + module(`Acceptance: ${name}`, function (hooks) { + hooks.beforeEach(function () { + server = setupPretender(function (pretender) { + requests.forEach((req) => { + pretender[req.verb](req.path, () => + response(req.status, req.response) + ); }); return pretender; }); app = startApp(); }); - hooks.afterEach(function() { + hooks.afterEach(function () { app.destroy(); server.shutdown(); }); @@ -28,9 +30,7 @@ function acceptance(name, requests, cb) { export default acceptance; -export { - server -}; +export { server }; // The discourse/test/helpers/qunit-helpers file has many functions and imports // we don't need, so there will be some duplciation here. diff --git a/assets/javascripts/wizard/tests/helpers/start-app.js.es6 b/assets/javascripts/wizard/tests/helpers/start-app.js.es6 index 6afe6eb9..821d8033 100644 --- a/assets/javascripts/wizard/tests/helpers/start-app.js.es6 +++ b/assets/javascripts/wizard/tests/helpers/start-app.js.es6 @@ -1,6 +1,12 @@ -const CustomWizard = requirejs("discourse/plugins/discourse-custom-wizard/wizard/application").default; -const initializer = requirejs("discourse/plugins/discourse-custom-wizard/wizard/lib/initialize/wizard").default; -const siteSettings = requirejs("discourse/plugins/discourse-custom-wizard/wizard/tests/fixtures/site-settings").default; +const CustomWizard = requirejs( + "discourse/plugins/discourse-custom-wizard/wizard/application" +).default; +const initializer = requirejs( + "discourse/plugins/discourse-custom-wizard/wizard/lib/initialize/wizard" +).default; +const siteSettings = requirejs( + "discourse/plugins/discourse-custom-wizard/wizard/tests/fixtures/site-settings" +).default; const { cloneJSON } = requirejs("discourse-common/lib/object").default; let app; diff --git a/assets/javascripts/wizard/tests/helpers/step.js.es6 b/assets/javascripts/wizard/tests/helpers/step.js.es6 index a24e04e1..41fe16cd 100644 --- a/assets/javascripts/wizard/tests/helpers/step.js.es6 +++ b/assets/javascripts/wizard/tests/helpers/step.js.es6 @@ -5,16 +5,13 @@ import wizardJson from "../fixtures/wizard"; const update = cloneJSON(updateJson); update.wizard = cloneJSON(wizardJson); -const saveStep = function(response) { +const saveStep = function (response) { return { verb: "put", - path: '/w/wizard/steps/:step_id', + path: "/w/wizard/steps/:step_id", status: 200, - response - } -} + response, + }; +}; -export { - saveStep, - update -} +export { saveStep, update }; diff --git a/assets/javascripts/wizard/tests/helpers/test.js.es6 b/assets/javascripts/wizard/tests/helpers/test.js.es6 index c7401fd5..360c883a 100644 --- a/assets/javascripts/wizard/tests/helpers/test.js.es6 +++ b/assets/javascripts/wizard/tests/helpers/test.js.es6 @@ -2,6 +2,4 @@ function exists(selector) { return document.querySelector(selector) !== null; } -export { - exists -} +export { exists }; diff --git a/assets/javascripts/wizard/tests/helpers/wizard.js.es6 b/assets/javascripts/wizard/tests/helpers/wizard.js.es6 index 997f6c36..4cd2e003 100644 --- a/assets/javascripts/wizard/tests/helpers/wizard.js.es6 +++ b/assets/javascripts/wizard/tests/helpers/wizard.js.es6 @@ -26,20 +26,20 @@ const allFieldsWizard = cloneJSON(wizard); allFieldsWizard.steps[0].fields = [ ...allFieldsWizard.steps[0].fields, ...allFieldsWizard.steps[1].fields, - ...allFieldsWizard.steps[2].fields + ...allFieldsWizard.steps[2].fields, ]; allFieldsWizard.steps = [cloneJSON(allFieldsWizard.steps[0])]; -allFieldsWizard.categories = cloneJSON(categoriesJson['categories']); -allFieldsWizard.groups = cloneJSON(groupsJson['groups']); +allFieldsWizard.categories = cloneJSON(categoriesJson["categories"]); +allFieldsWizard.groups = cloneJSON(groupsJson["groups"]); -const getWizard = function(response) { +const getWizard = function (response) { return { verb: "get", path: "/w/wizard", status: 200, - response - } -} + response, + }; +}; export { getWizard, @@ -48,5 +48,5 @@ export { wizardCompleted, stepNotPermitted, allFieldsWizard, - wizard -} + wizard, +}; diff --git a/assets/javascripts/wizard/tests/pretender.js.es6 b/assets/javascripts/wizard/tests/pretender.js.es6 index 88eae666..1f1d4a7d 100644 --- a/assets/javascripts/wizard/tests/pretender.js.es6 +++ b/assets/javascripts/wizard/tests/pretender.js.es6 @@ -1,23 +1,5 @@ import Pretender from "pretender"; -function parsePostData(query) { - const result = {}; - query.split("&").forEach(function (part) { - const item = part.split("="); - const firstSeg = decodeURIComponent(item[0]); - const m = /^([^\[]+)\[([^\]]+)\]/.exec(firstSeg); - - const val = decodeURIComponent(item[1]).replace(/\+/g, " "); - if (m) { - result[m[1]] = result[m[1]] || {}; - result[m[1]][m[2]] = val; - } else { - result[firstSeg] = val; - } - }); - return result; -} - function response(code, obj) { if (typeof code === "object") { obj = code; @@ -42,7 +24,7 @@ export default function (cb) { return body; }; - server.unhandledRequest = function (verb, path, request) { + server.unhandledRequest = function (verb, path) { const error = "Unhandled request in test environment: " + path + " (" + verb + ")"; window.console.error(error); From e7755b106f3edf805f817fec901296f320de034b Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 16 Mar 2022 14:09:23 +0100 Subject: [PATCH 05/11] Update workflow to add frontend tests && handle deprecations --- .github/workflows/plugin-tests.yml | 16 +------- .../components/custom-user-selector.js.es6 | 3 +- .../components/wizard-field-category.js.es6 | 3 +- .../components/wizard-field-composer.js.es6 | 3 +- .../wizard/components/wizard-step.js.es6 | 6 +-- .../components/wizard-text-field.js.es6 | 3 +- .../lib/initialize/inject-objects.js.es6 | 38 +++++++++---------- .../lib/initialize/patch-components.js.es6 | 16 ++++++++ .../wizard/lib/initialize/wizard.js.es6 | 1 + .../javascripts/wizard/lib/load-script.js.es6 | 16 ++++---- .../javascripts/wizard/lib/text-lite.js.es6 | 16 +++++--- .../javascripts/wizard/lib/user-search.js.es6 | 3 +- assets/javascripts/wizard/models/step.js.es6 | 3 +- .../javascripts/wizard/models/wizard.js.es6 | 3 +- .../components/wizard-composer-editor.hbs | 2 +- assets/javascripts/wizard/templates/step.hbs | 5 +-- 16 files changed, 76 insertions(+), 61 deletions(-) diff --git a/.github/workflows/plugin-tests.yml b/.github/workflows/plugin-tests.yml index 782ebc4f..baf5e381 100644 --- a/.github/workflows/plugin-tests.yml +++ b/.github/workflows/plugin-tests.yml @@ -73,18 +73,6 @@ jobs: ref: "${{ github.base_ref }}" fetch-depth: 1 - - name: Check spec existence - id: check_spec - uses: andstor/file-existence-action@v1 - with: - files: "plugins/${{ steps.repo-name.outputs.value }}/spec" - - - name: Check qunit existence - id: check_qunit - uses: andstor/file-existence-action@v1 - with: - files: "plugins/${{ steps.repo-name.outputs.value }}/test/javascripts" - - name: Setup Git run: | git config --global user.email "ci@ci.invalid" @@ -140,7 +128,7 @@ jobs: bin/rake db:migrate - name: Plugin RSpec with Coverage - if: matrix.build_type == 'backend' && steps.check_spec.outputs.files_exists == 'true' + if: matrix.build_type == 'backend' run: | if [ -e plugins/${{ steps.repo-name.outputs.value }}/.simplecov ] then @@ -150,6 +138,6 @@ jobs: bin/rake plugin:spec[${{ steps.repo-name.outputs.value }}] - name: Plugin QUnit - if: matrix.build_type == 'frontend' && steps.check_qunit.outputs.files_exists == 'true' + if: matrix.build_type == 'frontend' run: bundle exec rake plugin:qunit['${{ steps.repo-name.outputs.value }}','1200000'] timeout-minutes: 30 diff --git a/assets/javascripts/wizard/components/custom-user-selector.js.es6 b/assets/javascripts/wizard/components/custom-user-selector.js.es6 index c53c3bf4..56eb8f57 100644 --- a/assets/javascripts/wizard/components/custom-user-selector.js.es6 +++ b/assets/javascripts/wizard/components/custom-user-selector.js.es6 @@ -7,6 +7,7 @@ import userSearch from "../lib/user-search"; import WizardI18n from "../lib/wizard-i18n"; import Handlebars from "handlebars"; import { isEmpty } from "@ember/utils"; +import TextField from "@ember/component/text-field"; const template = function (params) { const options = params.options; @@ -31,7 +32,7 @@ const template = function (params) { return new Handlebars.SafeString(html).string; }; -export default Ember.TextField.extend({ +export default TextField.extend({ attributeBindings: ["autofocus", "maxLength"], autocorrect: false, autocapitalize: false, diff --git a/assets/javascripts/wizard/components/wizard-field-category.js.es6 b/assets/javascripts/wizard/components/wizard-field-category.js.es6 index 9f4b65ba..441f83d3 100644 --- a/assets/javascripts/wizard/components/wizard-field-category.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-category.js.es6 @@ -1,7 +1,8 @@ import { observes } from "discourse-common/utils/decorators"; import Category from "discourse/models/category"; +import Component from "@ember/component"; -export default Ember.Component.extend({ +export default Component.extend({ layoutName: "wizard/templates/components/wizard-field-category", didInsertElement() { diff --git a/assets/javascripts/wizard/components/wizard-field-composer.js.es6 b/assets/javascripts/wizard/components/wizard-field-composer.js.es6 index 07829e8a..255982ea 100644 --- a/assets/javascripts/wizard/components/wizard-field-composer.js.es6 +++ b/assets/javascripts/wizard/components/wizard-field-composer.js.es6 @@ -3,8 +3,9 @@ import { observes, } from "discourse-common/utils/decorators"; import EmberObject from "@ember/object"; +import Component from "@ember/component"; -export default Ember.Component.extend({ +export default Component.extend({ layoutName: "wizard/templates/components/wizard-field-composer", showPreview: false, diff --git a/assets/javascripts/wizard/components/wizard-step.js.es6 b/assets/javascripts/wizard/components/wizard-step.js.es6 index 18b1a255..ea1a63c6 100644 --- a/assets/javascripts/wizard/components/wizard-step.js.es6 +++ b/assets/javascripts/wizard/components/wizard-step.js.es6 @@ -87,7 +87,7 @@ export default Component.extend({ @observes("step.message") _handleMessage: function () { const message = this.get("step.message"); - this.sendAction("showMessage", message); + this.showMessage(message); }, keyPress(event) { @@ -162,7 +162,7 @@ export default Component.extend({ if (response["final"]) { CustomWizard.finished(response); } else { - this.sendAction("goNext", response); + this.goNext(response); } }) .catch(() => this.animateInvalidFields()) @@ -181,7 +181,7 @@ export default Component.extend({ }, showMessage(message) { - this.sendAction("showMessage", message); + this.sendAction(message); }, stylingDropdownChanged(id, value) { diff --git a/assets/javascripts/wizard/components/wizard-text-field.js.es6 b/assets/javascripts/wizard/components/wizard-text-field.js.es6 index 3d87be09..5991eefc 100644 --- a/assets/javascripts/wizard/components/wizard-text-field.js.es6 +++ b/assets/javascripts/wizard/components/wizard-text-field.js.es6 @@ -1,8 +1,9 @@ import computed from "discourse-common/utils/decorators"; import { isLTR, isRTL, siteDir } from "discourse/lib/text-direction"; import WizardI18n from "../lib/wizard-i18n"; +import TextField from "@ember/component/text-field"; -export default Ember.TextField.extend({ +export default TextField.extend({ attributeBindings: [ "autocorrect", "autocapitalize", diff --git a/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 b/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 index fb11c9e7..51dff7e1 100644 --- a/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 +++ b/assets/javascripts/wizard/lib/initialize/inject-objects.js.es6 @@ -1,5 +1,11 @@ export default { run(app) { + // siteSettings must always be registered first + if (!app.hasRegistration("site-settings:main")) { + const siteSettings = app.SiteSettings; + app.register("site-settings:main", siteSettings, { instantiate: false }); + } + const Store = requirejs("discourse/services/store").default; const Site = requirejs( "discourse/plugins/discourse-custom-wizard/wizard/models/site" @@ -10,11 +16,10 @@ export default { const sniffCapabilites = requirejs( "discourse/pre-initializers/sniff-capabilities" ).default; + const site = Site.current(); const session = Session.current(); - const registrations = [ - ["site-settings:main", app.SiteSettings, false], ["message-bus:main", messageBus, false], ["site:main", site, false], ["session:main", session, false], @@ -30,25 +35,18 @@ export default { } }); - const targets = [ - "controller", - "component", - "route", - "model", - "adapter", - "mixin", - ]; - const injections = [ - ["siteSettings", "site-settings:main"], - ["messageBus", "message-bus:main"], - ["site", "site:main"], - ["session", "session:main"], - ["store", "service:store"], - ["appEvents", "service:app-events"], - ]; + const targets = ["controller", "component", "route", "model", "adapter"]; - injections.forEach((injection) => { - targets.forEach((t) => app.inject(t, injection[0], injection[1])); + targets.forEach((t) => { + app.inject(t, "appEvents", "service:app-events"); + app.inject(t, "store", "service:store"); + app.inject(t, "site", "site:main"); + }); + + targets.concat("service").forEach((t) => { + app.inject(t, "session", "session:main"); + app.inject(t, "messageBus", "message-bus:main"); + app.inject(t, "siteSettings", "site-settings:main"); }); if (!app.hasRegistration("capabilities:main")) { diff --git a/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 b/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 index 75cc63f1..d5e7ea25 100644 --- a/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 +++ b/assets/javascripts/wizard/lib/initialize/patch-components.js.es6 @@ -22,6 +22,11 @@ export default { const DEditor = requirejs("discourse/components/d-editor").default; const { clipboardHelpers } = requirejs("discourse/lib/utilities"); const toMarkdown = requirejs("discourse/lib/to-markdown").default; + const discourseComputed = requirejs("discourse-common/utils/decorators") + .default; + const WizardI18n = requirejs( + "discourse/plugins/discourse-custom-wizard/wizard/lib/wizard-i18n" + ).default; const isInside = (text, regex) => { const matches = text.match(regex); return matches && matches.length % 2; @@ -46,6 +51,17 @@ export default { } }, + @discourseComputed("placeholder", "placeholderOverride") + placeholderTranslated(placeholder, placeholderOverride) { + if (placeholderOverride) { + return placeholderOverride; + } + if (placeholder) { + return WizardI18n(placeholder); + } + return null; + }, + _wizardInsertText(args = {}) { if (args.fieldId === this.fieldId) { this._insertText(args.text, args.options); diff --git a/assets/javascripts/wizard/lib/initialize/wizard.js.es6 b/assets/javascripts/wizard/lib/initialize/wizard.js.es6 index 0020f7a8..915e5f26 100644 --- a/assets/javascripts/wizard/lib/initialize/wizard.js.es6 +++ b/assets/javascripts/wizard/lib/initialize/wizard.js.es6 @@ -40,6 +40,7 @@ export default { const Session = requirejs("discourse/models/session").default; const session = Session.current(); session.set("highlightJsPath", setupData.highlightJsPath); + session.set("markdownItUrl", setupData.markdownItUrl); [ "register-files", diff --git a/assets/javascripts/wizard/lib/load-script.js.es6 b/assets/javascripts/wizard/lib/load-script.js.es6 index 43d97d0a..d0b07c26 100644 --- a/assets/javascripts/wizard/lib/load-script.js.es6 +++ b/assets/javascripts/wizard/lib/load-script.js.es6 @@ -1,5 +1,7 @@ import { ajax } from "wizard/lib/ajax"; -import getURL from "discourse-common/lib/get-url"; +import getURL, { getURLWithCDN } from "discourse-common/lib/get-url"; +import { run } from "@ember/runloop"; +import { Promise } from "rsvp"; const _loaded = {}; const _loading = {}; @@ -25,7 +27,7 @@ function loadWithTag(path, cb) { ) { s = s.onload = s.onreadystatechange = null; if (!abort) { - Ember.run(null, cb); + run(null, cb); } } }; @@ -38,7 +40,7 @@ export function loadCSS(url) { export default function loadScript(url, opts) { // TODO: Remove this once plugins have been updated not to use it: if (url === "defer/html-sanitizer-bundle") { - return Ember.RSVP.Promise.resolve(); + return Promise.resolve(); } opts = opts || {}; @@ -51,7 +53,7 @@ export default function loadScript(url, opts) { } }); - return new Ember.RSVP.Promise(function (resolve) { + return new Promise(function (resolve) { url = getURL(url); // If we already loaded this url @@ -63,7 +65,7 @@ export default function loadScript(url, opts) { } let done; - _loading[url] = new Ember.RSVP.Promise(function (_done) { + _loading[url] = new Promise(function (_done) { done = _done; }); @@ -84,8 +86,8 @@ export default function loadScript(url, opts) { // Scripts should always load from CDN // CSS is type text, to accept it from a CDN we would need to handle CORS - if (!opts.css && Discourse.CDN && url[0] === "/" && url[1] !== "/") { - cdnUrl = Discourse.CDN.replace(/\/$/, "") + url; + if (!opts.css) { + cdnUrl = getURLWithCDN(url); } // Some javascript depends on the path of where it is loaded (ace editor) diff --git a/assets/javascripts/wizard/lib/text-lite.js.es6 b/assets/javascripts/wizard/lib/text-lite.js.es6 index cc161426..26cfc27a 100644 --- a/assets/javascripts/wizard/lib/text-lite.js.es6 +++ b/assets/javascripts/wizard/lib/text-lite.js.es6 @@ -3,6 +3,8 @@ import { default as PrettyText, buildOptions } from "pretty-text/pretty-text"; import Handlebars from "handlebars"; import getURL from "discourse-common/lib/get-url"; import { getOwner } from "discourse-common/lib/get-owner"; +import { Promise } from "rsvp"; +import Session from "discourse/models/session"; export function cook(text, options) { if (!options) { @@ -18,11 +20,15 @@ export function cook(text, options) { // everything should eventually move to async API and this should be renamed // cook export function cookAsync(text, options) { - if (Discourse.MarkdownItURL) { - return loadScript(Discourse.MarkdownItURL) - .then(() => cook(text, options)) - .catch((e) => Ember.Logger.error(e)); + let markdownItURL = Session.currentProp("markdownItURL"); + if (markdownItURL) { + return ( + loadScript(markdownItURL) + .then(() => cook(text, options)) + // eslint-disable-next-line no-console + .catch((e) => console.error(e)) + ); } else { - return Ember.RSVP.Promise.resolve(cook(text)); + return Promise.resolve(cook(text)); } } diff --git a/assets/javascripts/wizard/lib/user-search.js.es6 b/assets/javascripts/wizard/lib/user-search.js.es6 index e7171f18..04b6f97c 100644 --- a/assets/javascripts/wizard/lib/user-search.js.es6 +++ b/assets/javascripts/wizard/lib/user-search.js.es6 @@ -1,6 +1,7 @@ import { CANCELLED_STATUS } from "discourse/lib/autocomplete"; import { debounce } from "@ember/runloop"; import getUrl from "discourse-common/lib/get-url"; +import { Promise } from "rsvp"; let cache = {}, cacheTopicId, @@ -120,7 +121,7 @@ export default function userSearch(options) { currentTerm = term; - return new Ember.RSVP.Promise(function (resolve) { + return new Promise(function (resolve) { // TODO site setting for allowed regex in username if (term.match(/[^\w_\-\.@\+]/)) { resolve([]); diff --git a/assets/javascripts/wizard/models/step.js.es6 b/assets/javascripts/wizard/models/step.js.es6 index 2729e993..36503276 100644 --- a/assets/javascripts/wizard/models/step.js.es6 +++ b/assets/javascripts/wizard/models/step.js.es6 @@ -3,6 +3,7 @@ import ValidState from "wizard/mixins/valid-state"; import { ajax } from "wizard/lib/ajax"; import discourseComputed from "discourse-common/utils/decorators"; import { translatedText } from "discourse/plugins/discourse-custom-wizard/wizard/lib/wizard-i18n"; +import { later } from "@ember/runloop"; export default EmberObject.extend(ValidState, { id: null, @@ -105,6 +106,6 @@ export default EmberObject.extend(ValidState, { state: "error", text: message, }); - Ember.run.later(() => this.set("message", null), 6000); + later(() => this.set("message", null), 6000); }, }); diff --git a/assets/javascripts/wizard/models/wizard.js.es6 b/assets/javascripts/wizard/models/wizard.js.es6 index b2e26b25..15bcbb8c 100644 --- a/assets/javascripts/wizard/models/wizard.js.es6 +++ b/assets/javascripts/wizard/models/wizard.js.es6 @@ -113,8 +113,7 @@ CustomWizard.reopenClass({ } }); - Site.currentProp("categoriesList", categories); - Site.currentProp("sortedCategories", categories); + Site.currentProp("categories", categories); Site.currentProp("listByActivity", categories); Site.currentProp("categoriesById", categoriesById); Site.currentProp( diff --git a/assets/javascripts/wizard/templates/components/wizard-composer-editor.hbs b/assets/javascripts/wizard/templates/components/wizard-composer-editor.hbs index be98db8e..7d453a0b 100644 --- a/assets/javascripts/wizard/templates/components/wizard-composer-editor.hbs +++ b/assets/javascripts/wizard/templates/components/wizard-composer-editor.hbs @@ -1,7 +1,7 @@ {{d-editor tabindex=field.tabindex value=composer.reply - placeholderTranslated=replyPlaceholder + placeholderOverride=replyPlaceholder previewUpdated=(action "previewUpdated") markdownOptions=markdownOptions extraButtons=(action "extraButtons") diff --git a/assets/javascripts/wizard/templates/step.hbs b/assets/javascripts/wizard/templates/step.hbs index 6456a59c..5ed14cdf 100644 --- a/assets/javascripts/wizard/templates/step.hbs +++ b/assets/javascripts/wizard/templates/step.hbs @@ -13,8 +13,7 @@ {{#if step.permitted}} {{wizard-step step=step wizard=wizard - goNext="goNext" + goNext=(action "goNext") goBack=(action "goBack") - finished="finished" - showMessage="showMessage"}} + showMessage=(action "showMessage")}} {{/if}} From ea52b2779bbe9c382f719e5f69b0dfffff94b0f0 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 16 Mar 2022 14:10:54 +0100 Subject: [PATCH 06/11] Remove duplicated functions --- assets/javascripts/wizard/components/validator.js.es6 | 1 - assets/javascripts/wizard/components/wizard-step.js.es6 | 2 -- 2 files changed, 3 deletions(-) diff --git a/assets/javascripts/wizard/components/validator.js.es6 b/assets/javascripts/wizard/components/validator.js.es6 index dafbf8c0..aa68660c 100644 --- a/assets/javascripts/wizard/components/validator.js.es6 +++ b/assets/javascripts/wizard/components/validator.js.es6 @@ -11,7 +11,6 @@ export default Component.extend({ invalidMessageKey: null, isValid: null, isInvalid: equal("isValid", false), - layoutName: "wizard/templates/components/validator", init() { this._super(...arguments); diff --git a/assets/javascripts/wizard/components/wizard-step.js.es6 b/assets/javascripts/wizard/components/wizard-step.js.es6 index ea1a63c6..cc23c5bf 100644 --- a/assets/javascripts/wizard/components/wizard-step.js.es6 +++ b/assets/javascripts/wizard/components/wizard-step.js.es6 @@ -169,8 +169,6 @@ export default Component.extend({ .finally(() => this.set("saving", false)); }, - keyPress() {}, - actions: { quit() { this.get("wizard").skip(); From 61928ce4360a3837002e07417935e06f376cf562 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 16 Mar 2022 14:12:13 +0100 Subject: [PATCH 07/11] Apply rubocop --- app/serializers/custom_wizard/submission_serializer.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/serializers/custom_wizard/submission_serializer.rb b/app/serializers/custom_wizard/submission_serializer.rb index 9c2f8133..732d6743 100644 --- a/app/serializers/custom_wizard/submission_serializer.rb +++ b/app/serializers/custom_wizard/submission_serializer.rb @@ -7,12 +7,12 @@ class CustomWizard::SubmissionSerializer < ApplicationSerializer has_one :user, serializer: ::BasicUserSerializer, embed: :objects def include_user? - object.user.present? + object.user.present? end def fields @fields ||= begin - result = {} + result = {} object.wizard.template['steps'].each do |step| step['fields'].each do |field| From 6cd6b111bd3d5bec16dbccc5d745560e3636e356 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 16 Mar 2022 14:13:45 +0100 Subject: [PATCH 08/11] Bump minor version --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index e8dcf457..e745c3a8 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Create custom wizards for topic creation, onboarding, user surveys and much more. -# version: 1.18.4 +# version: 1.19.0 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George # contact_emails: support@thepavilion.io # url: https://github.com/paviliondev/discourse-custom-wizard From 7e295dfb1419d51333241b0e11cb073b016e3db2 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 16 Mar 2022 14:22:18 +0100 Subject: [PATCH 09/11] Update plugin-tests.yml --- .github/workflows/plugin-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/plugin-tests.yml b/.github/workflows/plugin-tests.yml index baf5e381..13f76074 100644 --- a/.github/workflows/plugin-tests.yml +++ b/.github/workflows/plugin-tests.yml @@ -139,5 +139,5 @@ jobs: - name: Plugin QUnit if: matrix.build_type == 'frontend' - run: bundle exec rake plugin:qunit['${{ steps.repo-name.outputs.value }}','1200000'] + run: LOAD_PLUGINS=1 QUNIT_EMBER_CLI=0 bin/rake "qunit:test['600000','/w/qunit']" timeout-minutes: 30 From 01d972f6baa4b6b24a2558a0102025e114b9990a Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 16 Mar 2022 14:39:39 +0100 Subject: [PATCH 10/11] Try using bundle exec --- .github/workflows/plugin-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/plugin-tests.yml b/.github/workflows/plugin-tests.yml index 13f76074..34af2f04 100644 --- a/.github/workflows/plugin-tests.yml +++ b/.github/workflows/plugin-tests.yml @@ -139,5 +139,5 @@ jobs: - name: Plugin QUnit if: matrix.build_type == 'frontend' - run: LOAD_PLUGINS=1 QUNIT_EMBER_CLI=0 bin/rake "qunit:test['600000','/w/qunit']" + run: LOAD_PLUGINS=1 QUNIT_EMBER_CLI=0 bundle exec rake "qunit:test['600000','/w/qunit']" timeout-minutes: 30 From 591274d38fcf09e7c5816bfd184b0a095e59dc97 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 16 Mar 2022 15:07:49 +0100 Subject: [PATCH 11/11] Skip core qunit --- .github/workflows/plugin-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/plugin-tests.yml b/.github/workflows/plugin-tests.yml index 34af2f04..f32cdf5c 100644 --- a/.github/workflows/plugin-tests.yml +++ b/.github/workflows/plugin-tests.yml @@ -139,5 +139,5 @@ jobs: - name: Plugin QUnit if: matrix.build_type == 'frontend' - run: LOAD_PLUGINS=1 QUNIT_EMBER_CLI=0 bundle exec rake "qunit:test['600000','/w/qunit']" + run: QUNIT_SKIP_CORE=1 LOAD_PLUGINS=1 QUNIT_EMBER_CLI=0 bin/rake "qunit:test['600000','/w/qunit']" timeout-minutes: 30