diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 index 181c37ca..63d5d902 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -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; }, diff --git a/assets/javascripts/discourse/components/wizard-links.js.es6 b/assets/javascripts/discourse/components/wizard-links.js.es6 index c10b9d57..e973e648 100644 --- a/assets/javascripts/discourse/components/wizard-links.js.es6 +++ b/assets/javascripts/discourse/components/wizard-links.js.es6 @@ -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); }, diff --git a/assets/javascripts/discourse/controllers/admin-wizard.js.es6 b/assets/javascripts/discourse/controllers/admin-wizard.js.es6 index 2fde2bf8..d4b21192 100644 --- a/assets/javascripts/discourse/controllers/admin-wizard.js.es6 +++ b/assets/javascripts/discourse/controllers/admin-wizard.js.es6 @@ -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); diff --git a/assets/javascripts/discourse/lib/wizard-json.js.es6 b/assets/javascripts/discourse/lib/wizard-json.js.es6 index 1b9c2f80..3dccdd85 100644 --- a/assets/javascripts/discourse/lib/wizard-json.js.es6 +++ b/assets/javascripts/discourse/lib/wizard-json.js.es6 @@ -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 } \ No newline at end of file diff --git a/assets/javascripts/discourse/lib/wizard.js.es6 b/assets/javascripts/discourse/lib/wizard.js.es6 index 2b8a1ee8..5a33235c 100644 --- a/assets/javascripts/discourse/lib/wizard.js.es6 +++ b/assets/javascripts/discourse/lib/wizard.js.es6 @@ -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 }; \ No newline at end of file diff --git a/assets/javascripts/discourse/models/custom-wizard.js.es6 b/assets/javascripts/discourse/models/custom-wizard.js.es6 index 58a89e76..b76682b2 100644 --- a/assets/javascripts/discourse/models/custom-wizard.js.es6 +++ b/assets/javascripts/discourse/models/custom-wizard.js.es6 @@ -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; diff --git a/assets/javascripts/discourse/routes/admin-wizard.js.es6 b/assets/javascripts/discourse/routes/admin-wizard.js.es6 index 3ce498ec..607efaa6 100644 --- a/assets/javascripts/discourse/routes/admin-wizard.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizard.js.es6 @@ -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] }); }, diff --git a/assets/javascripts/discourse/templates/admin-wizard.hbs b/assets/javascripts/discourse/templates/admin-wizard.hbs index 6fba246e..f24f1650 100644 --- a/assets/javascripts/discourse/templates/admin-wizard.hbs +++ b/assets/javascripts/discourse/templates/admin-wizard.hbs @@ -150,7 +150,10 @@ {{/if}} - {{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 diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs index f05c75ff..c53d2614 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -16,7 +16,7 @@