0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-21 17:00:29 +01:00
Dieser Commit ist enthalten in:
Angus McLeod 2017-10-06 10:59:02 +08:00
Ursprung 7b09410a26
Commit 9f40821db0
20 geänderte Dateien mit 526 neuen und 157 gelöschten Zeilen

Datei anzeigen

@ -1,11 +1,8 @@
export default Ember.Component.extend({
classNames: 'wizard-custom-action',
types: ['create_topic', 'update_profile', 'send_message'],
profileFields: ['name', 'username', 'email'],
createTopic: Ember.computed.equal('action.type', 'create_topic'),
updateProfile: Ember.computed.equal('action.type', 'update_profile'),
sendMessage: Ember.computed.equal('action.type', 'send_message'),
test: function() {
console.log(this.get('stepFields'));
}.observes('stepFields.[]')
sendMessage: Ember.computed.equal('action.type', 'send_message')
});

Datei anzeigen

@ -1,9 +1,11 @@
import { observes } from 'ember-addons/ember-computed-decorators';
import { default as computed, on, observes } from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
classNames: 'wizard-custom-field',
isDropdown: Ember.computed.equal('field.type', 'dropdown'),
@on('init')
@observes('field.id')
init() {
this._super(...arguments);
@ -12,15 +14,16 @@ export default Ember.Component.extend({
}
},
@observes('field.label')
setFieldId() {
const label = this.get('field.label');
this.set('field.id', Ember.String.underscore(label));
},
@computed('field.choices.[]')
dropdownChoices: choices => choices,
actions: {
addChoice() {
this.get('field.choices').pushObject(Ember.Object.create());
},
removeChoice(c) {
this.get('field.choices').removeObject(c);
}
}
});

Datei anzeigen

@ -1,26 +1,103 @@
import { default as computed } from 'ember-addons/ember-computed-decorators';
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,
@computed('step.fields.@each.id')
allowAddAction: stepFields => stepFields.get('firstObject.id'),
@on('init')
@observes('step.id')
setup() {
this._super(...arguments);
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.[]', 'currentField')
fieldLinks(fields, current) {
return fields.map((f) => {
if (f) {
let link = {
id: f.get('id'),
label: f.get('label')
};
let classes = 'btn';
if (current && f.get('id') === current.get('id')) {
classes += ' btn-primary';
};
link['classes'] = classes;
return link;
}
});
},
@computed('step.actions.[]', 'currentAction')
actionLinks(actions, current) {
return actions.map((a) => {
if (a) {
let link = {
id: a.get('id'),
label: a.get('label')
};
let classes = 'btn';
if (current && a.get('id') === current.get('id')) {
classes += ' btn-primary';
};
link['classes'] = classes;
return link;
}
});
},
actions: {
addField() {
this.get('step.fields').pushObject(Ember.Object.create({ id: '', label: '' }));
const fields = this.get('step.fields');
const newNum = fields.length + 1;
const field = Ember.Object.create({
id: `field-${newNum}`, label: `Field ${newNum}`
});
fields.pushObject(field);
this.set('currentField', field);
},
addAction() {
this.get('step.actions').pushObject(Ember.Object.create({ id: '', label: '' }));
const actions = this.get('step.actions');
const newNum = actions.length + 1;
const action = Ember.Object.create({
id: `action-${newNum}`, label: `Action ${newNum}`
});
actions.pushObject(action);
this.set('currentAction', action);
},
removeField(field) {
this.get('step.fields').removeObject(field);
removeField(fieldId) {
const fields = this.get('step.fields');
fields.removeObject(fields.findBy('id', fieldId));
this.set('currentField', fields[fields.length - 1]);
},
removeAction(action) {
this.get('step.actions').removeObject(action);
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));
}
}
});

Datei anzeigen

@ -1,8 +1,37 @@
import { default as computed } from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({
@computed('model.steps.[]', 'currentStep')
stepLinks(steps, currentStep) {
return steps.map((s) => {
if (s) {
let link = {
id: s.get('id'),
title: s.get('title')
};
let classes = 'btn';
if (currentStep && s.get('id') === currentStep.get('id')) {
classes += ' btn-primary';
};
link['classes'] = classes;
return link;
}
});
},
@computed('model.id')
wizardUrl(wizardId) {
return window.location.origin + '/wizard/custom/' + wizardId;
},
actions: {
save() {
this.get('model').save().then(() => {
this.transitionToRoute('adminWizardsCustom');
this.send("refreshRoute");
});
},
@ -13,14 +42,27 @@ export default Ember.Controller.extend({
},
addStep() {
this.get('model.steps').pushObject(Ember.Object.create({
const steps = this.get('model.steps');
const newNum = steps.length + 1;
const step = Ember.Object.create({
fields: Ember.A(),
actions: Ember.A()
}));
actions: Ember.A(),
title: `Step ${newNum}`,
id: `step-${newNum}`
});
steps.pushObject(step);
this.set('currentStep', step);
},
removeStep(step) {
this.get('model.steps').removeObject(step);
removeStep(stepId) {
const steps = this.get('model.steps');
steps.removeObject(steps.findBy('id', stepId));
},
changeStep(stepId) {
const steps = this.get('model.steps');
this.set('currentStep', steps.findBy('id', stepId));
}
}
});

Datei anzeigen

@ -8,9 +8,7 @@ const CustomWizard = Discourse.Model.extend({
},
@computed('name')
id(name) {
return name ? Ember.String.dasherize(name) : null;
},
id: (name) => name ? Ember.String.dasherize(name) : null,
save() {
const stepsObj = this.get('steps');
@ -36,11 +34,12 @@ const CustomWizard = Discourse.Model.extend({
c.set('id', c.get('label'));
});
}
step['fields'].push(f);
});
s.actions.forEach((a) => {
a['id'] = Ember.String.dasherize(a.label);
a.set('id', Ember.String.dasherize(a.get('label')));
step['actions'].push(a);
});
@ -128,6 +127,7 @@ CustomWizard.reopenClass({
id: s.id,
title: s.title,
description: s.description,
banner: s.banner,
fields,
actions
}));

Datei anzeigen

@ -21,7 +21,15 @@ export default Discourse.Route.extend({
},
setupController(controller, model) {
controller.set("new", this.get('new'));
controller.set("model", model);
let props = { new: this.get('new'), model };
const steps = model.get('steps');
if (steps[0]) props['currentStep'] = steps[0];
controller.setProperties(props);
},
actions: {
refreshRoute() {
this.refresh();
}
}
});

Datei anzeigen

@ -5,6 +5,12 @@ export default Discourse.Route.extend({
return CustomWizard.findAll();
},
afterModel(model, transition) {
if (transition.intent.name !== 'adminWizard' && model.length > 0) {
this.transitionTo('adminWizard', model[0].id);
}
},
setupController(controller, model){
controller.set("model", model.toArray());
},

Datei anzeigen

@ -5,6 +5,12 @@ export default Discourse.Route.extend({
return CustomWizard.findAllSubmissions();
},
afterModel(model, transition) {
if (transition.intent.name !== 'adminWizardSubmissions' && model.length > 0) {
this.transitionTo('adminWizardSubmissions', model[0].id);
}
},
setupController(controller, model){
controller.set("model", model);
}

Datei anzeigen

@ -1,14 +1,16 @@
<table>
{{#each model.submissions as |s|}}
<tr>
{{#each-in s as |k v|}}
<th>{{k}}</th>
{{/each-in}}
</tr>
<tr>
{{#each-in s as |k v|}}
<td>{{v}}</td>
{{/each-in}}
</tr>
{{/each}}
</table>
<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-in s as |k v|}}
<td>{{v}}</td>
{{/each-in}}
</tr>
{{/each}}
</table>
</div>

Datei anzeigen

@ -1,22 +1,45 @@
<div class="form-horizontal">
<div>
<label for="name">{{i18n 'admin.wizard.name'}}</label>
{{text-field name="name" value=model.name placeholderKey="admin.wizard.name_placeholder"}}
<div class="admin-wizard settings">
<div class="wizard-header">
{{i18n 'admin.wizard.header'}}
</div>
<div>
{{input type='checkbox' checked=model.save_submissions}}
<span for="save">{{i18n 'admin.wizard.save_submissions'}}</span>
<div class="setting">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.name'}}</h3>
</div>
<div class="setting-value">
{{text-field name="name" value=model.name placeholderKey="admin.wizard.name_placeholder"}}
</div>
</div>
{{#if model.steps}}
{{#each model.steps as |s|}}
{{wizard-custom-step step=s fieldTypes=model.fieldTypes}}
{{d-button action='removeStep' actionParam=s label='admin.wizard.step.remove'}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.save_submissions'}}</h3>
</div>
<div class="setting-value">
{{input type='checkbox' checked=model.save_submissions}}
<span for="save">{{i18n 'admin.wizard.save_submissions_label'}}</span>
</div>
</div>
<div class="setting full">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.url'}}</h3>
</div>
<a href="{{wizardUrl}}" target="_blank">{{wizardUrl}}</a>
</div>
<div class="wizard-links">
<div class="wizard-header">{{i18n 'admin.wizard.step.header'}}</div>
{{#each stepLinks as |s|}}
{{d-button action="changeStep" actionParam=s.id translatedLabel=s.title class=s.classes}}
{{d-button action="removeStep" actionParam=s.id icon='times' class='remove'}}
{{/each}}
{{/if}}
{{d-button action='addStep' label='admin.wizard.add' icon='plus'}}
</div>
{{d-button action='addStep' label='admin.wizard.step.add'}}
{{wizard-custom-step step=currentStep fieldTypes=model.fieldTypes}}
<div class='buttons'>
<button {{action "save"}} disabled={{disableSave}} class='btn btn-primary'>{{i18n 'admin.wizard.save'}}</button>

Datei anzeigen

@ -1,7 +1 @@
<div class="groups-type-index">
<div>
{{#link-to 'adminWizard' 'new' class="btn"}}
{{d-icon "plus"}} {{i18n 'admin.wizard.new'}}
{{/link-to}}
</div>
</div>
<div class="groups-type-index"></div>

Datei anzeigen

@ -7,9 +7,14 @@
</li>
{{/each}}
</ul>
<div class="new-wizard">
{{#link-to 'adminWizard' 'new' class="btn"}}
{{d-icon "plus"}} {{i18n 'admin.wizard.new'}}
{{/link-to}}
</div>
</div>
<div class="span13">
<div class="content">
{{outlet}}
</div>
</div>

Datei anzeigen

@ -9,7 +9,7 @@
</ul>
</div>
<div class="span13">
<div class="content">
{{outlet}}
</div>
</div>

Datei anzeigen

@ -1,26 +1,96 @@
{{combo-box value=action.type content=types}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.label"}}</h3>
</div>
<div class="setting-value">
{{input value=action.label}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.type"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.type content=types}}
</div>
</div>
{{#if createTopic}}
<label>{{i18n "admin.wizard.action.create_topic.category"}}</label>
{{category-select-box value=action.category_id}}
<label>{{i18n "admin.wizard.action.create_topic.title"}}</label>
{{combo-box value=action.title content=stepFields nameProperty="label"}}
<label>{{i18n "admin.wizard.action.create_topic.post"}}</label>
{{combo-box value=action.post content=stepFields nameProperty="label"}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.create_topic.category"}}</h3>
</div>
<div class="setting-value">
{{category-select-box value=action.category_id}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.create_topic.title"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.title content=stepFields nameProperty="label"}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.create_topic.post"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.post content=stepFields nameProperty="label"}}
</div>
</div>
{{/if}}
{{#if sendMessage}}
<label>{{i18n "admin.wizard.action.send_message.title"}}</label>
{{combo-box value=action.title content=stepFields nameProperty="label"}}
<label>{{i18n "admin.wizard.action.send_message.post"}}</label>
{{combo-box value=action.post content=stepFields nameProperty="label"}}
<label>{{i18n "admin.wizard.action.send_message.recipient"}}</label>
{{user-selector single="true"
includeMentionableGroups="true"
usernames=action.username
allowedUsers="true"}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.send_message.title"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.title content=stepFields nameProperty="label"}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.send_message.post"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.post content=stepFields nameProperty="label"}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.send_message.recipient"}}</h3>
</div>
<div class="setting-value">
{{user-selector single="true"
includeMentionableGroups="true"
usernames=action.username
allowedUsers="true"}}
</div>
</div>
{{/if}}
{{#if updateProfile}}
<label>{{i18n "admin.wizard.action.source"}}</label>
{{combo-box value=action.source content=stepFields nameProperty="label"}}
<label>{{i18n "admin.wizard.action.profile_field"}}</label>
{{combo-box value=action.profile_field content=profileFields}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.source"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.source content=stepFields nameProperty="label"}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.profile_field"}}</h3>
</div>
<div class="setting-value">
{{combo-box value=action.profile_field content=profileFields}}
</div>
</div>
{{/if}}

Datei anzeigen

@ -1 +0,0 @@
{{input type='text' value=choice.label}}

Datei anzeigen

@ -1,25 +1,51 @@
<div for={{field.id}}>
<div>
<span>{{i18n 'admin.wizard.field.label'}}</span>
{{text-field name="label" value=field.label}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.field.label'}}</h3>
</div>
<div>
<span>{{i18n 'admin.wizard.field.description'}}</span>
{{text-field name="description" value=field.description}}
</div>
<div>
<span>{{i18n 'admin.wizard.field.type'}}</span>
{{combo-box value=field.type content=types}}
</div>
{{#if isDropdown}}
<span>{{i18n 'admin.wizard.field.choices_label'}}</span>
{{#each field.choices as |c|}}
{{wizard-custom-choice choice=c}}
{{/each}}
{{d-button action='addChoice' label='admin.wizard.field.add_choice'}}
{{/if}}
<div>
<span>{{i18n 'admin.wizard.field.required'}}</span>
{{input type='checkbox' checked=field.required}}
<div class="setting-value">
{{input name="label" value=field.label}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.field.description'}}</h3>
</div>
<div class="setting-value">
{{textarea name="description" value=field.description}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.field.type'}}</h3>
</div>
<div class="setting-value">
{{combo-box value=field.type content=types}}
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.field.required'}}</h3>
</div>
<div class="setting-value">
{{input type='checkbox' checked=field.required}}
<span>{{i18n 'admin.wizard.field.required_label'}}</span>
</div>
</div>
{{#if isDropdown}}
<div class="wizard-dropdown-choices">
<div class="wizard-header small">
{{i18n 'admin.wizard.field.choices_label'}}
</div>
{{#each dropdownChoices as |c|}}
<span class='wizard-dropdown-choice'>
{{input type='text' value=c.label}}
</span>
{{d-button action='removeChoice' actionParam=c icon='times'}}
{{/each}}
{{d-button action='addChoice' label='admin.wizard.add' icon='plus'}}
</div>
{{/if}}

Datei anzeigen

@ -1,30 +1,52 @@
<div>
<label for="title">{{i18n 'admin.wizard.step.title'}}</label>
{{text-field name="title" value=step.title placeholderKey="admin.wizard.step.title_placeholder"}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.step.title'}}</h3>
</div>
<div class="setting-value">
{{input name="title" value=step.title placeholderKey="admin.wizard.step.title_placeholder"}}
</div>
</div>
<div>
<label for="banner">{{i18n 'admin.wizard.step.banner'}}</label>
{{input name="banner" value=step.banner placeholderKey="admin.wizard.step.banner_placeholder"}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.step.banner'}}</h3>
</div>
<div class="setting-value">
{{input name="banner" value=step.banner placeholderKey="admin.wizard.step.banner_placeholder"}}
</div>
</div>
<div>
<label for="description">{{i18n 'admin.wizard.step.description'}}</label>
{{input name="description" value=step.description placeholderKey="admin.wizard.step.description_placeholder"}}
<div class="setting">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.step.description'}}</h3>
</div>
<div class="setting-value">
{{textarea name="description" value=step.description placeholderKey="admin.wizard.step.description_placeholder"}}
</div>
</div>
{{#each step.fields as |f|}}
{{wizard-custom-field field=f types=fieldTypes}}
{{d-button action='removeField' actionParam=f label="admin.wizard.field.remove"}}
{{/each}}
<div class="wizard-links">
<div class="wizard-header medium">{{i18n 'admin.wizard.field.header'}}</div>
{{#each fieldLinks as |f|}}
{{d-button action="changeField" actionParam=f.id translatedLabel=f.label class=f.classes}}
{{d-button action='removeField' actionParam=f.id icon='times' class='remove'}}
{{/each}}
{{d-button action='addField' label='admin.wizard.add' icon='plus'}}
</div>
{{d-button action='addField' label='admin.wizard.field.add'}}
{{#each step.actions as |a|}}
{{wizard-custom-action action=a stepFields=step.fields}}
{{d-button action='removeAction' actionParam=a label="admin.wizard.action.remove"}}
{{/each}}
{{#if allowAddAction}}
{{d-button action='addAction' label='admin.wizard.action.add'}}
{{#if currentField}}
{{wizard-custom-field field=currentField types=fieldTypes removeField="removeField"}}
{{/if}}
<div class="wizard-links">
<div class="wizard-header medium">{{i18n 'admin.wizard.action.header'}}</div>
{{#each actionLinks as |a|}}
{{d-button action="changeAction" actionParam=a.id translatedLabel=a.label class=a.classes}}
{{d-button action='removeAction' actionParam=a.id icon='times' class='remove'}}
{{/each}}
{{d-button action='addAction' label='admin.wizard.add' icon='plus'}}
</div>
{{#if currentAction}}
{{wizard-custom-action action=currentAction stepFields=step.fields removeAction="removeAction"}}
{{/if}}

Datei anzeigen

@ -65,6 +65,17 @@ export default {
});
WizardStep.reopen({
bannerImage: function() {
const src = this.get('step.banner');
if (!src) return;
if (src.indexOf('/uploads/') > -1) {
return getUrl(src);
} else {
return getUrl(`/images/wizard/${src}`);
};
}.property('step.banner'),
advance() {
this.set('saving', true);
this.get('step').save()

Datei anzeigen

@ -1,3 +1,78 @@
.wizards-nav-button {
@extend .nav-pills;
float: left;
}
.new-wizard {
margin-top: 15px;
}
.wizard-header {
font-size: 1.3em;
margin-bottom: 15px;
&.medium {
font-size: 1.1em;
}
&.small {
font-size: 0.97em;
}
}
.content-list + .content {
overflow: hidden;
}
.admin-wizard.settings {
margin-left: 30px;
margin-right: 30px;
.setting {
display: inline-block;
vertical-align: top;
min-width: 49%;
.setting-label {
width: 20%;
}
&.full {
width: 100%;
.setting-label {
width: 75px;
}
}
}
}
.wizard-links {
margin-bottom: 20px;
.remove {
margin-right: 10px;
}
}
.wizard-custom-step {
display: inline-block;
width: 100%;
margin-bottom: 20px;
padding: 15px;
background-color: dark-light-diff($primary, $secondary, 96%, -65%);
}
.wizard-dropdown-choices {
margin-bottom: 25px;
}
.wizard-dropdown-choice {
display: inline-block;
}
.wizard-submissions {
padding: 0 20px;
display: inline-block;
overflow: scroll;
}

Datei anzeigen

@ -8,41 +8,44 @@ en:
submissions_label: "Submissions"
name: "Name"
name_placeholder: "name of the wizard"
save_submissions: "Save wizard submissions"
save: "Save Wizard"
save_submissions: "Save"
save_submissions_label: "Save wizard submissions"
save: "Save Changes"
remove: "Delete Wizard"
header: "Wizard"
add: "Add"
url: "Url"
step:
title: "Step Title"
header: "Steps"
title: "Title"
title_placeholder: "This will appear at the top of the step"
banner: "Step Banner"
banner_placeholder: "This image will appear under the title"
description: "Step Description"
banner: "Banner"
banner_placeholder: "Image url"
description: "Description"
description_placeholder: "This will appear underneath the title and / or title"
add: "Add Step"
remove: "Remove Step"
field:
add: "Add Field"
remove: "Remove Field"
label: "Field Name"
description: "Field Description"
type: "Field Type"
header: "Fields"
label: "Label"
description: "Description"
type: "Type"
choices_label: "Dropdown Choices"
add_choice: "Add Choice"
required: "Field Required"
add_choice: "Add"
required: "Required"
required_label: "Field is Required"
action:
add: "Add Action"
remove: "Remove Action"
source: "Source"
header: "Actions"
label: "Label"
type: "Type"
send_message:
label: "Send Message"
title: "Message Title"
post: "Message Post"
recipient: "Message Recipient"
title: "Title"
post: "Post"
recipient: "Recipient"
create_topic:
label: "Create Topic"
title: "Topic Title"
post: "Topic Post"
category: "Topic Category"
title: "Title"
post: "Post"
category: "Category"
update_profile:
label: "Update Profile"
field: "Profile Field"