diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 index 513202b0..af027b58 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -1,9 +1,26 @@ -import { on, observes } from 'ember-addons/ember-computed-decorators'; +import { on, observes, default as computed } from 'ember-addons/ember-computed-decorators'; + +const PROFILE_FIELDS = [ + 'name', + 'email', + 'username', + 'title', + 'date_of_birth', + 'muted_usernames', + 'theme_key', + 'locale', + 'bio_raw', + 'location', + 'website', + 'dismissed_banner_key', + 'profile_background', + 'card_background' +]; export default Ember.Component.extend({ classNames: 'wizard-custom-action', types: ['create_topic', 'update_profile', 'send_message'], - profileFields: ['name', 'username', 'email'], + profileFields: PROFILE_FIELDS, createTopic: Ember.computed.equal('action.type', 'create_topic'), updateProfile: Ember.computed.equal('action.type', 'update_profile'), sendMessage: Ember.computed.equal('action.type', 'send_message'), @@ -11,6 +28,32 @@ export default Ember.Component.extend({ @on('init') @observes('action') setup() { - this.set('existingId', this.get('action.id')); + if (!this.get('isNew')) this.set('existingId', this.get('action.id')); + }, + + @computed('steps') + wizardFields(steps) { + let fields = []; + steps.forEach((s) => { + let stepFields = s.fields.map((f) => `${f.id} (${s.id})`); + fields.push(...stepFields); + }); + return fields; + }, + + @computed('action.profile_updates.[]') + profileUpdates: fields => fields, + + actions: { + addProfileUpdate() { + if (!this.get('action.profile_updates')) { + this.set('action.profile_updates', Ember.A()); + } + this.get('action.profile_updates').pushObject(Ember.Object.create()); + }, + + removeProfileUpdate(f) { + this.get('action.profile_updates').removeObject(f); + } } }); diff --git a/assets/javascripts/discourse/components/wizard-custom-field.js.es6 b/assets/javascripts/discourse/components/wizard-custom-field.js.es6 index f0e11ca3..90995897 100644 --- a/assets/javascripts/discourse/components/wizard-custom-field.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-field.js.es6 @@ -7,7 +7,7 @@ export default Ember.Component.extend({ @on('init') @observes('field') setup() { - this.set('existingId', this.get('field.id')); + if (!this.get('isNew')) this.set('existingId', this.get('field.id')); }, @computed('field.type') diff --git a/assets/javascripts/discourse/components/wizard-custom-step.js.es6 b/assets/javascripts/discourse/components/wizard-custom-step.js.es6 index b602d20f..b48dadea 100644 --- a/assets/javascripts/discourse/components/wizard-custom-step.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-step.js.es6 @@ -1,101 +1,6 @@ -import { default as computed, on, observes } from 'ember-addons/ember-computed-decorators'; - export default Ember.Component.extend({ classNames: 'wizard-custom-step', currentField: null, currentAction: null, - - @on('init') - @observes('step') - setCurrent() { - this.set('existingId', this.get('step.id')); - const fields = this.get('step.fields') || []; - const actions = this.get('step.actions') || []; - this.set('currentField', fields[0]); - this.set('currentAction', actions[0]); - }, - - @computed('step.fields.@each.id', 'currentField') - fieldLinks(fields, current) { - if (!fields) return; - - return fields.map((f) => { - if (f) { - const id = f.get('id'); - const label = f.get('label'); - - let link = { id, label: label || id || 'new' }; - - let classes = 'btn'; - if (current && f.get('id') === current.get('id')) { - classes += ' btn-primary'; - }; - - link['classes'] = classes; - - return link; - } - }); - }, - - @computed('step.actions.@each.id', 'currentAction') - actionLinks(actions, current) { - if (!actions) return; - - return actions.map((a) => { - if (a) { - const id = a.get('id'); - const label = a.get('label'); - - let link = { id, label: label || id || 'new' }; - - let classes = 'btn'; - if (current && a.get('id') === current.get('id')) { - classes += ' btn-primary'; - }; - - link['classes'] = classes; - - return link; - } - }); - }, - - actions: { - addField() { - const fields = this.get('step.fields'); - const field = Ember.Object.create(); - fields.pushObject(field); - this.set('currentField', field); - }, - - addAction() { - const actions = this.get('step.actions'); - const action = Ember.Object.create(); - actions.pushObject(action); - this.set('currentAction', action); - }, - - removeField(fieldId) { - const fields = this.get('step.fields'); - fields.removeObject(fields.findBy('id', fieldId)); - this.set('currentField', fields[fields.length - 1]); - }, - - removeAction(actionId) { - const actions = this.get('step.actions'); - actions.removeObject(actions.findBy('id', actionId)); - this.set('currentAction', actions[actions.length - 1]); - }, - - changeField(fieldId) { - const fields = this.get('step.fields'); - this.set('currentField', fields.findBy('id', fieldId)); - }, - - changeAction(actionId) { - const actions = this.get('step.actions'); - this.set('currentAction', actions.findBy('id', actionId)); - } - } + disableId: Ember.computed.not('step.isNew') }); diff --git a/assets/javascripts/discourse/components/wizard-links.js.es6 b/assets/javascripts/discourse/components/wizard-links.js.es6 new file mode 100644 index 00000000..ce8dd946 --- /dev/null +++ b/assets/javascripts/discourse/components/wizard-links.js.es6 @@ -0,0 +1,80 @@ +import { default as computed } from 'ember-addons/ember-computed-decorators'; + +export default Ember.Component.extend({ + classNames: 'wizard-links', + items: Ember.A(), + + didInsertElement() { + this.applySortable(); + }, + + applySortable() { + this.$("ul").sortable({tolerance: 'pointer'}).on('sortupdate', (e, ui) => { + const itemId = ui.item.data('id'); + const index = ui.item.index(); + Ember.run.bind(this, this.updateItemOrder(itemId, index)); + }); + }, + + updateItemOrder(itemId, newIndex) { + const items = this.get('items'); + const item = items.findBy('id', itemId); + items.removeObject(item); + items.insertAt(newIndex, item); + Ember.run.scheduleOnce('afterRender', this, () => this.applySortable()); + }, + + @computed('type') + header: (type) => `admin.wizard.${type}.header`, + + @computed('items.@each.id', 'current') + links(items, current) { + if (!items) return; + + return items.map((item) => { + if (item) { + const id = item.get('id'); + const label = item.get('label') || item.get('title'); + let link = { id, label: label || id }; + + let classes = 'btn'; + if (current && item.get('id') === current.get('id')) { + classes += ' btn-primary'; + }; + + link['classes'] = classes; + + return link; + } + }); + }, + + actions: { + add() { + const items = this.get('items'); + const newId = `step_${items.length + 1}`; + const type = this.get('type'); + let params = { id: newId, isNew: true }; + + if (type === 'step') { + params['fields'] = Ember.A(); + params['actions'] = Ember.A(); + }; + + const newItem = Ember.Object.create(params); + items.pushObject(newItem); + this.set('current', newItem); + }, + + change(itemId) { + const items = this.get('items'); + this.set('current', items.findBy('id', itemId)); + }, + + remove(itemId) { + const items = this.get('items'); + items.removeObject(items.findBy('id', itemId)); + this.set('current', items[items.length - 1]); + } + } +}); diff --git a/assets/javascripts/discourse/controllers/admin-wizard.js.es6 b/assets/javascripts/discourse/controllers/admin-wizard.js.es6 index ded0244f..a626f82e 100644 --- a/assets/javascripts/discourse/controllers/admin-wizard.js.es6 +++ b/assets/javascripts/discourse/controllers/admin-wizard.js.es6 @@ -1,27 +1,6 @@ import { default as computed } from 'ember-addons/ember-computed-decorators'; export default Ember.Controller.extend({ - @computed('model.steps.@each.id', 'currentStep') - stepLinks(steps, currentStep) { - return steps.map((s) => { - if (s) { - const id = s.get('id'); - const title = s.get('title'); - - let link = { id, title: title || id || 'new' }; - - let classes = 'btn'; - if (currentStep && id === currentStep.get('id')) { - classes += ' btn-primary'; - }; - - link['classes'] = classes; - - return link; - } - }); - }, - @computed('model.id', 'model.name') wizardUrl(wizardId) { return window.location.origin + '/w/' + Ember.String.dasherize(wizardId); @@ -52,27 +31,6 @@ export default Ember.Controller.extend({ this.get('model').remove().then(() => { this.send("refreshAllWizards"); }); - }, - - addStep() { - const steps = this.get('model.steps'); - const step = Ember.Object.create({ - fields: Ember.A(), - actions: Ember.A() - }); - steps.pushObject(step); - this.set('currentStep', step); - }, - - removeStep(stepId) { - const steps = this.get('model.steps'); - steps.removeObject(steps.findBy('id', stepId)); - this.set('currentStep', steps[steps.length - 1]); - }, - - changeStep(stepId) { - const steps = this.get('model.steps'); - this.set('currentStep', steps.findBy('id', stepId)); } } }); diff --git a/assets/javascripts/discourse/templates/admin-wizard.hbs b/assets/javascripts/discourse/templates/admin-wizard.hbs index 7515da7e..71ea7641 100644 --- a/assets/javascripts/discourse/templates/admin-wizard.hbs +++ b/assets/javascripts/discourse/templates/admin-wizard.hbs @@ -58,17 +58,9 @@ {{wizardUrl}} - - + {{wizard-links type="step" current=currentStep items=model.steps}} {{#if currentStep}} - {{wizard-custom-step step=currentStep fieldTypes=model.fieldTypes}} + {{wizard-custom-step step=currentStep steps=model.steps fieldTypes=model.fieldTypes}} {{/if}}
diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs index 685a25a4..8e8e699d 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -1,6 +1,6 @@
-

{{i18n "admin.wizard.action.id"}}

+

{{i18n "admin.wizard.id"}}

{{input value=action.id placeholderKey='admin.wizard.id_placeholder' disabled=existingId}} @@ -16,7 +16,6 @@
- {{#if createTopic}}
@@ -29,19 +28,28 @@
-

{{i18n "admin.wizard.action.create_topic.title"}}

+

{{i18n "admin.wizard.action.title"}}

- {{combo-box value=action.title content=stepFields nameProperty="label"}} + {{combo-box value=action.title content=wizardFields nameProperty="label" none='admin.wizard.action.none'}}
-

{{i18n "admin.wizard.action.create_topic.post"}}

+

{{i18n "admin.wizard.action.post"}}

- {{combo-box value=action.post content=stepFields nameProperty="label"}} + {{combo-box value=action.post content=wizardFields nameProperty="label" none='admin.wizard.action.none'}} +
+
+ +
+
+

{{i18n "admin.wizard.action.create_topic.featured_link"}}

+
+
+ {{combo-box value=action.featured_link content=wizardFields none='admin.wizard.action.none'}}
{{/if}} @@ -49,20 +57,22 @@ {{#if sendMessage}}
-

{{i18n "admin.wizard.action.send_message.title"}}

+

{{i18n "admin.wizard.action.title"}}

- {{combo-box value=action.title content=stepFields nameProperty="label"}} + {{combo-box value=action.title content=wizardFields none='admin.wizard.action.none'}}
+
-

{{i18n "admin.wizard.action.send_message.post"}}

+

{{i18n "admin.wizard.action.post"}}

- {{combo-box value=action.post content=stepFields nameProperty="label"}} + {{combo-box value=action.post content=wizardFields none='admin.wizard.action.none'}}
+

{{i18n "admin.wizard.action.send_message.recipient"}}

@@ -77,20 +87,14 @@ {{/if}} {{#if updateProfile}} -
-
-

{{i18n "admin.wizard.action.source"}}

-
-
- {{combo-box value=action.source content=stepFields nameProperty="label"}} -
-
-
-
-

{{i18n "admin.wizard.action.profile_field"}}

-
-
- {{combo-box value=action.profile_field content=profileFields}} -
+
+ {{#each profileUpdates as |pu|}} + + {{combo-box value=pu.wizard_field content=wizardFields none='admin.wizard.action.update_profile.wizard_field'}} + {{combo-box value=pu.profile_field content=profileFields none='admin.wizard.action.update_profile.profile_field'}} + + {{d-button action='removeProfileUpdate' actionParam=f icon='times'}} + {{/each}} +
{{d-button action='addProfileUpdate' label='admin.wizard.add' icon='plus'}}
{{/if}} diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs index 69e18738..42e1ee18 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-step.hbs @@ -3,7 +3,7 @@

{{i18n 'admin.wizard.id'}}

- {{input name="id" value=step.id placeholderKey="admin.wizard.id_placeholder" disabled=existingId}} + {{input name="id" value=step.id placeholderKey="admin.wizard.id_placeholder" disabled=disableId}}
@@ -43,28 +43,12 @@
- - +{{wizard-links type="field" current=currentField itesm=step.fields}} {{#if currentField}} {{wizard-custom-field field=currentField types=fieldTypes removeField="removeField"}} {{/if}} - - +{{wizard-links type="action" current=currentAction items=step.actions}} {{#if currentAction}} - {{wizard-custom-action action=currentAction stepFields=step.fields removeAction="removeAction"}} + {{wizard-custom-action action=currentAction steps=steps removeAction="removeAction"}} {{/if}} diff --git a/assets/javascripts/discourse/templates/components/wizard-links.hbs b/assets/javascripts/discourse/templates/components/wizard-links.hbs new file mode 100644 index 00000000..f5f373d7 --- /dev/null +++ b/assets/javascripts/discourse/templates/components/wizard-links.hbs @@ -0,0 +1,12 @@ + diff --git a/assets/stylesheets/wizard/wizard_custom.scss b/assets/stylesheets/wizard/wizard_custom.scss index cc182052..d8161458 100644 --- a/assets/stylesheets/wizard/wizard_custom.scss +++ b/assets/stylesheets/wizard/wizard_custom.scss @@ -3,6 +3,16 @@ .wizard-step-description { line-height: 1.7; + + ul { + margin: 0; + padding: 0; + list-style: none; + } + + i { + margin-right: 7px; + } } .wizard-column .wizard-step-banner { @@ -35,6 +45,31 @@ } } +.step-message { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 0; + line-height: 0; + text-align: center; + transition: all .2s; + + &.success { + height: 60px; + line-height: 60px; + background-color: #009900; + color: #ffffff; + } + + &.error { + height: 60px; + line-height: 60px; + background-color: #e45735; + color: #ffffff; + } +} + .p-list-box { max-width: 550px; position: relative; diff --git a/assets/stylesheets/wizard_custom_admin.scss b/assets/stylesheets/wizard_custom_admin.scss index 3b087e8a..1e3dc6aa 100644 --- a/assets/stylesheets/wizard_custom_admin.scss +++ b/assets/stylesheets/wizard_custom_admin.scss @@ -73,8 +73,27 @@ .wizard-links { margin-bottom: 20px; - .remove { + ul { + margin: 0; + padding: 0; + list-style: none; + display: inline-block; + + li { + display: inline-block; + margin-bottom: 7px; + margin-right: 7px; + } + } + + .sortable-placeholder { + height: 30px; + width: 100px; + display: inline-block; + vertical-align: top; + background-color: $primary-low; margin-right: 10px; + margin-left: 3px; } } @@ -89,31 +108,6 @@ background-color: dark-light-diff($primary, $secondary, 96%, -65%); } -.step-message { - position: absolute; - top: 0; - left: 0; - right: 0; - height: 0; - line-height: 0; - text-align: center; - transition: all .2s; - - &.success { - height: 60px; - line-height: 60px; - background-color: $success; - color: $secondary; - } - - &.error { - height: 60px; - line-height: 60px; - background-color: $danger; - color: $secondary; - } -} - .wizard-dropdown-choices { padding: 15px 15px 0 15px; margin-bottom: 20px; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 7d047b02..5803a10d 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -61,21 +61,21 @@ en: min_length_placeholder: "Minimum length in characters" action: header: "Actions" + include: "Include Fields" + title: "Title" + post: "Post" + none: "Select a field" send_message: label: "Send Message" - title: "Title" - post: "Post" recipient: "Recipient" create_topic: label: "Create Topic" - title: "Title" - post: "Post" category: "Category" + featured_link: "Featured Link" update_profile: label: "Update Profile" - field: "Profile Field" - save_input: - label: "Save Input" + wizard_field: "Wizard Field" + profile_field: "Profile Field" wizard_js: wizard: diff --git a/controllers/wizard.rb b/controllers/wizard.rb index ab95b1cd..d03e56c0 100644 --- a/controllers/wizard.rb +++ b/controllers/wizard.rb @@ -1,10 +1,14 @@ class CustomWizard::WizardController < ::ApplicationController - def set_layout - File.expand_path('../../views/layouts/custom_wizard.html.erb', __FILE__) + prepend_view_path(Rails.root.join('plugins', 'discourse-custom-wizard', 'views')) + layout 'wizard' + helper_method :wizard_page_title + + def wizard_page_title + wizard = PluginStore.get('custom_wizard', params[:wizard_id].underscore) + wizard['name'] || wizard['id'] end def index - puts "USING PROPER CONTROLLER" respond_to do |format| format.json do wizard = CustomWizard::Builder.new(current_user, params[:wizard_id].underscore).build diff --git a/lib/builder.rb b/lib/builder.rb index b0a43d3f..a3329b85 100644 --- a/lib/builder.rb +++ b/lib/builder.rb @@ -9,7 +9,8 @@ class CustomWizard::Builder id: wizard_id, save_submissions: data['save_submissions'], multiple_submissions: data['multiple_submissions'], - background: data["background"] + background: data["background"], + name: data["name"] ) end @@ -120,35 +121,57 @@ class CustomWizard::Builder if s['actions'] && s['actions'].length s['actions'].each do |a| if a['type'] === 'create_topic' - creator = PostCreator.new(user, - title: input[a['title']], - raw: input[a['post']], - category: a['category_id'], - skip_validations: true) + title = input[a['title']] + post = input[a['post']] - post = creator.create - if creator.errors.present? - updater.errors.add(:create_topic, creator.errors.full_messages.join(" ")) - else - updater.result = { topic_id: post.topic.id } + if title && post + params = { + title: title, + raw: post, + skip_validations: true + } + params[:category] = a['category_id'] if a['category_id'] + params[:featured_link] = input[a['featured_link']] if input[a['featured_link']] + + creator = PostCreator.new(user, params) + post = creator.create + + if creator.errors.present? + updater.errors.add(:create_topic, creator.errors.full_messages.join(" ")) + else + updater.result = { topic_id: post.topic.id } + end end end if a['type'] === 'send_message' - creator = PostCreator.new(user, - title: input[a['title']], - raw: input[a['post']], - archetype: Archetype.private_message, - target_usernames: a['username']) + title = input[a['title']] + post = input[a['post']] - post = creator.create + if title && post + creator = PostCreator.new(user, + title: title, + raw: post, + archetype: Archetype.private_message, + target_usernames: a['username']) - if creator.errors.present? - updater.errors.add(:send_message, creator.errors.full_messages.join(" ")) - else - updater.result = { topic_id: post.topic.id } + post = creator.create + + if creator.errors.present? + updater.errors.add(:send_message, creator.errors.full_messages.join(" ")) + else + updater.result = { topic_id: post.topic.id } + end end end + + if a['type'] === 'update_profile' && a['profile_updates'].length + updater = UserUpdater.new(user, user) + attributes = a['profile_updates'].map do |pu| + { pu['profile_field'].to_sym => input[pu['wizard_field']] } + end + updater.update(attributes) + end end end diff --git a/lib/wizard.rb b/lib/wizard.rb index 29bc545a..a3ae6a5d 100644 --- a/lib/wizard.rb +++ b/lib/wizard.rb @@ -6,13 +6,14 @@ require_dependency 'wizard/builder' class CustomWizard::Wizard attr_reader :steps, :user - attr_accessor :id, :background, :save_submissions, :multiple_submissions + attr_accessor :id, :name, :background, :save_submissions, :multiple_submissions def initialize(user, attrs = {}) @steps = [] @user = user @first_step = nil @id = attrs[:id] if attrs[:id] + @name = attrs[:name] if attrs[:name] @save_submissions = attrs[:save_submissions] if attrs[:save_submissions] @multiple_submissions = attrs[:multiple_submissions] if attrs[:multiple_submissions] @background = attrs[:background] if attrs[:background] diff --git a/lib/wizard_edits.rb b/lib/wizard_edits.rb index 20edb8d5..1259cef0 100644 --- a/lib/wizard_edits.rb +++ b/lib/wizard_edits.rb @@ -30,16 +30,24 @@ end object.id end + def include_id? + object.respond_to?(:id) + end + def background object.background end + def include_background? + object.respond_to?(:background) + end + def completed object.completed? end def include_completed? - object.completed? && !object.multiple_submissions && !scope.current_user.admin? + object.completed? && !object.respond_to?(:multiple_submissions) && !scope.current_user.admin? end def include_start? diff --git a/plugin.rb b/plugin.rb index 13906845..a1980d2b 100644 --- a/plugin.rb +++ b/plugin.rb @@ -6,16 +6,16 @@ register_asset 'stylesheets/wizard_custom_admin.scss' config = Rails.application.config -config.assets.paths << Rails.root.join("plugins", "discourse-custom-wizard", "assets", "javascripts") -config.assets.paths << Rails.root.join("plugins", "discourse-custom-wizard", "assets", "stylesheets", "wizard") +config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'javascripts') +config.assets.paths << Rails.root.join('plugins', 'discourse-custom-wizard', 'assets', 'stylesheets', 'wizard') after_initialize do UserHistory.actions[:custom_wizard_step] = 100 - require_dependency "application_controller" + require_dependency 'application_controller' module ::CustomWizard class Engine < ::Rails::Engine - engine_name "custom_wizard" + engine_name 'custom_wizard' isolate_namespace CustomWizard end end diff --git a/views/layouts/custom_wizard.html.erb b/views/layouts/wizard.html.erb similarity index 95% rename from views/layouts/custom_wizard.html.erb rename to views/layouts/wizard.html.erb index 8b6ed735..e46d157c 100644 --- a/views/layouts/custom_wizard.html.erb +++ b/views/layouts/wizard.html.erb @@ -17,7 +17,7 @@ <%= render partial: "layouts/head" %> - <%= t 'wizard.custom_title' %> + <%= wizard_page_title %>