wip
Dieser Commit ist enthalten in:
Ursprung
024ab63006
Commit
3c8dc540c8
18 geänderte Dateien mit 461 neuen und 454 gelöschten Zeilen
|
@ -1,11 +1,11 @@
|
||||||
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
|
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
|
||||||
import { equal, empty, or } from "@ember/object/computed";
|
import { equal, empty, or } from "@ember/object/computed";
|
||||||
import { actionTypes, generateName, selectKitContent } from '../lib/wizard';
|
import { generateName, selectKitContent, schema } from '../lib/wizard';
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: 'wizard-custom-action',
|
classNames: 'wizard-custom-action',
|
||||||
actionTypes: actionTypes.map(t => ({ id: t, name: generateName(t) })),
|
actionTypes: Object.keys(schema.action.types).map(t => ({ id: t, name: generateName(t) })),
|
||||||
createTopic: equal('action.type', 'create_topic'),
|
createTopic: equal('action.type', 'create_topic'),
|
||||||
updateProfile: equal('action.type', 'update_profile'),
|
updateProfile: equal('action.type', 'update_profile'),
|
||||||
sendMessage: equal('action.type', 'send_message'),
|
sendMessage: equal('action.type', 'send_message'),
|
||||||
|
@ -21,6 +21,17 @@ export default Component.extend({
|
||||||
publicTopicFields: or('createTopic', 'openComposer'),
|
publicTopicFields: or('createTopic', 'openComposer'),
|
||||||
showSkipRedirect: or('createTopic', 'sendMessage'),
|
showSkipRedirect: or('createTopic', 'sendMessage'),
|
||||||
|
|
||||||
|
@observes('action.type')
|
||||||
|
setupDefaults() {
|
||||||
|
const defaultProperties = schema.action.types[this.action.type];
|
||||||
|
|
||||||
|
Object.keys(defaultProperties).forEach(property => {
|
||||||
|
if (defaultProperties[property]) {
|
||||||
|
this.set(`action.${property}`, defaultProperties[property]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
@discourseComputed('wizard.steps')
|
@discourseComputed('wizard.steps')
|
||||||
runAfterContent(steps) {
|
runAfterContent(steps) {
|
||||||
let content = steps.map(function(step) {
|
let content = steps.map(function(step) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { default as discourseComputed, observes } from 'discourse-common/utils/decorators';
|
import { default as discourseComputed, observes } from 'discourse-common/utils/decorators';
|
||||||
import { equal, or } from "@ember/object/computed";
|
import { equal, or } from "@ember/object/computed";
|
||||||
import { selectKitContent } from '../lib/wizard';
|
import { selectKitContent, schema } from '../lib/wizard';
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
|
@ -16,24 +16,25 @@ export default Component.extend({
|
||||||
showPrefill: or('isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
showPrefill: or('isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
||||||
showContent: or('isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
showContent: or('isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
||||||
showLimit: or('isCategory', 'isTag'),
|
showLimit: or('isCategory', 'isTag'),
|
||||||
showMinLength: or('isText', 'isTextarea', 'isUrl'),
|
showMinLength: or('isText', 'isTextarea', 'isUrl', 'isComposer'),
|
||||||
categoryPropertyTypes: selectKitContent(['id', 'slug']),
|
categoryPropertyTypes: selectKitContent(['id', 'slug']),
|
||||||
|
|
||||||
@observes('isUpload', 'isCategory')
|
@observes('field.type')
|
||||||
setupDefaults() {
|
setupDefaults() {
|
||||||
if (this.isUpload && !this.field.file_types) {
|
const defaultProperties = schema.field.types[this.field.type];
|
||||||
this.set('field.file_types', '.jpg,.png');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isCategory && !this.field.property) {
|
Object.keys(defaultProperties).forEach(property => {
|
||||||
this.set('field.property', 'id');
|
if (defaultProperties[property]) {
|
||||||
}
|
this.set(`field.${property}`, defaultProperties[property]);
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes('field.type')
|
@observes('field.type')
|
||||||
clearMappedProperties() {
|
clearMapped() {
|
||||||
this.set('field.content', null);
|
schema.field.mapped.forEach(property => {
|
||||||
this.set('field.prefill', null);
|
this.set(`field.${property}`, null);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setupTypeOutput(fieldType, options) {
|
setupTypeOutput(fieldType, options) {
|
||||||
|
@ -66,7 +67,6 @@ export default Component.extend({
|
||||||
options.wizardFieldSelection = 'key,value';
|
options.wizardFieldSelection = 'key,value';
|
||||||
options.listSelection += ',assignment';
|
options.listSelection += ',assignment';
|
||||||
options.inputTypes = 'association,assignment';
|
options.inputTypes = 'association,assignment';
|
||||||
options.singular = true;
|
|
||||||
options.pairConnector = 'association';
|
options.pairConnector = 'association';
|
||||||
options.keyPlaceholder = 'admin.wizard.key';
|
options.keyPlaceholder = 'admin.wizard.key';
|
||||||
options.valuePlaceholder = 'admin.wizard.value';
|
options.valuePlaceholder = 'admin.wizard.value';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { default as discourseComputed, on, observes } from 'discourse-common/utils/decorators';
|
import { default as discourseComputed, on, observes } from 'discourse-common/utils/decorators';
|
||||||
import { generateName, defaultProperties } from '../lib/wizard';
|
import { generateName, schema } from '../lib/wizard';
|
||||||
import { notEmpty } from "@ember/object/computed";
|
import { notEmpty } from "@ember/object/computed";
|
||||||
import { scheduleOnce, bind } from "@ember/runloop";
|
import { scheduleOnce, bind } from "@ember/runloop";
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
|
@ -7,7 +7,7 @@ import Component from "@ember/component";
|
||||||
import { A } from "@ember/array";
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNameBindings: [':wizard-links', 'type'],
|
classNameBindings: [':wizard-links', 'itemType'],
|
||||||
items: A(),
|
items: A(),
|
||||||
anyLinks: notEmpty('links'),
|
anyLinks: notEmpty('links'),
|
||||||
|
|
||||||
|
@ -33,10 +33,10 @@ export default Component.extend({
|
||||||
scheduleOnce('afterRender', this, () => this.applySortable());
|
scheduleOnce('afterRender', this, () => this.applySortable());
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed('type')
|
@discourseComputed('itemType')
|
||||||
header: (type) => `admin.wizard.${type}.header`,
|
header: (itemType) => `admin.wizard.${itemType}.header`,
|
||||||
|
|
||||||
@discourseComputed('current', 'items.@each.id', 'items.@each.type')
|
@discourseComputed('current', 'items.@each.id', 'items.@each.type', 'items.@each.label', 'items.@each.title')
|
||||||
links(current, items) {
|
links(current, items) {
|
||||||
if (!items) return;
|
if (!items) return;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ export default Component.extend({
|
||||||
if (this.generateLabels && item.type) {
|
if (this.generateLabels && item.type) {
|
||||||
label = generateName(item.type);
|
label = generateName(item.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
link.label = label;
|
link.label = label;
|
||||||
|
|
||||||
let classes = 'btn';
|
let classes = 'btn';
|
||||||
|
@ -64,28 +64,37 @@ export default Component.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setDefaults(object, params) {
|
||||||
|
Object.keys(object).forEach(property => {
|
||||||
|
if (object[property]) {
|
||||||
|
params[property] = object[property];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return params;
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
add() {
|
add() {
|
||||||
const items = this.items;
|
const items = this.items;
|
||||||
const type = this.type;
|
const itemType = this.itemType;
|
||||||
const newId = `${type}_${items.length + 1}`;
|
|
||||||
|
|
||||||
let params = {
|
let params = {
|
||||||
id: newId,
|
id: `${itemType}_${items.length + 1}`,
|
||||||
isNew: true
|
isNew: true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (type === 'step') {
|
if (schema[itemType].objectArrays) {
|
||||||
params.fields = A();
|
Object.keys(schema[itemType].objectArrays).forEach(objectType => {
|
||||||
|
params[objectArrays[objectType].property] = A();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (defaultProperties[type]) {
|
params = this.setDefaults(schema[itemType].basic, params);
|
||||||
Object.keys(defaultProperties[type]).forEach(key => {
|
if (schema[itemType].types) {
|
||||||
params[key] = defaultProperties[type][key];
|
params = this.setDefaults(schema[itemType].types[params.type], params);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const newItem = EmberObject.create(params);
|
const newItem = EmberObject.create(params);
|
||||||
items.pushObject(newItem);
|
items.pushObject(newItem);
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
import { getOwner } from 'discourse-common/lib/get-owner';
|
import { getOwner } from 'discourse-common/lib/get-owner';
|
||||||
import { newInput, selectionTypes } from '../lib/wizard-mapper';
|
import { newInput, selectionTypes } from '../lib/wizard-mapper';
|
||||||
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
|
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
|
||||||
import { gt } from "@ember/object/computed";
|
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { A } from "@ember/array";
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: 'wizard-mapper',
|
classNames: 'wizard-mapper',
|
||||||
hasInput: gt('inputs.length', 0),
|
|
||||||
|
|
||||||
@discourseComputed('options.singular', 'hasInput')
|
@discourseComputed('inputs.@each.type')
|
||||||
canAdd(singular, hasInput) {
|
canAdd(inputs) {
|
||||||
return !singular || !hasInput;
|
return !inputs || inputs.every(i => {
|
||||||
|
return ['assignment','association'].indexOf(i.type) === -1;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed('options.@each.inputType')
|
@discourseComputed('options.@each.inputType')
|
||||||
inputOptions(options) {
|
inputOptions(options) {
|
||||||
let result = {
|
let result = {
|
||||||
inputTypes: options.inputTypes || 'conditional,assignment',
|
inputTypes: options.inputTypes || 'assignment,conditional',
|
||||||
inputConnector: options.inputConnector || 'or',
|
inputConnector: options.inputConnector || 'or',
|
||||||
pairConnector: options.pairConnector || null,
|
pairConnector: options.pairConnector || null,
|
||||||
outputConnector: options.outputConnector || null,
|
outputConnector: options.outputConnector || null,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { default as discourseComputed, on } from 'discourse-common/utils/decorators';
|
import { default as discourseComputed, on } from 'discourse-common/utils/decorators';
|
||||||
import { profileFields } from '../lib/wizard';
|
import { userProperties } from '../lib/wizard';
|
||||||
import { scheduleOnce } from "@ember/runloop";
|
import { scheduleOnce } from "@ember/runloop";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export default Component.extend({
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
userFieldList() {
|
userFieldList() {
|
||||||
return profileFields.map((f) => ` u{${f}}`);
|
return userProperties.map((f) => ` u{${f}}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed('wizardFields')
|
@discourseComputed('wizardFields')
|
||||||
|
|
|
@ -93,9 +93,16 @@ export default Controller.extend({
|
||||||
this.send("refreshWizard");
|
this.send("refreshWizard");
|
||||||
}
|
}
|
||||||
}).catch((result) => {
|
}).catch((result) => {
|
||||||
console.log('catch result: ', result)
|
|
||||||
this.set('saving', false);
|
this.set('saving', false);
|
||||||
this.set('error', I18n.t(`admin.wizard.error.${result.error}`, result.errorParams || {}));
|
|
||||||
|
let error = true;
|
||||||
|
if (result.error) {
|
||||||
|
let type = result.error.type;
|
||||||
|
let params = result.error.params || {};
|
||||||
|
error = I18n.t(`admin.wizard.error.${type}`, params);
|
||||||
|
}
|
||||||
|
this.set('error', error);
|
||||||
|
|
||||||
later(() => this.set('error', null), 10000);
|
later(() => this.set('error', null), 10000);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { properties, mappedProperties, advancedProperties, camelCase, snakeCase } from '../lib/wizard';
|
import { schema, listProperties, camelCase, snakeCase } from '../lib/wizard';
|
||||||
import EmberObject from '@ember/object';
|
import EmberObject from '@ember/object';
|
||||||
import { A } from "@ember/array";
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@ function present(val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapped(property, type) {
|
function mapped(property, type) {
|
||||||
return mappedProperties[type] &&
|
return schema[type].mapped.indexOf(property) > -1;
|
||||||
mappedProperties[type].indexOf(property) > -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function castCase(property, value) {
|
function castCase(property, value) {
|
||||||
|
@ -67,36 +66,54 @@ function buildProperty(json, property, type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildObject(json, type) {
|
function buildObject(json, type) {
|
||||||
let params = {
|
let props = {
|
||||||
isNew: false
|
isNew: false
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(json).forEach(prop => {
|
Object.keys(json).forEach(prop => {
|
||||||
params[prop] = buildProperty(json, prop, type)
|
props[prop] = buildProperty(json, prop, type)
|
||||||
});
|
});
|
||||||
|
|
||||||
return EmberObject.create(params);
|
return EmberObject.create(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
function wizardHasAdvanced(property, value) {
|
function buildObjectArray(json, type) {
|
||||||
if (property === 'save_submissions' && value == false) return true;
|
let array = A();
|
||||||
if (property === 'restart_on_revisit' && value == true) return true;
|
|
||||||
return false;
|
if (present(json)) {
|
||||||
|
json.forEach((objJson) => {
|
||||||
|
let object = buildObject(objJson, type);
|
||||||
|
|
||||||
|
if (hasAdvancedProperties(object, type)) {
|
||||||
|
object.set('showAdvanced', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
array.pushObject(object);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stepHasAdvanced(property, value) {
|
function buildBasicProperties(json, type, props) {
|
||||||
return advancedProperties.steps[property] && present(value);
|
listProperties(type).forEach((p) => {
|
||||||
|
props[p] = buildProperty(json, p, type);
|
||||||
|
|
||||||
|
if (hasAdvancedProperties(json, type)) {
|
||||||
|
result.showAdvanced = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
function objectHasAdvanced(params, type) {
|
function hasAdvancedProperties(object, type) {
|
||||||
return Object.keys(params).some(p => {
|
return Object.keys(object).some(p => {
|
||||||
let value = params[p];
|
return schema[type].advanced.indexOf(p) > -1 && present(object[p]);
|
||||||
let advanced = advancedProperties[type][params.type];
|
|
||||||
return advanced && advanced.indexOf(p) > -1 && present(value);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// to be removed
|
/// to be removed: necessary due to action array being moved from step to wizard
|
||||||
function actionPatch(json) {
|
function actionPatch(json) {
|
||||||
let actions = json.actions || [];
|
let actions = json.actions || [];
|
||||||
|
|
||||||
|
@ -117,86 +134,32 @@ function actionPatch(json) {
|
||||||
|
|
||||||
function buildProperties(json) {
|
function buildProperties(json) {
|
||||||
let props = {
|
let props = {
|
||||||
steps: A(),
|
steps: A()
|
||||||
actions: A()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (present(json)) {
|
if (present(json)) {
|
||||||
props.id = json.id;
|
|
||||||
props.existingId = true;
|
props.existingId = true;
|
||||||
|
props = buildBasicProperties(json, 'wizard', props);
|
||||||
// to fix
|
|
||||||
properties.wizard
|
|
||||||
.filter(p => ['steps', 'actions'].indexOf(p) === -1)
|
|
||||||
.forEach((p) => {
|
|
||||||
props[p] = buildProperty(json, p, 'wizard');
|
|
||||||
|
|
||||||
if (wizardHasAdvanced(p, json[p])) {
|
|
||||||
props.showAdvanced = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (present(json.steps)) {
|
if (present(json.steps)) {
|
||||||
json.steps.forEach((stepJson) => {
|
json.steps.forEach((stepJson) => {
|
||||||
let stepParams = {
|
let stepProps = {
|
||||||
isNew: false
|
isNew: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
stepProps = buildBasicProperties(stepJson, 'step', stepProps);
|
||||||
|
stepProps.fields = buildObjectArray(stepJson.fields, 'field');
|
||||||
|
|
||||||
properties.steps.forEach((p) => {
|
props.steps.pushObject(EmberObject.create(stepProps));
|
||||||
stepParams[p] = buildProperty(stepJson, p, 'wizard');
|
|
||||||
|
|
||||||
if (stepHasAdvanced(p, stepJson[p])) {
|
|
||||||
stepParams.showAdvanced = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
stepParams.fields = A();
|
|
||||||
|
|
||||||
if (present(stepJson.fields)) {
|
|
||||||
stepJson.fields.forEach((f) => {
|
|
||||||
let params = buildObject(f, 'fields');
|
|
||||||
|
|
||||||
if (objectHasAdvanced(params, 'fields')) {
|
|
||||||
params.showAdvanced = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
stepParams.fields.pushObject(params);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
props.steps.pushObject(
|
|
||||||
EmberObject.create(stepParams)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// to be removed
|
json = actionPatch(json); // to be removed - see above
|
||||||
json = actionPatch(json);
|
props.actions = buildObjectArray(json.actions, 'action');
|
||||||
// to be removed
|
|
||||||
|
|
||||||
if (present(json.actions)) {
|
|
||||||
json.actions.forEach((a) => {
|
|
||||||
let params = buildObject(a, 'actions');
|
|
||||||
|
|
||||||
if (objectHasAdvanced(params, 'actions')) {
|
|
||||||
params.showAdvanced = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
props.actions.pushObject(params);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
props.id = '';
|
listProperties('wizard').forEach(prop => {
|
||||||
props.name = '';
|
props[prop] = schema.wizard.basic[prop];
|
||||||
props.background = '';
|
});
|
||||||
props.save_submissions = true;
|
|
||||||
props.multiple_submissions = false;
|
|
||||||
props.after_signup = false;
|
|
||||||
props.after_time = false;
|
|
||||||
props.required = false;
|
|
||||||
props.prompt_completion = false;
|
|
||||||
props.restart_on_revisit = false;
|
|
||||||
props.permitted = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return props;
|
return props;
|
||||||
|
|
|
@ -30,7 +30,7 @@ function camelCase(string) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const profileFields = [
|
const userProperties = [
|
||||||
'name',
|
'name',
|
||||||
'email',
|
'email',
|
||||||
'avatar',
|
'avatar',
|
||||||
|
@ -45,164 +45,198 @@ const profileFields = [
|
||||||
'trust_level'
|
'trust_level'
|
||||||
];
|
];
|
||||||
|
|
||||||
const wizardProperties = [
|
const wizardProperties = {
|
||||||
'id',
|
basic: {
|
||||||
'name',
|
id: null,
|
||||||
'background',
|
name: null,
|
||||||
'save_submissions',
|
background: null,
|
||||||
'multiple_submissions',
|
save_submissions: true,
|
||||||
'after_signup',
|
multiple_submissions: null,
|
||||||
'after_time',
|
after_signup: null,
|
||||||
'after_time_scheduled',
|
after_time: null,
|
||||||
'required',
|
after_time_scheduled: null,
|
||||||
'prompt_completion',
|
required: null,
|
||||||
'restart_on_revisit',
|
prompt_completion: null,
|
||||||
'theme_id',
|
restart_on_revisit: null,
|
||||||
'permitted',
|
theme_id: null,
|
||||||
'steps',
|
permitted: null
|
||||||
'actions'
|
},
|
||||||
];
|
mapped: [
|
||||||
|
|
||||||
const stepProperties = [
|
|
||||||
'id',
|
|
||||||
'title',
|
|
||||||
'key',
|
|
||||||
'banner',
|
|
||||||
'raw_description',
|
|
||||||
'required_data',
|
|
||||||
'required_data_message',
|
|
||||||
'permitted_params',
|
|
||||||
'fields'
|
|
||||||
]
|
|
||||||
|
|
||||||
const fieldProperties = [
|
|
||||||
'id',
|
|
||||||
'label',
|
|
||||||
'key',
|
|
||||||
'image',
|
|
||||||
'description',
|
|
||||||
'type',
|
|
||||||
'required',
|
|
||||||
'min_length',
|
|
||||||
'file_types',
|
|
||||||
'property',
|
|
||||||
'limit',
|
|
||||||
'prefill',
|
|
||||||
'content'
|
|
||||||
]
|
|
||||||
|
|
||||||
const actionProperties = [
|
|
||||||
'id',
|
|
||||||
'type',
|
|
||||||
'run_after',
|
|
||||||
'title',
|
|
||||||
'post',
|
|
||||||
'post_builder',
|
|
||||||
'post_template',
|
|
||||||
'category',
|
|
||||||
'tags',
|
|
||||||
'skip_redirect',
|
|
||||||
'custom_fields',
|
|
||||||
'required',
|
|
||||||
'recipient',
|
|
||||||
'profile_updates',
|
|
||||||
'group',
|
|
||||||
'url',
|
|
||||||
'code',
|
|
||||||
'api',
|
|
||||||
'api_endpoint',
|
|
||||||
'api_body'
|
|
||||||
]
|
|
||||||
|
|
||||||
const properties = {
|
|
||||||
wizard: wizardProperties,
|
|
||||||
steps: stepProperties,
|
|
||||||
fields: fieldProperties,
|
|
||||||
actions: actionProperties
|
|
||||||
}
|
|
||||||
|
|
||||||
const actionTypeProperties = {
|
|
||||||
create_topic: [
|
|
||||||
'id',
|
|
||||||
'type',
|
|
||||||
'run_after',
|
|
||||||
'title',
|
|
||||||
'post',
|
|
||||||
'post_builder',
|
|
||||||
'post_template',
|
|
||||||
'category',
|
|
||||||
'tags',
|
|
||||||
'skip_redirect',
|
|
||||||
'custom_fields'
|
|
||||||
],
|
|
||||||
send_message: [
|
|
||||||
'id',
|
|
||||||
'type',
|
|
||||||
'run_after',
|
|
||||||
'title',
|
|
||||||
'post',
|
|
||||||
'post_builder',
|
|
||||||
'post_template',
|
|
||||||
'skip_redirect',
|
|
||||||
'custom_fields',
|
|
||||||
'required',
|
|
||||||
'recipient'
|
|
||||||
],
|
|
||||||
open_composer: [
|
|
||||||
'id',
|
|
||||||
'type',
|
|
||||||
'run_after',
|
|
||||||
'title',
|
|
||||||
'post',
|
|
||||||
'post_builder',
|
|
||||||
'post_template',
|
|
||||||
'category',
|
|
||||||
'tags',
|
|
||||||
'custom_fields'
|
|
||||||
],
|
|
||||||
update_profile: [
|
|
||||||
'id',
|
|
||||||
'type',
|
|
||||||
'run_after',
|
|
||||||
'profile_updates',
|
|
||||||
'custom_fields'
|
|
||||||
],
|
|
||||||
add_to_group: [
|
|
||||||
'id',
|
|
||||||
'type',
|
|
||||||
'run_after',
|
|
||||||
'group'
|
|
||||||
],
|
|
||||||
route_to: [
|
|
||||||
'id',
|
|
||||||
'type',
|
|
||||||
'run_after',
|
|
||||||
'url',
|
|
||||||
'code'
|
|
||||||
],
|
|
||||||
send_to_api: [
|
|
||||||
'id',
|
|
||||||
'type',
|
|
||||||
'run_after',
|
|
||||||
'api',
|
|
||||||
'api_endpoint',
|
|
||||||
'api_body'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const mappedProperties = {
|
|
||||||
wizard: [
|
|
||||||
'permitted'
|
'permitted'
|
||||||
],
|
],
|
||||||
steps: [
|
advanced: [
|
||||||
|
'restart_on_revisit',
|
||||||
|
],
|
||||||
|
required: [
|
||||||
|
'id',
|
||||||
|
],
|
||||||
|
dependent: {
|
||||||
|
after_time: 'after_time_scheduled'
|
||||||
|
},
|
||||||
|
objectArrays: {
|
||||||
|
step: {
|
||||||
|
property: 'steps',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
property: 'actions',
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const stepProperties = {
|
||||||
|
basic: {
|
||||||
|
id: null,
|
||||||
|
title: null,
|
||||||
|
key: null,
|
||||||
|
banner: null,
|
||||||
|
raw_description: null,
|
||||||
|
required_data: null,
|
||||||
|
required_data_message: null,
|
||||||
|
permitted_params: null
|
||||||
|
},
|
||||||
|
mapped: [
|
||||||
'required_data',
|
'required_data',
|
||||||
'permitted_params'
|
'permitted_params'
|
||||||
],
|
],
|
||||||
fields: [
|
advanced: [
|
||||||
|
'required_data',
|
||||||
|
'permitted_params'
|
||||||
|
],
|
||||||
|
required: [
|
||||||
|
'id'
|
||||||
|
],
|
||||||
|
dependent: {
|
||||||
|
},
|
||||||
|
objectArrays: {
|
||||||
|
field: {
|
||||||
|
property: 'fields',
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fieldProperties = {
|
||||||
|
basic: {
|
||||||
|
id: null,
|
||||||
|
label: null,
|
||||||
|
image: null,
|
||||||
|
description: null,
|
||||||
|
required: null,
|
||||||
|
key: null,
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
types: {
|
||||||
|
text: {
|
||||||
|
min_length: null
|
||||||
|
},
|
||||||
|
textarea: {
|
||||||
|
min_length: null
|
||||||
|
},
|
||||||
|
composer: {
|
||||||
|
min_length: null
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
min_length: null
|
||||||
|
},
|
||||||
|
'text-only': {
|
||||||
|
},
|
||||||
|
'user-selector': {
|
||||||
|
},
|
||||||
|
upload: {
|
||||||
|
file_types: '.jpg,.png'
|
||||||
|
},
|
||||||
|
dropdown: {
|
||||||
|
prefill: null,
|
||||||
|
content: null
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
limit: null,
|
||||||
|
prefill: null,
|
||||||
|
content: null
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
limit: 1,
|
||||||
|
property: 'id',
|
||||||
|
prefill: null,
|
||||||
|
content: null
|
||||||
|
},
|
||||||
|
group: {
|
||||||
|
prefill: null,
|
||||||
|
content: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mapped: [
|
||||||
'prefill',
|
'prefill',
|
||||||
'content'
|
'content'
|
||||||
],
|
],
|
||||||
actions: [
|
advanced: [
|
||||||
|
'prefill',
|
||||||
|
'content',
|
||||||
|
'property'
|
||||||
|
],
|
||||||
|
required: [
|
||||||
|
'id',
|
||||||
|
'type'
|
||||||
|
],
|
||||||
|
dependent: {
|
||||||
|
},
|
||||||
|
objectArrays: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionProperties = {
|
||||||
|
basic: {
|
||||||
|
id: null,
|
||||||
|
run_after: 'wizard_completion',
|
||||||
|
type: 'create_topic'
|
||||||
|
},
|
||||||
|
types: {
|
||||||
|
create_topic: {
|
||||||
|
title: null,
|
||||||
|
post: null,
|
||||||
|
post_builder: null,
|
||||||
|
post_template: null,
|
||||||
|
category: null,
|
||||||
|
tags: null,
|
||||||
|
custom_fields: null,
|
||||||
|
skip_redirect: null
|
||||||
|
},
|
||||||
|
send_message: {
|
||||||
|
title: null,
|
||||||
|
post: null,
|
||||||
|
post_builder: null,
|
||||||
|
post_template: null,
|
||||||
|
skip_redirect: null,
|
||||||
|
custom_fields: null,
|
||||||
|
required: null,
|
||||||
|
recipient: null
|
||||||
|
},
|
||||||
|
open_composer: {
|
||||||
|
title: null,
|
||||||
|
post: null,
|
||||||
|
post_builder: null,
|
||||||
|
post_template: null,
|
||||||
|
category: null,
|
||||||
|
tags: null,
|
||||||
|
custom_fields: null
|
||||||
|
},
|
||||||
|
update_profile: {
|
||||||
|
profile_updates: null,
|
||||||
|
custom_fields: null
|
||||||
|
},
|
||||||
|
add_to_group: {
|
||||||
|
group: null
|
||||||
|
},
|
||||||
|
route_to: {
|
||||||
|
url: null,
|
||||||
|
code: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mapped: [
|
||||||
'title',
|
'title',
|
||||||
'category',
|
'category',
|
||||||
'tags',
|
'tags',
|
||||||
|
@ -211,67 +245,46 @@ const mappedProperties = {
|
||||||
'recipient',
|
'recipient',
|
||||||
'profile_updates',
|
'profile_updates',
|
||||||
'group'
|
'group'
|
||||||
]
|
],
|
||||||
}
|
advanced: [
|
||||||
|
'code',
|
||||||
const defaultProperties = {
|
'custom_fields',
|
||||||
action: {
|
'skip_redirect',
|
||||||
run_after: 'wizard_completion'
|
'required'
|
||||||
|
],
|
||||||
|
required: [
|
||||||
|
'id',
|
||||||
|
'type'
|
||||||
|
],
|
||||||
|
dependent: {
|
||||||
|
},
|
||||||
|
objectArrays: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const advancedFieldTypes = [
|
if (Discourse.SiteSettings.wizard_api_features) {
|
||||||
'category',
|
actionProperties.types.send_to_api = {
|
||||||
'tag',
|
api: null,
|
||||||
'group',
|
api_endpoint: null,
|
||||||
'dropdown'
|
api_body: null
|
||||||
]
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const advancedFieldProperties = [
|
const schema = {
|
||||||
'prefill',
|
wizard: wizardProperties,
|
||||||
'content'
|
step: stepProperties,
|
||||||
]
|
field: fieldProperties,
|
||||||
|
action: actionProperties
|
||||||
|
}
|
||||||
|
|
||||||
const actionTypes = [
|
function listProperties(type, objectType = null) {
|
||||||
'create_topic',
|
let properties = Object.keys(schema[type].basic);
|
||||||
'update_profile',
|
|
||||||
'send_message',
|
if (schema[type].types && objectType) {
|
||||||
'send_to_api',
|
properties = properties.concat(Object.keys(schema[type].types[objectType]));
|
||||||
'add_to_group',
|
}
|
||||||
'route_to',
|
|
||||||
'open_composer'
|
return properties;
|
||||||
].filter(function(type) {
|
|
||||||
return Discourse.SiteSettings.wizard_api_features || type !== 'send_to_api';
|
|
||||||
});
|
|
||||||
|
|
||||||
const advancedProperties = {
|
|
||||||
steps: [
|
|
||||||
'required_data',
|
|
||||||
'permitted_params'
|
|
||||||
],
|
|
||||||
fields: advancedFieldTypes.reduce(
|
|
||||||
function(map, type) {
|
|
||||||
map[type] = advancedFieldProperties;
|
|
||||||
if (type === 'category') {
|
|
||||||
map[type].push('property');
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}, {}
|
|
||||||
),
|
|
||||||
actions: actionTypes.reduce(
|
|
||||||
function(map, type) {
|
|
||||||
if (type === 'route_to') {
|
|
||||||
map[type] = ['code'];
|
|
||||||
} else if (['create_topic', 'send_message', 'open_composer', 'update_profile'].indexOf(type) > -1) {
|
|
||||||
map[type] = ['custom_fields'];
|
|
||||||
} else if (['create_topic', 'send_message'].indexOf(type) > -1) {
|
|
||||||
map[type].push('skip_redirect');
|
|
||||||
} else if (type === 'send_message') {
|
|
||||||
map[type].push('required');
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}, {}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -280,12 +293,7 @@ export {
|
||||||
generateId,
|
generateId,
|
||||||
camelCase,
|
camelCase,
|
||||||
snakeCase,
|
snakeCase,
|
||||||
properties,
|
schema,
|
||||||
wizardProperties,
|
userProperties,
|
||||||
mappedProperties,
|
listProperties
|
||||||
profileFields,
|
|
||||||
advancedProperties,
|
|
||||||
actionTypes,
|
|
||||||
actionTypeProperties,
|
|
||||||
defaultProperties
|
|
||||||
};
|
};
|
|
@ -1,13 +1,9 @@
|
||||||
import { ajax } from 'discourse/lib/ajax';
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
import { buildProperties, present, mapped } from '../lib/wizard-json';
|
import { buildProperties, present, mapped } from '../lib/wizard-json';
|
||||||
import { properties, actionTypeProperties, camelCase, snakeCase } from '../lib/wizard';
|
import { schema, listProperties, camelCase, snakeCase } from '../lib/wizard';
|
||||||
import { Promise } from "rsvp";
|
import { Promise } from "rsvp";
|
||||||
|
|
||||||
const jsonStrings = ['api_body'];
|
|
||||||
const required = ['id', 'steps', 'type'];
|
|
||||||
const dependent = { after_time: 'after_time_scheduled' }
|
|
||||||
|
|
||||||
const CustomWizard = EmberObject.extend({
|
const CustomWizard = EmberObject.extend({
|
||||||
save() {
|
save() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -33,87 +29,96 @@ const CustomWizard = EmberObject.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
buildJson(object, type, result = {}) {
|
buildJson(object, type, result = {}) {
|
||||||
let allowedProperties;
|
let objectType = object.type || null;
|
||||||
|
|
||||||
if (type === 'actions') {
|
if (schema[type].types) {
|
||||||
if (!object.type) {
|
if (!objectType) {
|
||||||
result.error = {
|
result.error = {
|
||||||
type: 'required',
|
type: 'required',
|
||||||
params: {
|
params: { type, property: 'type' }
|
||||||
type,
|
|
||||||
property: 'type'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
allowedProperties = actionTypeProperties[object.type];
|
|
||||||
} else {
|
|
||||||
allowedProperties = properties[type];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let property of allowedProperties) {
|
for (let property of listProperties(type, objectType)) {
|
||||||
let value = object.get(property);
|
let value = object.get(property);
|
||||||
|
|
||||||
if (required[property] && !value) {
|
result = this.validateValue(property, value, type, result);
|
||||||
result.error = {
|
|
||||||
type: 'required',
|
|
||||||
params: { type, property }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let dependentOn = dependent[property];
|
|
||||||
if (dependentOn && value && !object[dependentOn]) {
|
|
||||||
result.error = {
|
|
||||||
type: 'dependent',
|
|
||||||
params: {
|
|
||||||
property,
|
|
||||||
dependentOn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonStrings[property]) {
|
|
||||||
try {
|
|
||||||
value = JSON.parse(value);
|
|
||||||
} catch (e) {
|
|
||||||
result.error = {
|
|
||||||
type: 'invalid',
|
|
||||||
params: { type, property }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (properties[property]) {
|
if (mapped(property, type)) {
|
||||||
result[property] = [];
|
value = this.buildMappedJson(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value !== undefined && value !== null) {
|
||||||
|
result[property] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!result.error) {
|
||||||
|
for (let arrayObjectType of Object.keys(schema[type].objectArrays)) {
|
||||||
|
let arraySchema = schema[type].objectArrays[arrayObjectType];
|
||||||
|
let objectArray = object.get(arraySchema.property);
|
||||||
|
|
||||||
for (let item of value) {
|
if (arraySchema.required && !present(objectArray)) {
|
||||||
let itemParams = this.buildJson(item, property);
|
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 (itemParams.error) {
|
if (itemProps.error) {
|
||||||
result.error = r.error;
|
result.error = itemProps.error;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
result[property].push(itemParams);
|
result[arraySchema.property].push(itemProps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
};
|
||||||
if (mapped(property, type)) {
|
}
|
||||||
value = this.buildMappedJson(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value !== undefined && value !== null) {
|
|
||||||
result[property] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
validateValue(property, value, type, result) {
|
||||||
|
if (schema[type].required.indexOf(property) > -1 && !value) {
|
||||||
|
result.error = {
|
||||||
|
type: 'required',
|
||||||
|
params: { type, property }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dependent = schema[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(inputs) {
|
buildMappedJson(inputs) {
|
||||||
if (!inputs || !inputs.length) return false;
|
if (!inputs || !inputs.length) return false;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import CustomWizard from '../models/custom-wizard';
|
import CustomWizard from '../models/custom-wizard';
|
||||||
import { ajax } from 'discourse/lib/ajax';
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
import { selectKitContent, profileFields, generateName } from '../lib/wizard';
|
import { selectKitContent, userProperties, generateName } from '../lib/wizard';
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
import { all } from "rsvp";
|
import { all } from "rsvp";
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ export default DiscourseRoute.extend({
|
||||||
id: `user_field_${f.id}`,
|
id: `user_field_${f.id}`,
|
||||||
name: f.name
|
name: f.name
|
||||||
})).concat(
|
})).concat(
|
||||||
profileFields.map((f) => ({
|
userProperties.map((f) => ({
|
||||||
id: f,
|
id: f,
|
||||||
name: generateName(f)
|
name: generateName(f)
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -151,7 +151,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{wizard-links
|
{{wizard-links
|
||||||
type="step"
|
itemType="step"
|
||||||
current=currentStep
|
current=currentStep
|
||||||
items=model.steps}}
|
items=model.steps}}
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{wizard-links
|
{{wizard-links
|
||||||
type="action"
|
itemType="action"
|
||||||
current=currentAction
|
current=currentAction
|
||||||
items=model.actions
|
items=model.actions
|
||||||
generateLabels=true}}
|
generateLabels=true}}
|
||||||
|
|
|
@ -112,6 +112,7 @@
|
||||||
inputs=action.tags
|
inputs=action.tags
|
||||||
options=(hash
|
options=(hash
|
||||||
tagSelection='output'
|
tagSelection='output'
|
||||||
|
outputDefaultSelection='tag'
|
||||||
listSelection='output'
|
listSelection='output'
|
||||||
wizardFieldSelection=true
|
wizardFieldSelection=true
|
||||||
userFieldSelection='key,value'
|
userFieldSelection='key,value'
|
||||||
|
@ -152,7 +153,6 @@
|
||||||
{{wizard-mapper
|
{{wizard-mapper
|
||||||
inputs=action.profile_updates
|
inputs=action.profile_updates
|
||||||
options=(hash
|
options=(hash
|
||||||
singular=true
|
|
||||||
inputTypes='association'
|
inputTypes='association'
|
||||||
textSelection='value'
|
textSelection='value'
|
||||||
userFieldSelection='key'
|
userFieldSelection='key'
|
||||||
|
@ -263,7 +263,6 @@
|
||||||
{{wizard-mapper
|
{{wizard-mapper
|
||||||
inputs=action.custom_fields
|
inputs=action.custom_fields
|
||||||
options=(hash
|
options=(hash
|
||||||
singular=true
|
|
||||||
inputTypes='association'
|
inputTypes='association'
|
||||||
wizardFieldSelection='value'
|
wizardFieldSelection='value'
|
||||||
userFieldSelection='value'
|
userFieldSelection='value'
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
inputs=step.required_data
|
inputs=step.required_data
|
||||||
options=(hash
|
options=(hash
|
||||||
inputTypes='validation'
|
inputTypes='validation'
|
||||||
|
inputConnector='and'
|
||||||
wizardFieldSelection='value'
|
wizardFieldSelection='value'
|
||||||
userFieldSelection='value'
|
userFieldSelection='value'
|
||||||
keyPlaceholder="admin.wizard.submission_key"
|
keyPlaceholder="admin.wizard.submission_key"
|
||||||
|
@ -98,7 +99,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{wizard-links type="field" current=currentField items=step.fields}}
|
{{wizard-links itemType="field" current=currentField items=step.fields}}
|
||||||
|
|
||||||
{{#if currentField}}
|
{{#if currentField}}
|
||||||
{{wizard-custom-field
|
{{wizard-custom-field
|
||||||
|
|
|
@ -31,20 +31,19 @@ body.admin-wizard {
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-settings,
|
.wizard-settings,
|
||||||
.wizard-custom-step {
|
.wizard-custom-step,
|
||||||
|
.wizard-custom-action {
|
||||||
@extend .wizard-settings-parent;
|
@extend .wizard-settings-parent;
|
||||||
@extend .wizard-settings-group;
|
@extend .wizard-settings-group;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-basic-details,
|
.wizard-basic-details,
|
||||||
.wizard-custom-field,
|
.wizard-custom-field,
|
||||||
.wizard-custom-action,
|
|
||||||
.advanced-settings {
|
.advanced-settings {
|
||||||
@extend .wizard-settings-group;
|
@extend .wizard-settings-group;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-custom-field,
|
.wizard-custom-field {
|
||||||
.wizard-custom-action {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
background-color: $setting-background;
|
background-color: $setting-background;
|
||||||
|
|
|
@ -97,7 +97,7 @@ en:
|
||||||
error:
|
error:
|
||||||
required: "{{type}} requires {{property}}"
|
required: "{{type}} requires {{property}}"
|
||||||
invalid: "{{property}} is invalid"
|
invalid: "{{property}} is invalid"
|
||||||
dependent: "{{property}} is dependent on {{dependentOn}}"
|
dependent: "{{property}} is dependent on {{dependent}}"
|
||||||
|
|
||||||
step:
|
step:
|
||||||
header: "Steps"
|
header: "Steps"
|
||||||
|
|
|
@ -106,18 +106,21 @@ class CustomWizard::AdminController < ::ApplicationController
|
||||||
|
|
||||||
def dependent_properties
|
def dependent_properties
|
||||||
{
|
{
|
||||||
after_time: 'after_time_scheduled'
|
wizard: {
|
||||||
|
after_time: 'after_time_scheduled'
|
||||||
|
},
|
||||||
|
step: {},
|
||||||
|
field: {},
|
||||||
|
action: {}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_required(object, type, error)
|
def check_required(object, type, error)
|
||||||
object.each do |property, value|
|
required_properties[type].each do |property|
|
||||||
required = required_properties[type].include?(property)
|
if object[property].blank?
|
||||||
|
|
||||||
if required && property.blank?
|
|
||||||
error = {
|
error = {
|
||||||
type: 'required',
|
type: 'required',
|
||||||
params: { property: property }
|
params: { type: type, property: property }
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -125,18 +128,16 @@ class CustomWizard::AdminController < ::ApplicationController
|
||||||
error
|
error
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_depdendent(object, error)
|
def check_depdendent(object, type, error)
|
||||||
object.each do |property, value|
|
dependent_properties[type].each do |property, dependent|
|
||||||
dependent = dependent_properties[property]
|
if object[property] && object[dependent].blank?
|
||||||
|
|
||||||
if dependent && object[dependent].blank?
|
|
||||||
error = {
|
error = {
|
||||||
type: 'dependent',
|
type: 'dependent',
|
||||||
params: { dependent: dependent, property: property }
|
params: { property: property, dependent: dependent }
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
error
|
error
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -144,27 +145,29 @@ class CustomWizard::AdminController < ::ApplicationController
|
||||||
error = nil
|
error = nil
|
||||||
|
|
||||||
error = check_required(wizard, :wizard, error)
|
error = check_required(wizard, :wizard, error)
|
||||||
error = check_depdendent(wizard, error)
|
error = check_depdendent(wizard, :wizard, error)
|
||||||
|
|
||||||
wizard['steps'].each do |step|
|
if !error
|
||||||
error = check_required(step, :step, error)
|
wizard['steps'].each do |step|
|
||||||
error = check_depdendent(step, error)
|
error = check_required(step, :step, error)
|
||||||
break if error.present?
|
error = check_depdendent(step, :step, error)
|
||||||
|
break if error.present?
|
||||||
if step['fields'].present?
|
|
||||||
step['fields'].each do |field|
|
if step['fields'].present?
|
||||||
error = check_required(field, :field, error)
|
step['fields'].each do |field|
|
||||||
error = check_depdendent(field, error)
|
error = check_required(field, :field, error)
|
||||||
break if error.present?
|
error = check_depdendent(field, :field, error)
|
||||||
|
break if error.present?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
if wizard['actions'].present?
|
||||||
if wizard['actions'].present?
|
wizard['actions'].each do |action|
|
||||||
wizard['actions'].each do |action|
|
error = check_required(action, :action, error)
|
||||||
error = check_required(action, :action, error)
|
error = check_depdendent(action, :action, error)
|
||||||
error = check_depdendent(action, error)
|
break if error.present?
|
||||||
break if error.present?
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -209,10 +212,10 @@ class CustomWizard::AdminController < ::ApplicationController
|
||||||
existing_wizard = PluginStore.get('custom_wizard', wizard['id']) || {}
|
existing_wizard = PluginStore.get('custom_wizard', wizard['id']) || {}
|
||||||
|
|
||||||
validation = validate_wizard(wizard)
|
validation = validate_wizard(wizard)
|
||||||
return validation[:error] if validation[:error]
|
return validation if validation[:error]
|
||||||
|
|
||||||
after_time_validation = validate_after_time(wizard, existing_wizard)
|
after_time_validation = validate_after_time(wizard, existing_wizard)
|
||||||
return after_time_validation[:error] if after_time_validation[:error]
|
return after_time_validation if after_time_validation[:error]
|
||||||
|
|
||||||
wizard['steps'].each do |step|
|
wizard['steps'].each do |step|
|
||||||
if step['raw_description']
|
if step['raw_description']
|
||||||
|
@ -220,7 +223,7 @@ class CustomWizard::AdminController < ::ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
result = {
|
{
|
||||||
wizard: wizard,
|
wizard: wizard,
|
||||||
existing_wizard: existing_wizard,
|
existing_wizard: existing_wizard,
|
||||||
new_after_time: after_time_validation[:new]
|
new_after_time: after_time_validation[:new]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class CustomWizard::Field
|
class CustomWizard::Field
|
||||||
def self.types
|
def self.types
|
||||||
@types ||= ['checkbox', 'composer', 'dropdown', 'tag', 'category', 'group', 'image', 'text', 'textarea', 'text-only', 'number', 'upload', 'user-selector', 'url']
|
@types ||= ['checkbox', 'composer', 'dropdown', 'tag', 'category', 'group', 'text', 'textarea', 'text-only', 'number', 'upload', 'user-selector', 'url']
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.require_assets
|
def self.require_assets
|
||||||
|
|
|
@ -18,6 +18,7 @@ describe CustomWizard::Builder do
|
||||||
let(:permitted_params) {[{"key":"param_key","value":"submission_param_key"}]}
|
let(:permitted_params) {[{"key":"param_key","value":"submission_param_key"}]}
|
||||||
let(:required_data) {[{"key":"nickname","connector":"equals","value":"name"}]}
|
let(:required_data) {[{"key":"nickname","connector":"equals","value":"name"}]}
|
||||||
let(:required_data_message) {"Nickname is required to match your name"}
|
let(:required_data_message) {"Nickname is required to match your name"}
|
||||||
|
|
||||||
let(:checkbox_field) {{"id":"checkbox","type":"checkbox","label":"Checkbox"}}
|
let(:checkbox_field) {{"id":"checkbox","type":"checkbox","label":"Checkbox"}}
|
||||||
let(:composer_field) {{"id": "composer","label":"Composer","type":"composer"}}
|
let(:composer_field) {{"id": "composer","label":"Composer","type":"composer"}}
|
||||||
let(:tag_field) {{"id": "tag","type": "tag","label": "Tag","limit": "2"}}
|
let(:tag_field) {{"id": "tag","type": "tag","label": "Tag","limit": "2"}}
|
||||||
|
@ -28,6 +29,7 @@ describe CustomWizard::Builder do
|
||||||
let(:text_only_field) {{"id": "text_only","type": "text-only","label": "Text only"}}
|
let(:text_only_field) {{"id": "text_only","type": "text-only","label": "Text only"}}
|
||||||
let(:upload_field) {{"id": "upload","type": "upload","file_types": ".jpg,.png,.pdf","label": "Upload"}}
|
let(:upload_field) {{"id": "upload","type": "upload","file_types": ".jpg,.png,.pdf","label": "Upload"}}
|
||||||
let(:user_selector_field) {{"id": "user_selector","type": "user-selector","label": "User selector"}}
|
let(:user_selector_field) {{"id": "user_selector","type": "user-selector","label": "User selector"}}
|
||||||
|
|
||||||
let(:create_topic_action) {{"id":"create_topic","type":"create_topic","title":"text","post":"textarea"}}
|
let(:create_topic_action) {{"id":"create_topic","type":"create_topic","title":"text","post":"textarea"}}
|
||||||
let(:send_message_action) {{"id":"send_message","type":"send_message","title":"text","post":"textarea","username":"angus"}}
|
let(:send_message_action) {{"id":"send_message","type":"send_message","title":"text","post":"textarea","username":"angus"}}
|
||||||
let(:route_to_action) {{"id":"route_to","type":"route_to","url":"https://google.com"}}
|
let(:route_to_action) {{"id":"route_to","type":"route_to","url":"https://google.com"}}
|
||||||
|
|
Laden …
In neuem Issue referenzieren