diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 index 6f04993b..7794b61c 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -19,8 +19,10 @@ export default Component.extend({ @on('didInsertElement') @observes('action.type') - updateId() { - if (this.action.type) this.set('action.id', generateName(this.action.type)); + setLabel() { + if (this.action.type) { + this.set('action.label', generateName(this.action.type)); + }; }, @discourseComputed('action.type') diff --git a/assets/javascripts/discourse/components/wizard-custom-field.js.es6 b/assets/javascripts/discourse/components/wizard-custom-field.js.es6 index 609908ec..7cd2908a 100644 --- a/assets/javascripts/discourse/components/wizard-custom-field.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-field.js.es6 @@ -34,14 +34,18 @@ export default Component.extend({ let options = { wizardFieldSelection: true, textSelection: 'key,value', - userFieldSelection: 'key,value' + userFieldSelection: 'key,value', + context: 'field' } if (this.isDropdown) { + options.wizardFieldSelection = 'key,value'; + options.listSelection = 'assignment'; options.inputTypes = 'pair,assignment'; - options.pairConnector = 'equal'; + options.pairConnector = 'association'; options.keyPlaceholder = 'admin.wizard.key'; options.valuePlaceholder = 'admin.wizard.value'; + options.outputDefaultSelection = 'list'; } return options; @@ -52,23 +56,29 @@ export default Component.extend({ let options = { wizardFieldSelection: true, textSelection: 'key,value', - userFieldSelection: 'key,value' + userFieldSelection: 'key,value', + context: 'field' } - if (!this.isDropdown) { - let selectionType = { - category: 'category', - tag: 'tag', - group: 'group', - dropdown: 'text' - }[fieldType]; - options[`${selectionType}Selection`] = 'output'; - options.outputDefaultSelection = selectionType; - } + let outputSelectionType = { + category: 'category', + tag: 'tag', + group: 'group', + dropdown: 'text' + }[fieldType]; + + options[`${outputSelectionType}Selection`] = 'output'; + options.outputDefaultSelection = outputSelectionType; return options; }, + @observes('field.type') + clearInputs() { + this.set('field.content', null); + this.set('field.prefill', null); + }, + actions: { imageUploadDone(upload) { this.set("field.image", upload.url); diff --git a/assets/javascripts/discourse/components/wizard-custom-step.js.es6 b/assets/javascripts/discourse/components/wizard-custom-step.js.es6 index 1ddd3fca..6b4dc4a9 100644 --- a/assets/javascripts/discourse/components/wizard-custom-step.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-step.js.es6 @@ -5,21 +5,7 @@ import Component from "@ember/component"; export default Component.extend({ classNames: 'wizard-custom-step', - currentField: null, - currentAction: null, disableId: not('step.isNew'), - - @on('didInsertElement') - @observes('step') - resetCurrentObjects() { - const fields = this.step.fields; - const actions = this.step.actions; - - this.setProperties({ - currentField: fields.length ? fields[0] : null, - currentAction: actions.length ? actions[0] : null - }); - }, @discourseComputed('wizardFields', 'wizard.steps') requiredContent(wizardFields, steps) { diff --git a/assets/javascripts/discourse/components/wizard-links.js.es6 b/assets/javascripts/discourse/components/wizard-links.js.es6 index 761d0521..c10b9d57 100644 --- a/assets/javascripts/discourse/components/wizard-links.js.es6 +++ b/assets/javascripts/discourse/components/wizard-links.js.es6 @@ -35,15 +35,15 @@ export default Component.extend({ @discourseComputed('type') header: (type) => `admin.wizard.${type}.header`, - @discourseComputed('items.@each.id', 'current') - links(items, current) { + @discourseComputed('current', 'items.@each.id', 'items.@each.label') + links(current, items) { if (!items) return; return items.map((item) => { if (item) { const id = item.id; const type = this.type; - const label = type === 'action' ? id : (item.label || item.title || id); + const label = item.label || item.title || id; let link = { id, label }; let classes = 'btn'; diff --git a/assets/javascripts/discourse/components/wizard-mapper-input.js.es6 b/assets/javascripts/discourse/components/wizard-mapper-input.js.es6 index ce175398..efeee646 100644 --- a/assets/javascripts/discourse/components/wizard-mapper-input.js.es6 +++ b/assets/javascripts/discourse/components/wizard-mapper-input.js.es6 @@ -2,6 +2,7 @@ import { computed, set } from "@ember/object"; import { alias, equal, or } from "@ember/object/computed"; import { newPair, connectorContent, inputTypesContent } from '../lib/wizard-mapper'; import Component from "@ember/component"; +import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ classNameBindings: [':mapper-input', 'type'], diff --git a/assets/javascripts/discourse/components/wizard-mapper-selector-type.js.es6 b/assets/javascripts/discourse/components/wizard-mapper-selector-type.js.es6 index d5041871..53baccef 100644 --- a/assets/javascripts/discourse/components/wizard-mapper-selector-type.js.es6 +++ b/assets/javascripts/discourse/components/wizard-mapper-selector-type.js.es6 @@ -1,19 +1,14 @@ import discourseComputed from 'discourse-common/utils/decorators'; -import { snakeCase } from '../lib/wizard'; -import { selectionTypes } from '../lib/wizard-mapper'; import Component from "@ember/component"; export default Component.extend({ tagName: 'a', - classNameBindings: ['type', 'active'], + classNameBindings: ['active'], - @discourseComputed('type', 'activeType') + @discourseComputed('item.type', 'activeType') active(type, activeType) { return type === activeType }, - @discourseComputed('type') - label(type) { return I18n.t(`admin.wizard.selector.label.${snakeCase(type)}`) }, - click() { - this.toggle(this.type) + this.toggle(this.item.type) } }) \ No newline at end of file diff --git a/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 b/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 index 38ed763a..fd165cff 100644 --- a/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 +++ b/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 @@ -1,10 +1,11 @@ -import { alias, or } from "@ember/object/computed"; +import { alias, or, gt } from "@ember/object/computed"; import { computed } from "@ember/object"; import { default as discourseComputed, observes } from "discourse-common/utils/decorators"; import { getOwner } from 'discourse-common/lib/get-owner'; import { defaultSelectionType, selectionTypes } from '../lib/wizard-mapper'; import { snakeCase, selectKitContent } from '../lib/wizard'; import Component from "@ember/component"; +import { bind } from "@ember/runloop"; export default Component.extend({ classNames: 'mapper-selector', @@ -28,25 +29,50 @@ export default Component.extend({ groupEnabled: computed('options.groupSelection', 'inputType', function() { return this.optionEnabled('groupSelection') }), userEnabled: computed('options.userSelection', 'inputType', function() { return this.optionEnabled('userSelection') }), listEnabled: computed('options.listSelection', 'inputType', function() { return this.optionEnabled('listSelection') }), + hasTypes: gt('selectorTypes.length', 1), + showTypes: false, + + didInsertElement() { + $(document).on("click", bind(this, this.documentClick)); + }, + + willDestroyElement() { + $(document).off("click", bind(this, this.documentClick)); + }, + + documentClick(e) { + let $element = $(this.element); + let $target = $(e.target); + + if (!$target.hasClass('type-selector-icon') && + $target.closest($element).length < 1 && + this._state !== "destroying") { + + this.set("showTypes", false); + } + }, + + @discourseComputed + selectorTypes() { + return selectionTypes.filter(type => (this[`${type}Enabled`])) + .map(type => ({ type, label: this.typeLabel(type) })); + }, @discourseComputed('activeType') - selectorTypes(activeType) { - return selectionTypes.filter(type => (this[`${type}Enabled`])); + activeTypeLabel(activeType) { + return this.typeLabel(activeType); }, - @discourseComputed - userFields() { - const controller = getOwner(this).lookup('controller:admin-wizard'); - return controller.model.userFields; + typeLabel(type) { + return I18n.t(`admin.wizard.selector.label.${snakeCase(type)}`) }, - @discourseComputed - wizardFields() { - const controller = getOwner(this).lookup('controller:admin-wizard'); - return controller.wizardFields; + @discourseComputed('showTypes') + typeSelectorIcon(showTypes) { + return showTypes ? 'chevron-down' : 'chevron-right'; }, - @observes('options.@each') + @observes('options.@each', 'inputType') resetActiveType() { this.set('activeType', defaultSelectionType(this.selectorType, this.options)); }, @@ -58,7 +84,15 @@ export default Component.extend({ @discourseComputed('activeType') comboBoxContent(activeType) { - return this[`${activeType}Fields`]; + const controller = getOwner(this).lookup('controller:admin-wizard'); + let content = controller[`${activeType}s`]; + + if (activeType === 'wizardField' && this.options.context === 'field') { + const currentField = controller.currentField; + content = content.filter(field => field.id !== currentField.id); + } + + return content; }, @discourseComputed('activeType') @@ -70,18 +104,19 @@ export default Component.extend({ }[activeType]; }, - @discourseComputed('activeType') - placeholder(activeType) { + @discourseComputed('activeType', 'inputType') + placeholderKey(activeType, inputType) { if (activeType === 'text' && this.options[`${this.selectorType}Placeholder`]) { return this.options[`${this.selectorType}Placeholder`]; - } - return `admin.wizard.selector.placeholder.${snakeCase(activeType)}`; + } else { + return `admin.wizard.selector.placeholder.${snakeCase(activeType)}`; + } }, @discourseComputed('activeType') multiSelectOptions(activeType) { let result = { - none: this.placeholder + none: this.placeholderKey }; if (activeType === 'list') { @@ -111,6 +146,11 @@ export default Component.extend({ actions: { toggleType(type) { this.set('activeType', type); + this.set('showTypes', false); + }, + + toggleTypes() { + this.toggleProperty('showTypes') } } }) \ No newline at end of file diff --git a/assets/javascripts/discourse/components/wizard-mapper.js.es6 b/assets/javascripts/discourse/components/wizard-mapper.js.es6 index 27363917..5db00dbe 100644 --- a/assets/javascripts/discourse/components/wizard-mapper.js.es6 +++ b/assets/javascripts/discourse/components/wizard-mapper.js.es6 @@ -18,11 +18,13 @@ export default Component.extend({ let result = { inputTypes: options.inputTypes || 'conditional,assignment', pairConnector: options.pairConnector || null, - outputConnector: options.outputConnector || null + outputConnector: options.outputConnector || null, + context: options.context || null } let inputTypes = ['key', 'value', 'output']; inputTypes.forEach(type => { + result[`${type}Placeholder`] = options[`${type}Placeholder`] || null; result[`${type}DefaultSelection`] = options[`${type}DefaultSelection`] || null; }); @@ -33,18 +35,16 @@ export default Component.extend({ result[`${type}Selection`] = type === 'text' ? true : false; } }); - + return result; }, - - @observes('options.inputTypes') - clearInputs() { - this.get('inputs').clear(); - }, actions: { add() { - if (!this.get('inputs')) this.set('inputs', A()); + if (!this.get('inputs')) { + this.set('inputs', A()); + } + this.get('inputs').pushObject(newInput(this.inputOptions)); }, diff --git a/assets/javascripts/discourse/controllers/admin-wizard.js.es6 b/assets/javascripts/discourse/controllers/admin-wizard.js.es6 index b99ba6d8..ae9c832b 100644 --- a/assets/javascripts/discourse/controllers/admin-wizard.js.es6 +++ b/assets/javascripts/discourse/controllers/admin-wizard.js.es6 @@ -1,5 +1,5 @@ -import { default as discourseComputed, observes } from 'discourse-common/utils/decorators'; -import { notEmpty } from "@ember/object/computed"; +import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators'; +import { notEmpty, alias } from "@ember/object/computed"; import showModal from 'discourse/lib/show-modal'; import { generateId } from '../lib/wizard'; import { buildProperties } from '../lib/wizard-json'; @@ -10,15 +10,27 @@ import Controller from "@ember/controller"; export default Controller.extend({ hasName: notEmpty('model.name'), - - init() { - this._super(); + userFields: alias('model.userFields'), + + @observes('currentStep') + resetCurrentObjects() { + const currentStep = this.currentStep; + const fields = currentStep.fields; + const actions = currentStep.actions; + + this.setProperties({ + currentField: fields.length ? fields[0] : null, + currentAction: actions.length ? actions[0] : null + }); + scheduleOnce('afterRender', () => ($("body").addClass('admin-wizard'))); }, @observes('model.name') setId() { - if (!this.model.existingId) this.set('model.id', generateId(this.model.name)); + if (!this.model.existingId) { + this.set('model.id', generateId(this.model.name)); + } }, @discourseComputed('model.id') diff --git a/assets/javascripts/discourse/controllers/next-session-scheduled.js.es6 b/assets/javascripts/discourse/controllers/next-session-scheduled.js.es6 index 00c0add2..cb7650e7 100644 --- a/assets/javascripts/discourse/controllers/next-session-scheduled.js.es6 +++ b/assets/javascripts/discourse/controllers/next-session-scheduled.js.es6 @@ -1,4 +1,4 @@ -import { default as computed } from 'discourse-common/utils/decorators'; +import { default as discourseComputed } from 'discourse-common/utils/decorators'; import { scheduleOnce } from "@ember/runloop"; import Controller from "@ember/controller"; @@ -24,12 +24,12 @@ export default Controller.extend({ }); }, - @computed('date', 'time') + @discourseComputed('date', 'time') dateTime: function(date, time) { return moment(date + 'T' + time).format(); }, - @computed('dateTime') + @discourseComputed('dateTime') submitDisabled(dateTime) { return moment().isAfter(dateTime); }, diff --git a/assets/javascripts/discourse/lib/wizard-mapper.js.es6 b/assets/javascripts/discourse/lib/wizard-mapper.js.es6 index 38f9429b..88d86dad 100644 --- a/assets/javascripts/discourse/lib/wizard-mapper.js.es6 +++ b/assets/javascripts/discourse/lib/wizard-mapper.js.es6 @@ -67,13 +67,13 @@ function connectorContent(connectorType, inputType, opts) { const selectionTypes = [ 'text', + 'list', 'wizardField', 'userField', 'group', 'category', 'tag', - 'user', - 'list' + 'user' ] function defaultSelectionType(inputType, options = {}) { @@ -116,9 +116,7 @@ function newPair(inputType, options = {}) { function newInput(options = {}) { const inputType = defaultInputType(options); - - console.log(inputType); - + let params = { type: inputType, pairs: A( @@ -134,7 +132,10 @@ function newInput(options = {}) { ) } - if (['conditional', 'assignment'].indexOf(inputType) > -1) { + if (['conditional', 'assignment'].indexOf(inputType) > -1 || + options.outputDefaultSelection || + options.outputConnector) { + params['output_type'] = defaultSelectionType('output', options); params['connector'] = defaultConnector('output', inputType, options); } diff --git a/assets/javascripts/discourse/lib/wizard.js.es6 b/assets/javascripts/discourse/lib/wizard.js.es6 index 9b085038..00bba29b 100644 --- a/assets/javascripts/discourse/lib/wizard.js.es6 +++ b/assets/javascripts/discourse/lib/wizard.js.es6 @@ -6,7 +6,7 @@ function generateName(id) { return id ? sentenceCase(id) : ''; } -function generateId(name) { +function generateId(name, opts={}) { return name ? snakeCase(name) : ''; } @@ -167,7 +167,9 @@ const actionTypes = [ 'add_to_group', 'route_to', 'open_composer' -]; +].filter(function(type) { + return Discourse.SiteSettings.wizard_api_features || type !== 'send_to_api'; +}); export { selectKitContent, diff --git a/assets/javascripts/discourse/models/custom-wizard-api.js.es6 b/assets/javascripts/discourse/models/custom-wizard-api.js.es6 index 90e74a7e..5359534e 100644 --- a/assets/javascripts/discourse/models/custom-wizard-api.js.es6 +++ b/assets/javascripts/discourse/models/custom-wizard-api.js.es6 @@ -1,10 +1,10 @@ import { ajax } from 'discourse/lib/ajax'; -import { default as computed } from 'discourse-common/utils/decorators'; +import { default as discourseComputed } from 'discourse-common/utils/decorators'; import EmberObject from "@ember/object"; import { A } from "@ember/array"; const CustomWizardApi = EmberObject.extend({ - @computed('name') + @discourseComputed('name') redirectUri(name) { let nameParam = name.toString().dasherize(); const baseUrl = location.protocol+'//'+location.hostname+(location.port ? ':'+location.port: ''); diff --git a/assets/javascripts/discourse/routes/admin-wizard.js.es6 b/assets/javascripts/discourse/routes/admin-wizard.js.es6 index 8f5173d3..3ce498ec 100644 --- a/assets/javascripts/discourse/routes/admin-wizard.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizard.js.es6 @@ -92,7 +92,7 @@ export default DiscourseRoute.extend({ setupController(controller, model) { const newWizard = this.get('newWizard'); const steps = model.get('steps') || []; - + controller.setProperties({ newWizard, model, diff --git a/assets/javascripts/discourse/templates/admin-wizard.hbs b/assets/javascripts/discourse/templates/admin-wizard.hbs index ba6fac31..fa4d65ac 100644 --- a/assets/javascripts/discourse/templates/admin-wizard.hbs +++ b/assets/javascripts/discourse/templates/admin-wizard.hbs @@ -48,7 +48,6 @@