From 024ab63006b0ab16d20c1361de693f9269d3a9a6 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Wed, 8 Apr 2020 17:59:54 +1000 Subject: [PATCH] various --- .../components/wizard-custom-action.js.es6 | 18 ++- .../discourse/components/wizard-links.js.es6 | 39 +++++-- .../discourse/controllers/admin-wizard.js.es6 | 10 +- .../discourse/lib/wizard-json.js.es6 | 76 ++++++++---- .../javascripts/discourse/lib/wizard.js.es6 | 102 ++++++++++++++--- .../discourse/models/custom-wizard.js.es6 | 108 +++++++++++------- .../discourse/routes/admin-wizard.js.es6 | 6 +- .../discourse/templates/admin-wizard.hbs | 11 +- .../components/wizard-custom-action.hbs | 2 +- config/locales/client.en.yml | 4 +- controllers/custom_wizard/admin.rb | 24 ++-- lib/custom_wizard/builder.rb | 4 +- lib/custom_wizard/template.rb | 9 +- 13 files changed, 281 insertions(+), 132 deletions(-) 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 @@
- +
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index a32d0272..415f3979 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -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" diff --git a/controllers/custom_wizard/admin.rb b/controllers/custom_wizard/admin.rb index 0ea04be6..53ba8058 100644 --- a/controllers/custom_wizard/admin.rb +++ b/controllers/custom_wizard/admin.rb @@ -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 diff --git a/lib/custom_wizard/builder.rb b/lib/custom_wizard/builder.rb index c65b46ac..a70fdad6 100644 --- a/lib/custom_wizard/builder.rb +++ b/lib/custom_wizard/builder.rb @@ -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, diff --git a/lib/custom_wizard/template.rb b/lib/custom_wizard/template.rb index f236fdcf..51536dfa 100644 --- a/lib/custom_wizard/template.rb +++ b/lib/custom_wizard/template.rb @@ -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