Angus McLeod 7 years ago
parent
commit
a09376e645

+ 21 - 12
assets/javascripts/discourse/components/wizard-custom-action.js.es6

@@ -1,9 +1,9 @@
 import { default as computed } from 'ember-addons/ember-computed-decorators';
 
 const ACTION_TYPES = [
-  { id: 'create_topic', name: 'create_topic *' },
-  { id: 'update_profile', name: 'update_profile *' },
-  { id: 'send_message', name: 'send_message *' }
+  { id: 'create_topic', name: 'Create Topic' },
+  { id: 'update_profile', name: 'Update Profile' },
+  { id: 'send_message', name: 'Send Message' }
 ];
 
 const PROFILE_FIELDS = [
@@ -18,7 +18,6 @@ const PROFILE_FIELDS = [
   'bio_raw',
   'location',
   'website',
-  'dismissed_banner_key',
   'profile_background',
   'card_background'
 ];
@@ -32,18 +31,28 @@ export default Ember.Component.extend({
   sendMessage: Ember.computed.equal('action.type', 'send_message'),
   disableId: Ember.computed.not('action.isNew'),
 
-  @computed('steps')
-  wizardFields(steps) {
+  @computed('currentStepId', 'wizard.save_submissions')
+  availableFields(currentStepId, saveSubmissions) {
+    const allSteps = this.get('wizard.steps');
+    let steps = allSteps;
     let fields = [];
+
+    if (!saveSubmissions) {
+      steps = [allSteps.findBy('id', currentStepId)];
+    }
+
     steps.forEach((s) => {
-      let stepFields = s.fields.map((f) => {
-        return Ember.Object.create({
-          id: f.id,
-          label: `${f.id} (${s.id})`
+      if (s.fields && s.fields.length > 0) {
+        let stepFields = s.fields.map((f) => {
+          return Ember.Object.create({
+            id: f.id,
+            label: `${f.id} (${s.id})`
+          });
         });
-      });
-      fields.push(...stepFields);
+        fields.push(...stepFields);
+      }
     });
+
     return fields;
   }
 });

+ 5 - 1
assets/javascripts/discourse/components/wizard-custom-field.js.es6

@@ -4,6 +4,10 @@ export default Ember.Component.extend({
   classNames: 'wizard-custom-field',
   isDropdown: Ember.computed.equal('field.type', 'dropdown'),
   disableId: Ember.computed.not('field.isNew'),
+  choicesTypes: ['translation', 'preset', 'custom'],
+  choicesTranslation: Ember.computed.equal('choicesType', 'translation'),
+  choicesPreset: Ember.computed.equal('choicesType', 'preset'),
+  choicesCustom: Ember.computed.equal('choicesType', 'custom'),
 
   @computed('field.type')
   isInput: (type) => type === 'text' || type === 'textarea',
@@ -13,5 +17,5 @@ export default Ember.Component.extend({
     return [
       { id: 'categories', name: I18n.t('admin.wizard.field.choices_preset.categories') }
     ];
-  }
+  },
 });

+ 3 - 1
assets/javascripts/discourse/components/wizard-custom-input.js.es6

@@ -1,6 +1,8 @@
 export default Ember.Component.extend({
-  noneKey: 'admin.wizard.none',
+  noneKey: 'admin.wizard.select_field',
   noneValue: 'admin.wizard.none',
+  inputKey: 'admin.wizard.key',
+  inputValue: 'admin.wizard.value',
 
   actions: {
     add() {

+ 3 - 2
assets/javascripts/discourse/controllers/admin-wizard.js.es6

@@ -20,9 +20,10 @@ export default Ember.Controller.extend({
         } else {
           this.send("refreshWizard");
         }
-      }).catch((error) => {
+      }).catch((result) => {
+        console.log(result)
         this.set('saving', false);
-        this.set('error', I18n.t(`admin.wizard.error.${error}`));
+        this.set('error', I18n.t(`admin.wizard.error.${result.error}`));
         Ember.run.later(() => this.set('error', null), 10000);
       });
     },

+ 1 - 0
assets/javascripts/discourse/helpers/custom-wizard.js.es6

@@ -1,5 +1,6 @@
 import { registerUnbound } from 'discourse-common/lib/helpers';
 
 registerUnbound('dasherize', function(string) {
+  console.log(string)
   return Ember.String.dasherize(string);
 });

+ 54 - 14
assets/javascripts/discourse/models/custom-wizard.js.es6

@@ -4,12 +4,24 @@ const CustomWizard = Discourse.Model.extend({
   save() {
     return new Ember.RSVP.Promise((resolve, reject) => {
       const id = this.get('id');
-      if (!id || !id.underscore()) reject('id_required');
+      if (!id || !id.underscore()) return reject({ error: 'id_required' });
 
       let wizard = { id: id.underscore() };
 
       const steps = this.get('steps');
-      if (steps.length) wizard['steps'] = this.buildSteps(steps, reject);
+      if (steps.length > 0)  {
+        const stepsResult = this.buildSteps(steps);
+        console.log(stepsResult)
+        if (stepsResult.error) {
+          reject({ error: stepsResult.error })
+        } else {
+          wizard['steps'] = stepsResult;
+        }
+      }
+
+      if (steps.length < 1 || !wizard['steps'] || wizard['steps'].length < 1) {
+        return reject({ error: 'steps_required' });
+      }
 
       const name = this.get('name');
       if (name) wizard['name'] = name;
@@ -28,15 +40,26 @@ const CustomWizard = Discourse.Model.extend({
         data: {
           wizard: JSON.stringify(wizard)
         }
-      }).then((result) => resolve(result));
+      }).then((result) => {
+        console.log(result)
+        if (result.error) {
+          reject(result);
+        } else {
+          resolve(result);
+        }
+      });
     });
   },
 
-  buildSteps(stepsObj, reject) {
+  buildSteps(stepsObj) {
     let steps = [];
+    let error = null;
 
     stepsObj.some((s) => {
-      if (!s.id || !s.id.underscore()) reject('id_required');
+      if (!s.id || !s.id.underscore()) {
+        error = 'id_required';
+        return;
+      };
 
       let step = { id: s.id.underscore() };
 
@@ -50,22 +73,31 @@ const CustomWizard = Discourse.Model.extend({
         step['fields'] = [];
 
         fields.some((f) => {
-          let id = f.get('id');
+          let id = f.id;
 
-          if (!id || !id.underscore()) reject('id_required');
+          if (!id || !id.underscore()) {
+            error = 'id_required';
+            return;
+          }
           f.set('id', id.underscore());
 
-          if (f.get('type') === 'dropdown') {
-            const choices = f.get('choices');
-            if (choices && choices.length < 1 && !f.get('choices_key') && !f.get('choices_categories')) {
-              reject('field.need_choices');
-            }
+          if (f.label === '') delete f.label;
+          if (f.description === '') delete f.description;
+
+          if (f.type === 'dropdown') {
+            const choices = f.choices;
+            //if ((!choices || choices.length < 1) && !f.choices_key && !f.choices_categories) {
+              //error = 'field.need_choices';
+              //return;
+            //}
           }
 
           delete f.isNew;
 
           step['fields'].push(f);
         });
+
+        if (error) return;
       }
 
       const actions = s.actions;
@@ -74,7 +106,10 @@ const CustomWizard = Discourse.Model.extend({
 
         actions.some((a) => {
           let id = a.get('id');
-          if (!id || !id.underscore()) reject('id_required');
+          if (!id || !id.underscore()) {
+            error = 'id_required';
+            return;
+          }
 
           a.set('id', id.underscore());
 
@@ -83,12 +118,17 @@ const CustomWizard = Discourse.Model.extend({
           step['actions'].push(a);
         });
 
+        if (error) return;
       }
 
       steps.push(step);
     });
 
-    return steps;
+    if (error) {
+      return { error };
+    } else {
+      return { steps };
+    };
   },
 
   remove() {

+ 18 - 2
assets/javascripts/discourse/routes/admin-wizard-submissions.js.es6

@@ -2,10 +2,26 @@ import CustomWizard from '../models/custom-wizard';
 
 export default Discourse.Route.extend({
   model(params) {
-    return CustomWizard.submissions(params.wizard_id);
+    return Ember.RSVP.hash({
+      submissions: CustomWizard.submissions(params.wizard_id),
+      wizard: this.modelFor('admin-wizards-submissions').findBy('id', params.wizard_id)
+    });
   },
 
   setupController(controller, model) {
-    controller.set("model", model);
+    let fields = ['user_id', 'completed'];
+
+    model.wizard.steps.forEach((s) => {
+      if (s.fields) {
+        s.fields.forEach((f) => {
+          fields.push(f.id);
+        });
+      };
+    });
+
+    controller.setProperties({
+      submissions: model.submissions,
+      fields
+    });
   }
 });

+ 6 - 6
assets/javascripts/discourse/templates/admin-wizard-submissions.hbs

@@ -1,11 +1,11 @@
 <div class="wizard-submissions">
   <table>
-    {{#each model.submissions as |s|}}
-      <tr>
-        {{#each-in s as |k v|}}
-          <th>{{k}}</th>
-        {{/each-in}}
-      </tr>
+    <tr>
+      {{#each fields as |f|}}
+        <th>{{f}}</th>
+      {{/each}}
+    </tr>
+    {{#each submissions as |s|}}
       <tr>
         {{#each-in s as |k v|}}
           <td>{{v}}</td>

+ 1 - 1
assets/javascripts/discourse/templates/admin-wizard.hbs

@@ -60,7 +60,7 @@
 
   {{wizard-links type="step" current=currentStep items=model.steps}}
   {{#if currentStep}}
-    {{wizard-custom-step step=currentStep steps=model.steps fieldTypes=model.fieldTypes}}
+    {{wizard-custom-step step=currentStep wizard=model}}
   {{/if}}
 
   <div class='buttons'>

+ 14 - 11
assets/javascripts/discourse/templates/components/wizard-custom-action.hbs

@@ -13,7 +13,6 @@
   </div>
   <div class="setting-value">
     {{combo-box value=action.type content=types}}
-    <label>*{{i18n 'admin.wizard.action.requires_save'}}</label>
   </div>
 </div>
 
@@ -23,7 +22,7 @@
       <h3>{{i18n "admin.wizard.action.create_topic.category"}}</h3>
     </div>
     <div class="setting-value">
-      {{category-select-box value=action.category_id}}
+      {{category-chooser value=action.category_id}}
     </div>
   </div>
 
@@ -32,7 +31,7 @@
       <h3>{{i18n "admin.wizard.action.title"}}</h3>
     </div>
     <div class="setting-value">
-      {{combo-box value=action.title content=wizardFields nameProperty="label" none='admin.wizard.action.none'}}
+      {{combo-box value=action.title content=availableFields nameProperty="label" none='admin.wizard.select_field'}}
     </div>
   </div>
 
@@ -41,13 +40,16 @@
       <h3>{{i18n "admin.wizard.action.post"}}</h3>
     </div>
     <div class="setting-value">
-      {{combo-box value=action.post content=wizardFields nameProperty="label" none='admin.wizard.action.none'}}
+      {{combo-box value=action.post content=availableFields nameProperty="label" none='admin.wizard.select_field'}}
     </div>
   </div>
 
   <div class="setting full">
     <label>{{i18n "admin.wizard.action.add_fields" type='Topic'}}</label>
-    {{wizard-custom-input inputs=action.add_fields valueContent=wizardFields noneValue='admin.wizard.action.none'}}
+    {{wizard-custom-input inputs=action.add_fields
+                          valueContent=availableFields
+                          inputKey='admin.wizard.action.topic_attr'
+                          noneValue='admin.wizard.select_field'}}
   </div>
 {{/if}}
 
@@ -57,7 +59,7 @@
       <h3>{{i18n "admin.wizard.action.title"}}</h3>
     </div>
     <div class="setting-value">
-      {{combo-box value=action.title content=wizardFields nameProperty='label' none='admin.wizard.action.none'}}
+      {{combo-box value=action.title content=availableFields nameProperty='label' none='admin.wizard.select_field'}}
     </div>
   </div>
 
@@ -66,7 +68,7 @@
       <h3>{{i18n "admin.wizard.action.post"}}</h3>
     </div>
     <div class="setting-value">
-      {{combo-box value=action.post content=wizardFields nameProperty='label' none='admin.wizard.action.none'}}
+      {{combo-box value=action.post content=availableFields nameProperty='label' none='admin.wizard.select_field'}}
     </div>
   </div>
 
@@ -84,7 +86,9 @@
 
   <div class="setting full">
     <label>{{i18n "admin.wizard.action.add_fields" type='Message'}}</label>
-    {{wizard-custom-input inputs=action.add_fields valueContent=wizardFields noneValue='admin.wizard.action.none'}}
+    {{wizard-custom-input inputs=action.add_fields
+                          keyContent=availableFields
+                          inputValue='admin.wizard.action.topic_attr'}}
   </div>
 {{/if}}
 
@@ -93,8 +97,7 @@
     <label>{{i18n "admin.wizard.action.add_fields" type='Profile'}}</label>
     {{wizard-custom-input inputs=action.profile_updates
                           valueContent=profileFields
-                          keyContent=wizardFields
-                          noneKey='admin.wizard.action.none'
-                          noneValue='admin.wizard.action.none'}}
+                          keyContent=availableFields
+                          noneValue='admin.wizard.action.update_profile.profile_field'}}
   </div>
 {{/if}}

+ 16 - 11
assets/javascripts/discourse/templates/components/wizard-custom-field.hbs

@@ -66,30 +66,35 @@
 
 {{#if isDropdown}}
   <div class="wizard-dropdown-choices">
-    <div class="wizard-header medium">
+    <div class="wizard-header small underline">
       {{i18n 'admin.wizard.field.choices_label'}}
     </div>
-    <div class="setting">
+
+    {{combo-box value=choicesType content=choicesTypes none="admin.wizard.field.choices_type"}}
+
+    {{#if choicesTranslation}}
       <div class="wizard-header small">
         {{i18n 'admin.wizard.field.choices_translation'}}
       </div>
-      <div class="setting-value">
-        {{input name="key" value=field.choices_key placeholderKey="admin.wizard.key_placeholder"}}
-      </div>
-    </div>
-    <div class="setting full">
+      {{input name="key" value=field.choices_key placeholderKey="admin.wizard.key_placeholder"}}
+    {{/if}}
+
+    {{#if choicesPreset}}
       <div class="wizard-header small">
         {{i18n 'admin.wizard.field.choices_preset.label'}}
       </div>
       {{combo-box value=field.choices_preset content=presetChoices none='admin.wizard.none'}}
-      <label>{{i18n 'admin.wizard.field.choices_preset.filter'}}</label>
+      <div class="wizard-header small">
+        {{i18n 'admin.wizard.field.choices_preset.filter'}}
+      </div>
       {{wizard-custom-input inputs=field.choices_filters}}
-    </div>
-    <div class="setting full">
+    {{/if}}
+
+    {{#if choicesCustom}}
       <div class="wizard-header small">
         {{i18n 'admin.wizard.field.choices_custom'}}
       </div>
       {{wizard-custom-input inputs=field.choices}}
-    </div>
+    {{/if}}
   </div>
 {{/if}}

+ 8 - 6
assets/javascripts/discourse/templates/components/wizard-custom-input.hbs

@@ -1,16 +1,18 @@
 {{#each inputs as |in|}}
-  <span class='custom-input'>
+  <div class='custom-input'>
     {{#if keyContent}}
       {{combo-box value=in.key content=keyContent nameProperty="label" none=noneKey}}
     {{else}}
-      {{input type="text" value=in.key placeholder=(i18n 'admin.wizard.key')}}
+      {{input type="text" value=in.key placeholder=(i18n inputKey)}}
     {{/if}}
     {{#if valueContent}}
       {{combo-box value=in.value content=valueContent nameProperty="label" none=noneValue}}
     {{else}}
-      {{input type="text" value=in.value placeholder=(i18n 'admin.wizard.value')}}
+      {{input type="text" value=in.value placeholder=(i18n inputValue)}}
     {{/if}}
-  </span>
-  {{d-button action='remove' actionParam=in icon='times'}}
+    {{d-button action='remove' actionParam=in icon='times'}}
+  </div>
 {{/each}}
-<div>{{d-button action='add' label='admin.wizard.add' icon='plus'}}</div>
+<div class="add-custom-input">
+  {{d-button action='add' label='admin.wizard.add' icon='plus'}}
+</div>

+ 4 - 2
assets/javascripts/discourse/templates/components/wizard-custom-step.hbs

@@ -45,10 +45,12 @@
 
 {{wizard-links type="field" current=currentField items=step.fields}}
 {{#if currentField}}
-  {{wizard-custom-field field=currentField types=fieldTypes removeField="removeField"}}
+  {{wizard-custom-field field=currentField types=wizard.fieldTypes removeField="removeField"}}
 {{/if}}
 
 {{wizard-links type="action" current=currentAction items=step.actions}}
 {{#if currentAction}}
-  {{wizard-custom-action action=currentAction steps=steps removeAction="removeAction"}}
+  {{wizard-custom-action action=currentAction wizard=wizard removeAction="removeAction" currentStepId=step.id}}
 {{/if}}
+
+<label>{{i18n 'admin.wizard.action.available_fields'}}</label>

+ 1 - 1
assets/javascripts/discourse/templates/components/wizard-links.hbs

@@ -1,5 +1,5 @@
 <div class="wizard-links {{type}}">
-  <div class="wizard-header medium">{{i18n header}}</div>
+  <div class="wizard-header medium">{{{i18n header}}}</div>
   <ul>
     {{#each links as |l|}}
       <li data-id='{{l.id}}'>

+ 33 - 5
assets/stylesheets/wizard_custom_admin.scss

@@ -22,9 +22,12 @@
 
   &.small {
     font-size: 1em;
-    text-decoration: underline;
     margin-bottom: 5px;
   }
+
+  &.underline {
+    text-decoration: underline;
+  }
 }
 
 .content-list + .content {
@@ -63,6 +66,10 @@
     }
   }
 
+  .select-box-kit-header {
+    height: initial;
+  }
+
   .buttons .error {
     color: $danger;
 
@@ -115,19 +122,40 @@
 }
 
 .wizard-dropdown-choices {
-  padding: 15px 15px 0 15px;
+  padding: 15px;
   margin-bottom: 20px;
   background-color: $secondary;
+
+  .wizard-header:not(.underline) {
+    margin-top: 15px;
+  }
 }
 
-.setting .custom-input {
-  display: inline-block;
+.custom-input {
+  margin: 5px 0;
+
+  > * {
+    margin-bottom: 0 !important;
+    margin-right: 5px;
+  }
+
+  .select-box-kit {
+    width: 150px !important;
+  }
 }
 
-.wizard-submissions {
+.setting .add-custom-input {
+  margin-top: 5px;
+}
+
+.admin-contents .wizard-submissions {
   padding: 0 20px;
   display: inline-block;
   overflow: scroll;
+
+  table {
+    margin-top: 0;
+  }
 }
 
 .wizard-field-composer textarea {

+ 10 - 9
config/locales/client.en.yml

@@ -27,12 +27,13 @@ en:
         custom_text_placeholder: "Overrides translation"
         type: "Type"
         none: "Make a selection"
+        select_field: "Wizard Field"
         error:
           name_required: "Wizards must have a name."
           steps_required: "Wizards must have at least one step."
-          id_required: "All Step, Fields and Actions need an Id"
+          id_required: "All wizards, steps, fields and actions need an id."
           field:
-            need_choices: "All dropdowns need a translated choices, custom choies or preset choices."
+            need_choices: "All dropdowns need choices."
             choices_label_empty: "Custom choice labels cannot be empty."
         step:
           header: "Steps"
@@ -44,13 +45,14 @@ en:
           header: "Fields"
           label: "Label"
           description: "Description"
-          choices_label: "Dropdown Choices (use one type)"
+          choices_label: "Dropdown Choices"
+          choices_type: "Choose a type"
           choices_translation: "Translation"
           choices_custom: "Custom"
           choices_preset:
             label: "Preset"
             categories: "Categories"
-            filter: "Filter"
+            filter: "Preset Filter"
           choice:
             value: "Value"
             label: "Label"
@@ -59,13 +61,13 @@ en:
           min_length: "Min Length"
           min_length_placeholder: "Minimum length in characters"
         action:
-          header: "Actions"
+          header: "Actions<sup>*</sup>"
           include: "Include Fields"
           title: "Title"
           post: "Post"
-          none: "Select a field"
-          requires_save: "Requires 'Save' to be turned on."
           add_fields: "Add Fields To {{type}}"
+          available_fields: "* If 'Save wizard submissions' is disabled, only the fields of the current step are available to the current step's actions."
+          topic_attr: "Topic Attribute"
           send_message:
             label: "Send Message"
             recipient: "Recipient"
@@ -74,7 +76,6 @@ en:
             category: "Category"
           update_profile:
             label: "Update Profile"
-            wizard_field: "Wizard Field"
             profile_field: "Profile Field"
 
   wizard_js:
@@ -105,7 +106,7 @@ en:
         no_results: "No results. Please double check the spelling."
         show_map: "Show Map"
       validation:
-        city: "Please enter a city or town."
+        city: "Please enter a city, town or village."
         countrycode: "Please enter a country."
         geo_location: "Search and select a result."
 

+ 49 - 1
controllers/admin.rb

@@ -15,6 +15,54 @@ class CustomWizard::AdminController < ::ApplicationController
 
     wizard = ::JSON.parse(params[:wizard])
 
+    error = nil
+
+    if !wizard["id"] || wizard["id"].empty?
+      error = 'id_required'
+    elsif !wizard["name"] || wizard["name"].empty?
+      error = 'name_required'
+    elsif !wizard["steps"] || wizard["steps"].empty?
+      error = 'steps_required'
+    end
+
+    return render json: { error: error } if error
+
+    wizard["steps"].each do |s|
+      puts "HERE IS THE ID: #{s["id"]}"
+      if s["id"].blank?
+        error = 'id_required'
+        break
+      end
+
+      if s["fields"] && s["fields"].present?
+        s["fields"].each do |f|
+          if f["id"].blank?
+            error = 'id_required'
+            break
+          end
+
+          if f["type"] === 'dropdown'
+            choices = f["choices"]
+            if (!choices || choices.length < 1) && !f["choices_key"] && !f["choices_categories"]
+              error = 'field.need_choices'
+              break
+            end
+          end
+        end
+      end
+
+      if s["actions"] && s["actions"].present?
+        s["actions"].each do |a|
+          if a["id"].blank?
+            error = 'id_required'
+            break
+          end
+        end
+      end
+    end
+
+    return render json: { error: error } if error
+
     PluginStore.set('custom_wizard', wizard["id"], wizard)
 
     render json: success_json
@@ -49,7 +97,7 @@ class CustomWizard::AdminController < ::ApplicationController
 
     rows = PluginStoreRow.where(plugin_name: "#{params[:wizard_id]}_submissions").order(:id)
 
-    submissions = [*rows].map { |r| ::JSON.parse(r.value) }
+    submissions = [*rows].map { |r| ::JSON.parse(r.value) }.flatten
 
     render json: success_json.merge(submissions: submissions)
   end

+ 11 - 9
lib/builder.rb

@@ -122,11 +122,13 @@ class CustomWizard::Builder
 
             next if updater.errors.any?
 
+            data = @wizard.save_submissions ? submission : step_input
+
             if s['actions'] && s['actions'].length
               s['actions'].each do |a|
-                if a['type'] === 'create_topic' && submission
-                  title = submission[a['title']]
-                  post = submission[a['post']]
+                if a['type'] === 'create_topic' && data
+                  title = data[a['title']]
+                  post = data[a['post']]
 
                   if title
                     params = {
@@ -140,7 +142,7 @@ class CustomWizard::Builder
 
                     if a['add_fields']
                       a['add_fields'].each do |f|
-                        value = submission[f['value']]
+                        value = data[f['value']]
                         key = f['key']
 
                         if key.include?('custom_fields')
@@ -180,9 +182,9 @@ class CustomWizard::Builder
                   end
                 end
 
-                if a['type'] === 'send_message' && submission
-                  title = submission[a['title']]
-                  post = submission[a['post']]
+                if a['type'] === 'send_message' && data
+                  title = data[a['title']]
+                  post = data[a['post']]
 
                   if title && post
                     creator = PostCreator.new(user,
@@ -201,11 +203,11 @@ class CustomWizard::Builder
                   end
                 end
 
-                if a['type'] === 'update_profile' && a['profile_updates'].length && submission
+                if a['type'] === 'update_profile' && a['profile_updates'].length && data
                   user_updater = UserUpdater.new(user, user)
                   attributes = {}
                   a['profile_updates'].each do |pu|
-                    attributes[pu['key'].to_sym] = submission[pu['value']]
+                    attributes[pu['key'].to_sym] = data[pu['value']]
                   end
                   user_updater.update(attributes) if attributes.present?
                 end

+ 1 - 1
lib/field.rb

@@ -1,6 +1,6 @@
 class CustomWizard::Field
   def self.types
-    @types ||= ['dropdown', 'image', 'radio', 'text', 'textarea']
+    @types ||= ['text', 'textarea', 'dropdown', 'image', 'radio']
   end
 
   def self.require_assets