Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-24 18:30:27 +01:00
First release candidate
Dieser Commit ist enthalten in:
Ursprung
11ff38ae90
Commit
60823cd87a
35 geänderte Dateien mit 788 neuen und 880 gelöschten Zeilen
5
.github/workflows/plugin-linting.yml
gevendort
5
.github/workflows/plugin-linting.yml
gevendort
|
@ -46,8 +46,9 @@ jobs:
|
|||
yarn prettier --list-different "assets/javascripts/{discourse,wizard}/**/*.{scss,js,es6}" ; \
|
||||
fi
|
||||
|
||||
- name: Ember template lint
|
||||
run: yarn ember-template-lint assets/javascripts
|
||||
# Until templates are converted
|
||||
#- name: Ember template lint
|
||||
#run: yarn ember-template-lint assets/javascripts
|
||||
|
||||
- name: Rubocop
|
||||
run: bundle exec rubocop .
|
||||
|
|
5
.github/workflows/plugin-tests.yml
gevendort
5
.github/workflows/plugin-tests.yml
gevendort
|
@ -132,3 +132,8 @@ jobs:
|
|||
export COVERAGE=1
|
||||
fi
|
||||
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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import CustomWizard from "../models/wizard";
|
||||
import CustomWizard from "../models/custom-wizard";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import { dasherize } from "@ember/string";
|
||||
|
|
|
@ -7,7 +7,7 @@ import { schedule } from "@ember/runloop";
|
|||
import { cookAsync } from "discourse/lib/text";
|
||||
import CustomWizard, {
|
||||
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";
|
||||
|
||||
const alreadyWarned = {};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import CustomWizard from "../../models/custom-wizard";
|
||||
import CustomWizardAdmin from "../../models/custom-wizard-admin";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default {
|
||||
setupComponent(attrs, component) {
|
||||
CustomWizard.all()
|
||||
CustomWizardAdmin.all()
|
||||
.then((result) => {
|
||||
component.set("wizardList", result);
|
||||
})
|
||||
|
|
|
@ -20,29 +20,8 @@ export default Controller.extend({
|
|||
"application/x-www-form-urlencoded",
|
||||
]),
|
||||
successCodes: selectKitContent([
|
||||
100,
|
||||
101,
|
||||
102,
|
||||
200,
|
||||
201,
|
||||
202,
|
||||
203,
|
||||
204,
|
||||
205,
|
||||
206,
|
||||
207,
|
||||
208,
|
||||
226,
|
||||
300,
|
||||
301,
|
||||
302,
|
||||
303,
|
||||
303,
|
||||
304,
|
||||
305,
|
||||
306,
|
||||
307,
|
||||
308,
|
||||
100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301,
|
||||
302, 303, 303, 304, 305, 306, 307, 308,
|
||||
]),
|
||||
|
||||
@discourseComputed(
|
||||
|
@ -166,7 +145,7 @@ export default Controller.extend({
|
|||
|
||||
const originalTitle = this.get("api.originalTitle");
|
||||
if (api.get("isNew") || (originalTitle && api.title !== originalTitle)) {
|
||||
refreshList = true;
|
||||
refreshList = true; // eslint-disable-line
|
||||
}
|
||||
|
||||
if (api.get("isNew")) {
|
||||
|
|
55
assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6
Normale Datei
55
assets/javascripts/discourse/custom-wizard-admin-route-map.js.es6
Normale Datei
|
@ -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,
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
import { dasherize } from "@ember/string";
|
||||
|
||||
registerUnbound("dasherize", function (string) {
|
||||
return dasherize(string);
|
||||
});
|
|
@ -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);
|
||||
}
|
||||
});
|
|
@ -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);
|
||||
});
|
|
@ -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 };
|
|
@ -38,6 +38,7 @@ export default {
|
|||
});
|
||||
|
||||
api.modifyClass("component:uppy-image-uploader", {
|
||||
pluginId: "custom-wizard",
|
||||
// Needed to ensure appEvents get registered when navigating between steps
|
||||
@observes("id")
|
||||
initOnStepChange() {
|
||||
|
|
227
assets/javascripts/discourse/models/custom-wizard-admin.js.es6
Normale Datei
227
assets/javascripts/discourse/models/custom-wizard-admin.js.es6
Normale Datei
|
@ -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;
|
|
@ -1,227 +1,127 @@
|
|||
import { ajax } from "discourse/lib/ajax";
|
||||
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";
|
||||
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({
|
||||
save(opts) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let wizard = this.buildJson(this, "wizard");
|
||||
@discourseComputed("steps.length")
|
||||
totalSteps: (length) => length,
|
||||
|
||||
if (wizard.error) {
|
||||
reject(wizard);
|
||||
skip() {
|
||||
if (this.required && !this.completed && this.permitted) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
CustomWizard.skip(this.id);
|
||||
},
|
||||
|
||||
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);
|
||||
restart() {
|
||||
CustomWizard.restart(this.id);
|
||||
},
|
||||
});
|
||||
|
||||
CustomWizard.reopenClass({
|
||||
all() {
|
||||
return ajax("/admin/wizards/wizard", {
|
||||
type: "GET",
|
||||
})
|
||||
skip(wizardId) {
|
||||
ajax({ url: `/w/${wizardId}/skip`, type: "PUT" })
|
||||
.then((result) => {
|
||||
return result.wizard_list;
|
||||
CustomWizard.finished(result);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
submissions(wizardId) {
|
||||
return ajax(`/admin/wizards/submissions/${wizardId}`, {
|
||||
type: "GET",
|
||||
}).catch(popupAjaxError);
|
||||
restart(wizardId) {
|
||||
ajax({ url: `/w/${wizardId}/skip`, type: "PUT" })
|
||||
.then(() => {
|
||||
window.location.href = `/w/${wizardId}`;
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
create(wizardJson = {}) {
|
||||
const wizard = this._super.apply(this);
|
||||
wizard.setProperties(buildProperties(wizardJson));
|
||||
return wizard;
|
||||
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 = 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;
|
||||
|
|
|
@ -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", {});
|
||||
},
|
||||
});
|
|
@ -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;
|
|
@ -1,9 +1,9 @@
|
|||
import CustomWizard from "../models/custom-wizard";
|
||||
import CustomWizardAdmin from "../models/custom-wizard-admin";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model() {
|
||||
return CustomWizard.all();
|
||||
return CustomWizardAdmin.all();
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import CustomWizard from "../models/custom-wizard";
|
||||
import CustomWizardAdmin from "../models/custom-wizard-admin";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
const excludedMetaFields = ["route_to", "redirect_on_complete", "redirect_to"];
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model(params) {
|
||||
return CustomWizard.submissions(params.wizardId);
|
||||
return CustomWizardAdmin.submissions(params.wizardId);
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import CustomWizard from "../models/custom-wizard";
|
||||
import CustomWizardAdmin from "../models/custom-wizard-admin";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "I18n";
|
||||
|
@ -20,7 +20,9 @@ export default DiscourseRoute.extend({
|
|||
|
||||
setupController(controller, model) {
|
||||
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) => {
|
||||
return {
|
||||
id: type,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { getCachedWizard } from "../models/wizard";
|
||||
import { getCachedWizard } from "../models/custom-wizard";
|
||||
import Route from "@ember/routing/route";
|
||||
|
||||
export default Route.extend({
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import I18n from "I18n";
|
||||
import { getCachedWizard } from "../models/wizard";
|
||||
import { getCachedWizard } from "../models/custom-wizard";
|
||||
import Route from "@ember/routing/route";
|
||||
|
||||
export default Route.extend({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { findCustomWizard, updateCachedWizard } from "../models/wizard";
|
||||
import { findCustomWizard, updateCachedWizard } from "../models/custom-wizard";
|
||||
import I18n from "I18n";
|
||||
import Route from "@ember/routing/route";
|
||||
|
||||
|
@ -50,6 +50,7 @@ export default Route.extend({
|
|||
customWizard: true,
|
||||
logoUrl: this.siteSettings.logo_small,
|
||||
reset: null,
|
||||
model,
|
||||
});
|
||||
|
||||
const stepModel = this.modelFor("step");
|
||||
|
@ -60,22 +61,17 @@ export default Route.extend({
|
|||
) {
|
||||
this.showDialog(model);
|
||||
}
|
||||
},
|
||||
|
||||
getWizardBackground() {
|
||||
const wizard = this.controllerFor("custom-wizard").get("model");
|
||||
return wizard ? wizard.get("background") : "";
|
||||
const background = model.get("background");
|
||||
if (background) {
|
||||
document.body.style.background = background;
|
||||
}
|
||||
},
|
||||
|
||||
activate() {
|
||||
if (!document.body.classList.contains("custom-wizard")) {
|
||||
document.body.classList.add("custom-wizard");
|
||||
}
|
||||
|
||||
const background = this.getWizardBackground();
|
||||
if (background) {
|
||||
document.body.style.background = background;
|
||||
}
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
|
@ -83,9 +79,6 @@ export default Route.extend({
|
|||
document.body.classList.remove("custom-wizard");
|
||||
}
|
||||
|
||||
const background = this.getWizardBackground();
|
||||
if (background) {
|
||||
document.body.style.background = "";
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
img.avatar {
|
||||
border-radius: 50%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.ac-wrap {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
max-height: 150px;
|
||||
min-height: 34px;
|
||||
background-color: var(--secondary);
|
||||
border: 1px solid var(--primary-medium);
|
||||
padding: 5px 4px 1px 4px;
|
||||
padding: 5px;
|
||||
|
||||
div.item {
|
||||
float: left;
|
||||
margin-bottom: 4px;
|
||||
margin-right: 10px;
|
||||
line-height: 1.6;
|
||||
|
||||
span {
|
||||
height: 24px;
|
||||
|
@ -46,20 +54,31 @@ div.ac-wrap {
|
|||
color: var(--danger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
border-radius: 50%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.ac-loading {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.autocomplete {
|
||||
input {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.autocomplete {
|
||||
z-index: 999999;
|
||||
position: absolute;
|
||||
width: 240px;
|
||||
width: inherit;
|
||||
max-width: 240px;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--secondary);
|
||||
border: 1px solid var(--primary-low);
|
||||
|
||||
li,
|
||||
.no-results {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
@ -91,50 +110,30 @@ img.avatar {
|
|||
color: var(--primary);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
span.name {
|
||||
font-size: $font-down-1;
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: var(--tertiary);
|
||||
|
||||
span.username,
|
||||
span.name {
|
||||
color: var(--secondary);
|
||||
}
|
||||
&:hover {
|
||||
}
|
||||
|
||||
&:hover:not(.selected) {
|
||||
background-color: var(--highlight-low);
|
||||
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 {
|
||||
margin: 5px 0;
|
||||
|
|
|
@ -60,6 +60,7 @@ body.custom-wizard {
|
|||
& > label.field-label {
|
||||
order: 1;
|
||||
font-weight: 400;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
& > .field-description {
|
||||
|
@ -70,6 +71,7 @@ body.custom-wizard {
|
|||
|
||||
.url-field input {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
font-size: 1.1487em;
|
||||
padding: 6px;
|
||||
transition: border-color 0.5s;
|
||||
|
@ -136,10 +138,16 @@ body.custom-wizard {
|
|||
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;
|
||||
padding: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.d-date-time-input {
|
||||
display: flex;
|
||||
|
|
|
@ -2,6 +2,66 @@ en:
|
|||
js:
|
||||
wizard:
|
||||
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:
|
||||
|
@ -483,78 +543,3 @@ en:
|
|||
countrycode: "Please select a country."
|
||||
coordinates: "Please complete the set of coordinates."
|
||||
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"
|
||||
|
|
|
@ -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
|
|
@ -1,9 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe CustomWizard::RealtimeValidationsController do
|
||||
|
||||
fab!(:validation_type) { "test_stub" }
|
||||
fab!(:validation_type_stub) {
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
let(:validation_type) { "test_stub" }
|
||||
let(:validation_type_stub) {
|
||||
{
|
||||
types: [:text],
|
||||
component: "similar-topics-validator",
|
||||
|
@ -12,9 +12,8 @@ describe CustomWizard::RealtimeValidationsController do
|
|||
}
|
||||
}
|
||||
|
||||
before(:all) do
|
||||
sign_in(Fabricate(:user))
|
||||
CustomWizard::RealtimeValidation.types = { test_stub: validation_type_stub }
|
||||
before do
|
||||
sign_in(user)
|
||||
|
||||
class CustomWizard::RealtimeValidation::TestStub
|
||||
attr_accessor :user
|
||||
|
@ -40,6 +39,7 @@ describe CustomWizard::RealtimeValidationsController do
|
|||
end
|
||||
|
||||
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 }
|
||||
expect(response.status).to eq(200)
|
||||
expected_response = [
|
||||
|
@ -50,11 +50,13 @@ describe CustomWizard::RealtimeValidationsController do
|
|||
end
|
||||
|
||||
it "gives 400 error when no type is passed" do
|
||||
CustomWizard::RealtimeValidation.types = { test_stub: validation_type_stub }
|
||||
get '/realtime-validations.json'
|
||||
expect(response.status).to eq(400)
|
||||
end
|
||||
|
||||
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]
|
||||
get '/realtime-validations.json', params: { type: validation_type }
|
||||
expect(response.status).to eq(400)
|
||||
|
@ -63,6 +65,7 @@ describe CustomWizard::RealtimeValidationsController do
|
|||
end
|
||||
|
||||
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" }
|
||||
expect(response.status).to eq(500)
|
||||
end
|
||||
|
|
|
@ -1,38 +1,42 @@
|
|||
import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { exists } from "../helpers/test";
|
||||
import acceptance, {
|
||||
import {
|
||||
acceptance,
|
||||
count,
|
||||
query,
|
||||
server,
|
||||
visible,
|
||||
} from "../helpers/acceptance";
|
||||
import { allFieldsWizard, getWizard } from "../helpers/wizard";
|
||||
exists,
|
||||
visible
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { allFieldsWizard } from "../helpers/wizard";
|
||||
import tagsJson from "../fixtures/tags";
|
||||
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) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(exists(".wizard-field.text-field input.wizard-focusable"));
|
||||
});
|
||||
|
||||
test("Textarea", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(
|
||||
visible(".wizard-field.textarea-field textarea.wizard-focusable")
|
||||
);
|
||||
});
|
||||
|
||||
test("Composer", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/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(
|
||||
exists(".wizard-field.composer-field .d-editor-button-bar button")
|
||||
);
|
||||
assert.ok(visible(".wizard-btn.toggle-preview"));
|
||||
|
||||
|
@ -50,19 +54,19 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
|
|||
});
|
||||
|
||||
test("Text Only", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(visible(".wizard-field.text-only-field label.field-label"));
|
||||
});
|
||||
|
||||
test("Date", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/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");
|
||||
await visit("/w/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"
|
||||
|
@ -71,7 +75,7 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
|
|||
});
|
||||
|
||||
test("Date Time", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(
|
||||
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) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(visible(".wizard-field.number-field input[type='number']"));
|
||||
});
|
||||
|
||||
test("Checkbox", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(visible(".wizard-field.checkbox-field input[type='checkbox']"));
|
||||
});
|
||||
|
||||
test("Url", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(visible(".wizard-field.url-field input[type='text']"));
|
||||
});
|
||||
|
||||
test("Upload", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(
|
||||
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) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(visible(".wizard-field.dropdown-field .single-select-header"));
|
||||
await click(".wizard-field.dropdown-field .select-kit-header");
|
||||
assert.strictEqual(
|
||||
|
@ -121,10 +125,7 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
|
|||
});
|
||||
|
||||
test("Tag", async function (assert) {
|
||||
server.get("/tags/filter/search", () =>
|
||||
response(200, { results: tagsJson["tags"] })
|
||||
);
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(visible(".wizard-field.tag-field .multi-select-header"));
|
||||
await click(".wizard-field.tag-field .select-kit-header");
|
||||
assert.strictEqual(
|
||||
|
@ -134,17 +135,16 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
|
|||
});
|
||||
|
||||
test("Category", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/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
|
||||
assert.ok(
|
||||
exists(".wizard-field.category-field .select-kit-collection li")
|
||||
);
|
||||
});
|
||||
|
||||
test("Group", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(visible(".wizard-field.group-field .single-select-header"));
|
||||
await click(".wizard-field.group-field .select-kit-header");
|
||||
assert.strictEqual(
|
||||
|
@ -154,9 +154,7 @@ acceptance("Field | Fields", [getWizard(allFieldsWizard)], function () {
|
|||
});
|
||||
|
||||
test("User", async function (assert) {
|
||||
server.get("/u/search/users", () => response(200, usersJson));
|
||||
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
await fillIn(
|
||||
".wizard-field.user-selector-field input.ember-text-field",
|
||||
"a"
|
|
@ -1,20 +1,33 @@
|
|||
import { click, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { exists } from "../helpers/test";
|
||||
import acceptance, { count, query, visible } from "../helpers/acceptance";
|
||||
import { getWizard, stepNotPermitted, wizard } from "../helpers/wizard";
|
||||
import { saveStep, update } from "../helpers/step";
|
||||
import {
|
||||
acceptance,
|
||||
count,
|
||||
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) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
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) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.strictEqual(
|
||||
query(".wizard-step-title p").textContent.trim(),
|
||||
"Text"
|
||||
|
@ -33,7 +46,7 @@ acceptance("Step | Step", [getWizard(wizard), saveStep(update)], function () {
|
|||
});
|
||||
|
||||
test("Goes to the next step", async function (assert) {
|
||||
await visit("/wizard");
|
||||
await visit("/w/wizard");
|
||||
assert.ok(visible(".wizard-step.step_1"), true);
|
||||
await click(".wizard-btn.next");
|
||||
assert.ok(visible(".wizard-step.step_2"), true);
|
96
test/javascripts/acceptance/wizard-test.js
Normale Datei
96
test/javascripts/acceptance/wizard-test.js
Normale Datei
|
@ -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);
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
});
|
||||
});
|
47
test/javascripts/helpers/wizard.js
Normale Datei
47
test/javascripts/helpers/wizard.js
Normale Datei
|
@ -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
|
||||
};
|
Laden …
In neuem Issue referenzieren