1
0
Fork 0

First release candidate

Dieser Commit ist enthalten in:
Angus McLeod 2022-07-27 11:47:50 +01:00
Ursprung 11ff38ae90
Commit 60823cd87a
35 geänderte Dateien mit 788 neuen und 880 gelöschten Zeilen

Datei anzeigen

@ -46,8 +46,9 @@ jobs:
yarn prettier --list-different "assets/javascripts/{discourse,wizard}/**/*.{scss,js,es6}" ; \ yarn prettier --list-different "assets/javascripts/{discourse,wizard}/**/*.{scss,js,es6}" ; \
fi fi
- name: Ember template lint # Until templates are converted
run: yarn ember-template-lint assets/javascripts #- name: Ember template lint
#run: yarn ember-template-lint assets/javascripts
- name: Rubocop - name: Rubocop
run: bundle exec rubocop . run: bundle exec rubocop .

Datei anzeigen

@ -132,3 +132,8 @@ jobs:
export COVERAGE=1 export COVERAGE=1
fi fi
bin/rake plugin:spec[${{ steps.repo-name.outputs.value }}] bin/rake plugin:spec[${{ steps.repo-name.outputs.value }}]
- name: Plugin QUnit
if: matrix.build_type == 'frontend'
run: bin/rake plugin:qunit['${{ steps.repo-name.outputs.value }}','1200000']
timeout-minutes: 30

Datei anzeigen

@ -1,4 +1,4 @@
import CustomWizard from "../models/wizard"; import CustomWizard from "../models/custom-wizard";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import Component from "@ember/component"; import Component from "@ember/component";
import { dasherize } from "@ember/string"; import { dasherize } from "@ember/string";

Datei anzeigen

@ -7,7 +7,7 @@ import { schedule } from "@ember/runloop";
import { cookAsync } from "discourse/lib/text"; import { cookAsync } from "discourse/lib/text";
import CustomWizard, { import CustomWizard, {
updateCachedWizard, updateCachedWizard,
} from "discourse/plugins/discourse-custom-wizard/discourse/models/wizard"; } from "discourse/plugins/discourse-custom-wizard/discourse/models/custom-wizard";
import { alias, not } from "@ember/object/computed"; import { alias, not } from "@ember/object/computed";
const alreadyWarned = {}; const alreadyWarned = {};

Datei anzeigen

@ -1,9 +1,9 @@
import CustomWizard from "../../models/custom-wizard"; import CustomWizardAdmin from "../../models/custom-wizard-admin";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
export default { export default {
setupComponent(attrs, component) { setupComponent(attrs, component) {
CustomWizard.all() CustomWizardAdmin.all()
.then((result) => { .then((result) => {
component.set("wizardList", result); component.set("wizardList", result);
}) })

Datei anzeigen

@ -20,29 +20,8 @@ export default Controller.extend({
"application/x-www-form-urlencoded", "application/x-www-form-urlencoded",
]), ]),
successCodes: selectKitContent([ successCodes: selectKitContent([
100, 100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301,
101, 302, 303, 303, 304, 305, 306, 307, 308,
102,
200,
201,
202,
203,
204,
205,
206,
207,
208,
226,
300,
301,
302,
303,
303,
304,
305,
306,
307,
308,
]), ]),
@discourseComputed( @discourseComputed(
@ -166,7 +145,7 @@ export default Controller.extend({
const originalTitle = this.get("api.originalTitle"); const originalTitle = this.get("api.originalTitle");
if (api.get("isNew") || (originalTitle && api.title !== originalTitle)) { if (api.get("isNew") || (originalTitle && api.title !== originalTitle)) {
refreshList = true; refreshList = true; // eslint-disable-line
} }
if (api.get("isNew")) { if (api.get("isNew")) {

Datei anzeigen

@ -0,0 +1,55 @@
export default {
resource: "admin",
map() {
this.route(
"adminWizards",
{ path: "/wizards", resetNamespace: true },
function () {
this.route(
"adminWizardsWizard",
{ path: "/wizard/", resetNamespace: true },
function () {
this.route("adminWizardsWizardShow", {
path: "/:wizardId/",
resetNamespace: true,
});
}
);
this.route("adminWizardsCustomFields", {
path: "/custom-fields",
resetNamespace: true,
});
this.route(
"adminWizardsSubmissions",
{ path: "/submissions", resetNamespace: true },
function () {
this.route("adminWizardsSubmissionsShow", {
path: "/:wizardId/",
resetNamespace: true,
});
}
);
this.route(
"adminWizardsApi",
{ path: "/api", resetNamespace: true },
function () {
this.route("adminWizardsApiShow", {
path: "/:name",
resetNamespace: true,
});
}
);
this.route("adminWizardsLogs", { path: "/logs", resetNamespace: true });
this.route("adminWizardsManager", {
path: "/manager",
resetNamespace: true,
});
}
);
},
};

Datei anzeigen

@ -9,55 +9,4 @@ export default function () {
}); });
} }
); );
this.route(
"adminWizards",
{ path: "/wizards", resetNamespace: true },
function () {
this.route(
"adminWizardsWizard",
{ path: "/wizard/", resetNamespace: true },
function () {
this.route("adminWizardsWizardShow", {
path: "/:wizardId/",
resetNamespace: true,
});
}
);
this.route("adminWizardsCustomFields", {
path: "/custom-fields",
resetNamespace: true,
});
this.route(
"adminWizardsSubmissions",
{ path: "/submissions", resetNamespace: true },
function () {
this.route("adminWizardsSubmissionsShow", {
path: "/:wizardId/",
resetNamespace: true,
});
}
);
this.route(
"adminWizardsApi",
{ path: "/api", resetNamespace: true },
function () {
this.route("adminWizardsApiShow", {
path: "/:name",
resetNamespace: true,
});
}
);
this.route("adminWizardsLogs", { path: "/logs", resetNamespace: true });
this.route("adminWizardsManager", {
path: "/manager",
resetNamespace: true,
});
}
);
} }

Datei anzeigen

@ -1,6 +0,0 @@
import { registerUnbound } from "discourse-common/lib/helpers";
import { dasherize } from "@ember/string";
registerUnbound("dasherize", function (string) {
return dasherize(string);
});

Datei anzeigen

@ -1,23 +0,0 @@
import { registerUnbound } from "discourse-common/lib/helpers";
import { longDate, relativeAge } from "discourse/lib/formatter";
import Handlebars from "handlebars";
export default registerUnbound("date-node", function (dt) {
if (typeof dt === "string") {
dt = new Date(dt);
}
if (dt) {
const attributes = {
title: longDate(dt),
"data-time": dt.getTime(),
"data-format": "tiny",
};
const finalString = `<span class="relative-date" title="${
attributes["title"]
}" data-time="${attributes["data-time"]}" data-format="${
attributes["data-format"]
}">${relativeAge(dt)}</span>`;
return new Handlebars.SafeString(finalString);
}
});

Datei anzeigen

@ -1,6 +0,0 @@
import { registerUnbound } from "discourse-common/lib/helpers";
import Handlebars from "handlebars";
export default registerUnbound("dir-span", function (str) {
return new Handlebars.SafeString(str);
});

Datei anzeigen

@ -1,17 +0,0 @@
import { htmlHelper } from "discourse-common/lib/helpers";
function renderSpinner(cssClass) {
var html = "<div class='spinner";
if (cssClass) {
html += " " + cssClass;
}
return html + "'></div>";
}
var spinnerHTML = renderSpinner();
export default htmlHelper((params) => {
const hash = params.hash;
return renderSpinner(hash && hash.size ? hash.size : undefined);
});
export { spinnerHTML, renderSpinner };

Datei anzeigen

@ -38,6 +38,7 @@ export default {
}); });
api.modifyClass("component:uppy-image-uploader", { api.modifyClass("component:uppy-image-uploader", {
pluginId: "custom-wizard",
// Needed to ensure appEvents get registered when navigating between steps // Needed to ensure appEvents get registered when navigating between steps
@observes("id") @observes("id")
initOnStepChange() { initOnStepChange() {

Datei anzeigen

@ -0,0 +1,227 @@
import EmberObject from "@ember/object";
import { buildProperties, mapped, present } from "../lib/wizard-json";
import { listProperties, snakeCase } from "../lib/wizard";
import wizardSchema from "../lib/wizard-schema";
import { Promise } from "rsvp";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
const CustomWizardAdmin = EmberObject.extend({
save(opts) {
return new Promise((resolve, reject) => {
let wizard = this.buildJson(this, "wizard");
if (wizard.error) {
reject(wizard);
}
let data = {
wizard,
};
if (opts.create) {
data.create = true;
}
ajax(`/admin/wizards/wizard/${wizard.id}`, {
type: "PUT",
contentType: "application/json",
data: JSON.stringify(data),
}).then((result) => {
if (result.backend_validation_error) {
reject(result);
} else {
resolve(result);
}
});
});
},
buildJson(object, type, result = {}) {
let objectType = object.type || null;
if (wizardSchema[type].types) {
if (!objectType) {
result.error = {
type: "required",
params: { type, property: "type" },
};
return result;
}
}
for (let property of listProperties(type, { objectType })) {
let value = object.get(property);
result = this.validateValue(property, value, object, type, result);
if (result.error) {
break;
}
if (mapped(property, type)) {
value = this.buildMappedJson(value);
}
if (value !== undefined && value !== null) {
result[property] = value;
}
}
if (!result.error) {
for (let arrayObjectType of Object.keys(
wizardSchema[type].objectArrays
)) {
let arraySchema = wizardSchema[type].objectArrays[arrayObjectType];
let objectArray = object.get(arraySchema.property);
if (arraySchema.required && !present(objectArray)) {
result.error = {
type: "required",
params: { type, property: arraySchema.property },
};
break;
}
result[arraySchema.property] = [];
for (let item of objectArray) {
let itemProps = this.buildJson(item, arrayObjectType);
if (itemProps.error) {
result.error = itemProps.error;
break;
} else {
result[arraySchema.property].push(itemProps);
}
}
}
}
return result;
},
validateValue(property, value, object, type, result) {
if (wizardSchema[type].required.indexOf(property) > -1 && !value) {
result.error = {
type: "required",
params: { type, property },
};
}
let dependent = wizardSchema[type].dependent[property];
if (dependent && value && !object[dependent]) {
result.error = {
type: "dependent",
params: { property, dependent },
};
}
if (property === "api_body") {
try {
value = JSON.parse(value);
} catch (e) {
result.error = {
type: "invalid",
params: { type, property },
};
}
}
return result;
},
buildMappedJson(value) {
if (typeof value === "string" || Number.isInteger(value)) {
return value;
}
if (!value || !value.length) {
return false;
}
let inputs = value;
let result = [];
inputs.forEach((inpt) => {
let input = {
type: inpt.type,
};
if (inpt.connector) {
input.connector = inpt.connector;
}
if (present(inpt.output)) {
input.output = inpt.output;
input.output_type = snakeCase(inpt.output_type);
input.output_connector = inpt.output_connector;
}
if (present(inpt.pairs)) {
input.pairs = [];
inpt.pairs.forEach((pr) => {
if (present(pr.key) && present(pr.value)) {
let pairParams = {
index: pr.index,
key: pr.key,
key_type: snakeCase(pr.key_type),
value: pr.value,
value_type: snakeCase(pr.value_type),
connector: pr.connector,
};
input.pairs.push(pairParams);
}
});
}
if (
(input.type === "assignment" && present(input.output)) ||
present(input.pairs)
) {
result.push(input);
}
});
if (!result.length) {
result = false;
}
return result;
},
remove() {
return ajax(`/admin/wizards/wizard/${this.id}`, {
type: "DELETE",
})
.then(() => this.destroy())
.catch(popupAjaxError);
},
});
CustomWizardAdmin.reopenClass({
all() {
return ajax("/admin/wizards/wizard", {
type: "GET",
})
.then((result) => {
return result.wizard_list;
})
.catch(popupAjaxError);
},
submissions(wizardId) {
return ajax(`/admin/wizards/submissions/${wizardId}`, {
type: "GET",
}).catch(popupAjaxError);
},
create(wizardJson = {}) {
const wizard = this._super.apply(this);
wizard.setProperties(buildProperties(wizardJson));
return wizard;
},
});
export default CustomWizardAdmin;

Datei anzeigen

@ -1,227 +1,127 @@
import { ajax } from "discourse/lib/ajax";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import { buildProperties, mapped, present } from "../lib/wizard-json"; import { ajax } from "discourse/lib/ajax";
import { listProperties, snakeCase } from "../lib/wizard";
import wizardSchema from "../lib/wizard-schema";
import { Promise } from "rsvp";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import discourseComputed from "discourse-common/utils/decorators";
import getUrl from "discourse-common/lib/get-url";
import CustomWizardField from "./custom-wizard-field";
import CustomWizardStep from "./custom-wizard-step";
const CustomWizard = EmberObject.extend({ const CustomWizard = EmberObject.extend({
save(opts) { @discourseComputed("steps.length")
return new Promise((resolve, reject) => { totalSteps: (length) => length,
let wizard = this.buildJson(this, "wizard");
if (wizard.error) { skip() {
reject(wizard); if (this.required && !this.completed && this.permitted) {
return;
} }
CustomWizard.skip(this.id);
let data = {
wizard,
};
if (opts.create) {
data.create = true;
}
ajax(`/admin/wizards/wizard/${wizard.id}`, {
type: "PUT",
contentType: "application/json",
data: JSON.stringify(data),
}).then((result) => {
if (result.backend_validation_error) {
reject(result);
} else {
resolve(result);
}
});
});
}, },
buildJson(object, type, result = {}) { restart() {
let objectType = object.type || null; CustomWizard.restart(this.id);
if (wizardSchema[type].types) {
if (!objectType) {
result.error = {
type: "required",
params: { type, property: "type" },
};
return result;
}
}
for (let property of listProperties(type, { objectType })) {
let value = object.get(property);
result = this.validateValue(property, value, object, type, result);
if (result.error) {
break;
}
if (mapped(property, type)) {
value = this.buildMappedJson(value);
}
if (value !== undefined && value !== null) {
result[property] = value;
}
}
if (!result.error) {
for (let arrayObjectType of Object.keys(
wizardSchema[type].objectArrays
)) {
let arraySchema = wizardSchema[type].objectArrays[arrayObjectType];
let objectArray = object.get(arraySchema.property);
if (arraySchema.required && !present(objectArray)) {
result.error = {
type: "required",
params: { type, property: arraySchema.property },
};
break;
}
result[arraySchema.property] = [];
for (let item of objectArray) {
let itemProps = this.buildJson(item, arrayObjectType);
if (itemProps.error) {
result.error = itemProps.error;
break;
} else {
result[arraySchema.property].push(itemProps);
}
}
}
}
return result;
},
validateValue(property, value, object, type, result) {
if (wizardSchema[type].required.indexOf(property) > -1 && !value) {
result.error = {
type: "required",
params: { type, property },
};
}
let dependent = wizardSchema[type].dependent[property];
if (dependent && value && !object[dependent]) {
result.error = {
type: "dependent",
params: { property, dependent },
};
}
if (property === "api_body") {
try {
value = JSON.parse(value);
} catch (e) {
result.error = {
type: "invalid",
params: { type, property },
};
}
}
return result;
},
buildMappedJson(value) {
if (typeof value === "string" || Number.isInteger(value)) {
return value;
}
if (!value || !value.length) {
return false;
}
let inputs = value;
let result = [];
inputs.forEach((inpt) => {
let input = {
type: inpt.type,
};
if (inpt.connector) {
input.connector = inpt.connector;
}
if (present(inpt.output)) {
input.output = inpt.output;
input.output_type = snakeCase(inpt.output_type);
input.output_connector = inpt.output_connector;
}
if (present(inpt.pairs)) {
input.pairs = [];
inpt.pairs.forEach((pr) => {
if (present(pr.key) && present(pr.value)) {
let pairParams = {
index: pr.index,
key: pr.key,
key_type: snakeCase(pr.key_type),
value: pr.value,
value_type: snakeCase(pr.value_type),
connector: pr.connector,
};
input.pairs.push(pairParams);
}
});
}
if (
(input.type === "assignment" && present(input.output)) ||
present(input.pairs)
) {
result.push(input);
}
});
if (!result.length) {
result = false;
}
return result;
},
remove() {
return ajax(`/admin/wizards/wizard/${this.id}`, {
type: "DELETE",
})
.then(() => this.destroy())
.catch(popupAjaxError);
}, },
}); });
CustomWizard.reopenClass({ CustomWizard.reopenClass({
all() { skip(wizardId) {
return ajax("/admin/wizards/wizard", { ajax({ url: `/w/${wizardId}/skip`, type: "PUT" })
type: "GET",
})
.then((result) => { .then((result) => {
return result.wizard_list; CustomWizard.finished(result);
}) })
.catch(popupAjaxError); .catch(popupAjaxError);
}, },
submissions(wizardId) { restart(wizardId) {
return ajax(`/admin/wizards/submissions/${wizardId}`, { ajax({ url: `/w/${wizardId}/skip`, type: "PUT" })
type: "GET", .then(() => {
}).catch(popupAjaxError); window.location.href = `/w/${wizardId}`;
})
.catch(popupAjaxError);
}, },
create(wizardJson = {}) { finished(result) {
const wizard = this._super.apply(this); let url = "/";
wizard.setProperties(buildProperties(wizardJson)); if (result.redirect_on_complete) {
return wizard; url = result.redirect_on_complete;
}
window.location.href = getUrl(url);
},
build(wizardJson) {
if (!wizardJson) {
return null;
}
if (!wizardJson.completed && wizardJson.steps) {
wizardJson.steps = wizardJson.steps
.map((step) => {
const stepObj = CustomWizardStep.create(step);
stepObj.wizardId = wizardJson.id;
stepObj.fields.sort((a, b) => {
return parseFloat(a.number) - parseFloat(b.number);
});
let tabindex = 1;
stepObj.fields.forEach((f) => {
f.tabindex = tabindex;
if (["date_time"].includes(f.type)) {
tabindex = tabindex + 2;
} else {
tabindex++;
}
});
stepObj.fields = stepObj.fields.map((f) => {
f.wizardId = wizardJson.id;
f.stepId = stepObj.id;
return CustomWizardField.create(f);
});
return stepObj;
})
.sort((a, b) => {
return parseFloat(a.index) - parseFloat(b.index);
});
}
return CustomWizard.create(wizardJson);
}, },
}); });
export function findCustomWizard(wizardId, params = {}) {
let url = `/w/${wizardId}.json`;
let paramKeys = Object.keys(params).filter((k) => {
if (k === "wizard_id") {
return false;
}
return !!params[k];
});
if (paramKeys.length) {
url += "?";
paramKeys.forEach((k, i) => {
if (i > 0) {
url += "&";
}
url += `${k}=${params[k]}`;
});
}
return ajax(url).then((result) => {
return CustomWizard.build(result);
});
}
let _wizard_store;
export function updateCachedWizard(wizard) {
_wizard_store = wizard;
}
export function getCachedWizard() {
return _wizard_store;
}
export default CustomWizard; export default CustomWizard;

Datei anzeigen

@ -1,11 +0,0 @@
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 = getOwner(this).lookup("service:store");
return store.createRecord("site", {});
},
});

Datei anzeigen

@ -1,164 +0,0 @@
import { default as computed } from "discourse-common/utils/decorators";
import getUrl from "discourse-common/lib/get-url";
import Field from "./field";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import Step from "./step";
import EmberObject from "@ember/object";
import Site from "./site";
const CustomWizard = EmberObject.extend({
@computed("steps.length")
totalSteps: (length) => length,
skip() {
if (this.required && !this.completed && this.permitted) {
return;
}
CustomWizard.skip(this.id);
},
restart() {
CustomWizard.restart(this.id);
},
});
CustomWizard.reopenClass({
skip(wizardId) {
ajax({ url: `/w/${wizardId}/skip`, type: "PUT" })
.then((result) => {
CustomWizard.finished(result);
})
.catch(popupAjaxError);
},
restart(wizardId) {
ajax({ url: `/w/${wizardId}/skip`, type: "PUT" })
.then(() => {
window.location.href = `/w/${wizardId}`;
})
.catch(popupAjaxError);
},
finished(result) {
let url = "/";
if (result.redirect_on_complete) {
url = result.redirect_on_complete;
}
window.location.href = getUrl(url);
},
build(wizardJson) {
if (!wizardJson) {
return null;
}
if (!wizardJson.completed && wizardJson.steps) {
wizardJson.steps = wizardJson.steps
.map((step) => {
const stepObj = Step.create(step);
stepObj.wizardId = wizardJson.id;
stepObj.fields.sort((a, b) => {
return parseFloat(a.number) - parseFloat(b.number);
});
let tabindex = 1;
stepObj.fields.forEach((f) => {
f.tabindex = tabindex;
if (["date_time"].includes(f.type)) {
tabindex = tabindex + 2;
} else {
tabindex++;
}
});
stepObj.fields = stepObj.fields.map((f) => {
f.wizardId = wizardJson.id;
f.stepId = stepObj.id;
return Field.create(f);
});
return stepObj;
})
.sort((a, b) => {
return parseFloat(a.index) - parseFloat(b.index);
});
}
if (wizardJson.categories) {
let subcatMap = {};
let categoriesById = {};
let categories = wizardJson.categories.map((c) => {
if (c.parent_category_id) {
subcatMap[c.parent_category_id] =
subcatMap[c.parent_category_id] || [];
subcatMap[c.parent_category_id].push(c.id);
}
return (categoriesById[c.id] = EmberObject.create(c));
});
// Associate the categories with their parents
categories.forEach((c) => {
let subcategoryIds = subcatMap[c.get("id")];
if (subcategoryIds) {
c.set(
"subcategories",
subcategoryIds.map((id) => categoriesById[id])
);
}
if (c.get("parent_category_id")) {
c.set("parentCategory", categoriesById[c.get("parent_category_id")]);
}
});
Site.currentProp("categories", categories);
Site.currentProp("listByActivity", categories);
Site.currentProp("categoriesById", categoriesById);
Site.currentProp(
"uncategorized_category_id",
wizardJson.uncategorized_category_id
);
}
return CustomWizard.create(wizardJson);
},
});
export function findCustomWizard(wizardId, params = {}) {
let url = `/w/${wizardId}`;
let paramKeys = Object.keys(params).filter((k) => {
if (k === "wizard_id") {
return false;
}
return !!params[k];
});
if (paramKeys.length) {
url += "?";
paramKeys.forEach((k, i) => {
if (i > 0) {
url += "&";
}
url += `${k}=${params[k]}`;
});
}
return ajax({ url, cache: false, dataType: "json" }).then((result) => {
return CustomWizard.build(result);
});
}
let _wizard_store;
export function updateCachedWizard(wizard) {
_wizard_store = wizard;
}
export function getCachedWizard() {
return _wizard_store;
}
export default CustomWizard;

Datei anzeigen

@ -1,9 +1,9 @@
import CustomWizard from "../models/custom-wizard"; import CustomWizardAdmin from "../models/custom-wizard-admin";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
model() { model() {
return CustomWizard.all(); return CustomWizardAdmin.all();
}, },
setupController(controller, model) { setupController(controller, model) {

Datei anzeigen

@ -1,11 +1,11 @@
import CustomWizard from "../models/custom-wizard"; import CustomWizardAdmin from "../models/custom-wizard-admin";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
const excludedMetaFields = ["route_to", "redirect_on_complete", "redirect_to"]; const excludedMetaFields = ["route_to", "redirect_on_complete", "redirect_to"];
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
model(params) { model(params) {
return CustomWizard.submissions(params.wizardId); return CustomWizardAdmin.submissions(params.wizardId);
}, },
setupController(controller, model) { setupController(controller, model) {

Datei anzeigen

@ -1,4 +1,4 @@
import CustomWizard from "../models/custom-wizard"; import CustomWizardAdmin from "../models/custom-wizard-admin";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import I18n from "I18n"; import I18n from "I18n";
@ -20,7 +20,9 @@ export default DiscourseRoute.extend({
setupController(controller, model) { setupController(controller, model) {
const parentModel = this.modelFor("adminWizardsWizard"); const parentModel = this.modelFor("adminWizardsWizard");
const wizard = CustomWizard.create(!model || model.create ? {} : model); const wizard = CustomWizardAdmin.create(
!model || model.create ? {} : model
);
const fieldTypes = Object.keys(parentModel.field_types).map((type) => { const fieldTypes = Object.keys(parentModel.field_types).map((type) => {
return { return {
id: type, id: type,

Datei anzeigen

@ -1,4 +1,4 @@
import { getCachedWizard } from "../models/wizard"; import { getCachedWizard } from "../models/custom-wizard";
import Route from "@ember/routing/route"; import Route from "@ember/routing/route";
export default Route.extend({ export default Route.extend({

Datei anzeigen

@ -1,5 +1,5 @@
import I18n from "I18n"; import I18n from "I18n";
import { getCachedWizard } from "../models/wizard"; import { getCachedWizard } from "../models/custom-wizard";
import Route from "@ember/routing/route"; import Route from "@ember/routing/route";
export default Route.extend({ export default Route.extend({

Datei anzeigen

@ -1,4 +1,4 @@
import { findCustomWizard, updateCachedWizard } from "../models/wizard"; import { findCustomWizard, updateCachedWizard } from "../models/custom-wizard";
import I18n from "I18n"; import I18n from "I18n";
import Route from "@ember/routing/route"; import Route from "@ember/routing/route";
@ -50,6 +50,7 @@ export default Route.extend({
customWizard: true, customWizard: true,
logoUrl: this.siteSettings.logo_small, logoUrl: this.siteSettings.logo_small,
reset: null, reset: null,
model,
}); });
const stepModel = this.modelFor("step"); const stepModel = this.modelFor("step");
@ -60,22 +61,17 @@ export default Route.extend({
) { ) {
this.showDialog(model); this.showDialog(model);
} }
},
getWizardBackground() { const background = model.get("background");
const wizard = this.controllerFor("custom-wizard").get("model"); if (background) {
return wizard ? wizard.get("background") : ""; document.body.style.background = background;
}
}, },
activate() { activate() {
if (!document.body.classList.contains("custom-wizard")) { if (!document.body.classList.contains("custom-wizard")) {
document.body.classList.add("custom-wizard"); document.body.classList.add("custom-wizard");
} }
const background = this.getWizardBackground();
if (background) {
document.body.style.background = background;
}
}, },
deactivate() { deactivate() {
@ -83,9 +79,6 @@ export default Route.extend({
document.body.classList.remove("custom-wizard"); document.body.classList.remove("custom-wizard");
} }
const background = this.getWizardBackground();
if (background) {
document.body.style.background = ""; document.body.style.background = "";
}
}, },
}); });

Datei anzeigen

@ -1,15 +1,23 @@
img.avatar {
border-radius: 50%;
vertical-align: middle;
}
div.ac-wrap { div.ac-wrap {
box-sizing: border-box;
position: relative;
overflow: visible; overflow: visible;
max-height: 150px; max-height: 150px;
min-height: 34px; min-height: 34px;
background-color: var(--secondary); background-color: var(--secondary);
border: 1px solid var(--primary-medium); border: 1px solid var(--primary-medium);
padding: 5px 4px 1px 4px; padding: 5px;
div.item { div.item {
float: left; float: left;
margin-bottom: 4px; margin-bottom: 4px;
margin-right: 10px; margin-right: 10px;
line-height: 1.6;
span { span {
height: 24px; height: 24px;
@ -46,20 +54,31 @@ div.ac-wrap {
color: var(--danger); color: var(--danger);
} }
} }
.ac-loading {
position: absolute;
top: 7px;
right: 5px;
} }
img.avatar { input {
border-radius: 50%; margin-bottom: 0;
vertical-align: middle;
} }
.autocomplete { .autocomplete {
z-index: 999999; z-index: 999999;
position: absolute; position: absolute;
width: 240px; width: inherit;
max-width: 240px;
box-sizing: border-box;
background-color: var(--secondary); background-color: var(--secondary);
border: 1px solid var(--primary-low); border: 1px solid var(--primary-low);
li,
.no-results {
padding: 10px;
}
ul { ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
@ -91,50 +110,30 @@ img.avatar {
color: var(--primary); color: var(--primary);
vertical-align: middle; vertical-align: middle;
} }
span.name { span.name {
font-size: $font-down-1; font-size: $font-down-1;
vertical-align: middle; vertical-align: middle;
margin-left: 5px; margin-left: 5px;
color: var(--primary); color: var(--primary);
} }
&.selected { &.selected {
background-color: var(--tertiary); background-color: var(--tertiary);
span.username,
span.name {
color: var(--secondary); color: var(--secondary);
} }
&:hover { }
&:hover:not(.selected) {
background-color: var(--highlight-low); background-color: var(--highlight-low);
text-decoration: none; text-decoration: none;
} }
} }
} }
} }
}
.ac-wrap {
box-sizing: border-box;
position: relative;
.ac-loading {
position: absolute;
top: 7px;
right: 5px;
}
.item {
line-height: 1.6;
}
.autocomplete {
width: inherit;
left: 0 !important;
width: 100%;
top: 30px !important;
box-sizing: border-box;
li,
.no-results {
padding: 10px;
}
ul > label { ul > label {
margin: 5px 0; margin: 5px 0;

Datei anzeigen

@ -60,6 +60,7 @@ body.custom-wizard {
& > label.field-label { & > label.field-label {
order: 1; order: 1;
font-weight: 400; font-weight: 400;
margin-bottom: 0;
} }
& > .field-description { & > .field-description {
@ -70,6 +71,7 @@ body.custom-wizard {
.url-field input { .url-field input {
width: 100%; width: 100%;
max-width: 500px;
font-size: 1.1487em; font-size: 1.1487em;
padding: 6px; padding: 6px;
transition: border-color 0.5s; transition: border-color 0.5s;
@ -136,10 +138,16 @@ body.custom-wizard {
position: absolute !important; position: absolute !important;
} }
.d-time-input .select-kit.combo-box .select-kit-header { .d-time-input {
.select-kit.combo-box {
width: 90px;
.select-kit-header {
font-size: 1.1487em; font-size: 1.1487em;
padding: 6px; padding: 6px;
} }
}
}
.d-date-time-input { .d-date-time-input {
display: flex; display: flex;

Datei anzeigen

@ -2,6 +2,66 @@ en:
js: js:
wizard: wizard:
complete_custom: "Complete the {{name}}" complete_custom: "Complete the {{name}}"
completed: "You have completed this wizard."
not_permitted: "You are not permitted to access this wizard."
none: "There is no wizard here."
return_to_site: "Return to {{siteName}}"
requires_login: "You need to be logged in to access this wizard."
reset: "Reset this wizard."
step_not_permitted: "You're not permitted to view this step."
incomplete_submission:
title: "Continue editing your draft submission from %{date}?"
resume: "Continue"
restart: "Start over"
x_characters:
one: "%{count} Character"
other: "%{count} Characters"
wizard_composer:
show_preview: "Preview Post"
hide_preview: "Edit Post"
quote_post_title: "Quote whole post"
bold_label: "B"
bold_title: "Strong"
bold_text: "strong text"
italic_label: "I"
italic_title: "Emphasis"
italic_text: "emphasized text"
link_title: "Hyperlink"
link_description: "enter link description here"
link_dialog_title: "Insert Hyperlink"
link_optional_text: "optional title"
link_url_placeholder: "http://example.com"
quote_title: "Blockquote"
quote_text: "Blockquote"
blockquote_text: "Blockquote"
code_title: "Preformatted text"
code_text: "indent preformatted text by 4 spaces"
paste_code_text: "type or paste code here"
upload_title: "Upload"
upload_description: "enter upload description here"
olist_title: "Numbered List"
ulist_title: "Bulleted List"
list_item: "List item"
toggle_direction: "Toggle Direction"
help: "Markdown Editing Help"
collapse: "minimize the composer panel"
abandon: "close composer and discard draft"
modal_ok: "OK"
modal_cancel: "Cancel"
cant_send_pm: "Sorry, you can't send a message to %{username}."
yourself_confirm:
title: "Did you forget to add recipients?"
body: "Right now this message is only being sent to yourself!"
realtime_validations:
similar_topics:
insufficient_characters: "Type a minimum 5 characters to start looking for similar topics"
insufficient_characters_categories: "Type a minimum 5 characters to start looking for similar topics in %{catLinks}"
results: "Your topic is similar to..."
no_results: "No similar topics."
loading: "Looking for similar topics..."
show: "show"
admin_js: admin_js:
admin: admin:
@ -483,78 +543,3 @@ en:
countrycode: "Please select a country." countrycode: "Please select a country."
coordinates: "Please complete the set of coordinates." coordinates: "Please complete the set of coordinates."
geo_location: "Search and select a result." geo_location: "Search and select a result."
select_kit:
default_header_text: Select...
no_content: No matches found
filter_placeholder: Search...
filter_placeholder_with_any: Search or create...
create: "Create: '{{content}}'"
max_content_reached:
one: "You can only select {{count}} item."
other: "You can only select {{count}} items."
min_content_not_reached:
one: "Select at least {{count}} item."
other: "Select at least {{count}} items."
wizard:
completed: "You have completed this wizard."
not_permitted: "You are not permitted to access this wizard."
none: "There is no wizard here."
return_to_site: "Return to {{siteName}}"
requires_login: "You need to be logged in to access this wizard."
reset: "Reset this wizard."
step_not_permitted: "You're not permitted to view this step."
incomplete_submission:
title: "Continue editing your draft submission from %{date}?"
resume: "Continue"
restart: "Start over"
x_characters:
one: "%{count} Character"
other: "%{count} Characters"
wizard_composer:
show_preview: "Preview Post"
hide_preview: "Edit Post"
quote_post_title: "Quote whole post"
bold_label: "B"
bold_title: "Strong"
bold_text: "strong text"
italic_label: "I"
italic_title: "Emphasis"
italic_text: "emphasized text"
link_title: "Hyperlink"
link_description: "enter link description here"
link_dialog_title: "Insert Hyperlink"
link_optional_text: "optional title"
link_url_placeholder: "http://example.com"
quote_title: "Blockquote"
quote_text: "Blockquote"
blockquote_text: "Blockquote"
code_title: "Preformatted text"
code_text: "indent preformatted text by 4 spaces"
paste_code_text: "type or paste code here"
upload_title: "Upload"
upload_description: "enter upload description here"
olist_title: "Numbered List"
ulist_title: "Bulleted List"
list_item: "List item"
toggle_direction: "Toggle Direction"
help: "Markdown Editing Help"
collapse: "minimize the composer panel"
abandon: "close composer and discard draft"
modal_ok: "OK"
modal_cancel: "Cancel"
cant_send_pm: "Sorry, you can't send a message to %{username}."
yourself_confirm:
title: "Did you forget to add recipients?"
body: "Right now this message is only being sent to yourself!"
realtime_validations:
similar_topics:
insufficient_characters: "Type a minimum 5 characters to start looking for similar topics"
insufficient_characters_categories: "Type a minimum 5 characters to start looking for similar topics in %{catLinks}"
results: "Your topic is similar to..."
no_results: "No similar topics."
loading: "Looking for similar topics..."
show: "show"

Datei anzeigen

@ -1,53 +0,0 @@
# frozen_string_literal: true
describe "Sprockets: require_tree_discourse directive" do
let(:discourse_asset_path) {
"#{Rails.root}/app/assets/javascripts/"
}
let(:fixture_asset_path) {
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/sprockets/"
}
let(:test_file_contents) {
"console.log('hello')"
}
let(:resolved_file_contents) {
File.read(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/sprockets/resolved_js_file_contents.txt"
)
}
before do
@env ||= Sprockets::Environment.new
discourse_asset_path = "#{Rails.root}/app/assets/javascripts/"
fixture_asset_path = "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/sprockets/"
@env.append_path(discourse_asset_path)
@env.append_path(fixture_asset_path)
@env.cache = {}
end
def create_tmp_folder_and_run(path, file_contents, &block)
dir = File.dirname(path)
unless File.directory?(dir)
FileUtils.mkdir_p(dir)
end
File.new(path, 'w')
File.write(path, file_contents)
yield block if block_given?
FileUtils.rm_r(dir)
end
it "includes assets from the discourse core" do
create_tmp_folder_and_run("#{discourse_asset_path}/sptest/test.js", test_file_contents) do
expect(@env.find_asset("require_tree_discourse_test.js").to_s).to eq(resolved_file_contents)
end
end
it "throws ArgumentError if path is empty" do
expect { @env.find_asset("require_tree_discourse_empty.js") }.to raise_error(CustomWizard::SprocketsEmptyPath).with_message("path cannot be empty")
end
it "throws ArgumentError if path is non non-existent" do
expect { @env.find_asset("require_tree_discourse_non_existant.js") }.to raise_error(CustomWizard::SprocketsFileNotFound)
end
end

Datei anzeigen

@ -1,9 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
describe CustomWizard::RealtimeValidationsController do describe CustomWizard::RealtimeValidationsController do
fab!(:user) { Fabricate(:user) }
fab!(:validation_type) { "test_stub" } let(:validation_type) { "test_stub" }
fab!(:validation_type_stub) { let(:validation_type_stub) {
{ {
types: [:text], types: [:text],
component: "similar-topics-validator", component: "similar-topics-validator",
@ -12,9 +12,8 @@ describe CustomWizard::RealtimeValidationsController do
} }
} }
before(:all) do before do
sign_in(Fabricate(:user)) sign_in(user)
CustomWizard::RealtimeValidation.types = { test_stub: validation_type_stub }
class CustomWizard::RealtimeValidation::TestStub class CustomWizard::RealtimeValidation::TestStub
attr_accessor :user attr_accessor :user
@ -40,6 +39,7 @@ describe CustomWizard::RealtimeValidationsController do
end end
it "gives the correct response for a given type" do it "gives the correct response for a given type" do
CustomWizard::RealtimeValidation.types = { test_stub: validation_type_stub }
get '/realtime-validations.json', params: { type: validation_type } get '/realtime-validations.json', params: { type: validation_type }
expect(response.status).to eq(200) expect(response.status).to eq(200)
expected_response = [ expected_response = [
@ -50,11 +50,13 @@ describe CustomWizard::RealtimeValidationsController do
end end
it "gives 400 error when no type is passed" do it "gives 400 error when no type is passed" do
CustomWizard::RealtimeValidation.types = { test_stub: validation_type_stub }
get '/realtime-validations.json' get '/realtime-validations.json'
expect(response.status).to eq(400) expect(response.status).to eq(400)
end end
it "gives 400 error when a required additional param is missing" do it "gives 400 error when a required additional param is missing" do
CustomWizard::RealtimeValidation.types = { test_stub: validation_type_stub }
CustomWizard::RealtimeValidation.types[:test_stub][:required_params] = [:test1] CustomWizard::RealtimeValidation.types[:test_stub][:required_params] = [:test1]
get '/realtime-validations.json', params: { type: validation_type } get '/realtime-validations.json', params: { type: validation_type }
expect(response.status).to eq(400) expect(response.status).to eq(400)
@ -63,6 +65,7 @@ describe CustomWizard::RealtimeValidationsController do
end end
it "gives 500 response code when a non existant type is passed" do it "gives 500 response code when a non existant type is passed" do
CustomWizard::RealtimeValidation.types = { test_stub: validation_type_stub }
get '/realtime-validations.json', params: { type: "random_type" } get '/realtime-validations.json', params: { type: "random_type" }
expect(response.status).to eq(500) expect(response.status).to eq(500)
end end

Datei anzeigen

@ -1,38 +1,42 @@
import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers"; import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers";
import { test } from "qunit"; import { test } from "qunit";
import { exists } from "../helpers/test"; import {
import acceptance, { acceptance,
count, count,
query, query,
server, exists,
visible, visible
} from "../helpers/acceptance"; } from "discourse/tests/helpers/qunit-helpers";
import { allFieldsWizard, getWizard } from "../helpers/wizard"; import { allFieldsWizard } from "../helpers/wizard";
import tagsJson from "../fixtures/tags"; import tagsJson from "../fixtures/tags";
import usersJson from "../fixtures/users"; import usersJson from "../fixtures/users";
import { response } from "../pretender";
acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () { acceptance("Field | Fields", function (needs) {
needs.pretender((server, helper) => {
server.get("/w/wizard.json", (request) => (helper.response(allFieldsWizard)));
server.get("/tags/filter/search", (request) => (helper.response({ results: tagsJson["tags"] })));
server.get("/u/search/users", (request) => (helper.response(usersJson)));
});
test("Text", async function (assert) { test("Text", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(exists(".wizard-field.text-field input.wizard-focusable")); assert.ok(exists(".wizard-field.text-field input.wizard-focusable"));
}); });
test("Textarea", async function (assert) { test("Textarea", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok( assert.ok(
visible(".wizard-field.textarea-field textarea.wizard-focusable") visible(".wizard-field.textarea-field textarea.wizard-focusable")
); );
}); });
test("Composer", async function (assert) { test("Composer", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok( assert.ok(
visible(".wizard-field.composer-field .wizard-field-composer textarea") visible(".wizard-field.composer-field .wizard-field-composer textarea")
); );
assert.strictEqual( assert.ok(
count(".wizard-field.composer-field .d-editor-button-bar button"), exists(".wizard-field.composer-field .d-editor-button-bar button")
8
); );
assert.ok(visible(".wizard-btn.toggle-preview")); assert.ok(visible(".wizard-btn.toggle-preview"));
@ -50,19 +54,19 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
}); });
test("Text Only", async function (assert) { test("Text Only", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-field.text-only-field label.field-label")); assert.ok(visible(".wizard-field.text-only-field label.field-label"));
}); });
test("Date", async function (assert) { test("Date", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-field.date-field input.date-picker")); assert.ok(visible(".wizard-field.date-field input.date-picker"));
await click(".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")); assert.ok(visible(".wizard-field.date-field .pika-single"));
}); });
test("Time", async function (assert) { test("Time", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-field.time-field .d-time-input .select-kit")); assert.ok(visible(".wizard-field.time-field .d-time-input .select-kit"));
await click( await click(
".wizard-field.time-field .d-time-input .select-kit .select-kit-header" ".wizard-field.time-field .d-time-input .select-kit .select-kit-header"
@ -71,7 +75,7 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
}); });
test("Date Time", async function (assert) { test("Date Time", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok( assert.ok(
visible(".wizard-field.date-time-field .d-date-time-input .select-kit") visible(".wizard-field.date-time-field .d-date-time-input .select-kit")
); );
@ -88,22 +92,22 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
}); });
test("Number", async function (assert) { test("Number", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-field.number-field input[type='number']")); assert.ok(visible(".wizard-field.number-field input[type='number']"));
}); });
test("Checkbox", async function (assert) { test("Checkbox", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-field.checkbox-field input[type='checkbox']")); assert.ok(visible(".wizard-field.checkbox-field input[type='checkbox']"));
}); });
test("Url", async function (assert) { test("Url", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-field.url-field input[type='text']")); assert.ok(visible(".wizard-field.url-field input[type='text']"));
}); });
test("Upload", async function (assert) { test("Upload", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok( assert.ok(
visible(".wizard-field.upload-field label.wizard-btn-upload-file") visible(".wizard-field.upload-field label.wizard-btn-upload-file")
); );
@ -111,7 +115,7 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
}); });
test("Dropdown", async function (assert) { test("Dropdown", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-field.dropdown-field .single-select-header")); assert.ok(visible(".wizard-field.dropdown-field .single-select-header"));
await click(".wizard-field.dropdown-field .select-kit-header"); await click(".wizard-field.dropdown-field .select-kit-header");
assert.strictEqual( assert.strictEqual(
@ -121,10 +125,7 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
}); });
test("Tag", async function (assert) { test("Tag", async function (assert) {
server.get("/tags/filter/search", () => await visit("/w/wizard");
response(200, { results: tagsJson["tags"] })
);
await visit("/wizard");
assert.ok(visible(".wizard-field.tag-field .multi-select-header")); assert.ok(visible(".wizard-field.tag-field .multi-select-header"));
await click(".wizard-field.tag-field .select-kit-header"); await click(".wizard-field.tag-field .select-kit-header");
assert.strictEqual( assert.strictEqual(
@ -134,17 +135,16 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
}); });
test("Category", async function (assert) { test("Category", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-field.category-field .multi-select-header")); assert.ok(visible(".wizard-field.category-field .multi-select-header"));
await click(".wizard-field.category-field .select-kit-header"); await click(".wizard-field.category-field .select-kit-header");
assert.strictEqual( assert.ok(
count(".wizard-field.category-field .select-kit-collection li"), exists(".wizard-field.category-field .select-kit-collection li")
5
); );
}); });
test("Group", async function (assert) { test("Group", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-field.group-field .single-select-header")); assert.ok(visible(".wizard-field.group-field .single-select-header"));
await click(".wizard-field.group-field .select-kit-header"); await click(".wizard-field.group-field .select-kit-header");
assert.strictEqual( assert.strictEqual(
@ -154,9 +154,7 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
}); });
test("User", async function (assert) { test("User", async function (assert) {
server.get("/u/search/users", () => response(200, usersJson)); await visit("/w/wizard");
await visit("/wizard");
await fillIn( await fillIn(
".wizard-field.user-selector-field input.ember-text-field", ".wizard-field.user-selector-field input.ember-text-field",
"a" "a"

Datei anzeigen

@ -1,20 +1,33 @@
import { click, visit } from "@ember/test-helpers"; import { click, visit } from "@ember/test-helpers";
import { test } from "qunit"; import { test } from "qunit";
import { exists } from "../helpers/test"; import {
import acceptance, { count, query, visible } from "../helpers/acceptance"; acceptance,
import { getWizard, stepNotPermitted, wizard } from "../helpers/wizard"; count,
import { saveStep, update } from "../helpers/step"; query,
exists,
visible
} from "discourse/tests/helpers/qunit-helpers";
import { stepNotPermitted, wizard, update } from "../helpers/wizard";
acceptance("Step | Not permitted", function (needs) {
needs.pretender((server, helper) => {
server.get("/w/wizard.json", (request) => (helper.response(stepNotPermitted)));
});
acceptance("Step | Not permitted", [getWizard(stepNotPermitted)], function () {
test("Shows not permitted message", async function (assert) { test("Shows not permitted message", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(exists(".step-message.not-permitted")); assert.ok(exists(".step-message.not-permitted"));
}); });
}); });
acceptance("Step | Step", [getWizard(wizard), saveStep(update)], function () { acceptance("Step | Step", function (needs) {
needs.pretender((server, helper) => {
server.get("/w/wizard.json", (request) => (helper.response(wizard)));
server.put("/w/wizard/steps/:step_id", (request) => (helper.response(update)));
});
test("Renders the step", async function (assert) { test("Renders the step", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.strictEqual( assert.strictEqual(
query(".wizard-step-title p").textContent.trim(), query(".wizard-step-title p").textContent.trim(),
"Text" "Text"
@ -33,7 +46,7 @@ acceptance("Step | Step", [getWizard(wizard), saveStep(update)], function () {
}); });
test("Goes to the next step", async function (assert) { test("Goes to the next step", async function (assert) {
await visit("/wizard"); await visit("/w/wizard");
assert.ok(visible(".wizard-step.step_1"), true); assert.ok(visible(".wizard-step.step_1"), true);
await click(".wizard-btn.next"); await click(".wizard-btn.next");
assert.ok(visible(".wizard-step.step_2"), true); assert.ok(visible(".wizard-step.step_2"), true);

Datei anzeigen

@ -0,0 +1,96 @@
import { visit, settled } from "@ember/test-helpers";
import { test } from "qunit";
import {
acceptance,
count,
query,
exists,
} from "discourse/tests/helpers/qunit-helpers";
import {
wizard,
wizardCompleted,
wizardNoUser,
wizardNotPermitted,
} from "../helpers/wizard";
acceptance("Wizard | Not logged in", function (needs) {
needs.pretender((server, helper) => {
server.get("/w/wizard.json", (request) => (helper.response(wizardNoUser)));
});
test("Wizard no access requires login", async function (assert) {
await visit("/w/wizard");
assert.ok(exists(".wizard-no-access.requires-login"));
});
});
acceptance(
"Wizard | Not permitted",
function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get("/w/wizard.json", (request) => (helper.response(wizardNotPermitted)));
});
test("Wizard no access not permitted", async function (assert) {
await visit("/w/wizard");
assert.ok(exists(".wizard-no-access.not-permitted"));
});
}
);
acceptance("Wizard | Completed", function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get("/w/wizard.json", (request) => (helper.response(wizardCompleted)));
});
test("Wizard no access completed", async function (assert) {
await visit("/w/wizard");
assert.ok(exists(".wizard-no-access.completed"));
});
});
acceptance("Wizard | Wizard", function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get("/w/wizard.json", (request) => {
return helper.response(wizard);
});
});
test("Starts", async function (assert) {
await visit("/w/wizard");
assert.ok(query(".wizard-column"), true);
});
test("Applies the body background color", async function (assert) {
await visit("/w/wizard");
assert.ok($("body")[0].style.background);
});
test("Renders the wizard form", async function (assert) {
await visit("/w/wizard");
assert.ok(exists(".wizard-column-contents .wizard-step"), true);
assert.ok(exists(".wizard-footer img"), true);
});
test("Renders the first step", async function (assert) {
await visit("/w/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(exists(".wizard-step-footer .wizard-progress"), true);
assert.ok(exists(".wizard-step-footer .wizard-buttons"), true);
});
});

Datei anzeigen

@ -1,73 +0,0 @@
import { visit } from "@ember/test-helpers";
import { test } from "qunit";
import { exists } from "../helpers/test";
import acceptance, { count, query, visible } from "../helpers/acceptance";
import {
getWizard,
wizard,
wizardCompleted,
wizardNoUser,
wizardNotPermitted,
} from "../helpers/wizard";
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 () {
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 () {
test("Wizard no access completed", async function (assert) {
await visit("/wizard");
assert.ok(exists(".wizard-no-access.completed"));
});
});
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("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);
});
});

Datei anzeigen

@ -0,0 +1,47 @@
import wizardJson from "../fixtures/wizard";
import userJson from "../fixtures/user";
import categoriesJson from "../fixtures/categories";
import groupsJson from "../fixtures/groups";
import updateJson from "../fixtures/update";
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 update = cloneJSON(updateJson);
update.wizard = cloneJSON(wizardJson);
export {
wizardNoUser,
wizardNotPermitted,
wizardCompleted,
stepNotPermitted,
allFieldsWizard,
wizard,
update
};