0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-22 09:20:29 +01:00
Dieser Commit ist enthalten in:
Angus McLeod 2017-10-30 14:24:51 +08:00
Ursprung 18e93a84eb
Commit a09376e645
19 geänderte Dateien mit 259 neuen und 95 gelöschten Zeilen

Datei anzeigen

@ -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,10 +31,18 @@ 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) => {
if (s.fields && s.fields.length > 0) {
let stepFields = s.fields.map((f) => {
return Ember.Object.create({
id: f.id,
@ -43,7 +50,9 @@ export default Ember.Component.extend({
});
});
fields.push(...stepFields);
}
});
return fields;
}
});

Datei anzeigen

@ -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') }
];
}
},
});

Datei anzeigen

@ -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() {

Datei anzeigen

@ -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);
});
},

Datei anzeigen

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

Datei anzeigen

@ -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() {

Datei anzeigen

@ -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
});
}
});

Datei anzeigen

@ -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}}
{{#each fields as |f|}}
<th>{{f}}</th>
{{/each}}
</tr>
{{#each submissions as |s|}}
<tr>
{{#each-in s as |k v|}}
<td>{{v}}</td>

Datei anzeigen

@ -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'>

Datei anzeigen

@ -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}}

Datei anzeigen

@ -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">
{{/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>
{{wizard-custom-input inputs=field.choices_filters}}
<div class="wizard-header small">
{{i18n 'admin.wizard.field.choices_preset.filter'}}
</div>
<div class="setting full">
{{wizard-custom-input inputs=field.choices_filters}}
{{/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}}

Datei anzeigen

@ -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'}}
</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>

Datei anzeigen

@ -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>

Datei anzeigen

@ -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}}'>

Datei anzeigen

@ -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 {

Datei anzeigen

@ -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."

Datei anzeigen

@ -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

Datei anzeigen

@ -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

Datei anzeigen

@ -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