0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-09-19 23:31:11 +02:00
Dieser Commit ist enthalten in:
Angus McLeod 2020-04-08 17:59:54 +10:00
Ursprung 98f9215d65
Commit 024ab63006
13 geänderte Dateien mit 281 neuen und 132 gelöschten Zeilen

Datei anzeigen

@ -1,4 +1,4 @@
import { default as discourseComputed, observes } 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 { actionTypes, generateName, selectKitContent } from '../lib/wizard';
import Component from "@ember/component";
@ -21,22 +21,20 @@ export default Component.extend({
publicTopicFields: or('createTopic', 'openComposer'),
showSkipRedirect: or('createTopic', 'sendMessage'),
@observes('action.type')
setupDefaults() {
if (this.action.type) {
this.set('action.label', generateName(this.action.type));
};
},
@discourseComputed('wizard.steps')
runAfterContent(steps) {
let content = steps.map(s => ({ id: s.id, name: s.label }));
let content = steps.map(function(step) {
return {
id: step.id,
name: step.title || step.id
};
});
content.unshift({
id: 'wizard_completion',
name: I18n.t('admin.wizard.action.run_after.wizard_completion')
});
return content;
},

Datei anzeigen

@ -1,4 +1,5 @@
import { default as discourseComputed, on, observes } from 'discourse-common/utils/decorators';
import { generateName, defaultProperties } from '../lib/wizard';
import { notEmpty } from "@ember/object/computed";
import { scheduleOnce, bind } from "@ember/runloop";
import EmberObject from "@ember/object";
@ -35,23 +36,29 @@ export default Component.extend({
@discourseComputed('type')
header: (type) => `admin.wizard.${type}.header`,
@discourseComputed('current', 'items.@each.id', 'items.@each.label')
@discourseComputed('current', 'items.@each.id', 'items.@each.type')
links(current, items) {
if (!items) return;
return items.map((item) => {
if (item) {
const id = item.id;
const type = this.type;
const label = item.label || item.title || id;
let link = { id, label };
let link = {
id: item.id
}
let label = item.label || item.title || item.id;
if (this.generateLabels && item.type) {
label = generateName(item.type);
}
link.label = label;
let classes = 'btn';
if (current && item.id === current.id) {
classes += ' btn-primary';
};
link['classes'] = classes;
link.classes = classes;
return link;
}
@ -63,15 +70,25 @@ export default Component.extend({
const items = this.items;
const type = this.type;
const newId = `${type}_${items.length + 1}`;
let params = { id: newId, isNew: true };
if (type === 'step') {
params['fields'] = A();
params['actions'] = A();
let params = {
id: newId,
isNew: true
};
if (type === 'step') {
params.fields = A();
};
if (defaultProperties[type]) {
Object.keys(defaultProperties[type]).forEach(key => {
params[key] = defaultProperties[type][key];
});
}
const newItem = EmberObject.create(params);
items.pushObject(newItem);
this.set('current', newItem);
},

Datei anzeigen

@ -11,19 +11,14 @@ import Controller from "@ember/controller";
export default Controller.extend({
hasName: notEmpty('model.name'),
userFields: alias('model.userFields'),
@observes('currentStep')
resetCurrentObjects() {
const currentStep = this.currentStep;
if (currentStep) {
const fields = currentStep.fields;
const actions = currentStep.actions;
this.setProperties({
currentField: fields.length ? fields[0] : null,
currentAction: actions.length ? actions[0] : null
});
this.set('currentField', fields && fields.length ? fields[0] : null)
}
scheduleOnce('afterRender', () => ($("body").addClass('admin-wizard')));
@ -98,6 +93,7 @@ export default Controller.extend({
this.send("refreshWizard");
}
}).catch((result) => {
console.log('catch result: ', result)
this.set('saving', false);
this.set('error', I18n.t(`admin.wizard.error.${result.error}`, result.errorParams || {}));
later(() => this.set('error', null), 10000);

Datei anzeigen

@ -85,7 +85,7 @@ function wizardHasAdvanced(property, value) {
}
function stepHasAdvanced(property, value) {
return advancedProperties.step[property] && present(value);
return advancedProperties.steps[property] && present(value);
}
function objectHasAdvanced(params, type) {
@ -96,31 +96,53 @@ function objectHasAdvanced(params, type) {
});
}
/// to be removed
function actionPatch(json) {
let actions = json.actions || [];
json.steps.forEach(step => {
if (step.actions && step.actions.length) {
step.actions.forEach(action => {
action.run_after = 'wizard_completion';
actions.push(action);
});
}
});
json.actions = actions;
return json;
}
///
function buildProperties(json) {
let props = {
steps: A();
action: A();
steps: A(),
actions: A()
};
if (present(json)) {
props.id = json.id;
props.existingId = true;
properties.wizard.forEach((p) => {
props[p] = buildProperty(json, p, 'wizard');
if (wizardHasAdvanced(p, json[p])) {
props.showAdvanced = true;
}
});
// 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)) {
json.steps.forEach((stepJson) => {
let stepParams = {
isNew: false
};
properties.step.forEach((p) => {
properties.steps.forEach((p) => {
stepParams[p] = buildProperty(stepJson, p, 'wizard');
if (stepHasAdvanced(p, stepJson[p])) {
@ -132,27 +154,31 @@ function buildProperties(json) {
if (present(stepJson.fields)) {
stepJson.fields.forEach((f) => {
let params = buildObject(f, 'field');
let params = buildObject(f, 'fields');
if (objectHasAdvanced(params, 'field')) {
if (objectHasAdvanced(params, 'fields')) {
params.showAdvanced = true;
}
stepParams.fields.pushObject(params);
});
}
steps.pushObject(
props.steps.pushObject(
EmberObject.create(stepParams)
);
});
};
// to be removed
json = actionPatch(json);
// to be removed
if (present(json.actions)) {
json.actions.forEach((a) => {
let params = buildObject(a, 'action');
let params = buildObject(a, 'actions');
if (objectHasAdvanced(params, 'action')) {
if (objectHasAdvanced(params, 'actions')) {
params.showAdvanced = true;
}
@ -172,12 +198,12 @@ function buildProperties(json) {
props.restart_on_revisit = false;
props.permitted = null;
}
return props;
}
export {
buildStepJson,
buildJson,
buildProperties
buildProperties,
present,
mapped
}

Datei anzeigen

@ -116,30 +116,93 @@ const actionProperties = [
const properties = {
wizard: wizardProperties,
step: stepProperties,
field: fieldProperties,
action: actionProperties
steps: stepProperties,
fields: fieldProperties,
actions: actionProperties
}
const objectArrays = [
'steps',
'fields',
'actions'
];
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'
],
step: [
steps: [
'required_data',
'permitted_params'
],
field: [
fields: [
'prefill',
'content'
],
action: [
actions: [
'title',
'category',
'tags',
@ -151,6 +214,12 @@ const mappedProperties = {
]
}
const defaultProperties = {
action: {
run_after: 'wizard_completion'
}
}
const advancedFieldTypes = [
'category',
'tag',
@ -176,11 +245,11 @@ const actionTypes = [
});
const advancedProperties = {
step: [
steps: [
'required_data',
'permitted_params'
],
field: advancedFieldTypes.reduce(
fields: advancedFieldTypes.reduce(
function(map, type) {
map[type] = advancedFieldProperties;
if (type === 'category') {
@ -189,7 +258,7 @@ const advancedProperties = {
return map;
}, {}
),
action: actionTypes.reduce(
actions: actionTypes.reduce(
function(map, type) {
if (type === 'route_to') {
map[type] = ['code'];
@ -212,10 +281,11 @@ export {
camelCase,
snakeCase,
properties,
objectArrays,
wizardProperties,
mappedProperties,
profileFields,
advancedProperties,
actionTypes
actionTypes,
actionTypeProperties,
defaultProperties
};

Datei anzeigen

@ -1,7 +1,7 @@
import { ajax } from 'discourse/lib/ajax';
import EmberObject from "@ember/object";
import { buildJson, buildProperties, present } from '../lib/wizard-json';
import { properties, arrays, camelCase, snakeCase } from '../lib/wizard';
import { buildProperties, present, mapped } from '../lib/wizard-json';
import { properties, actionTypeProperties, camelCase, snakeCase } from '../lib/wizard';
import { Promise } from "rsvp";
const jsonStrings = ['api_body'];
@ -10,17 +10,17 @@ const dependent = { after_time: 'after_time_scheduled' }
const CustomWizard = EmberObject.extend({
save() {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
let json = this.buildJson(this, 'wizard');
if (json.error) {
reject({ eror: json.error });
reject({ error: json.error });
}
ajax("/admin/wizards/custom/save", {
type: 'PUT',
data: {
wizard: JSON.stringify(wizardJson)
wizard: JSON.stringify(json)
}
}).then((result) => {
if (result.error) {
@ -32,35 +32,44 @@ const CustomWizard = EmberObject.extend({
});
},
buildJson(object, type, result = {}) {
for (let property of properties[type]) {
buildJson(object, type, result = {}) {
let allowedProperties;
if (type === 'actions') {
if (!object.type) {
result.error = {
type: 'required',
params: {
type,
property: 'type'
}
}
return result;
}
allowedProperties = actionTypeProperties[object.type];
} else {
allowedProperties = properties[type];
}
for (let property of allowedProperties) {
let value = object.get(property);
if (objectArrays[type]) {
result[property] = [];
for (let obj of value) {
let obj = this.buildJson(value, property, result);
if (obj.error) {
result.error = r.error;
break;
} else {
result[property].push(obj);
}
if (required[property] && !value) {
result.error = {
type: 'required',
params: { type, property }
}
}
if (required[property] && !value) {
result.error = 'required'
result.errorParams = { type, property };
}
if (dependent[property] && !properties[type][dependent[property]]) {
result.error = 'dependent';
result.errorParams = {
dependentProperty: properties[type][dependent[property]],
property
let dependentOn = dependent[property];
if (dependentOn && value && !object[dependentOn]) {
result.error = {
type: 'dependent',
params: {
property,
dependentOn
}
}
}
@ -68,24 +77,43 @@ const CustomWizard = EmberObject.extend({
try {
value = JSON.parse(value);
} catch (e) {
result.error = 'invalid';
result.errorParams = { property };
result.error = {
type: 'invalid',
params: { type, property }
}
}
}
if (mapped(property, type)) {
value = this.buildMappedJson(value);
}
if (result.error) {
break;
} else if (value) {
result[property] = value;
}
});
if (properties[property]) {
result[property] = [];
for (let item of value) {
let itemParams = this.buildJson(item, property);
if (itemParams.error) {
result.error = r.error;
break;
} else {
result[property].push(itemParams);
}
}
} else {
if (mapped(property, type)) {
value = this.buildMappedJson(value);
}
if (value !== undefined && value !== null) {
result[property] = value;
}
}
};
return result;
}
},
buildMappedJson(inputs) {
if (!inputs || !inputs.length) return false;

Datei anzeigen

@ -91,12 +91,12 @@ export default DiscourseRoute.extend({
setupController(controller, model) {
const newWizard = this.get('newWizard');
const steps = model.get('steps') || [];
controller.setProperties({
newWizard,
model,
currentStep: steps[0]
currentStep: model.steps[0],
currentAction: model.actions[0]
});
},

Datei anzeigen

@ -150,7 +150,10 @@
{{/if}}
</div>
{{wizard-links type="step" current=currentStep items=model.steps}}
{{wizard-links
type="step"
current=currentStep
items=model.steps}}
{{#if currentStep}}
{{wizard-custom-step
@ -160,7 +163,11 @@
wizardFields=wizardFields}}
{{/if}}
{{wizard-links type="action" current=currentAction items=model.actions}}
{{wizard-links
type="action"
current=currentAction
items=model.actions
generateLabels=true}}
{{#if currentAction}}
{{wizard-custom-action

Datei anzeigen

@ -16,7 +16,7 @@
<div class="setting">
<div class="setting-label">
<label>{{i18n "admin.wizard.run_after"}}</label>
<label>{{i18n "admin.wizard.action.run_after.label"}}</label>
</div>
<div class="setting-value">

Datei anzeigen

@ -97,7 +97,7 @@ en:
error:
required: "{{type}} requires {{property}}"
invalid: "{{property}} is invalid"
dependent: "{{dependentProperty}} is dependent on {{property}}"
dependent: "{{property}} is dependent on {{dependentOn}}"
step:
header: "Steps"
@ -152,7 +152,7 @@ en:
run_after:
label: "Run After"
wizard_completion: "Wizard completes"
wizard_completion: "Wizard Completion"
custom_fields:
label: "Custom"

Datei anzeigen

@ -151,17 +151,21 @@ class CustomWizard::AdminController < ::ApplicationController
error = check_depdendent(step, error)
break if error.present?
step['fields'].each do |field|
error = check_required(field, :field, error)
error = check_depdendent(field, error)
break if error.present?
if step['fields'].present?
step['fields'].each do |field|
error = check_required(field, :field, error)
error = check_depdendent(field, error)
break if error.present?
end
end
end
wizard['actions'].each do |action|
error = check_required(action, :action, error)
error = check_depdendent(action, error)
break if error.present?
if wizard['actions'].present?
wizard['actions'].each do |action|
error = check_required(action, :action, error)
error = check_depdendent(action, error)
break if error.present?
end
end
if error
@ -211,8 +215,8 @@ class CustomWizard::AdminController < ::ApplicationController
return after_time_validation[:error] if after_time_validation[:error]
wizard['steps'].each do |step|
if s['raw_description']
step['description'] = PrettyText.cook(s['raw_description'])
if step['raw_description']
step['description'] = PrettyText.cook(step['raw_description'])
end
end

Datei anzeigen

@ -151,8 +151,8 @@ class CustomWizard::Builder
if @actions.present?
@actions.each do |action|
if (action.run_after === updater.step.id) ||
(final_step && (!action.run_after || (action.run_after === 'wizard_completion')))
if (action['run_after'] === updater.step.id) ||
(final_step && (!action['run_after'] || (action['run_after'] === 'wizard_completion')))
CustomWizard::Action.new(
action: action,

Datei anzeigen

@ -2,7 +2,6 @@ class CustomWizard::Template
attr_reader :id,
:name,
:steps,
:background,
:save_submissions,
:multiple_submissions,
@ -13,7 +12,9 @@ class CustomWizard::Template
:after_time_scheduled,
:required,
:theme_id,
:permitted
:permitted,
:steps,
:actions
def initialize(data)
data = data.is_a?(String) ? ::JSON.parse(data) : data
@ -22,7 +23,6 @@ class CustomWizard::Template
@id = data['id']
@name = data['name']
@steps = data['steps']
@background = data['background']
@save_submissions = data['save_submissions'] || false
@multiple_submissions = data['multiple_submissions'] || false
@ -39,5 +39,8 @@ class CustomWizard::Template
theme = Theme.find_by(name: data['theme'])
@theme_id = theme.id if theme
end
@steps = data['steps']
@actions = data['actions']
end
end