Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-26 02:50:28 +01:00
Commit
28ae6fd19f
145 geänderte Dateien mit 6056 neuen und 3572 gelöschten Zeilen
|
@ -0,0 +1,19 @@
|
||||||
|
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNames: 'wizard-advanced-toggle',
|
||||||
|
|
||||||
|
@discourseComputed('showAdvanced')
|
||||||
|
toggleClass(showAdvanced) {
|
||||||
|
let classes = 'btn'
|
||||||
|
if (showAdvanced) classes += ' btn-primary';
|
||||||
|
return classes;
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
toggleAdvanced() {
|
||||||
|
this.toggleProperty('showAdvanced');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -1,92 +1,44 @@
|
||||||
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
|
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
|
||||||
|
import { equal, empty, or } from "@ember/object/computed";
|
||||||
|
import { generateName, selectKitContent, schema } from '../lib/wizard';
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
const ACTION_TYPES = [
|
export default Component.extend({
|
||||||
{ id: 'create_topic', name: 'Create Topic' },
|
|
||||||
{ id: 'update_profile', name: 'Update Profile' },
|
|
||||||
{ id: 'send_message', name: 'Send Message' },
|
|
||||||
{ id: 'send_to_api', name: 'Send to API' },
|
|
||||||
{ id: 'add_to_group', name: 'Add to Group' },
|
|
||||||
{ id: 'route_to', name: 'Route To' },
|
|
||||||
{ id: 'open_composer', name: 'Open Composer' }
|
|
||||||
];
|
|
||||||
|
|
||||||
const PROFILE_FIELDS = [
|
|
||||||
'name',
|
|
||||||
'user_avatar',
|
|
||||||
'date_of_birth',
|
|
||||||
'title',
|
|
||||||
'locale',
|
|
||||||
'location',
|
|
||||||
'website',
|
|
||||||
'bio_raw',
|
|
||||||
'profile_background',
|
|
||||||
'card_background',
|
|
||||||
'theme_id'
|
|
||||||
];
|
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
classNames: 'wizard-custom-action',
|
classNames: 'wizard-custom-action',
|
||||||
types: ACTION_TYPES,
|
actionTypes: Object.keys(schema.action.types).map(t => ({ id: t, name: generateName(t) })),
|
||||||
profileFields: PROFILE_FIELDS,
|
createTopic: equal('action.type', 'create_topic'),
|
||||||
createTopic: Ember.computed.equal('action.type', 'create_topic'),
|
updateProfile: equal('action.type', 'update_profile'),
|
||||||
updateProfile: Ember.computed.equal('action.type', 'update_profile'),
|
sendMessage: equal('action.type', 'send_message'),
|
||||||
sendMessage: Ember.computed.equal('action.type', 'send_message'),
|
openComposer: equal('action.type', 'open_composer'),
|
||||||
sendToApi: Ember.computed.equal('action.type', 'send_to_api'),
|
sendToApi: equal('action.type', 'send_to_api'),
|
||||||
apiEmpty: Ember.computed.empty('action.api'),
|
addToGroup: equal('action.type', 'add_to_group'),
|
||||||
addToGroup: Ember.computed.equal('action.type', 'add_to_group'),
|
routeTo: equal('action.type', 'route_to'),
|
||||||
routeTo: Ember.computed.equal('action.type', 'route_to'),
|
apiEmpty: empty('action.api'),
|
||||||
disableId: Ember.computed.not('action.isNew'),
|
groupPropertyTypes: selectKitContent(['id', 'name']),
|
||||||
|
hasAdvanced: or('hasCustomFields', 'routeTo'),
|
||||||
|
hasCustomFields: or('basicTopicFields', 'updateProfile'),
|
||||||
|
basicTopicFields: or('createTopic', 'sendMessage', 'openComposer'),
|
||||||
|
publicTopicFields: or('createTopic', 'openComposer'),
|
||||||
|
showSkipRedirect: or('createTopic', 'sendMessage'),
|
||||||
|
|
||||||
@computed('action.type')
|
@discourseComputed('wizard.steps')
|
||||||
basicTopicFields(actionType) {
|
runAfterContent(steps) {
|
||||||
return ['create_topic', 'send_message', 'open_composer'].indexOf(actionType) > -1;
|
let content = steps.map(function(step) {
|
||||||
|
return {
|
||||||
|
id: step.id,
|
||||||
|
name: step.title || step.id
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
content.unshift({
|
||||||
|
id: 'wizard_completion',
|
||||||
|
name: I18n.t('admin.wizard.action.run_after.wizard_completion')
|
||||||
|
});
|
||||||
|
|
||||||
|
return content;
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('action.type')
|
@discourseComputed('wizard.apis')
|
||||||
publicTopicFields(actionType) {
|
|
||||||
return ['create_topic', 'open_composer'].indexOf(actionType) > -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('action.type')
|
|
||||||
newTopicFields(actionType) {
|
|
||||||
return ['create_topic', 'send_message'].indexOf(actionType) > -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('availableFields')
|
|
||||||
builderWizardFields(fields) {
|
|
||||||
return fields.map((f) => ` w{${f.id}}`);
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('availableFields')
|
|
||||||
categoryFields(fields) {
|
|
||||||
return fields.filter(f => f.type == 'category');
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('availableFields')
|
|
||||||
tagFields(fields) {
|
|
||||||
return fields.filter(f => f.type == 'tag');
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed()
|
|
||||||
builderUserFields() {
|
|
||||||
const noTheme = PROFILE_FIELDS.filter((f) => f !== 'theme_id');
|
|
||||||
const fields = noTheme.concat(['email', 'username']);
|
|
||||||
return fields.map((f) => ` u{${f}}`);
|
|
||||||
},
|
|
||||||
|
|
||||||
@observes('action.custom_category_wizard_field')
|
|
||||||
toggleCustomCategoryUserField() {
|
|
||||||
const wizard = this.get('action.custom_category_wizard_field');
|
|
||||||
if (wizard) this.set('action.custom_category_user_field', false);
|
|
||||||
},
|
|
||||||
|
|
||||||
@observes('action.custom_category_user_field')
|
|
||||||
toggleCustomCategoryWizardField() {
|
|
||||||
const user = this.get('action.custom_category_user_field');
|
|
||||||
if (user) this.set('action.custom_category_wizard_field', false);
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('wizard.apis')
|
|
||||||
availableApis(apis) {
|
availableApis(apis) {
|
||||||
return apis.map(a => {
|
return apis.map(a => {
|
||||||
return {
|
return {
|
||||||
|
@ -96,7 +48,7 @@ export default Ember.Component.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('wizard.apis', 'action.api')
|
@discourseComputed('wizard.apis', 'action.api')
|
||||||
availableEndpoints(apis, api) {
|
availableEndpoints(apis, api) {
|
||||||
if (!api) return [];
|
if (!api) return [];
|
||||||
return apis.find(a => a.name === api).endpoints;
|
return apis.find(a => a.name === api).endpoints;
|
||||||
|
|
|
@ -1,47 +1,97 @@
|
||||||
import { default as computed, observes, on } from 'ember-addons/ember-computed-decorators';
|
import { default as discourseComputed, observes } from 'discourse-common/utils/decorators';
|
||||||
import { generateSelectKitContent } from '../lib/custom-wizard';
|
import { equal, or } from "@ember/object/computed";
|
||||||
|
import { selectKitContent, schema } from '../lib/wizard';
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Component.extend({
|
||||||
classNames: 'wizard-custom-field',
|
classNames: 'wizard-custom-field',
|
||||||
isDropdown: Ember.computed.equal('field.type', 'dropdown'),
|
isDropdown: equal('field.type', 'dropdown'),
|
||||||
isUpload: Ember.computed.equal('field.type', 'upload'),
|
isUpload: equal('field.type', 'upload'),
|
||||||
isCategory: Ember.computed.equal('field.type', 'category'),
|
isCategory: equal('field.type', 'category'),
|
||||||
disableId: Ember.computed.not('field.isNew'),
|
isGroup: equal('field.type', 'group'),
|
||||||
choicesTypes: generateSelectKitContent(['translation', 'preset', 'custom']),
|
isTag: equal('field.type', 'tag'),
|
||||||
choicesTranslation: Ember.computed.equal('field.choices_type', 'translation'),
|
isText: equal('field.type', 'text'),
|
||||||
choicesPreset: Ember.computed.equal('field.choices_type', 'preset'),
|
isTextarea: equal('field.type', 'textarea'),
|
||||||
choicesCustom: Ember.computed.equal('field.choices_type', 'custom'),
|
isUrl: equal('field.type', 'url'),
|
||||||
categoryPropertyTypes: generateSelectKitContent(['id', 'slug']),
|
showPrefill: or('isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
||||||
|
showContent: or('isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
||||||
|
showLimit: or('isCategory', 'isTag'),
|
||||||
|
showMinLength: or('isText', 'isTextarea', 'isUrl', 'isComposer'),
|
||||||
|
categoryPropertyTypes: selectKitContent(['id', 'slug']),
|
||||||
|
|
||||||
@computed('field.type')
|
// clearMapped only clears mapped fields if the field type of a specific field
|
||||||
isInput: (type) => type === 'text' || type === 'textarea' || type === 'url',
|
// changes, and not when switching between fields. Switching between fields also
|
||||||
|
// changes the field.type property in this component
|
||||||
|
|
||||||
@computed('field.type')
|
@observes('field.id', 'field.type')
|
||||||
isCategoryOrTag: (type) => type === 'tag' || type === 'category',
|
clearMapped(ctx, changed) {
|
||||||
|
if (this.field.id === this.bufferedFieldId) {
|
||||||
|
schema.field.mapped.forEach(property => {
|
||||||
|
this.set(`field.${property}`, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@computed()
|
if (changed === 'field.type') {
|
||||||
presetChoices() {
|
this.set('bufferedFieldId', this.field.id);
|
||||||
let presets = [
|
}
|
||||||
{
|
|
||||||
id: 'categories',
|
|
||||||
name: I18n.t('admin.wizard.field.choices_preset.categories')
|
|
||||||
},{
|
|
||||||
id: 'groups',
|
|
||||||
name: I18n.t('admin.wizard.field.choices_preset.groups')
|
|
||||||
},{
|
|
||||||
id: 'tags',
|
|
||||||
name: I18n.t('admin.wizard.field.choices_preset.tags')
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return presets;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@on('didInsertElement')
|
setupTypeOutput(fieldType, options) {
|
||||||
@observes('isUpload')
|
const selectionType = {
|
||||||
setupFileType() {
|
category: 'category',
|
||||||
if (this.get('isUpload') && !this.get('field.file_types')) {
|
tag: 'tag',
|
||||||
this.set('field.file_types', '.jpg,.png');
|
group: 'group'
|
||||||
|
}[fieldType];
|
||||||
|
|
||||||
|
if (selectionType) {
|
||||||
|
options[`${selectionType}Selection`] = 'output';
|
||||||
|
options.outputDefaultSelection = selectionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('field.type')
|
||||||
|
contentOptions(fieldType) {
|
||||||
|
let options = {
|
||||||
|
wizardFieldSelection: true,
|
||||||
|
textSelection: 'key,value',
|
||||||
|
userFieldSelection: 'key,value',
|
||||||
|
context: 'field'
|
||||||
|
}
|
||||||
|
|
||||||
|
options = this.setupTypeOutput(fieldType, options);
|
||||||
|
|
||||||
|
if (this.isDropdown) {
|
||||||
|
options.wizardFieldSelection = 'key,value';
|
||||||
|
options.inputTypes = 'association';
|
||||||
|
options.pairConnector = 'association';
|
||||||
|
options.keyPlaceholder = 'admin.wizard.key';
|
||||||
|
options.valuePlaceholder = 'admin.wizard.value';
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('field.type')
|
||||||
|
prefillOptions(fieldType) {
|
||||||
|
let options = {
|
||||||
|
wizardFieldSelection: true,
|
||||||
|
textSelection: true,
|
||||||
|
userFieldSelection: 'key,value',
|
||||||
|
context: 'field'
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.setupTypeOutput(fieldType, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
imageUploadDone(upload) {
|
||||||
|
this.set("field.image", upload.url);
|
||||||
|
},
|
||||||
|
|
||||||
|
imageUploadDeleted() {
|
||||||
|
this.set("field.image", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { default as computed, on } from 'ember-addons/ember-computed-decorators';
|
|
||||||
import { getOwner } from 'discourse-common/lib/get-owner';
|
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
classNames: 'custom-input',
|
|
||||||
noneKey: 'admin.wizard.select_field',
|
|
||||||
noneValue: 'admin.wizard.none',
|
|
||||||
connectorNone: 'admin.wizard.none',
|
|
||||||
inputKey: 'admin.wizard.key',
|
|
||||||
customDisabled: Ember.computed.alias('input.user_field'),
|
|
||||||
|
|
||||||
@computed('input.value_custom', 'input.user_field')
|
|
||||||
valueDisabled(custom, user) {
|
|
||||||
return Boolean(custom || user);
|
|
||||||
},
|
|
||||||
|
|
||||||
@on('init')
|
|
||||||
setupUserFields() {
|
|
||||||
const allowUserField = this.get('allowUserField');
|
|
||||||
if (allowUserField) {
|
|
||||||
const store = getOwner(this).lookup('store:main');
|
|
||||||
store.findAll('user-field').then((result) => {
|
|
||||||
if (result && result.content && result.content.length) {
|
|
||||||
this.set('userFields', result.content.map((f) => {
|
|
||||||
return {
|
|
||||||
id: `user_field_${f.id}`,
|
|
||||||
name: f.name
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,17 +0,0 @@
|
||||||
export default Ember.Component.extend({
|
|
||||||
classNames: 'custom-inputs',
|
|
||||||
valuePlaceholder: 'admin.wizard.value',
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
add() {
|
|
||||||
if (!this.get('inputs')) {
|
|
||||||
this.set('inputs', Ember.A());
|
|
||||||
}
|
|
||||||
this.get('inputs').pushObject(Ember.Object.create());
|
|
||||||
},
|
|
||||||
|
|
||||||
remove(input) {
|
|
||||||
this.get('inputs').removeObject(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,76 +1,22 @@
|
||||||
import { observes, default as computed } from 'ember-addons/ember-computed-decorators';
|
import Component from "@ember/component";
|
||||||
|
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||||
|
import { wizardFieldList } from '../lib/wizard';
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Component.extend({
|
||||||
classNames: 'wizard-custom-step',
|
classNames: 'wizard-custom-step',
|
||||||
currentField: null,
|
|
||||||
currentAction: null,
|
|
||||||
disableId: Ember.computed.not('step.isNew'),
|
|
||||||
|
|
||||||
@observes('step')
|
@discourseComputed('wizard.steps', 'step.id')
|
||||||
resetCurrentObjects() {
|
descriptionWizardFields(steps, stepId) {
|
||||||
const fields = this.get('step.fields');
|
return wizardFieldList(steps, { upTo: stepId });
|
||||||
const actions = this.get('step.actions');
|
|
||||||
this.setProperties({
|
|
||||||
currentField: fields.length ? fields[0] : null,
|
|
||||||
currentAction: actions.length ? actions[0] : null
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('availableFields', 'wizard.steps')
|
actions: {
|
||||||
requiredContent(availableFields, steps) {
|
bannerUploadDone(upload) {
|
||||||
let content = availableFields;
|
this.set("step.banner", upload.url);
|
||||||
let actions = [];
|
},
|
||||||
|
|
||||||
steps.forEach(s => {
|
bannerUploadDeleted() {
|
||||||
actions.push(...s.actions);
|
this.set("step.banner", null);
|
||||||
});
|
|
||||||
|
|
||||||
actions.forEach(a => {
|
|
||||||
if (a.type === 'route_to' && a.code) {
|
|
||||||
content.push(Ember.Object.create({
|
|
||||||
id: a.code,
|
|
||||||
label: "code (Route To)"
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return content;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed
|
|
||||||
requiredConnectorContent() {
|
|
||||||
const label = (id) => I18n.t(`admin.wizard.step.required_data.connector.${id}`);
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: 'equals',
|
|
||||||
label: label('equals')
|
|
||||||
}
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('step.id', '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,
|
|
||||||
label: `${f.id} (${s.id})`,
|
|
||||||
type: f.type
|
|
||||||
});
|
|
||||||
});
|
|
||||||
fields.push(...stepFields);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return fields;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
export default Ember.Component.extend({
|
import Component from "@ember/component";
|
||||||
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
classNames: ['container', 'export'],
|
classNames: ['container', 'export'],
|
||||||
selected: Ember.A(),
|
selected: A(),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
checkChanged(event) {
|
checkChanged(event) {
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import { ajax } from 'discourse/lib/ajax';
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||||
|
import { notEmpty } from "@ember/object/computed";
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Component.extend({
|
||||||
classNames: ['container', 'import'],
|
classNames: ['container', 'import'],
|
||||||
hasLogs: Ember.computed.notEmpty('logs'),
|
hasLogs: notEmpty('logs'),
|
||||||
|
|
||||||
@computed('successIds', 'failureIds')
|
@discourseComputed('successIds', 'failureIds')
|
||||||
logs(successIds, failureIds) {
|
logs(successIds, failureIds) {
|
||||||
let logs = [];
|
let logs = [];
|
||||||
|
|
||||||
|
|
|
@ -1,86 +1,140 @@
|
||||||
import { default as computed, on, observes } from 'ember-addons/ember-computed-decorators';
|
import { default as discourseComputed, on, observes } from 'discourse-common/utils/decorators';
|
||||||
|
import { generateName, schema } from '../lib/wizard';
|
||||||
|
import { notEmpty } from "@ember/object/computed";
|
||||||
|
import { scheduleOnce, bind } from "@ember/runloop";
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Component.extend({
|
||||||
classNames: 'wizard-links',
|
classNameBindings: [':wizard-links', 'itemType'],
|
||||||
items: Ember.A(),
|
items: A(),
|
||||||
|
anyLinks: notEmpty('links'),
|
||||||
|
|
||||||
@on('didInsertElement')
|
@on('didInsertElement')
|
||||||
@observes('links.@each')
|
@observes('links.@each')
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
Ember.run.scheduleOnce('afterRender', () => {
|
scheduleOnce('afterRender', () => (this.applySortable()));
|
||||||
this.applySortable();
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
applySortable() {
|
applySortable() {
|
||||||
this.$("ul").sortable({tolerance: 'pointer'}).on('sortupdate', (e, ui) => {
|
$(this.element).find("ul")
|
||||||
const itemId = ui.item.data('id');
|
.sortable({ tolerance: 'pointer' })
|
||||||
const index = ui.item.index();
|
.on('sortupdate', (e, ui) => {
|
||||||
Ember.run.bind(this, this.updateItemOrder(itemId, index));
|
this.updateItemOrder(ui.item.data('id'), ui.item.index());
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateItemOrder(itemId, newIndex) {
|
updateItemOrder(itemId, newIndex) {
|
||||||
const items = this.get('items');
|
const items = this.items;
|
||||||
const item = items.findBy('id', itemId);
|
const item = items.findBy('id', itemId);
|
||||||
items.removeObject(item);
|
items.removeObject(item);
|
||||||
items.insertAt(newIndex, item);
|
items.insertAt(newIndex, item);
|
||||||
Ember.run.scheduleOnce('afterRender', this, () => this.applySortable());
|
scheduleOnce('afterRender', this, () => this.applySortable());
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('type')
|
@discourseComputed('itemType')
|
||||||
header: (type) => `admin.wizard.${type}.header`,
|
header: (itemType) => `admin.wizard.${itemType}.header`,
|
||||||
|
|
||||||
@computed('items.@each.id', 'current')
|
@discourseComputed('current', 'items.@each.id', 'items.@each.type', 'items.@each.label', 'items.@each.title')
|
||||||
links(items, current) {
|
links(current, items) {
|
||||||
if (!items) return;
|
if (!items) return;
|
||||||
|
|
||||||
return items.map((item) => {
|
return items.map((item) => {
|
||||||
if (item) {
|
if (item) {
|
||||||
const id = item.get('id');
|
let link = {
|
||||||
const type = this.get('type');
|
id: item.id
|
||||||
const label = type === 'action' ? id : (item.get('label') || item.get('title') || id);
|
}
|
||||||
let link = { id, label };
|
|
||||||
|
let label = item.label || item.title || item.id;
|
||||||
|
if (this.generateLabels && item.type) {
|
||||||
|
label = generateName(item.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
link.label = `${label} (${item.id})`;
|
||||||
|
|
||||||
let classes = 'btn';
|
let classes = 'btn';
|
||||||
if (current && item.get('id') === current.get('id')) {
|
if (current && item.id === current.id) {
|
||||||
classes += ' btn-primary';
|
classes += ' btn-primary';
|
||||||
};
|
};
|
||||||
|
|
||||||
link['classes'] = classes;
|
link.classes = classes;
|
||||||
|
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setDefaults(object, params) {
|
||||||
|
Object.keys(object).forEach(property => {
|
||||||
|
if (object[property]) {
|
||||||
|
params[property] = object[property];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return params;
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
add() {
|
add() {
|
||||||
const items = this.get('items');
|
const items = this.items;
|
||||||
const type = this.get('type');
|
const itemType = this.itemType;
|
||||||
const newId = `${type}_${items.length + 1}`;
|
let next = 1;
|
||||||
let params = { id: newId, isNew: true };
|
|
||||||
|
|
||||||
if (type === 'step') {
|
if (items.length) {
|
||||||
params['fields'] = Ember.A();
|
next = Math.max.apply(Math, items.map((i) => (i.id.split('_')[1]))) + 1;
|
||||||
params['actions'] = Ember.A();
|
}
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
id: `${itemType}_${next}`,
|
||||||
|
isNew: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const newItem = Ember.Object.create(params);
|
let objectArrays = schema[itemType].objectArrays;
|
||||||
|
if (objectArrays) {
|
||||||
|
Object.keys(objectArrays).forEach(objectType => {
|
||||||
|
params[objectArrays[objectType].property] = A();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
params = this.setDefaults(schema[itemType].basic, params);
|
||||||
|
|
||||||
|
let types = schema[itemType].types;
|
||||||
|
if (types && params.type) {
|
||||||
|
params = this.setDefaults(types[params.type], params);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newItem = EmberObject.create(params);
|
||||||
items.pushObject(newItem);
|
items.pushObject(newItem);
|
||||||
|
|
||||||
this.set('current', newItem);
|
this.set('current', newItem);
|
||||||
this.sendAction('isNew');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
change(itemId) {
|
change(itemId) {
|
||||||
const items = this.get('items');
|
this.set('current', this.items.findBy('id', itemId));
|
||||||
this.set('current', items.findBy('id', itemId));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
remove(itemId) {
|
remove(itemId) {
|
||||||
const items = this.get('items');
|
const items = this.items;
|
||||||
items.removeObject(items.findBy('id', itemId));
|
let item;
|
||||||
this.set('current', items[items.length - 1]);
|
let index;
|
||||||
|
|
||||||
|
items.forEach((it, ind) => {
|
||||||
|
if (it.id === itemId) {
|
||||||
|
item = it;
|
||||||
|
index = ind;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let nextIndex;
|
||||||
|
if (this.current.id === itemId) {
|
||||||
|
nextIndex = index < (items.length-2) ? (index+1) : (index-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
items.removeObject(item);
|
||||||
|
|
||||||
|
if (nextIndex) {
|
||||||
|
this.set('current', items[nextIndex]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { gt } from '@ember/object/computed';
|
||||||
|
import { computed } from "@ember/object";
|
||||||
|
import { defaultConnector } from '../lib/wizard-mapper';
|
||||||
|
import { later } from "@ember/runloop";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNameBindings: [':mapper-connector', ':mapper-block', 'hasMultiple::single'],
|
||||||
|
hasMultiple: gt('connectors.length', 1),
|
||||||
|
connectorLabel: computed(function() {
|
||||||
|
let key = this.connector;
|
||||||
|
let path = this.inputTypes ? `input.${key}.name` : `connector.${key}`;
|
||||||
|
return I18n.t(`admin.wizard.${path}`);
|
||||||
|
}),
|
||||||
|
|
||||||
|
didReceiveAttrs() {
|
||||||
|
if (!this.connector) {
|
||||||
|
later(() => {
|
||||||
|
this.set(
|
||||||
|
'connector',
|
||||||
|
defaultConnector(this.connectorType, this.inputType, this.options)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
65
assets/javascripts/discourse/components/wizard-mapper-input.js.es6
Normale Datei
65
assets/javascripts/discourse/components/wizard-mapper-input.js.es6
Normale Datei
|
@ -0,0 +1,65 @@
|
||||||
|
import { computed, set } from "@ember/object";
|
||||||
|
import { alias, equal, or, not } from "@ember/object/computed";
|
||||||
|
import { newPair, connectorContent, inputTypesContent, defaultSelectionType, defaultConnector } from '../lib/wizard-mapper';
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { observes } from "discourse-common/utils/decorators";
|
||||||
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNameBindings: [':mapper-input', 'inputType'],
|
||||||
|
inputType: alias('input.type'),
|
||||||
|
isConditional: equal('inputType', 'conditional'),
|
||||||
|
isAssignment: equal('inputType', 'assignment'),
|
||||||
|
isAssociation: equal('inputType', 'association'),
|
||||||
|
isValidation: equal('inputType', 'validation'),
|
||||||
|
hasOutput: or('isConditional', 'isAssignment'),
|
||||||
|
hasPairs: or('isConditional', 'isAssociation', 'isValidation'),
|
||||||
|
canAddPair: not('isAssignment'),
|
||||||
|
connectors: computed(function() { return connectorContent('output', this.input.type, this.options) }),
|
||||||
|
inputTypes: computed(function() { return inputTypesContent(this.options) }),
|
||||||
|
|
||||||
|
@observes('input.type')
|
||||||
|
setupType() {
|
||||||
|
if (this.hasPairs && (!this.input.pairs || this.input.pairs.length < 1)) {
|
||||||
|
this.send('addPair');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hasOutput && !this.input.outputConnector) {
|
||||||
|
const options = this.options;
|
||||||
|
this.set('input.output_type', defaultSelectionType('output', options));
|
||||||
|
this.set('input.output_connector', defaultConnector('output', this.inputType, options));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
addPair() {
|
||||||
|
if (!this.input.pairs) {
|
||||||
|
this.set('input.pairs', A());
|
||||||
|
}
|
||||||
|
|
||||||
|
const pairs = this.input.pairs;
|
||||||
|
const pairCount = pairs.length + 1;
|
||||||
|
|
||||||
|
pairs.forEach(p => (set(p, 'pairCount', pairCount)));
|
||||||
|
|
||||||
|
pairs.pushObject(
|
||||||
|
newPair(
|
||||||
|
this.input.type,
|
||||||
|
Object.assign(
|
||||||
|
{},
|
||||||
|
this.options,
|
||||||
|
{ index: pairs.length, pairCount }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
removePair(pair) {
|
||||||
|
const pairs = this.input.pairs;
|
||||||
|
const pairCount = pairs.length - 1;
|
||||||
|
|
||||||
|
pairs.forEach(p => (set(p, 'pairCount', pairCount)));
|
||||||
|
pairs.removeObject(pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
12
assets/javascripts/discourse/components/wizard-mapper-pair.js.es6
Normale Datei
12
assets/javascripts/discourse/components/wizard-mapper-pair.js.es6
Normale Datei
|
@ -0,0 +1,12 @@
|
||||||
|
import { connectorContent } from '../lib/wizard-mapper';
|
||||||
|
import { gt, or, alias } from "@ember/object/computed";
|
||||||
|
import { computed, observes } from "@ember/object";
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNameBindings: [':mapper-pair', 'hasConnector::no-connector'],
|
||||||
|
firstPair: gt('pair.index', 0),
|
||||||
|
showRemove: alias('firstPair'),
|
||||||
|
showJoin: computed('pair.pairCount', function() { return this.pair.index < (this.pair.pairCount - 1) }),
|
||||||
|
connectors: computed(function() { return connectorContent('pair', this.inputType, this.options) })
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
import discourseComputed from 'discourse-common/utils/decorators';
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
tagName: 'a',
|
||||||
|
classNameBindings: ['active'],
|
||||||
|
|
||||||
|
@discourseComputed('item.type', 'activeType')
|
||||||
|
active(type, activeType) { return type === activeType },
|
||||||
|
|
||||||
|
click() {
|
||||||
|
this.toggle(this.item.type)
|
||||||
|
}
|
||||||
|
})
|
162
assets/javascripts/discourse/components/wizard-mapper-selector.js.es6
Normale Datei
162
assets/javascripts/discourse/components/wizard-mapper-selector.js.es6
Normale Datei
|
@ -0,0 +1,162 @@
|
||||||
|
import { alias, or, gt } from "@ember/object/computed";
|
||||||
|
import { computed } from "@ember/object";
|
||||||
|
import { default as discourseComputed, observes, on } from "discourse-common/utils/decorators";
|
||||||
|
import { getOwner } from 'discourse-common/lib/get-owner';
|
||||||
|
import { defaultSelectionType, selectionTypes } from '../lib/wizard-mapper';
|
||||||
|
import { snakeCase } from '../lib/wizard';
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { bind, later } from "@ember/runloop";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNameBindings: [':mapper-selector', 'activeType'],
|
||||||
|
groups: alias('site.groups'),
|
||||||
|
categories: alias('site.categories'),
|
||||||
|
showText: computed('activeType', function() { return this.showInput('text') }),
|
||||||
|
showWizardField: computed('activeType', function() { return this.showInput('wizardField') }),
|
||||||
|
showUserField: computed('activeType', function() { return this.showInput('userField') }),
|
||||||
|
showCategory: computed('activeType', function() { return this.showInput('category') }),
|
||||||
|
showTag: computed('activeType', function() { return this.showInput('tag') }),
|
||||||
|
showGroup: computed('activeType', function() { return this.showInput('group') }),
|
||||||
|
showUser: computed('activeType', function() { return this.showInput('user') }),
|
||||||
|
showList: computed('activeType', function() { return this.showInput('list') }),
|
||||||
|
showComboBox: or('showWizardField', 'showUserField'),
|
||||||
|
showMultiSelect: or('showCategory', 'showGroup'),
|
||||||
|
textEnabled: computed('options.textSelection', 'inputType', function() { return this.optionEnabled('textSelection') }),
|
||||||
|
wizardFieldEnabled: computed('options.wizardFieldSelection', 'inputType', function() { return this.optionEnabled('wizardFieldSelection') }),
|
||||||
|
userFieldEnabled: computed('options.userFieldSelection', 'inputType', function() { return this.optionEnabled('userFieldSelection') }),
|
||||||
|
categoryEnabled: computed('options.categorySelection', 'inputType', function() { return this.optionEnabled('categorySelection') }),
|
||||||
|
tagEnabled: computed('options.tagSelection', 'inputType', function() { return this.optionEnabled('tagSelection') }),
|
||||||
|
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() {
|
||||||
|
if (this.activeType && !this[`${this.activeType}Enabled`]) {
|
||||||
|
later(() => this.resetActiveType());
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click", bind(this, this.documentClick));
|
||||||
|
},
|
||||||
|
|
||||||
|
willDestroyElement() {
|
||||||
|
$(document).off("click", bind(this, this.documentClick));
|
||||||
|
},
|
||||||
|
|
||||||
|
documentClick(e) {
|
||||||
|
if (this._state == "destroying") return;
|
||||||
|
let $target = $(e.target);
|
||||||
|
|
||||||
|
if (!$target.parents('.type-selector').length && this.showTypes) {
|
||||||
|
this.set('showTypes', false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed
|
||||||
|
selectorTypes() {
|
||||||
|
return selectionTypes.filter(type => (this[`${type}Enabled`]))
|
||||||
|
.map(type => ({ type, label: this.typeLabel(type) }));
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('activeType')
|
||||||
|
activeTypeLabel(activeType) {
|
||||||
|
return this.typeLabel(activeType);
|
||||||
|
},
|
||||||
|
|
||||||
|
typeLabel(type) {
|
||||||
|
return I18n.t(`admin.wizard.selector.label.${snakeCase(type)}`)
|
||||||
|
},
|
||||||
|
|
||||||
|
@observes('inputType')
|
||||||
|
resetActiveType() {
|
||||||
|
this.set('activeType', defaultSelectionType(this.selectorType, this.options));
|
||||||
|
},
|
||||||
|
|
||||||
|
@observes('activeType')
|
||||||
|
clearValue() {
|
||||||
|
this.set('value', null);
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('activeType')
|
||||||
|
comboBoxContent(activeType) {
|
||||||
|
const controller = getOwner(this).lookup('controller:admin-wizards-wizard-show');
|
||||||
|
let content = controller[`${activeType}s`];
|
||||||
|
|
||||||
|
// you can't select the current field in the field context
|
||||||
|
if (activeType === 'wizardField' && this.options.context === 'field') {
|
||||||
|
content = content.filter(field => field.id !== controller.currentField.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// updating certain user fields via the profile update action is not supported
|
||||||
|
if (activeType === 'userField' &&
|
||||||
|
this.options.context === 'action' &&
|
||||||
|
this.inputType === 'association' &&
|
||||||
|
this.selectorType === 'key') {
|
||||||
|
|
||||||
|
const excludedFields = ['username','email', 'trust_level'];
|
||||||
|
content = content.filter(userField => excludedFields.indexOf(userField.id) === -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('activeType')
|
||||||
|
multiSelectContent(activeType) {
|
||||||
|
return {
|
||||||
|
category: this.categories,
|
||||||
|
group: this.groups,
|
||||||
|
list: ''
|
||||||
|
}[activeType];
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('activeType', 'inputType')
|
||||||
|
placeholderKey(activeType, inputType) {
|
||||||
|
if (activeType === 'text' && this.options[`${this.selectorType}Placeholder`]) {
|
||||||
|
return this.options[`${this.selectorType}Placeholder`];
|
||||||
|
} else {
|
||||||
|
return `admin.wizard.selector.placeholder.${snakeCase(activeType)}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('activeType')
|
||||||
|
multiSelectOptions(activeType) {
|
||||||
|
let result = {
|
||||||
|
none: this.placeholderKey
|
||||||
|
};
|
||||||
|
|
||||||
|
if (activeType === 'list') {
|
||||||
|
result.allowAny = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
optionEnabled(type) {
|
||||||
|
const options = this.options;
|
||||||
|
if (!options) return false;
|
||||||
|
|
||||||
|
const option = options[type];
|
||||||
|
if (option === true) return true;
|
||||||
|
if (typeof option !== 'string') return false;
|
||||||
|
|
||||||
|
return option.split(',').filter(option => {
|
||||||
|
return [this.selectorType, this.inputType].indexOf(option) !== -1;
|
||||||
|
}).length;
|
||||||
|
},
|
||||||
|
|
||||||
|
showInput(type) {
|
||||||
|
return this.activeType === type && this[`${type}Enabled`];
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
toggleType(type) {
|
||||||
|
this.set('activeType', type);
|
||||||
|
this.set('showTypes', false);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleTypes() {
|
||||||
|
this.toggleProperty('showTypes');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
73
assets/javascripts/discourse/components/wizard-mapper.js.es6
Normale Datei
73
assets/javascripts/discourse/components/wizard-mapper.js.es6
Normale Datei
|
@ -0,0 +1,73 @@
|
||||||
|
import { getOwner } from 'discourse-common/lib/get-owner';
|
||||||
|
import { newInput, selectionTypes } from '../lib/wizard-mapper';
|
||||||
|
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
|
||||||
|
import { later } from "@ember/runloop";
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNames: 'wizard-mapper',
|
||||||
|
|
||||||
|
didReceiveAttrs() {
|
||||||
|
if (this.inputs && this.inputs.constructor !== Array) {
|
||||||
|
later(() => this.set('inputs', null));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('inputs.@each.type')
|
||||||
|
canAdd(inputs) {
|
||||||
|
return !inputs ||
|
||||||
|
inputs.constructor !== Array ||
|
||||||
|
inputs.every(i => {
|
||||||
|
return ['assignment','association'].indexOf(i.type) === -1;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('options.@each.inputType')
|
||||||
|
inputOptions(options) {
|
||||||
|
let result = {
|
||||||
|
inputTypes: options.inputTypes || 'assignment,conditional',
|
||||||
|
inputConnector: options.inputConnector || 'or',
|
||||||
|
pairConnector: options.pairConnector || 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;
|
||||||
|
});
|
||||||
|
|
||||||
|
selectionTypes.forEach(type => {
|
||||||
|
if (options[`${type}Selection`] !== undefined) {
|
||||||
|
result[`${type}Selection`] = options[`${type}Selection`]
|
||||||
|
} else {
|
||||||
|
result[`${type}Selection`] = type === 'text' ? true : false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
add() {
|
||||||
|
if (!this.get('inputs')) {
|
||||||
|
this.set('inputs', A());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.get('inputs').pushObject(
|
||||||
|
newInput(this.inputOptions, this.inputs.length)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
remove(input) {
|
||||||
|
const inputs = this.inputs;
|
||||||
|
inputs.removeObject(input);
|
||||||
|
|
||||||
|
if (inputs.length) {
|
||||||
|
inputs[0].set('connector', null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
57
assets/javascripts/discourse/components/wizard-text-editor.js.es6
Normale Datei
57
assets/javascripts/discourse/components/wizard-text-editor.js.es6
Normale Datei
|
@ -0,0 +1,57 @@
|
||||||
|
import { default as discourseComputed, on } from 'discourse-common/utils/decorators';
|
||||||
|
import { notEmpty } from "@ember/object/computed";
|
||||||
|
import { userProperties } from '../lib/wizard';
|
||||||
|
import { scheduleOnce } from "@ember/runloop";
|
||||||
|
import Component from "@ember/component";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
classNames: 'wizard-text-editor',
|
||||||
|
barEnabled: true,
|
||||||
|
previewEnabled: true,
|
||||||
|
fieldsEnabled: true,
|
||||||
|
hasWizardFields: notEmpty('wizardFieldList'),
|
||||||
|
|
||||||
|
didReceiveAttrs() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
if (!this.barEnabled) {
|
||||||
|
scheduleOnce('afterRender', () => {
|
||||||
|
$(this.element).find('.d-editor-button-bar').addClass('hidden');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('forcePreview')
|
||||||
|
previewLabel(forcePreview) {
|
||||||
|
return I18n.t("admin.wizard.editor.preview", {
|
||||||
|
action: I18n.t(`admin.wizard.editor.${forcePreview ? 'hide' : 'show'}`)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('showPopover')
|
||||||
|
popoverLabel(showPopover) {
|
||||||
|
return I18n.t("admin.wizard.editor.popover", {
|
||||||
|
action: I18n.t(`admin.wizard.editor.${showPopover ? 'hide' : 'show'}`)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed()
|
||||||
|
userFieldList() {
|
||||||
|
return userProperties.map((f) => ` u{${f}}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('wizardFields')
|
||||||
|
wizardFieldList(wizardFields) {
|
||||||
|
return wizardFields.map((f) => ` w{${f.id}}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
togglePreview() {
|
||||||
|
this.toggleProperty('forcePreview');
|
||||||
|
},
|
||||||
|
|
||||||
|
togglePopover() {
|
||||||
|
this.toggleProperty('showPopover');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,3 +1,3 @@
|
||||||
{{#if currentUser.admin}}
|
{{#if currentUser.admin}}
|
||||||
{{nav-item route='adminWizards' label='admin.wizard.label'}}
|
{{nav-item route='adminWizards' label='admin.wizard.nav_label'}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{{#each site.complete_custom_wizard as |wizard|}}
|
||||||
|
<div class='row'>
|
||||||
|
<div class='alert alert-info alert-wizard'>
|
||||||
|
<a href="{{wizard.url}}">{{i18n 'wizard.complete_custom' name=wizard.name}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
shouldRender(_, ctx) {
|
||||||
|
return ctx.siteSettings.custom_wizard_enabled &&
|
||||||
|
ctx.site.complete_custom_wizard;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
|
||||||
import showModal from 'discourse/lib/show-modal';
|
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
|
||||||
@computed('model.id', 'model.name')
|
|
||||||
wizardUrl(wizardId) {
|
|
||||||
return window.location.origin + '/w/' + Ember.String.dasherize(wizardId);
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('model.after_time_scheduled')
|
|
||||||
nextSessionScheduledLabel(scheduled) {
|
|
||||||
return scheduled ? moment(scheduled).format('MMMM Do, HH:mm') :
|
|
||||||
I18n.t('admin.wizard.after_time_time_label');
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
save() {
|
|
||||||
this.setProperties({
|
|
||||||
saving: true,
|
|
||||||
error: null
|
|
||||||
});
|
|
||||||
const wizard = this.get('model');
|
|
||||||
wizard.save().then(() => {
|
|
||||||
this.set('saving', false);
|
|
||||||
if (this.get('newWizard')) {
|
|
||||||
this.send("refreshAllWizards");
|
|
||||||
} else {
|
|
||||||
this.send("refreshWizard");
|
|
||||||
}
|
|
||||||
}).catch((result) => {
|
|
||||||
this.set('saving', false);
|
|
||||||
this.set('error', I18n.t(`admin.wizard.error.${result.error}`));
|
|
||||||
Ember.run.later(() => this.set('error', null), 10000);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
remove() {
|
|
||||||
const wizard = this.get('model');
|
|
||||||
wizard.remove().then(() => {
|
|
||||||
this.send("refreshAllWizards");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setNextSessionScheduled() {
|
|
||||||
let controller = showModal('next-session-scheduled', {
|
|
||||||
model: {
|
|
||||||
dateTime: this.get('model.after_time_scheduled'),
|
|
||||||
update: (dateTime) => this.set('model.after_time_scheduled', dateTime)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
controller.setup();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,42 +1,44 @@
|
||||||
import { ajax } from 'discourse/lib/ajax';
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import CustomWizardApi from '../models/custom-wizard-api';
|
import CustomWizardApi from '../models/custom-wizard-api';
|
||||||
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||||
import { generateSelectKitContent } from '../lib/custom-wizard';
|
import { not, and, equal } from "@ember/object/computed";
|
||||||
|
import { selectKitContent } from '../lib/wizard';
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Controller.extend({
|
||||||
queryParams: ['refresh_list'],
|
queryParams: ['refresh_list'],
|
||||||
loadingSubscriptions: false,
|
loadingSubscriptions: false,
|
||||||
notAuthorized: Ember.computed.not('api.authorized'),
|
notAuthorized: not('api.authorized'),
|
||||||
endpointMethods: generateSelectKitContent(['GET', 'PUT', 'POST', 'PATCH', 'DELETE']),
|
endpointMethods: selectKitContent(['GET', 'PUT', 'POST', 'PATCH', 'DELETE']),
|
||||||
showRemove: Ember.computed.not('isNew'),
|
showRemove: not('isNew'),
|
||||||
showRedirectUri: Ember.computed.and('threeLeggedOauth', 'api.name'),
|
showRedirectUri: and('threeLeggedOauth', 'api.name'),
|
||||||
responseIcon: null,
|
responseIcon: null,
|
||||||
contentTypes: generateSelectKitContent(['application/json', 'application/x-www-form-urlencoded']),
|
contentTypes: selectKitContent(['application/json', 'application/x-www-form-urlencoded']),
|
||||||
successCodes: generateSelectKitContent([100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 303, 304, 305, 306, 307, 308]),
|
successCodes: selectKitContent([100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 303, 304, 305, 306, 307, 308]),
|
||||||
|
|
||||||
@computed('saveDisabled', 'api.authType', 'api.authUrl', 'api.tokenUrl', 'api.clientId', 'api.clientSecret', 'threeLeggedOauth')
|
@discourseComputed('saveDisabled', 'api.authType', 'api.authUrl', 'api.tokenUrl', 'api.clientId', 'api.clientSecret', 'threeLeggedOauth')
|
||||||
authDisabled(saveDisabled, authType, authUrl, tokenUrl, clientId, clientSecret, threeLeggedOauth) {
|
authDisabled(saveDisabled, authType, authUrl, tokenUrl, clientId, clientSecret, threeLeggedOauth) {
|
||||||
if (saveDisabled || !authType || !tokenUrl || !clientId || !clientSecret) return true;
|
if (saveDisabled || !authType || !tokenUrl || !clientId || !clientSecret) return true;
|
||||||
if (threeLeggedOauth) return !authUrl;
|
if (threeLeggedOauth) return !authUrl;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('api.name', 'api.authType')
|
@discourseComputed('api.name', 'api.authType')
|
||||||
saveDisabled(name, authType) {
|
saveDisabled(name, authType) {
|
||||||
return !name || !authType;
|
return !name || !authType;
|
||||||
},
|
},
|
||||||
|
|
||||||
authorizationTypes: generateSelectKitContent(['none', 'basic', 'oauth_2', 'oauth_3']),
|
authorizationTypes: selectKitContent(['none', 'basic', 'oauth_2', 'oauth_3']),
|
||||||
isBasicAuth: Ember.computed.equal('api.authType', 'basic'),
|
isBasicAuth: equal('api.authType', 'basic'),
|
||||||
|
|
||||||
@computed('api.authType')
|
@discourseComputed('api.authType')
|
||||||
isOauth(authType) {
|
isOauth(authType) {
|
||||||
return authType && authType.indexOf('oauth') > -1;
|
return authType && authType.indexOf('oauth') > -1;
|
||||||
},
|
},
|
||||||
|
|
||||||
twoLeggedOauth: Ember.computed.equal('api.authType', 'oauth_2'),
|
twoLeggedOauth: equal('api.authType', 'oauth_2'),
|
||||||
threeLeggedOauth: Ember.computed.equal('api.authType', 'oauth_3'),
|
threeLeggedOauth: equal('api.authType', 'oauth_3'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
addParam() {
|
addParam() {
|
|
@ -1,3 +0,0 @@
|
||||||
export default Ember.Controller.extend({
|
|
||||||
queryParams: ['refresh']
|
|
||||||
});
|
|
49
assets/javascripts/discourse/controllers/admin-wizards-logs.js.es6
Normale Datei
49
assets/javascripts/discourse/controllers/admin-wizards-logs.js.es6
Normale Datei
|
@ -0,0 +1,49 @@
|
||||||
|
import { default as computed } from 'discourse-common/utils/decorators';
|
||||||
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
import { notEmpty } from "@ember/object/computed";
|
||||||
|
import CustomWizardLogs from '../models/custom-wizard-logs';
|
||||||
|
|
||||||
|
export default Ember.Controller.extend({
|
||||||
|
refreshing: false,
|
||||||
|
hasLogs: notEmpty("logs"),
|
||||||
|
page: 0,
|
||||||
|
canLoadMore: true,
|
||||||
|
logs: [],
|
||||||
|
|
||||||
|
loadLogs() {
|
||||||
|
if (!this.canLoadMore) return;
|
||||||
|
|
||||||
|
this.set("refreshing", true);
|
||||||
|
|
||||||
|
CustomWizardLogs.list()
|
||||||
|
.then(result => {
|
||||||
|
if (!result || result.length === 0) {
|
||||||
|
this.set('canLoadMore', false);
|
||||||
|
}
|
||||||
|
this.set("logs", this.logs.concat(result));
|
||||||
|
})
|
||||||
|
.finally(() => this.set("refreshing", false));
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed('hasLogs', 'refreshing')
|
||||||
|
noResults(hasLogs, refreshing) {
|
||||||
|
return !hasLogs && !refreshing;
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
loadMore() {
|
||||||
|
this.set('page', this.page += 1);
|
||||||
|
this.loadLogs();
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.setProperties({
|
||||||
|
canLoadMore: true,
|
||||||
|
page: 0,
|
||||||
|
logs: []
|
||||||
|
})
|
||||||
|
this.loadLogs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
import { fmt } from "discourse/lib/computed";
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
downloadUrl: fmt("wizard.id", "/admin/wizards/submissions/%@/download")
|
||||||
|
});
|
|
@ -1 +1,3 @@
|
||||||
export default Ember.Controller.extend();
|
import Controller from "@ember/controller";
|
||||||
|
|
||||||
|
export default Controller.extend();
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
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, wizardFieldList } from '../lib/wizard';
|
||||||
|
import { buildProperties } from '../lib/wizard-json';
|
||||||
|
import { dasherize } from "@ember/string";
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
import { scheduleOnce, later } from "@ember/runloop";
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
import copyText from "discourse/lib/copy-text";
|
||||||
|
import CustomWizard from '../models/custom-wizard';
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
hasName: notEmpty('wizard.name'),
|
||||||
|
|
||||||
|
@observes('currentStep')
|
||||||
|
resetCurrentObjects() {
|
||||||
|
const currentStep = this.currentStep;
|
||||||
|
|
||||||
|
if (currentStep) {
|
||||||
|
const fields = currentStep.fields;
|
||||||
|
this.set('currentField', fields && fields.length ? fields[0] : null)
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleOnce('afterRender', () => ($("body").addClass('admin-wizard')));
|
||||||
|
},
|
||||||
|
|
||||||
|
@observes('wizard.name')
|
||||||
|
setId() {
|
||||||
|
const wizard = this.wizard;
|
||||||
|
if (wizard && !wizard.existingId) {
|
||||||
|
this.set('wizard.id', generateId(wizard.name));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('wizard.id')
|
||||||
|
wizardUrl(wizardId) {
|
||||||
|
return window.location.origin + '/w/' + dasherize(wizardId);
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('wizard.after_time_scheduled')
|
||||||
|
nextSessionScheduledLabel(scheduled) {
|
||||||
|
return scheduled ?
|
||||||
|
moment(scheduled).format('MMMM Do, HH:mm') :
|
||||||
|
I18n.t('admin.wizard.after_time_time_label');
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('currentStep.id', 'wizard.save_submissions', 'wizard.steps.@each.fields[]')
|
||||||
|
wizardFields(currentStepId, saveSubmissions) {
|
||||||
|
let steps = this.wizard.steps;
|
||||||
|
if (!saveSubmissions) {
|
||||||
|
steps = [steps.findBy('id', currentStepId)];
|
||||||
|
}
|
||||||
|
return wizardFieldList(steps);
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
save() {
|
||||||
|
this.setProperties({
|
||||||
|
saving: true,
|
||||||
|
error: null
|
||||||
|
});
|
||||||
|
|
||||||
|
const wizard = this.wizard;
|
||||||
|
const creating = this.creating;
|
||||||
|
let opts = {};
|
||||||
|
|
||||||
|
if (creating) {
|
||||||
|
opts.create = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wizard.save(opts).then((result) => {
|
||||||
|
this.send('afterSave', result.wizard_id);
|
||||||
|
}).catch((result) => {
|
||||||
|
let errorType = 'failed';
|
||||||
|
let errorParams = {};
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
errorType = result.error.type;
|
||||||
|
errorParams = result.error.params;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set('error', I18n.t(`admin.wizard.error.${errorType}`, errorParams));
|
||||||
|
|
||||||
|
later(() => this.set('error', null), 10000);
|
||||||
|
}).finally(() => this.set('saving', false));
|
||||||
|
},
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
this.wizard.remove().then(() => this.send('afterDestroy'));
|
||||||
|
},
|
||||||
|
|
||||||
|
setNextSessionScheduled() {
|
||||||
|
let controller = showModal('next-session-scheduled', {
|
||||||
|
model: {
|
||||||
|
dateTime: this.wizard.after_time_scheduled,
|
||||||
|
update: (dateTime) => this.set('wizard.after_time_scheduled', dateTime)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
controller.setup();
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleAdvanced() {
|
||||||
|
this.toggleProperty('wizard.showAdvanced');
|
||||||
|
},
|
||||||
|
|
||||||
|
copyUrl() {
|
||||||
|
const $copyRange = $('<p id="copy-range"></p>');
|
||||||
|
$copyRange.html(this.wizardUrl);
|
||||||
|
|
||||||
|
$(document.body).append($copyRange);
|
||||||
|
|
||||||
|
if (copyText(this.wizardUrl, $copyRange[0])) {
|
||||||
|
this.set("copiedUrl", true);
|
||||||
|
later(() => this.set("copiedUrl", false), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
$copyRange.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
25
assets/javascripts/discourse/controllers/admin-wizards-wizard.js.es6
Normale Datei
25
assets/javascripts/discourse/controllers/admin-wizards-wizard.js.es6
Normale Datei
|
@ -0,0 +1,25 @@
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||||
|
import { equal } from '@ember/object/computed';
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
creating: equal('wizardId', 'create'),
|
||||||
|
|
||||||
|
@discourseComputed('creating', 'wizardId')
|
||||||
|
wizardListVal(creating, wizardId) {
|
||||||
|
return creating ? null : wizardId;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed('creating', 'wizardId')
|
||||||
|
message(creating, wizardId) {
|
||||||
|
let type = 'select';
|
||||||
|
|
||||||
|
if (creating) {
|
||||||
|
type = 'create';
|
||||||
|
} else if (wizardId) {
|
||||||
|
type = 'edit';
|
||||||
|
}
|
||||||
|
|
||||||
|
return I18n.t(`admin.wizard.message.${type}`);
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,6 +1,8 @@
|
||||||
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||||
|
import { scheduleOnce } from "@ember/runloop";
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Controller.extend({
|
||||||
title: 'admin.wizard.after_time_modal.title',
|
title: 'admin.wizard.after_time_modal.title',
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
|
@ -14,7 +16,7 @@ export default Ember.Controller.extend({
|
||||||
|
|
||||||
this.setProperties({ date, time });
|
this.setProperties({ date, time });
|
||||||
|
|
||||||
Ember.run.scheduleOnce('afterRender', this, () => {
|
scheduleOnce('afterRender', this, () => {
|
||||||
const $timePicker = $("#time-picker");
|
const $timePicker = $("#time-picker");
|
||||||
$timePicker.timepicker({ timeFormat: 'H:i' });
|
$timePicker.timepicker({ timeFormat: 'H:i' });
|
||||||
$timePicker.timepicker('setTime', time);
|
$timePicker.timepicker('setTime', time);
|
||||||
|
@ -22,12 +24,12 @@ export default Ember.Controller.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('date', 'time')
|
@discourseComputed('date', 'time')
|
||||||
dateTime: function(date, time) {
|
dateTime: function(date, time) {
|
||||||
return moment(date + 'T' + time).format();
|
return moment(date + 'T' + time).format();
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('dateTime')
|
@discourseComputed('dateTime')
|
||||||
submitDisabled(dateTime) {
|
submitDisabled(dateTime) {
|
||||||
return moment().isAfter(dateTime);
|
return moment().isAfter(dateTime);
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,18 +2,22 @@ export default {
|
||||||
resource: 'admin',
|
resource: 'admin',
|
||||||
map() {
|
map() {
|
||||||
this.route('adminWizards', { path: '/wizards', resetNamespace: true }, function() {
|
this.route('adminWizards', { path: '/wizards', resetNamespace: true }, function() {
|
||||||
this.route('adminWizardsCustom', { path: '/custom', resetNamespace: true }, function() {
|
|
||||||
this.route('adminWizard', { path: '/:wizard_id', resetNamespace: true });
|
this.route('adminWizardsWizard', { path: '/wizard/', resetNamespace: true }, function() {
|
||||||
|
this.route('adminWizardsWizardShow', { path: '/:wizardId/', resetNamespace: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
this.route('adminWizardsSubmissions', { path: '/submissions', resetNamespace: true }, function() {
|
this.route('adminWizardsSubmissions', { path: '/submissions', resetNamespace: true }, function() {
|
||||||
this.route('adminWizardSubmissions', { path: '/:wizard_id', resetNamespace: true });
|
this.route('adminWizardsSubmissionsShow', { path: '/:wizardId/', resetNamespace: true });
|
||||||
});
|
})
|
||||||
this.route('adminWizardsApis', { path: '/apis', resetNamespace: true }, function() {
|
|
||||||
this.route('adminWizardsApi', { path: '/:name', resetNamespace: true });
|
this.route('adminWizardsApi', { path: '/api', resetNamespace: true }, function() {
|
||||||
|
this.route('adminWizardsApiShow', { path: '/:name', resetNamespace: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.route('adminWizardsLogs', { path: '/logs', resetNamespace: true });
|
||||||
|
|
||||||
this.route('adminWizardsTransfer', { path: '/transfer', resetNamespace: true });
|
this.route('adminWizardsTransfer', { path: '/transfer', resetNamespace: true });
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||||
|
import { dasherize } from "@ember/string";
|
||||||
|
|
||||||
registerUnbound('dasherize', function(string) {
|
registerUnbound('dasherize', function(string) {
|
||||||
return Ember.String.dasherize(string);
|
return dasherize(string);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,25 +8,6 @@ export default {
|
||||||
|
|
||||||
if (!siteSettings.custom_wizard_enabled) return;
|
if (!siteSettings.custom_wizard_enabled) return;
|
||||||
|
|
||||||
withPluginApi('0.8.12', api => {
|
|
||||||
api.modifyClass('component:global-notice', {
|
|
||||||
buildBuffer(buffer) {
|
|
||||||
this._super(...arguments);
|
|
||||||
const wizards = this.site.get('complete_custom_wizard');
|
|
||||||
if (wizards) {
|
|
||||||
wizards.forEach((w) => {
|
|
||||||
const text = I18n.t('wizard.complete_custom', {
|
|
||||||
wizard_url: w.url,
|
|
||||||
wizard_name: w.name,
|
|
||||||
site_name: this.siteSettings.title
|
|
||||||
});
|
|
||||||
buffer.push(`<div class='row'><div class='alert alert-info alert-wizard'>${text}</div></div>`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const existing = DiscourseURL.routeTo;
|
const existing = DiscourseURL.routeTo;
|
||||||
DiscourseURL.routeTo = function(path, opts) {
|
DiscourseURL.routeTo = function(path, opts) {
|
||||||
if (path && path.indexOf('/w/') > -1) {
|
if (path && path.indexOf('/w/') > -1) {
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
function generateSelectKitContent(content) {
|
|
||||||
return content.map(i => ({id: i, name: i}))
|
|
||||||
}
|
|
||||||
|
|
||||||
export { generateSelectKitContent };
|
|
178
assets/javascripts/discourse/lib/wizard-json.js.es6
Normale Datei
178
assets/javascripts/discourse/lib/wizard-json.js.es6
Normale Datei
|
@ -0,0 +1,178 @@
|
||||||
|
import { schema, listProperties, camelCase, snakeCase } from '../lib/wizard';
|
||||||
|
import EmberObject from '@ember/object';
|
||||||
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
|
function present(val) {
|
||||||
|
if (val === null || val === undefined) {
|
||||||
|
return false;
|
||||||
|
} else if (typeof val === 'object') {
|
||||||
|
return Object.keys(val).length !== 0;
|
||||||
|
} else if (typeof val === 'string' || val.constructor === Array) {
|
||||||
|
return val && val.length;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapped(property, type) {
|
||||||
|
return schema[type].mapped.indexOf(property) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function castCase(property, value) {
|
||||||
|
return property.indexOf('_type') > -1 ? camelCase(value) : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildProperty(json, property, type) {
|
||||||
|
let value = json[property];
|
||||||
|
|
||||||
|
if (mapped(property, type) &&
|
||||||
|
present(value) &&
|
||||||
|
value.constructor === Array) {
|
||||||
|
|
||||||
|
let inputs = [];
|
||||||
|
|
||||||
|
value.forEach(inputJson => {
|
||||||
|
let input = {}
|
||||||
|
|
||||||
|
Object.keys(inputJson).forEach(inputKey => {
|
||||||
|
if (inputKey === 'pairs') {
|
||||||
|
let pairs = [];
|
||||||
|
let pairCount = inputJson.pairs.length;
|
||||||
|
|
||||||
|
inputJson.pairs.forEach(pairJson => {
|
||||||
|
let pair = {};
|
||||||
|
|
||||||
|
Object.keys(pairJson).forEach(pairKey => {
|
||||||
|
pair[pairKey] = castCase(pairKey, pairJson[pairKey]);
|
||||||
|
});
|
||||||
|
|
||||||
|
pair.pairCount = pairCount;
|
||||||
|
|
||||||
|
pairs.push(
|
||||||
|
EmberObject.create(pair)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
input.pairs = pairs;
|
||||||
|
} else {
|
||||||
|
input[inputKey] = castCase(inputKey, inputJson[inputKey]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
inputs.push(
|
||||||
|
EmberObject.create(input)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return A(inputs);
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildObject(json, type) {
|
||||||
|
let props = {
|
||||||
|
isNew: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(json).forEach(prop => {
|
||||||
|
props[prop] = buildProperty(json, prop, type)
|
||||||
|
});
|
||||||
|
|
||||||
|
return EmberObject.create(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildObjectArray(json, type) {
|
||||||
|
let array = A();
|
||||||
|
|
||||||
|
if (present(json)) {
|
||||||
|
json.forEach((objJson) => {
|
||||||
|
let object = buildObject(objJson, type);
|
||||||
|
|
||||||
|
if (hasAdvancedProperties(object, type)) {
|
||||||
|
object.set('showAdvanced', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
array.pushObject(object);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildBasicProperties(json, type, props) {
|
||||||
|
listProperties(type).forEach((p) => {
|
||||||
|
props[p] = buildProperty(json, p, type);
|
||||||
|
|
||||||
|
if (hasAdvancedProperties(json, type)) {
|
||||||
|
result.showAdvanced = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasAdvancedProperties(object, type) {
|
||||||
|
return Object.keys(object).some(p => {
|
||||||
|
return schema[type].advanced.indexOf(p) > -1 && present(object[p]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// to be removed: necessary due to action array being moved from step to wizard
|
||||||
|
function actionPatch(json) {
|
||||||
|
let actions = json.actions || [];
|
||||||
|
|
||||||
|
json.steps.forEach(step => {
|
||||||
|
if (step.actions && step.actions.length) {
|
||||||
|
step.actions.forEach(action => {
|
||||||
|
action.run_after = 'wizard_completion';
|
||||||
|
actions.push(action);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
json.actions = actions;
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
///
|
||||||
|
|
||||||
|
function buildProperties(json) {
|
||||||
|
let props = {
|
||||||
|
steps: A(),
|
||||||
|
actions: A()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (present(json)) {
|
||||||
|
props.existingId = true;
|
||||||
|
props = buildBasicProperties(json, 'wizard', props);
|
||||||
|
|
||||||
|
if (present(json.steps)) {
|
||||||
|
json.steps.forEach((stepJson) => {
|
||||||
|
let stepProps = {
|
||||||
|
isNew: false
|
||||||
|
};
|
||||||
|
|
||||||
|
stepProps = buildBasicProperties(stepJson, 'step', stepProps);
|
||||||
|
stepProps.fields = buildObjectArray(stepJson.fields, 'field');
|
||||||
|
|
||||||
|
props.steps.pushObject(EmberObject.create(stepProps));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
json = actionPatch(json); // to be removed - see above
|
||||||
|
props.actions = buildObjectArray(json.actions, 'action');
|
||||||
|
} else {
|
||||||
|
listProperties('wizard').forEach(prop => {
|
||||||
|
props[prop] = schema.wizard.basic[prop];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
buildProperties,
|
||||||
|
present,
|
||||||
|
mapped
|
||||||
|
}
|
168
assets/javascripts/discourse/lib/wizard-mapper.js.es6
Normale Datei
168
assets/javascripts/discourse/lib/wizard-mapper.js.es6
Normale Datei
|
@ -0,0 +1,168 @@
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
|
||||||
|
function defaultInputType(options = {}) {
|
||||||
|
return options.inputTypes.split(',')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapInputTypes(types) {
|
||||||
|
return types.map(function(type) {
|
||||||
|
return {
|
||||||
|
id: type,
|
||||||
|
name: I18n.t(`admin.wizard.input.${type}.name`)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputTypesContent(options = {}) {
|
||||||
|
return options.inputTypes ?
|
||||||
|
mapInputTypes(options.inputTypes.split(',')) :
|
||||||
|
mapInputTypes(selectableInputTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// connectorTypes
|
||||||
|
|
||||||
|
const connectors = {
|
||||||
|
pair: [
|
||||||
|
'equal',
|
||||||
|
'greater',
|
||||||
|
'less',
|
||||||
|
'greater_or_equal',
|
||||||
|
'less_or_equal',
|
||||||
|
'regex'
|
||||||
|
],
|
||||||
|
output: [
|
||||||
|
'then',
|
||||||
|
'set',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultConnector(connectorType, inputType, options={}) {
|
||||||
|
if (connectorType === 'input') {
|
||||||
|
return defaultInputType(options);
|
||||||
|
}
|
||||||
|
if (connectorType === 'pair') {
|
||||||
|
if (inputType === 'conditional') return 'equal';
|
||||||
|
if (inputType === 'association') return 'association';
|
||||||
|
if (inputType === 'validation') return 'equal';
|
||||||
|
}
|
||||||
|
if (connectorType === 'output') {
|
||||||
|
if (inputType === 'conditional') return 'then';
|
||||||
|
if (inputType === 'assignment') return 'set';
|
||||||
|
}
|
||||||
|
return 'equal';
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectorContent(connectorType, inputType, opts) {
|
||||||
|
let connector = opts[`${connectorType}Connector`];
|
||||||
|
|
||||||
|
if ((!connector && connectorType === 'output') || inputType === 'association') {
|
||||||
|
connector = defaultConnector(connectorType, inputType);
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = connector ? [connector] : connectors[connectorType];
|
||||||
|
|
||||||
|
return content.map(function(item) {
|
||||||
|
return {
|
||||||
|
id: item,
|
||||||
|
name: I18n.t(`admin.wizard.connector.${item}`)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selectors
|
||||||
|
|
||||||
|
const selectionTypes = [
|
||||||
|
'text',
|
||||||
|
'list',
|
||||||
|
'wizardField',
|
||||||
|
'userField',
|
||||||
|
'group',
|
||||||
|
'category',
|
||||||
|
'tag',
|
||||||
|
'user'
|
||||||
|
]
|
||||||
|
|
||||||
|
function defaultSelectionType(inputType, options = {}) {
|
||||||
|
if (options[`${inputType}DefaultSelection`]) {
|
||||||
|
return options[`${inputType}DefaultSelection`];
|
||||||
|
}
|
||||||
|
|
||||||
|
let type = selectionTypes[0];
|
||||||
|
|
||||||
|
for (let t of selectionTypes) {
|
||||||
|
let inputTypes = options[`${t}Selection`];
|
||||||
|
|
||||||
|
if (inputTypes === true ||
|
||||||
|
((typeof inputTypes === 'string') &&
|
||||||
|
inputTypes.split(',').indexOf(inputType) > -1)) {
|
||||||
|
|
||||||
|
type = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// items
|
||||||
|
|
||||||
|
function newPair(inputType, options = {}) {
|
||||||
|
let params = {
|
||||||
|
index: options.index,
|
||||||
|
pairCount: options.pairCount,
|
||||||
|
key: '',
|
||||||
|
key_type: defaultSelectionType('key', options),
|
||||||
|
value: '',
|
||||||
|
value_type: defaultSelectionType('value', options),
|
||||||
|
connector: defaultConnector('pair', inputType, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return EmberObject.create(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
function newInput(options = {}, count) {
|
||||||
|
const inputType = defaultInputType(options);
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
type: inputType,
|
||||||
|
pairs: A(
|
||||||
|
[
|
||||||
|
newPair(
|
||||||
|
inputType,
|
||||||
|
Object.assign({},
|
||||||
|
options,
|
||||||
|
{ index: 0, pairCount: 1 }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
params.connector = options.inputConnector;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['conditional', 'assignment'].indexOf(inputType) > -1 ||
|
||||||
|
options.outputDefaultSelection ||
|
||||||
|
options.outputConnector) {
|
||||||
|
|
||||||
|
params['output_type'] = defaultSelectionType('output', options);
|
||||||
|
params['output_connector'] = defaultConnector('output', inputType, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EmberObject.create(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
defaultInputType,
|
||||||
|
defaultSelectionType,
|
||||||
|
defaultConnector,
|
||||||
|
connectorContent,
|
||||||
|
inputTypesContent,
|
||||||
|
selectionTypes,
|
||||||
|
newInput,
|
||||||
|
newPair
|
||||||
|
}
|
331
assets/javascripts/discourse/lib/wizard.js.es6
Normale Datei
331
assets/javascripts/discourse/lib/wizard.js.es6
Normale Datei
|
@ -0,0 +1,331 @@
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
|
||||||
|
function selectKitContent(content) {
|
||||||
|
return content.map(i => ({id: i, name: i}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateName(id) {
|
||||||
|
return id ? sentenceCase(id) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateId(name, opts={}) {
|
||||||
|
return name ? snakeCase(name) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function sentenceCase(string) {
|
||||||
|
return string.replace(/[_\-]+/g, ' ')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/(^\w|\b\w)/g, (m) => m.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
function snakeCase(string) {
|
||||||
|
return string.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
|
||||||
|
.map(x => x.toLowerCase())
|
||||||
|
.join('_');
|
||||||
|
}
|
||||||
|
|
||||||
|
function camelCase(string) {
|
||||||
|
return string.replace(/([-_][a-z])/ig, ($1) => {
|
||||||
|
return $1.toUpperCase()
|
||||||
|
.replace('-', '')
|
||||||
|
.replace('_', '');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const userProperties = [
|
||||||
|
'name',
|
||||||
|
'username',
|
||||||
|
'email',
|
||||||
|
'avatar',
|
||||||
|
'date_of_birth',
|
||||||
|
'title',
|
||||||
|
'profile_background',
|
||||||
|
'card_background',
|
||||||
|
'locale',
|
||||||
|
'location',
|
||||||
|
'website',
|
||||||
|
'bio_raw',
|
||||||
|
'trust_level'
|
||||||
|
];
|
||||||
|
|
||||||
|
const wizardProperties = {
|
||||||
|
basic: {
|
||||||
|
id: null,
|
||||||
|
name: null,
|
||||||
|
background: null,
|
||||||
|
save_submissions: true,
|
||||||
|
multiple_submissions: null,
|
||||||
|
after_signup: null,
|
||||||
|
after_time: null,
|
||||||
|
after_time_scheduled: null,
|
||||||
|
required: null,
|
||||||
|
prompt_completion: null,
|
||||||
|
restart_on_revisit: null,
|
||||||
|
theme_id: null,
|
||||||
|
permitted: null
|
||||||
|
},
|
||||||
|
mapped: [
|
||||||
|
'permitted'
|
||||||
|
],
|
||||||
|
advanced: [
|
||||||
|
'restart_on_revisit',
|
||||||
|
],
|
||||||
|
required: [
|
||||||
|
'id',
|
||||||
|
],
|
||||||
|
dependent: {
|
||||||
|
after_time: 'after_time_scheduled'
|
||||||
|
},
|
||||||
|
objectArrays: {
|
||||||
|
step: {
|
||||||
|
property: 'steps',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
property: 'actions',
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const stepProperties = {
|
||||||
|
basic: {
|
||||||
|
id: null,
|
||||||
|
title: null,
|
||||||
|
key: null,
|
||||||
|
banner: null,
|
||||||
|
raw_description: null,
|
||||||
|
required_data: null,
|
||||||
|
required_data_message: null,
|
||||||
|
permitted_params: null
|
||||||
|
},
|
||||||
|
mapped: [
|
||||||
|
'required_data',
|
||||||
|
'permitted_params'
|
||||||
|
],
|
||||||
|
advanced: [
|
||||||
|
'required_data',
|
||||||
|
'permitted_params'
|
||||||
|
],
|
||||||
|
required: [
|
||||||
|
'id'
|
||||||
|
],
|
||||||
|
dependent: {
|
||||||
|
},
|
||||||
|
objectArrays: {
|
||||||
|
field: {
|
||||||
|
property: 'fields',
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fieldProperties = {
|
||||||
|
basic: {
|
||||||
|
id: null,
|
||||||
|
label: null,
|
||||||
|
image: null,
|
||||||
|
description: null,
|
||||||
|
required: null,
|
||||||
|
key: null,
|
||||||
|
type: null
|
||||||
|
},
|
||||||
|
types: {
|
||||||
|
text: {
|
||||||
|
min_length: null
|
||||||
|
},
|
||||||
|
textarea: {
|
||||||
|
min_length: null
|
||||||
|
},
|
||||||
|
composer: {
|
||||||
|
min_length: null
|
||||||
|
},
|
||||||
|
text_only: {
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
},
|
||||||
|
checkbox: {
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
min_length: null
|
||||||
|
},
|
||||||
|
upload: {
|
||||||
|
file_types: '.jpg,.png'
|
||||||
|
},
|
||||||
|
dropdown: {
|
||||||
|
prefill: null,
|
||||||
|
content: null
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
limit: null,
|
||||||
|
prefill: null,
|
||||||
|
content: null
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
limit: 1,
|
||||||
|
property: 'id',
|
||||||
|
prefill: null,
|
||||||
|
content: null
|
||||||
|
},
|
||||||
|
group: {
|
||||||
|
prefill: null,
|
||||||
|
content: null
|
||||||
|
},
|
||||||
|
user_selector: {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mapped: [
|
||||||
|
'prefill',
|
||||||
|
'content'
|
||||||
|
],
|
||||||
|
advanced: [
|
||||||
|
'property',
|
||||||
|
'key'
|
||||||
|
],
|
||||||
|
required: [
|
||||||
|
'id',
|
||||||
|
'type'
|
||||||
|
],
|
||||||
|
dependent: {
|
||||||
|
},
|
||||||
|
objectArrays: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionProperties = {
|
||||||
|
basic: {
|
||||||
|
id: null,
|
||||||
|
run_after: 'wizard_completion',
|
||||||
|
type: null
|
||||||
|
},
|
||||||
|
types: {
|
||||||
|
create_topic: {
|
||||||
|
title: null,
|
||||||
|
post: null,
|
||||||
|
post_builder: null,
|
||||||
|
post_template: null,
|
||||||
|
category: null,
|
||||||
|
tags: null,
|
||||||
|
custom_fields: null,
|
||||||
|
skip_redirect: null
|
||||||
|
},
|
||||||
|
send_message: {
|
||||||
|
title: null,
|
||||||
|
post: null,
|
||||||
|
post_builder: null,
|
||||||
|
post_template: null,
|
||||||
|
skip_redirect: null,
|
||||||
|
custom_fields: null,
|
||||||
|
required: null,
|
||||||
|
recipient: null
|
||||||
|
},
|
||||||
|
open_composer: {
|
||||||
|
title: null,
|
||||||
|
post: null,
|
||||||
|
post_builder: null,
|
||||||
|
post_template: null,
|
||||||
|
category: null,
|
||||||
|
tags: null,
|
||||||
|
custom_fields: null
|
||||||
|
},
|
||||||
|
update_profile: {
|
||||||
|
profile_updates: null,
|
||||||
|
custom_fields: null
|
||||||
|
},
|
||||||
|
add_to_group: {
|
||||||
|
group: null
|
||||||
|
},
|
||||||
|
route_to: {
|
||||||
|
url: null,
|
||||||
|
code: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mapped: [
|
||||||
|
'title',
|
||||||
|
'category',
|
||||||
|
'tags',
|
||||||
|
'custom_fields',
|
||||||
|
'required',
|
||||||
|
'recipient',
|
||||||
|
'profile_updates',
|
||||||
|
'group'
|
||||||
|
],
|
||||||
|
advanced: [
|
||||||
|
'code',
|
||||||
|
'custom_fields',
|
||||||
|
'skip_redirect',
|
||||||
|
'required'
|
||||||
|
],
|
||||||
|
required: [
|
||||||
|
'id',
|
||||||
|
'type'
|
||||||
|
],
|
||||||
|
dependent: {
|
||||||
|
},
|
||||||
|
objectArrays: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Discourse.SiteSettings.wizard_apis_enabled) {
|
||||||
|
actionProperties.types.send_to_api = {
|
||||||
|
api: null,
|
||||||
|
api_endpoint: null,
|
||||||
|
api_body: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
wizard: wizardProperties,
|
||||||
|
step: stepProperties,
|
||||||
|
field: fieldProperties,
|
||||||
|
action: actionProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
function listProperties(type, objectType = null) {
|
||||||
|
let properties = Object.keys(schema[type].basic);
|
||||||
|
|
||||||
|
if (schema[type].types && objectType) {
|
||||||
|
properties = properties.concat(Object.keys(schema[type].types[objectType]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
function wizardFieldList(steps = [], opts = {}) {
|
||||||
|
let upToIndex = null;
|
||||||
|
|
||||||
|
if (opts.upTo) {
|
||||||
|
upToIndex = steps.map((s) => (s.id)).indexOf(opts.upTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return steps.reduce((result, step, index) => {
|
||||||
|
let fields = step.fields;
|
||||||
|
|
||||||
|
if (fields && fields.length > 0) {
|
||||||
|
|
||||||
|
if (upToIndex === null || index < upToIndex) {
|
||||||
|
result.push(...fields.map((field) => {
|
||||||
|
return EmberObject.create({
|
||||||
|
id: field.id,
|
||||||
|
label: `${field.label} (${step.id}, ${field.id})`,
|
||||||
|
type: field.type
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
selectKitContent,
|
||||||
|
generateName,
|
||||||
|
generateId,
|
||||||
|
camelCase,
|
||||||
|
snakeCase,
|
||||||
|
schema,
|
||||||
|
userProperties,
|
||||||
|
listProperties,
|
||||||
|
wizardFieldList
|
||||||
|
};
|
|
@ -1,8 +1,10 @@
|
||||||
import { ajax } from 'discourse/lib/ajax';
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
import { default as discourseComputed } from 'discourse-common/utils/decorators';
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
import { A } from "@ember/array";
|
||||||
|
|
||||||
const CustomWizardApi = Discourse.Model.extend({
|
const CustomWizardApi = EmberObject.extend({
|
||||||
@computed('name')
|
@discourseComputed('name')
|
||||||
redirectUri(name) {
|
redirectUri(name) {
|
||||||
let nameParam = name.toString().dasherize();
|
let nameParam = name.toString().dasherize();
|
||||||
const baseUrl = location.protocol+'//'+location.hostname+(location.port ? ':'+location.port: '');
|
const baseUrl = location.protocol+'//'+location.hostname+(location.port ? ':'+location.port: '');
|
||||||
|
@ -27,14 +29,14 @@ CustomWizardApi.reopenClass({
|
||||||
clientSecret: authorization.client_secret,
|
clientSecret: authorization.client_secret,
|
||||||
username: authorization.username,
|
username: authorization.username,
|
||||||
password: authorization.password,
|
password: authorization.password,
|
||||||
authParams: Ember.A(authorization.auth_params),
|
authParams: A(authorization.auth_params),
|
||||||
authorized: authorization.authorized,
|
authorized: authorization.authorized,
|
||||||
accessToken: authorization.access_token,
|
accessToken: authorization.access_token,
|
||||||
refreshToken: authorization.refresh_token,
|
refreshToken: authorization.refresh_token,
|
||||||
code: authorization.code,
|
code: authorization.code,
|
||||||
tokenExpiresAt: authorization.token_expires_at,
|
tokenExpiresAt: authorization.token_expires_at,
|
||||||
tokenRefreshAt: authorization.token_refresh_at,
|
tokenRefreshAt: authorization.token_refresh_at,
|
||||||
endpoints: Ember.A(endpoints),
|
endpoints: A(endpoints),
|
||||||
isNew: params.isNew,
|
isNew: params.isNew,
|
||||||
log: params.log
|
log: params.log
|
||||||
});
|
});
|
||||||
|
|
17
assets/javascripts/discourse/models/custom-wizard-logs.js.es6
Normale Datei
17
assets/javascripts/discourse/models/custom-wizard-logs.js.es6
Normale Datei
|
@ -0,0 +1,17 @@
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
|
||||||
|
const CustomWizardLogs = EmberObject.extend();
|
||||||
|
|
||||||
|
CustomWizardLogs.reopenClass({
|
||||||
|
list(page = 0) {
|
||||||
|
return ajax('/admin/wizards/logs', {
|
||||||
|
data: {
|
||||||
|
page
|
||||||
|
}
|
||||||
|
}).catch(popupAjaxError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CustomWizardLogs;
|
|
@ -1,57 +1,30 @@
|
||||||
import { ajax } from 'discourse/lib/ajax';
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
import { buildProperties, present, mapped } from '../lib/wizard-json';
|
||||||
|
import { schema, listProperties, camelCase, snakeCase } from '../lib/wizard';
|
||||||
|
import { Promise } from "rsvp";
|
||||||
|
|
||||||
const wizardProperties = [
|
const CustomWizard = EmberObject.extend({
|
||||||
'name',
|
save(opts) {
|
||||||
'background',
|
return new Promise((resolve, reject) => {
|
||||||
'save_submissions',
|
let wizard = this.buildJson(this, 'wizard');
|
||||||
'multiple_submissions',
|
|
||||||
'after_signup',
|
|
||||||
'after_time',
|
|
||||||
'after_time_scheduled',
|
|
||||||
'required',
|
|
||||||
'prompt_completion',
|
|
||||||
'restart_on_revisit',
|
|
||||||
'min_trust',
|
|
||||||
'theme_id'
|
|
||||||
];
|
|
||||||
|
|
||||||
const CustomWizard = Discourse.Model.extend({
|
if (wizard.error) {
|
||||||
save() {
|
reject(wizard);
|
||||||
return new Ember.RSVP.Promise((resolve, reject) => {
|
}
|
||||||
|
|
||||||
const id = this.get('id');
|
let data = {
|
||||||
if (!id || !id.underscore()) return reject({ error: 'id_required' });
|
wizard
|
||||||
|
|
||||||
let wizard = { id: id.underscore() };
|
|
||||||
|
|
||||||
wizardProperties.forEach((p) => {
|
|
||||||
const value = this.get(p);
|
|
||||||
if (value) wizard[p] = value;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (wizard['after_time'] && !wizard['after_time_scheduled']) {
|
|
||||||
return reject({ error: 'after_time_need_time' });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const steps = this.get('steps');
|
if (opts.create) {
|
||||||
if (steps.length > 0) {
|
data.create = true;
|
||||||
const stepsResult = this.buildSteps(steps);
|
|
||||||
if (stepsResult.error) {
|
|
||||||
reject({ error: stepsResult.error });
|
|
||||||
} else {
|
|
||||||
wizard['steps'] = stepsResult.steps;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (steps.length < 1 || !wizard['steps'] || wizard['steps'].length < 1) {
|
ajax(`/admin/wizards/wizard/${wizard.id}`, {
|
||||||
return reject({ error: 'steps_required' });
|
|
||||||
}
|
|
||||||
|
|
||||||
ajax("/admin/wizards/custom/save", {
|
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
data: {
|
contentType: "application/json",
|
||||||
wizard: JSON.stringify(wizard)
|
data: JSON.stringify(data)
|
||||||
}
|
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
reject(result);
|
reject(result);
|
||||||
|
@ -62,216 +35,177 @@ const CustomWizard = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
buildSteps(stepsObj) {
|
buildJson(object, type, result = {}) {
|
||||||
let steps = [];
|
let objectType = object.type || null;
|
||||||
let error = null;
|
|
||||||
|
|
||||||
stepsObj.some((s) => {
|
if (schema[type].types) {
|
||||||
if (!s.id || !s.id.underscore()) {
|
if (!objectType) {
|
||||||
error = 'id_required';
|
result.error = {
|
||||||
return;
|
type: 'required',
|
||||||
|
params: { type, property: 'type' }
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let property of listProperties(type, objectType)) {
|
||||||
|
let value = object.get(property);
|
||||||
|
|
||||||
|
result = this.validateValue(property, value, object, type, result);
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapped(property, type)) {
|
||||||
|
value = this.buildMappedJson(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value !== undefined && value !== null) {
|
||||||
|
result[property] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!result.error) {
|
||||||
|
for (let arrayObjectType of Object.keys(schema[type].objectArrays)) {
|
||||||
|
let arraySchema = schema[type].objectArrays[arrayObjectType];
|
||||||
|
let objectArray = object.get(arraySchema.property);
|
||||||
|
|
||||||
|
if (arraySchema.required && !present(objectArray)) {
|
||||||
|
result.error = {
|
||||||
|
type: 'required',
|
||||||
|
params: { type, property: arraySchema.property }
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result[arraySchema.property] = [];
|
||||||
|
|
||||||
|
for (let item of objectArray) {
|
||||||
|
let itemProps = this.buildJson(item, arrayObjectType);
|
||||||
|
|
||||||
|
if (itemProps.error) {
|
||||||
|
result.error = itemProps.error;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
result[arraySchema.property].push(itemProps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
validateValue(property, value, object, type, result) {
|
||||||
|
if (schema[type].required.indexOf(property) > -1 && !value) {
|
||||||
|
result.error = {
|
||||||
|
type: 'required',
|
||||||
|
params: { type, property }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dependent = schema[type].dependent[property];
|
||||||
|
if (dependent && value && !object[dependent]) {
|
||||||
|
result.error = {
|
||||||
|
type: 'dependent',
|
||||||
|
params: { property, dependent }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property === 'api_body') {
|
||||||
|
try {
|
||||||
|
value = JSON.parse(value);
|
||||||
|
} catch (e) {
|
||||||
|
result.error = {
|
||||||
|
type: 'invalid',
|
||||||
|
params: { type, property }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
buildMappedJson(inputs) {
|
||||||
|
if (!inputs || !inputs.length) return false;
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
inputs.forEach(inpt => {
|
||||||
|
let input = {
|
||||||
|
type: inpt.type,
|
||||||
};
|
};
|
||||||
|
|
||||||
let step = { id: s.id.underscore() };
|
if (inpt.connector) {
|
||||||
|
input.connector = inpt.connector;
|
||||||
if (s.title) step['title'] = s.title;
|
|
||||||
if (s.key) step['key'] = s.key;
|
|
||||||
if (s.banner) step['banner'] = s.banner;
|
|
||||||
if (s.raw_description) step['raw_description'] = s.raw_description;
|
|
||||||
if (s.required_data) step['required_data'] = s.required_data;
|
|
||||||
if (s.required_data_message) step['required_data_message'] = s.required_data_message;
|
|
||||||
if (s.permitted_params) step['permitted_params'] = s.permitted_params;
|
|
||||||
|
|
||||||
const fields = s.get('fields');
|
|
||||||
if (fields.length) {
|
|
||||||
step['fields'] = [];
|
|
||||||
|
|
||||||
fields.some((f) => {
|
|
||||||
let id = f.id;
|
|
||||||
|
|
||||||
if (!id || !id.underscore()) {
|
|
||||||
error = 'id_required';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!f.type) {
|
|
||||||
error = 'type_required';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
f.set('id', id.underscore());
|
|
||||||
|
|
||||||
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_preset) {
|
|
||||||
error = 'field.need_choices';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f.dropdown_none === '') delete f.dropdown_none;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete f.isNew;
|
|
||||||
|
|
||||||
step['fields'].push(f);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = s.actions;
|
if (present(inpt.output)) {
|
||||||
if (actions.length) {
|
input.output = inpt.output;
|
||||||
step['actions'] = [];
|
input.output_type = snakeCase(inpt.output_type);
|
||||||
|
input.output_connector = inpt.output_connector;
|
||||||
actions.some((a) => {
|
|
||||||
let id = a.get('id');
|
|
||||||
if (!id || !id.underscore()) {
|
|
||||||
error = 'id_required';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//check if api_body is valid JSON
|
|
||||||
let api_body = a.get('api_body');
|
|
||||||
if (api_body) {
|
|
||||||
try {
|
|
||||||
JSON.parse(api_body);
|
|
||||||
} catch (e) {
|
|
||||||
error = 'invalid_api_body';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a.set('id', id.underscore());
|
|
||||||
|
|
||||||
delete a.isNew;
|
|
||||||
|
|
||||||
step['actions'].push(a);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
steps.push(step);
|
if (present(inpt.pairs)) {
|
||||||
|
input.pairs = [];
|
||||||
|
|
||||||
|
inpt.pairs.forEach(pr => {
|
||||||
|
if (present(pr.key) && present(pr.value)) {
|
||||||
|
|
||||||
|
let pairParams = {
|
||||||
|
index: pr.index,
|
||||||
|
key: pr.key,
|
||||||
|
key_type: snakeCase(pr.key_type),
|
||||||
|
value: pr.value,
|
||||||
|
value_type: snakeCase(pr.value_type),
|
||||||
|
connector: pr.connector
|
||||||
|
}
|
||||||
|
|
||||||
|
input.pairs.push(pairParams);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((input.type === 'assignment' && present(input.output)) ||
|
||||||
|
present(input.pairs)) {
|
||||||
|
|
||||||
|
result.push(input);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (!result.length) {
|
||||||
return { error };
|
result = false;
|
||||||
} else {
|
}
|
||||||
return { steps };
|
|
||||||
};
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
remove() {
|
remove() {
|
||||||
return ajax("/admin/wizards/custom/remove", {
|
return ajax(`/admin/wizards/wizard/${this.id}`, {
|
||||||
type: 'DELETE',
|
type: 'DELETE'
|
||||||
data: {
|
|
||||||
id: this.get('id')
|
|
||||||
}
|
|
||||||
}).then(() => this.destroy());
|
}).then(() => this.destroy());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
CustomWizard.reopenClass({
|
CustomWizard.reopenClass({
|
||||||
all() {
|
all() {
|
||||||
return ajax("/admin/wizards/custom/all", {
|
return ajax("/admin/wizards/wizard", {
|
||||||
type: 'GET'
|
type: 'GET'
|
||||||
}).then(result => {
|
}).then(result => {
|
||||||
return result.wizards.map(w => CustomWizard.create(w));
|
return result.wizard_list;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
submissions(wizardId) {
|
submissions(wizardId) {
|
||||||
return ajax(`/admin/wizards/submissions/${wizardId}`, {
|
return ajax(`/admin/wizards/submissions/${wizardId}`, {
|
||||||
type: "GET"
|
type: "GET"
|
||||||
}).then(result => {
|
|
||||||
return result.submissions;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
create(w) {
|
create(wizardJson = {}) {
|
||||||
const wizard = this._super.apply(this);
|
const wizard = this._super.apply(this);
|
||||||
let steps = Ember.A();
|
wizard.setProperties(buildProperties(wizardJson));
|
||||||
let props = { steps };
|
|
||||||
|
|
||||||
if (w) {
|
|
||||||
props['id'] = w.id;
|
|
||||||
props['existingId'] = true;
|
|
||||||
|
|
||||||
wizardProperties.forEach((p) => {
|
|
||||||
props[p] = w[p];
|
|
||||||
});
|
|
||||||
|
|
||||||
if (w.steps && w.steps.length) {
|
|
||||||
w.steps.forEach((s) => {
|
|
||||||
// clean empty strings
|
|
||||||
Object.keys(s).forEach((key) => (s[key] === '') && delete s[key]);
|
|
||||||
|
|
||||||
let fields = Ember.A();
|
|
||||||
|
|
||||||
if (s.fields && s.fields.length) {
|
|
||||||
s.fields.forEach((f) => {
|
|
||||||
Object.keys(f).forEach((key) => (f[key] === '') && delete f[key]);
|
|
||||||
|
|
||||||
const fieldParams = { isNew: false };
|
|
||||||
let field = Ember.Object.create($.extend(f, fieldParams));
|
|
||||||
|
|
||||||
if (f.choices) {
|
|
||||||
let choices = Ember.A();
|
|
||||||
|
|
||||||
f.choices.forEach((c) => {
|
|
||||||
choices.pushObject(Ember.Object.create(c));
|
|
||||||
});
|
|
||||||
|
|
||||||
field.set('choices', choices);
|
|
||||||
}
|
|
||||||
|
|
||||||
fields.pushObject(field);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let actions = Ember.A();
|
|
||||||
if (s.actions && s.actions.length) {
|
|
||||||
s.actions.forEach((a) => {
|
|
||||||
const actionParams = { isNew: false };
|
|
||||||
const action = Ember.Object.create($.extend(a, actionParams));
|
|
||||||
actions.pushObject(action);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
steps.pushObject(Ember.Object.create({
|
|
||||||
id: s.id,
|
|
||||||
key: s.key,
|
|
||||||
title: s.title,
|
|
||||||
raw_description: s.raw_description,
|
|
||||||
banner: s.banner,
|
|
||||||
required_data: s.required_data,
|
|
||||||
required_data_message: s.required_data_message,
|
|
||||||
permitted_params: s.permitted_params,
|
|
||||||
fields,
|
|
||||||
actions,
|
|
||||||
isNew: false
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
props['id'] = '';
|
|
||||||
props['name'] = '';
|
|
||||||
props['background'] = '';
|
|
||||||
props['save_submissions'] = true;
|
|
||||||
props['multiple_submissions'] = false;
|
|
||||||
props['after_signup'] = false;
|
|
||||||
props['after_time'] = false;
|
|
||||||
props['required'] = false;
|
|
||||||
props['prompt_completion'] = false;
|
|
||||||
props['restart_on_revisit'] = false;
|
|
||||||
props['min_trust'] = 0;
|
|
||||||
props['steps'] = Ember.A();
|
|
||||||
};
|
|
||||||
|
|
||||||
wizard.setProperties(props);
|
|
||||||
|
|
||||||
return wizard;
|
return wizard;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import CustomWizard from '../models/custom-wizard';
|
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
|
||||||
model(params) {
|
|
||||||
return CustomWizard.submissions(params.wizard_id);
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
let fields = [];
|
|
||||||
model.forEach((s) => {
|
|
||||||
Object.keys(s).forEach((k) => {
|
|
||||||
if (fields.indexOf(k) < 0) {
|
|
||||||
fields.push(k);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let submissions = [];
|
|
||||||
model.forEach((s) => {
|
|
||||||
let submission = {};
|
|
||||||
fields.forEach((f) => {
|
|
||||||
submission[f] = s[f];
|
|
||||||
});
|
|
||||||
submissions.push(submission);
|
|
||||||
});
|
|
||||||
|
|
||||||
controller.setProperties({ submissions, fields });
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,78 +0,0 @@
|
||||||
import CustomWizard from '../models/custom-wizard';
|
|
||||||
import { ajax } from 'discourse/lib/ajax';
|
|
||||||
import { generateSelectKitContent } from '../lib/custom-wizard';
|
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
|
||||||
beforeModel() {
|
|
||||||
const param = this.paramsFor('adminWizard').wizard_id;
|
|
||||||
const wizards = this.modelFor('admin-wizards-custom');
|
|
||||||
|
|
||||||
if (wizards.length && (param === 'first' || param === 'last')) {
|
|
||||||
const wizard = wizards.get(`${param}Object`);
|
|
||||||
if (wizard) {
|
|
||||||
this.transitionTo('adminWizard', wizard.id.dasherize());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
model(params) {
|
|
||||||
const wizardId = params.wizard_id;
|
|
||||||
|
|
||||||
if (wizardId === 'new') {
|
|
||||||
this.set('newWizard', true);
|
|
||||||
return CustomWizard.create();
|
|
||||||
};
|
|
||||||
this.set('newWizard', false);
|
|
||||||
|
|
||||||
const wizard = this.modelFor('admin-wizards-custom').findBy('id', wizardId.underscore());
|
|
||||||
|
|
||||||
if (!wizard) return this.transitionTo('adminWizard', 'new');
|
|
||||||
|
|
||||||
return wizard;
|
|
||||||
},
|
|
||||||
|
|
||||||
afterModel(model) {
|
|
||||||
return Ember.RSVP.all([
|
|
||||||
this._getFieldTypes(model),
|
|
||||||
this._getThemes(model),
|
|
||||||
this._getApis(model)
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
|
|
||||||
_getFieldTypes(model) {
|
|
||||||
return ajax('/admin/wizards/field-types')
|
|
||||||
.then((result) => {
|
|
||||||
model.set(
|
|
||||||
'fieldTypes',
|
|
||||||
generateSelectKitContent([...result.types])
|
|
||||||
)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_getThemes(model) {
|
|
||||||
return this.store.findAll('theme').then((result) => {
|
|
||||||
model.set('themes', result.content);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_getApis(model) {
|
|
||||||
return ajax('/admin/wizards/apis')
|
|
||||||
.then((result) => model.set('apis', result));
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
const newWizard = this.get('newWizard');
|
|
||||||
const steps = model.get('steps') || [];
|
|
||||||
controller.setProperties({
|
|
||||||
newWizard,
|
|
||||||
model,
|
|
||||||
currentStep: steps[0]
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
refreshWizard() {
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
22
assets/javascripts/discourse/routes/admin-wizards-api-show.js.es6
Normale Datei
22
assets/javascripts/discourse/routes/admin-wizards-api-show.js.es6
Normale Datei
|
@ -0,0 +1,22 @@
|
||||||
|
import CustomWizardApi from '../models/custom-wizard-api';
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
|
export default DiscourseRoute.extend({
|
||||||
|
queryParams: {
|
||||||
|
refresh_list: {
|
||||||
|
refreshModel: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
model(params) {
|
||||||
|
if (params.name === 'new') {
|
||||||
|
return CustomWizardApi.create({ isNew: true });
|
||||||
|
} else {
|
||||||
|
return CustomWizardApi.find(params.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model){
|
||||||
|
controller.set("api", model);
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,21 +1,7 @@
|
||||||
import CustomWizardApi from '../models/custom-wizard-api';
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
export default DiscourseRoute.extend({
|
||||||
queryParams: {
|
beforeModel() {
|
||||||
refresh_list: {
|
this.transitionTo('adminWizardsApiShow');
|
||||||
refreshModel: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
model(params) {
|
|
||||||
if (params.name === 'new') {
|
|
||||||
return CustomWizardApi.create({ isNew: true });
|
|
||||||
} else {
|
|
||||||
return CustomWizardApi.find(params.name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model){
|
|
||||||
controller.set("api", model);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -1,31 +0,0 @@
|
||||||
import CustomWizardApi from '../models/custom-wizard-api';
|
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
|
||||||
model() {
|
|
||||||
return CustomWizardApi.list();
|
|
||||||
},
|
|
||||||
|
|
||||||
afterModel(model) {
|
|
||||||
const apiParams = this.paramsFor('admin-wizards-api');
|
|
||||||
|
|
||||||
if (model.length) {
|
|
||||||
if (!apiParams.name) {
|
|
||||||
this.transitionTo('adminWizardsApi', model[0].name.dasherize());
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.transitionTo('adminWizardsApi', 'new');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model){
|
|
||||||
controller.set("model", model);
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
refreshModel() {
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,5 +0,0 @@
|
||||||
export default Discourse.Route.extend({
|
|
||||||
redirect() {
|
|
||||||
this.transitionTo('adminWizard', 'first');
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,26 +0,0 @@
|
||||||
import CustomWizard from '../models/custom-wizard';
|
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
|
||||||
model() {
|
|
||||||
return CustomWizard.all();
|
|
||||||
},
|
|
||||||
|
|
||||||
afterModel(model) {
|
|
||||||
const transitionToWizard = this.get('transitionToWizard');
|
|
||||||
if (transitionToWizard && model.length) {
|
|
||||||
this.set('transitionToWizard', null);
|
|
||||||
this.transitionTo('adminWizard', transitionToWizard);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model){
|
|
||||||
controller.set("model", model.toArray());
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
refreshAllWizards() {
|
|
||||||
this.set('transitionToWizard', 'last');
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,5 +0,0 @@
|
||||||
export default Discourse.Route.extend({
|
|
||||||
redirect() {
|
|
||||||
this.transitionTo('adminWizardsCustom');
|
|
||||||
}
|
|
||||||
});
|
|
11
assets/javascripts/discourse/routes/admin-wizards-logs.js.es6
Normale Datei
11
assets/javascripts/discourse/routes/admin-wizards-logs.js.es6
Normale Datei
|
@ -0,0 +1,11 @@
|
||||||
|
import CustomWizardLogs from '../models/custom-wizard-logs';
|
||||||
|
|
||||||
|
export default Discourse.Route.extend({
|
||||||
|
model() {
|
||||||
|
return CustomWizardLogs.list();
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model) {
|
||||||
|
controller.set('logs', model);
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,36 @@
|
||||||
|
import CustomWizard from '../models/custom-wizard';
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
|
export default DiscourseRoute.extend({
|
||||||
|
model(params) {
|
||||||
|
return CustomWizard.submissions(params.wizardId);
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model) {
|
||||||
|
if (model.submissions) {
|
||||||
|
let fields = [];
|
||||||
|
model.submissions.forEach((s) => {
|
||||||
|
Object.keys(s).forEach((k) => {
|
||||||
|
if (fields.indexOf(k) < 0) {
|
||||||
|
fields.push(k);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let submissions = [];
|
||||||
|
model.submissions.forEach((s) => {
|
||||||
|
let submission = {};
|
||||||
|
fields.forEach((f) => {
|
||||||
|
submission[f] = s[f];
|
||||||
|
});
|
||||||
|
submissions.push(submission);
|
||||||
|
});
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
wizard: model.wizard,
|
||||||
|
submissions,
|
||||||
|
fields
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,11 +1,24 @@
|
||||||
import CustomWizard from '../models/custom-wizard';
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
export default DiscourseRoute.extend({
|
||||||
model() {
|
model() {
|
||||||
return CustomWizard.all();
|
return ajax(`/admin/wizards/wizard`);
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController(controller, model){
|
setupController(controller, model) {
|
||||||
controller.set("model", model);
|
const showParams = this.paramsFor('adminWizardsSubmissionsShow');
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
wizardId: showParams.wizardId,
|
||||||
|
wizardList: model.wizard_list
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
changeWizard(wizardId) {
|
||||||
|
this.controllerFor('adminWizardsSubmissions').set('wizardId', wizardId);
|
||||||
|
this.transitionTo('adminWizardsSubmissionsShow', wizardId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -1,7 +1,12 @@
|
||||||
import CustomWizard from '../models/custom-wizard';
|
import CustomWizard from '../models/custom-wizard';
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
export default DiscourseRoute.extend({
|
||||||
model() {
|
model() {
|
||||||
return CustomWizard.all();
|
return CustomWizard.all();
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model) {
|
||||||
|
controller.set('wizards', model)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
37
assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6
Normale Datei
37
assets/javascripts/discourse/routes/admin-wizards-wizard-show.js.es6
Normale Datei
|
@ -0,0 +1,37 @@
|
||||||
|
import CustomWizard from '../models/custom-wizard';
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
import { selectKitContent } from '../lib/wizard';
|
||||||
|
|
||||||
|
export default DiscourseRoute.extend({
|
||||||
|
model(params) {
|
||||||
|
if (params.wizardId === 'create') {
|
||||||
|
return { create: true };
|
||||||
|
} else {
|
||||||
|
return ajax(`/admin/wizards/wizard/${params.wizardId}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
afterModel(model) {
|
||||||
|
if (model.none) {
|
||||||
|
return this.transitionTo('adminWizardsWizard');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model) {
|
||||||
|
const parentModel = this.modelFor('adminWizardsWizard');
|
||||||
|
const wizard = CustomWizard.create((!model || model.create) ? {} : model);
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
wizardList: parentModel.wizard_list,
|
||||||
|
fieldTypes: selectKitContent(parentModel.field_types),
|
||||||
|
userFields: parentModel.userFields,
|
||||||
|
apis: parentModel.apis,
|
||||||
|
themes: parentModel.themes,
|
||||||
|
wizard,
|
||||||
|
currentStep: wizard.steps[0],
|
||||||
|
currentAction: wizard.actions[0],
|
||||||
|
creating: model.create
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
98
assets/javascripts/discourse/routes/admin-wizards-wizard.js.es6
Normale Datei
98
assets/javascripts/discourse/routes/admin-wizards-wizard.js.es6
Normale Datei
|
@ -0,0 +1,98 @@
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
import { userProperties, generateName } from '../lib/wizard';
|
||||||
|
import { set } from "@ember/object";
|
||||||
|
import { all } from "rsvp";
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
|
||||||
|
export default DiscourseRoute.extend({
|
||||||
|
model() {
|
||||||
|
return ajax("/admin/wizards/wizard");
|
||||||
|
},
|
||||||
|
|
||||||
|
afterModel(model) {
|
||||||
|
return all([
|
||||||
|
this._getThemes(model),
|
||||||
|
this._getApis(model),
|
||||||
|
this._getUserFields(model)
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
_getThemes(model) {
|
||||||
|
return ajax('/admin/themes')
|
||||||
|
.then((result) => {
|
||||||
|
set(model, 'themes', result.themes.map(t => {
|
||||||
|
return {
|
||||||
|
id: t.id,
|
||||||
|
name: t.name
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_getApis(model) {
|
||||||
|
return ajax('/admin/wizards/api')
|
||||||
|
.then((result) => set(model, 'apis', result));
|
||||||
|
},
|
||||||
|
|
||||||
|
_getUserFields(model) {
|
||||||
|
return this.store.findAll('user-field').then((result) => {
|
||||||
|
if (result && result.content) {
|
||||||
|
set(model, 'userFields',
|
||||||
|
result.content.map((f) => ({
|
||||||
|
id: `user_field_${f.id}`,
|
||||||
|
name: f.name
|
||||||
|
})).concat(
|
||||||
|
userProperties.map((f) => ({
|
||||||
|
id: f,
|
||||||
|
name: generateName(f)
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
currentWizard() {
|
||||||
|
const params = this.paramsFor('adminWizardsWizardShow');
|
||||||
|
|
||||||
|
if (params && params.wizardId) {
|
||||||
|
return params.wizardId;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model) {
|
||||||
|
let props = {
|
||||||
|
wizardList: model.wizard_list,
|
||||||
|
wizardId: this.currentWizard()
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.setProperties(props);
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
changeWizard(wizardId) {
|
||||||
|
this.controllerFor('adminWizardsWizard').set('wizardId', wizardId);
|
||||||
|
|
||||||
|
if (wizardId) {
|
||||||
|
this.transitionTo('adminWizardsWizardShow', wizardId);
|
||||||
|
} else {
|
||||||
|
this.transitionTo('adminWizardsWizard');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
afterDestroy() {
|
||||||
|
this.transitionTo('adminWizardsWizard').then(() => this.refresh());
|
||||||
|
},
|
||||||
|
|
||||||
|
afterSave(wizardId) {
|
||||||
|
this.refresh().then(() => this.send('changeWizard', wizardId));
|
||||||
|
},
|
||||||
|
|
||||||
|
createWizard() {
|
||||||
|
this.controllerFor('adminWizardsWizard').set('wizardId', 'create');
|
||||||
|
this.transitionTo('adminWizardsWizardShow', 'create');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
9
assets/javascripts/discourse/routes/admin-wizards.js.es6
Normale Datei
9
assets/javascripts/discourse/routes/admin-wizards.js.es6
Normale Datei
|
@ -0,0 +1,9 @@
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
|
export default DiscourseRoute.extend({
|
||||||
|
beforeModel(transition) {
|
||||||
|
if (transition.targetName === "adminWizards.index") {
|
||||||
|
this.transitionTo('adminWizardsWizard');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,16 +0,0 @@
|
||||||
<div class="wizard-submissions">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
{{#each fields as |f|}}
|
|
||||||
<th>{{f}}</th>
|
|
||||||
{{/each}}
|
|
||||||
</tr>
|
|
||||||
{{#each submissions as |s|}}
|
|
||||||
<tr>
|
|
||||||
{{#each-in s as |k v|}}
|
|
||||||
<td>{{v}}</td>
|
|
||||||
{{/each-in}}
|
|
||||||
</tr>
|
|
||||||
{{/each}}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
|
@ -1,150 +0,0 @@
|
||||||
<div class="admin-wizard settings">
|
|
||||||
|
|
||||||
<div class="wizard-header">
|
|
||||||
{{i18n 'admin.wizard.header'}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.id'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input name="name" value=model.id placeholderKey="admin.wizard.id_placeholder" disabled=model.existingId}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.name'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input name="name" value=model.name placeholderKey="admin.wizard.name_placeholder"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.background'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input name="background" value=model.background placeholderKey="admin.wizard.background_placeholder"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>{{i18n 'admin.wizard.save_submissions_label'}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.multiple_submissions'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type='checkbox' checked=model.multiple_submissions}}
|
|
||||||
<span>{{i18n 'admin.wizard.multiple_submissions_label'}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.required'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type='checkbox' checked=model.required}}
|
|
||||||
<span>{{i18n 'admin.wizard.required_label'}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.after_signup'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type='checkbox' checked=model.after_signup}}
|
|
||||||
<span>{{i18n 'admin.wizard.after_signup_label'}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.after_time'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type='checkbox' checked=model.after_time}}
|
|
||||||
<span>{{i18n 'admin.wizard.after_time_label'}}</span>
|
|
||||||
{{d-button action='setNextSessionScheduled' translatedLabel=nextSessionScheduledLabel icon='calendar-o'}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.prompt_completion'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type='checkbox' checked=model.prompt_completion}}
|
|
||||||
<span>{{i18n 'admin.wizard.prompt_completion_label'}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.min_trust'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
<span>{{i18n 'admin.wizard.min_trust_label'}}</span>
|
|
||||||
{{input type='number' value=model.min_trust class='input-small'}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.theme_id'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{combo-box
|
|
||||||
content=model.themes
|
|
||||||
valueProperty='id'
|
|
||||||
value=model.theme_id
|
|
||||||
none='admin.wizard.no_theme'}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.restart_on_revisit'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input type='checkbox' checked=model.restart_on_revisit}}
|
|
||||||
<span>{{i18n 'admin.wizard.restart_on_revisit_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>
|
|
||||||
|
|
||||||
{{wizard-links type="step" current=currentStep items=model.steps}}
|
|
||||||
{{#if currentStep}}
|
|
||||||
{{wizard-custom-step step=currentStep wizard=model}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class='buttons'>
|
|
||||||
<button {{action "save"}} disabled={{disableSave}} class='btn btn-primary'>{{i18n 'admin.wizard.save'}}</button>
|
|
||||||
{{#unless newWizard}}
|
|
||||||
<button {{action "remove"}} class='btn btn-danger remove'>{{d-icon "trash-o"}}{{i18n 'admin.wizard.remove'}}</button>
|
|
||||||
{{/unless}}
|
|
||||||
{{conditional-loading-spinner condition=saving size='small'}}
|
|
||||||
{{#if error}}
|
|
||||||
<span class="error">{{d-icon "times"}}{{error}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
310
assets/javascripts/discourse/templates/admin-wizards-api-show.hbs
Normale Datei
310
assets/javascripts/discourse/templates/admin-wizards-api-show.hbs
Normale Datei
|
@ -0,0 +1,310 @@
|
||||||
|
<div class="wizard-api-header page">
|
||||||
|
<div class='buttons'>
|
||||||
|
{{#if updating}}
|
||||||
|
{{loading-spinner size="small"}}
|
||||||
|
{{else}}
|
||||||
|
{{#if responseIcon}}
|
||||||
|
{{d-icon responseIcon}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{d-button label="admin.wizard.api.save" action=(action "save") class="btn-primary" disabled=saveDisabled}}
|
||||||
|
|
||||||
|
{{#if showRemove}}
|
||||||
|
{{d-button action=(action "remove") label="admin.wizard.api.remove"}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if error}}
|
||||||
|
<div class="error">
|
||||||
|
{{error}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-header">
|
||||||
|
{{#if api.isNew}}
|
||||||
|
{{i18n 'admin.wizard.api.new'}}
|
||||||
|
{{else}}
|
||||||
|
{{api.title}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="metadata">
|
||||||
|
<div class="title">
|
||||||
|
<label>{{i18n 'admin.wizard.api.title'}}</label>
|
||||||
|
{{input value=api.title placeholder=(i18n 'admin.wizard.api.title_placeholder')}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="name">
|
||||||
|
<label>{{i18n 'admin.wizard.api.name'}}</label>
|
||||||
|
{{#if api.isNew}}
|
||||||
|
{{input value=api.name placeholder=(i18n 'admin.wizard.api.name_placeholder')}}
|
||||||
|
{{else}}
|
||||||
|
{{api.name}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-api-header">
|
||||||
|
<div class="buttons">
|
||||||
|
{{#if isOauth}}
|
||||||
|
{{#if authorizing}}
|
||||||
|
{{loading-spinner size="small"}}
|
||||||
|
{{else}}
|
||||||
|
{{#if authErrorMessage}}
|
||||||
|
<span>{{authErrorMessage}}</span>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{d-button label="admin.wizard.api.auth.btn"
|
||||||
|
action=(action "authorize")
|
||||||
|
disabled=authDisabled
|
||||||
|
class="btn-primary"}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-header">
|
||||||
|
{{i18n 'admin.wizard.api.auth.label'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-api-authentication">
|
||||||
|
<div class="settings">
|
||||||
|
|
||||||
|
<div class="wizard-header medium">
|
||||||
|
{{i18n 'admin.wizard.api.auth.settings'}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if showRedirectUri}}
|
||||||
|
<div class="control-group redirect-uri">
|
||||||
|
<div class="control-label">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth.redirect_uri'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.redirectUri}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="control-group auth-type">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth.type'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{combo-box
|
||||||
|
value=api.authType
|
||||||
|
content=authorizationTypes
|
||||||
|
onChange=(action (mut authorizationTypes))
|
||||||
|
options=(hash
|
||||||
|
none='admin.wizard.api.auth.type_none'
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if isOauth}}
|
||||||
|
{{#if threeLeggedOauth}}
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth.url'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.authUrl}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth.token_url'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.tokenUrl}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth.client_id'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.clientId}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth.client_secret'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.clientSecret}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth.params.label'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{#each api.authParams as |param|}}
|
||||||
|
<div class="param">
|
||||||
|
{{input value=param.key placeholder=(i18n 'admin.wizard.key')}}
|
||||||
|
{{input value=param.value placeholder=(i18n 'admin.wizard.value')}}
|
||||||
|
{{d-button action=(action "removeParam") actionParam=param icon='times'}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
{{d-button label='admin.wizard.api.auth.params.new' icon='plus' action=(action "addParam")}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if isBasicAuth}}
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth.username'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.username}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.auth.password'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{input value=api.password}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if isOauth}}
|
||||||
|
<div class="status">
|
||||||
|
<div class="authorization">
|
||||||
|
{{#if api.authorized}}
|
||||||
|
<span class="authorization-indicator authorized"></span>
|
||||||
|
<span>{{i18n "admin.wizard.api.status.authorized"}}</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="authorization-indicator not-authorized"></span>
|
||||||
|
<span>{{i18n "admin.wizard.api.status.not_authorized"}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-header medium">
|
||||||
|
{{i18n 'admin.wizard.api.status.label'}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if threeLeggedOauth}}
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.status.code'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.code}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.status.access_token'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.accessToken}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if threeLeggedOauth}}
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.status.refresh_token'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.refreshToken}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.status.expires_at'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.tokenExpiresAt}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'admin.wizard.api.status.refresh_at'}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
{{api.tokenRefreshAt}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-header">
|
||||||
|
{{i18n 'admin.wizard.api.endpoint.label'}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-api-endpoints">
|
||||||
|
{{d-button action=(action "addEndpoint") label='admin.wizard.api.endpoint.add' icon='plus'}}
|
||||||
|
|
||||||
|
{{#if api.endpoints}}
|
||||||
|
<div class="endpoint-list">
|
||||||
|
<ul>
|
||||||
|
{{#each api.endpoints as |endpoint|}}
|
||||||
|
<li>
|
||||||
|
<div class="endpoint">
|
||||||
|
<div class="endpoint-">
|
||||||
|
<div class="top">
|
||||||
|
{{input value=endpoint.name
|
||||||
|
placeholder=(i18n 'admin.wizard.api.endpoint.name')}}
|
||||||
|
{{input value=endpoint.url
|
||||||
|
placeholder=(i18n 'admin.wizard.api.endpoint.url')
|
||||||
|
class='endpoint-url'}}
|
||||||
|
{{d-button action=(action "removeEndpoint")
|
||||||
|
actionParam=endpoint
|
||||||
|
icon='times'
|
||||||
|
class='remove-endpoint'}}
|
||||||
|
</div>
|
||||||
|
<div class="bottom">
|
||||||
|
{{combo-box
|
||||||
|
content=endpointMethods
|
||||||
|
value=endpoint.method
|
||||||
|
onChange=(action (mut endpoint.method))
|
||||||
|
options=(hash
|
||||||
|
none="admin.wizard.api.endpoint.method"
|
||||||
|
)}}
|
||||||
|
{{combo-box
|
||||||
|
content=contentTypes
|
||||||
|
value=endpoint.content_type
|
||||||
|
onChange=(action (mut endpoint.content_type))
|
||||||
|
options=(hash
|
||||||
|
none="admin.wizard.api.endpoint.content_type"
|
||||||
|
)}}
|
||||||
|
{{multi-select
|
||||||
|
content=successCodes
|
||||||
|
values=endpoint.success_codes
|
||||||
|
onChange=(action (mut endpoint.success_codes))
|
||||||
|
options=(hash
|
||||||
|
none="admin.wizard.api.endpoint.success_codes"
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-header">
|
||||||
|
{{i18n 'admin.wizard.api.log.label'}}
|
||||||
|
{{d-button action=(action "clearLogs")
|
||||||
|
icon='trash-alt'
|
||||||
|
class='clear-logs'}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-api-log">
|
||||||
|
<div class="log-list">
|
||||||
|
<table class="wizard-api-log-table">
|
||||||
|
<th>Datetime</th>
|
||||||
|
<th>User</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>URL</th>
|
||||||
|
<th>Error</th>
|
||||||
|
{{#each api.log as |logentry|}}
|
||||||
|
<tr>
|
||||||
|
<td>{{logentry.time}}</td>
|
||||||
|
<td class="user-image">
|
||||||
|
<div class="user-image-inner">
|
||||||
|
<a href="{{unbound logentry.userpath}}" data-user-card="{{unbound logentry.username}}">{{avatar logentry imageSize="large"}}</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>{{logentry.status}}</td>
|
||||||
|
<td>{{logentry.url}}</td>
|
||||||
|
<td>{{logentry.error}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,298 +1,3 @@
|
||||||
<div class="wizard-api-header page">
|
<div class="admin-wizard-container">
|
||||||
<div class='buttons'>
|
{{outlet}}
|
||||||
{{#if updating}}
|
|
||||||
{{loading-spinner size="small"}}
|
|
||||||
{{else}}
|
|
||||||
{{#if responseIcon}}
|
|
||||||
{{d-icon responseIcon}}
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{d-button label="admin.wizard.api.save" action=(action "save") class="btn-primary" disabled=saveDisabled}}
|
|
||||||
|
|
||||||
{{#if showRemove}}
|
|
||||||
{{d-button action=(action "remove") label="admin.wizard.api.remove"}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if error}}
|
|
||||||
<div class="error">
|
|
||||||
{{error}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wizard-header">
|
|
||||||
{{#if api.isNew}}
|
|
||||||
{{i18n 'admin.wizard.api.new'}}
|
|
||||||
{{else}}
|
|
||||||
{{api.title}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="metadata">
|
|
||||||
<div class="title">
|
|
||||||
<label>{{i18n 'admin.wizard.api.title'}}</label>
|
|
||||||
{{input value=api.title placeholder=(i18n 'admin.wizard.api.title_placeholder')}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="name">
|
|
||||||
<label>{{i18n 'admin.wizard.api.name'}}</label>
|
|
||||||
{{#if api.isNew}}
|
|
||||||
{{input value=api.name placeholder=(i18n 'admin.wizard.api.name_placeholder')}}
|
|
||||||
{{else}}
|
|
||||||
{{api.name}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wizard-api-header">
|
|
||||||
<div class="buttons">
|
|
||||||
{{#if isOauth}}
|
|
||||||
{{#if authorizing}}
|
|
||||||
{{loading-spinner size="small"}}
|
|
||||||
{{else}}
|
|
||||||
{{#if authErrorMessage}}
|
|
||||||
<span>{{authErrorMessage}}</span>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
{{d-button label="admin.wizard.api.auth.btn"
|
|
||||||
action=(action "authorize")
|
|
||||||
disabled=authDisabled
|
|
||||||
class="btn-primary"}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wizard-header">
|
|
||||||
{{i18n 'admin.wizard.api.auth.label'}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wizard-api-authentication">
|
|
||||||
<div class="settings">
|
|
||||||
|
|
||||||
<div class="wizard-header medium">
|
|
||||||
{{i18n 'admin.wizard.api.auth.settings'}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if showRedirectUri}}
|
|
||||||
<div class="control-group redirect-uri">
|
|
||||||
<div class="control-label">
|
|
||||||
<label>{{i18n 'admin.wizard.api.auth.redirect_uri'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{api.redirectUri}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="control-group auth-type">
|
|
||||||
<label>{{i18n 'admin.wizard.api.auth.type'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{combo-box
|
|
||||||
value=api.authType
|
|
||||||
content=authorizationTypes
|
|
||||||
none='admin.wizard.api.auth.type_none'}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if isOauth}}
|
|
||||||
{{#if threeLeggedOauth}}
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.auth.url'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{input value=api.authUrl}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.auth.token_url'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{input value=api.tokenUrl}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.auth.client_id'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{input value=api.clientId}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.auth.client_secret'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{input value=api.clientSecret}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.auth.params.label'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{#each api.authParams as |param|}}
|
|
||||||
<div class="param">
|
|
||||||
{{input value=param.key placeholder=(i18n 'admin.wizard.api.auth.params.key')}}
|
|
||||||
{{input value=param.value placeholder=(i18n 'admin.wizard.api.auth.params.value')}}
|
|
||||||
{{d-button action=(action "removeParam") actionParam=param icon='times'}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
{{d-button label='admin.wizard.api.auth.params.new' icon='plus' action=(action "addParam")}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if isBasicAuth}}
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.auth.username'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{input value=api.username}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.auth.password'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{input value=api.password}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if isOauth}}
|
|
||||||
<div class="status">
|
|
||||||
<div class="authorization">
|
|
||||||
{{#if api.authorized}}
|
|
||||||
<span class="authorization-indicator authorized"></span>
|
|
||||||
<span>{{i18n "admin.wizard.api.status.authorized"}}</span>
|
|
||||||
{{else}}
|
|
||||||
<span class="authorization-indicator not-authorized"></span>
|
|
||||||
<span>{{i18n "admin.wizard.api.status.not_authorized"}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wizard-header medium">
|
|
||||||
{{i18n 'admin.wizard.api.status.label'}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if threeLeggedOauth}}
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.status.code'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{api.code}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.status.access_token'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{api.accessToken}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if threeLeggedOauth}}
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.status.refresh_token'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{api.refreshToken}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.status.expires_at'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{api.tokenExpiresAt}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'admin.wizard.api.status.refresh_at'}}</label>
|
|
||||||
<div class="controls">
|
|
||||||
{{api.tokenRefreshAt}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wizard-header">
|
|
||||||
{{i18n 'admin.wizard.api.endpoint.label'}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wizard-api-endpoints">
|
|
||||||
{{d-button action=(action "addEndpoint") label='admin.wizard.api.endpoint.add' icon='plus'}}
|
|
||||||
|
|
||||||
{{#if api.endpoints}}
|
|
||||||
<div class="endpoint-list">
|
|
||||||
<ul>
|
|
||||||
{{#each api.endpoints as |endpoint|}}
|
|
||||||
<li>
|
|
||||||
<div class="endpoint">
|
|
||||||
<div class="endpoint-">
|
|
||||||
<div class="top">
|
|
||||||
{{input value=endpoint.name
|
|
||||||
placeholder=(i18n 'admin.wizard.api.endpoint.name')}}
|
|
||||||
{{input value=endpoint.url
|
|
||||||
placeholder=(i18n 'admin.wizard.api.endpoint.url')
|
|
||||||
class='endpoint-url'}}
|
|
||||||
{{d-button action=(action "removeEndpoint")
|
|
||||||
actionParam=endpoint
|
|
||||||
icon='times'
|
|
||||||
class='remove-endpoint'}}
|
|
||||||
</div>
|
|
||||||
<div class="bottom">
|
|
||||||
{{combo-box
|
|
||||||
content=endpointMethods
|
|
||||||
value=endpoint.method
|
|
||||||
none="admin.wizard.api.endpoint.method"}}
|
|
||||||
{{combo-box
|
|
||||||
content=contentTypes
|
|
||||||
value=endpoint.content_type
|
|
||||||
none="admin.wizard.api.endpoint.content_type"}}
|
|
||||||
{{multi-select
|
|
||||||
content=successCodes
|
|
||||||
values=endpoint.success_codes
|
|
||||||
none="admin.wizard.api.endpoint.success_codes"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wizard-header">
|
|
||||||
{{i18n 'admin.wizard.api.log.label'}}
|
|
||||||
{{d-button action=(action "clearLogs")
|
|
||||||
icon='trash-alt'
|
|
||||||
class='clear-logs'}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wizard-api-log">
|
|
||||||
<div class="log-list">
|
|
||||||
<table class="wizard-api-log-table">
|
|
||||||
<th>Datetime</th>
|
|
||||||
<th>User</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>URL</th>
|
|
||||||
<th>Error</th>
|
|
||||||
{{#each api.log as |logentry|}}
|
|
||||||
<tr>
|
|
||||||
<td>{{logentry.time}}</td>
|
|
||||||
<td class="user-image">
|
|
||||||
<div class="user-image-inner">
|
|
||||||
<a href="{{unbound logentry.userpath}}" data-user-card="{{unbound logentry.username}}">{{avatar logentry imageSize="large"}}</a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>{{logentry.status}}</td>
|
|
||||||
<td>{{logentry.url}}</td>
|
|
||||||
<td>{{logentry.error}}</td>
|
|
||||||
</tr>
|
|
||||||
{{/each}}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
|
@ -1,26 +0,0 @@
|
||||||
<div class='row'>
|
|
||||||
<div class='content-list wizard-list'>
|
|
||||||
<ul>
|
|
||||||
{{#each model as |api|}}
|
|
||||||
<li>
|
|
||||||
{{#link-to "adminWizardsApi" (dasherize api.name)}}
|
|
||||||
{{#if api.title}}
|
|
||||||
{{api.title}}
|
|
||||||
{{else}}
|
|
||||||
{{api.name}}
|
|
||||||
{{/if}}
|
|
||||||
{{/link-to}}
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
<div class="new-api">
|
|
||||||
{{#link-to 'adminWizardsApi' 'new' class="btn"}}
|
|
||||||
{{d-icon "plus"}} {{i18n 'admin.wizard.api.new'}}
|
|
||||||
{{/link-to}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content">
|
|
||||||
{{outlet}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1 +0,0 @@
|
||||||
<div class="groups-type-index"></div>
|
|
|
@ -1,20 +0,0 @@
|
||||||
<div class='row'>
|
|
||||||
<div class='content-list wizard-list'>
|
|
||||||
<ul>
|
|
||||||
{{#each model as |w|}}
|
|
||||||
<li>
|
|
||||||
{{#link-to "adminWizard" (dasherize w.id)}}{{w.name}}{{/link-to}}
|
|
||||||
</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="content">
|
|
||||||
{{outlet}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
34
assets/javascripts/discourse/templates/admin-wizards-logs.hbs
Normale Datei
34
assets/javascripts/discourse/templates/admin-wizards-logs.hbs
Normale Datei
|
@ -0,0 +1,34 @@
|
||||||
|
<div class="admin-wizard-controls">
|
||||||
|
<h3>{{i18n 'admin.wizard.log.nav_label'}}</h3>
|
||||||
|
|
||||||
|
{{d-button
|
||||||
|
label="refresh"
|
||||||
|
icon="refresh"
|
||||||
|
action="refresh"
|
||||||
|
class="refresh"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#load-more selector=".log-list tr" action=(action "loadMore") class="wizard-logs"}}
|
||||||
|
{{#if noResults}}
|
||||||
|
<p>{{i18n 'search.no_results'}}</p>
|
||||||
|
{{else}}
|
||||||
|
<table class="table grid">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Message</th>
|
||||||
|
<th class="date">Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#each logs as |log|}}
|
||||||
|
<tr>
|
||||||
|
<td>{{log.message}}</td>
|
||||||
|
<td class="date">{{bound-date log.date}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{conditional-loading-spinner condition=refreshing}}
|
||||||
|
{{/load-more}}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{{#if submissions}}
|
||||||
|
<div class="wizard-header large">
|
||||||
|
<label>{{i18n 'admin.wizard.submissions.title' name=wizard.name}}</label>
|
||||||
|
|
||||||
|
<a class="btn btn-default download-link" href="{{downloadUrl}}" target="_blank">
|
||||||
|
{{d-icon 'download'}}
|
||||||
|
<span class="d-button-label">
|
||||||
|
{{i18n "admin.wizard.submissions.download"}}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-submissions">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
{{#each fields as |f|}}
|
||||||
|
<th>{{f}}</th>
|
||||||
|
{{/each}}
|
||||||
|
</tr>
|
||||||
|
{{#each submissions as |s|}}
|
||||||
|
<tr>
|
||||||
|
{{#each-in s as |k v|}}
|
||||||
|
<td>{{v}}</td>
|
||||||
|
{{/each-in}}
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
|
@ -1,15 +1,13 @@
|
||||||
<div class='row'>
|
<div class="admin-wizard-select">
|
||||||
<div class='content-list wizard-list'>
|
{{combo-box
|
||||||
<ul>
|
value=wizardId
|
||||||
{{#each model as |w|}}
|
content=wizardList
|
||||||
<li>
|
onChange=(route-action 'changeWizard')
|
||||||
{{#link-to "adminWizardSubmissions" w.id}}{{w.name}}{{/link-to}}
|
options=(hash
|
||||||
</li>
|
none='admin.wizard.select'
|
||||||
{{/each}}
|
)}}
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="admin-wizard-container">
|
||||||
<div class="content">
|
{{outlet}}
|
||||||
{{outlet}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
{{wizard-export wizards=model}}
|
{{wizard-export wizards=wizards}}
|
||||||
{{wizard-import}}
|
{{wizard-import}}
|
||||||
|
|
203
assets/javascripts/discourse/templates/admin-wizards-wizard-show.hbs
Normale Datei
203
assets/javascripts/discourse/templates/admin-wizards-wizard-show.hbs
Normale Datei
|
@ -0,0 +1,203 @@
|
||||||
|
{{#if wizard}}
|
||||||
|
<div class="wizard-header large">
|
||||||
|
{{input
|
||||||
|
name="name"
|
||||||
|
value=wizard.name
|
||||||
|
placeholderKey="admin.wizard.name_placeholder"}}
|
||||||
|
|
||||||
|
<div class="wizard-url">
|
||||||
|
{{#if wizard.name}}
|
||||||
|
{{#if copiedUrl}}
|
||||||
|
{{d-button class="btn-hover pull-right" icon="copy" label="ip_lookup.copied"}}
|
||||||
|
{{else}}
|
||||||
|
{{d-button action=(action "copyUrl") class="pull-right no-text" icon="copy"}}
|
||||||
|
{{/if}}
|
||||||
|
<a href="{{wizardUrl}}" target="_blank">{{wizardUrl}}</a>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-basic-details">
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.background'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input
|
||||||
|
name="background"
|
||||||
|
value=wizard.background
|
||||||
|
placeholderKey="admin.wizard.background_placeholder"
|
||||||
|
class="small"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.theme_id'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{combo-box
|
||||||
|
content=themes
|
||||||
|
valueProperty='id'
|
||||||
|
value=wizard.theme_id
|
||||||
|
onChange=(action (mut wizard.theme_id))
|
||||||
|
options=(hash
|
||||||
|
none='admin.wizard.no_theme'
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-header medium">
|
||||||
|
{{i18n 'admin.wizard.label'}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-settings">
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.required'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type='checkbox' checked=wizard.required}}
|
||||||
|
<span>{{i18n 'admin.wizard.required_label'}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.after_signup'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type='checkbox' checked=wizard.after_signup}}
|
||||||
|
<span>{{i18n 'admin.wizard.after_signup_label'}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.multiple_submissions'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type='checkbox' checked=wizard.multiple_submissions}}
|
||||||
|
<span>{{i18n 'admin.wizard.multiple_submissions_label'}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.prompt_completion'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type='checkbox' checked=wizard.prompt_completion}}
|
||||||
|
<span>{{i18n 'admin.wizard.prompt_completion_label'}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting full-inline">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.after_time'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type='checkbox' checked=wizard.after_time}}
|
||||||
|
<span>{{i18n 'admin.wizard.after_time_label'}}</span>
|
||||||
|
{{d-button
|
||||||
|
action='setNextSessionScheduled'
|
||||||
|
translatedLabel=nextSessionScheduledLabel
|
||||||
|
class="btn-after-time"
|
||||||
|
icon='far-calendar'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting full field-mapper-setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.permitted'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{wizard-mapper
|
||||||
|
inputs=wizard.permitted
|
||||||
|
options=(hash
|
||||||
|
context='wizard'
|
||||||
|
inputTypes='assignment,validation'
|
||||||
|
groupSelection='output'
|
||||||
|
userFieldSelection='key'
|
||||||
|
textSelection='value'
|
||||||
|
inputConnector='and'
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{wizard-advanced-toggle showAdvanced=wizard.showAdvanced}}
|
||||||
|
|
||||||
|
{{#if wizard.showAdvanced}}
|
||||||
|
<div class="advanced-settings">
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.save_submissions'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type='checkbox' checked=wizard.save_submissions}}
|
||||||
|
<span>{{i18n 'admin.wizard.save_submissions_label'}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.restart_on_revisit'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type='checkbox' checked=wizard.restart_on_revisit}}
|
||||||
|
<span>{{i18n 'admin.wizard.restart_on_revisit_label'}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{wizard-links
|
||||||
|
itemType="step"
|
||||||
|
current=currentStep
|
||||||
|
items=wizard.steps}}
|
||||||
|
|
||||||
|
{{#if currentStep}}
|
||||||
|
{{wizard-custom-step
|
||||||
|
step=currentStep
|
||||||
|
wizard=wizard
|
||||||
|
currentField=currentField
|
||||||
|
wizardFields=wizardFields
|
||||||
|
fieldTypes=fieldTypes}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{wizard-links
|
||||||
|
itemType="action"
|
||||||
|
current=currentAction
|
||||||
|
items=wizard.actions
|
||||||
|
generateLabels=true}}
|
||||||
|
|
||||||
|
{{#if currentAction}}
|
||||||
|
{{wizard-custom-action
|
||||||
|
action=currentAction
|
||||||
|
wizard=wizard
|
||||||
|
removeAction="removeAction"
|
||||||
|
wizardFields=wizardFields}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class='admin-wizard-buttons'>
|
||||||
|
<button {{action "save"}} disabled={{disableSave}} class='btn btn-primary'>
|
||||||
|
{{i18n 'admin.wizard.save'}}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{{#unless creating}}
|
||||||
|
<button {{action "remove"}} class='btn btn-danger remove'>
|
||||||
|
{{d-icon "far-trash-alt"}}{{i18n 'admin.wizard.remove'}}
|
||||||
|
</button>
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
|
{{conditional-loading-spinner condition=saving size='small'}}
|
||||||
|
|
||||||
|
{{#if error}}
|
||||||
|
<span class="error">{{d-icon "times"}}{{error}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
37
assets/javascripts/discourse/templates/admin-wizards-wizard.hbs
Normale Datei
37
assets/javascripts/discourse/templates/admin-wizards-wizard.hbs
Normale Datei
|
@ -0,0 +1,37 @@
|
||||||
|
<div class="admin-wizard-controls">
|
||||||
|
{{combo-box
|
||||||
|
value=wizardListVal
|
||||||
|
content=wizardList
|
||||||
|
onChange=(route-action 'changeWizard')
|
||||||
|
options=(hash
|
||||||
|
none='admin.wizard.select'
|
||||||
|
)}}
|
||||||
|
|
||||||
|
{{d-button
|
||||||
|
action="createWizard"
|
||||||
|
label="admin.wizard.create"
|
||||||
|
icon="plus"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="admin-wizard-message">
|
||||||
|
<div class="wizard-message">
|
||||||
|
{{d-icon 'info-circle'}}
|
||||||
|
<span>{{message}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-message">
|
||||||
|
{{d-icon 'question-circle'}}
|
||||||
|
|
||||||
|
<a href="https://thepavilion.io/c/knowledge/custom-wizard" target="_blank">
|
||||||
|
{{i18n 'admin.wizard.message.documentation'}}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{{!--<a href="mailto:help@thepavilion.io" target="_blank">
|
||||||
|
{{i18n 'admin.wizard.message.contact'}}
|
||||||
|
</a>--}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="admin-wizard-container settings">
|
||||||
|
{{outlet}}
|
||||||
|
</div>
|
|
@ -1,7 +1,10 @@
|
||||||
{{#admin-nav}}
|
{{#admin-nav}}
|
||||||
{{nav-item route='adminWizardsCustom' label='admin.wizard.custom_label'}}
|
{{nav-item route='adminWizardsWizard' label='admin.wizard.nav_label'}}
|
||||||
{{nav-item route='adminWizardsSubmissions' label='admin.wizard.submissions_label'}}
|
{{nav-item route='adminWizardsSubmissions' label='admin.wizard.submissions.nav_label'}}
|
||||||
{{nav-item route='adminWizardsApis' label='admin.wizard.api.nav_label'}}
|
{{#if siteSettings.wizard_apis_enabled}}
|
||||||
|
{{nav-item route='adminWizardsApi' label='admin.wizard.api.nav_label'}}
|
||||||
|
{{/if}}
|
||||||
|
{{nav-item route='adminWizardsLogs' label='admin.wizard.log.nav_label'}}
|
||||||
{{nav-item route='adminWizardsTransfer' label='admin.wizard.transfer.nav_label'}}
|
{{nav-item route='adminWizardsTransfer' label='admin.wizard.transfer.nav_label'}}
|
||||||
{{/admin-nav}}
|
{{/admin-nav}}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
{{d-button
|
||||||
|
action="toggleAdvanced"
|
||||||
|
label='admin.wizard.advanced'
|
||||||
|
class=toggleClass}}
|
|
@ -1,57 +1,65 @@
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.id"}}</h3>
|
<label>{{i18n "admin.wizard.type"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input value=action.id placeholderKey='admin.wizard.id_placeholder' disabled=disableId}}
|
{{combo-box
|
||||||
|
value=action.type
|
||||||
|
content=actionTypes
|
||||||
|
onChange=(action (mut action.type))
|
||||||
|
options=(hash
|
||||||
|
none="admin.wizard.field.type"
|
||||||
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.type"}}</h3>
|
<label>{{i18n "admin.wizard.action.run_after.label"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{combo-box
|
||||||
value=action.type
|
value=action.run_after
|
||||||
content=types
|
content=runAfterContent
|
||||||
none="admin.wizard.field.type"}}
|
onChange=(action (mut action.run_after))}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if basicTopicFields}}
|
{{#if basicTopicFields}}
|
||||||
<div class="setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.action.title"}}</h3>
|
<label>{{i18n "admin.wizard.action.title"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{wizard-mapper
|
||||||
value=action.title
|
inputs=action.title
|
||||||
content=availableFields
|
options=(hash
|
||||||
nameProperty="label"
|
wizardFieldSelection=true
|
||||||
isDisabled=action.custom_title_enabled
|
userFieldSelection='key,value'
|
||||||
none='admin.wizard.select_field'}}
|
context='action'
|
||||||
<div class="setting-gutter">
|
)}}
|
||||||
{{input type='checkbox' checked=action.custom_title_enabled}}
|
|
||||||
<span>{{i18n 'admin.wizard.action.custom_title'}}</span>
|
|
||||||
{{#if action.custom_title_enabled}}
|
|
||||||
{{input value=action.custom_title}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.action.post"}}</h3>
|
<label>{{i18n "admin.wizard.action.post"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{combo-box
|
||||||
value=action.post
|
value=action.post
|
||||||
content=availableFields
|
content=wizardFields
|
||||||
nameProperty='label'
|
nameProperty='label'
|
||||||
isDisabled=action.post_builder
|
onChange=(action (mut action.post))
|
||||||
none='admin.wizard.select_field'}}
|
options=(hash
|
||||||
|
none='admin.wizard.selector.placeholder.wizard_field'
|
||||||
|
isDisabled=showPostBuilder
|
||||||
|
)}}
|
||||||
|
|
||||||
<div class="setting-gutter">
|
<div class="setting-gutter">
|
||||||
{{input type='checkbox' checked=action.post_builder}}
|
{{input type='checkbox' checked=action.post_builder}}
|
||||||
<span>{{i18n 'admin.wizard.action.post_builder.checkbox'}}</span>
|
<span>{{i18n 'admin.wizard.action.post_builder.checkbox'}}</span>
|
||||||
|
@ -62,213 +70,167 @@
|
||||||
{{#if action.post_builder}}
|
{{#if action.post_builder}}
|
||||||
<div class="setting full">
|
<div class="setting full">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.action.post_builder.label'}}</h3>
|
<label>{{i18n 'admin.wizard.action.post_builder.label'}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value editor">
|
<div class="setting-value editor">
|
||||||
{{d-editor value=action.post_template
|
{{wizard-text-editor
|
||||||
placeholder='admin.wizard.action.interpolate_fields'
|
value=action.post_template
|
||||||
classNames='post-builder-editor'}}
|
wizardFields=wizardFields}}
|
||||||
<div>
|
|
||||||
<label>{{i18n 'admin.wizard.action.post_builder.user_fields'}}{{builderUserFields}}</label>
|
|
||||||
<label>{{i18n 'admin.wizard.action.post_builder.wizard_fields'}}{{builderWizardFields}}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if publicTopicFields}}
|
{{#if publicTopicFields}}
|
||||||
<div class="setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.action.create_topic.category"}}</h3>
|
<label>{{i18n "admin.wizard.action.create_topic.category"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{category-chooser
|
{{wizard-mapper
|
||||||
value=action.category_id
|
inputs=action.category
|
||||||
isDisabled=action.custom_category_enabled}}
|
options=(hash
|
||||||
<div class="setting-gutter">
|
textSelection='key,value'
|
||||||
{{input type='checkbox' checked=action.custom_category_enabled}}
|
wizardFieldSelection=true
|
||||||
<span>{{i18n 'admin.wizard.action.custom_category.label'}}</span>
|
userFieldSelection='key,value'
|
||||||
{{#if action.custom_category_enabled}}
|
categorySelection='output'
|
||||||
<div class="custom-category">
|
outputDefaultSelection='category'
|
||||||
<div>
|
context='action'
|
||||||
{{input type='checkbox' checked=action.custom_category_wizard_field}}
|
)}}
|
||||||
<span>{{i18n 'admin.wizard.action.custom_category.wizard_field'}}</span>
|
|
||||||
{{#if action.custom_category_wizard_field}}
|
|
||||||
{{combo-box
|
|
||||||
value=action.category_id
|
|
||||||
content=categoryFields
|
|
||||||
nameProperty="label"
|
|
||||||
none='admin.wizard.select_field'}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{input type='checkbox' checked=action.custom_category_user_field}}
|
|
||||||
<span>{{i18n 'admin.wizard.action.custom_category.user_field'}}</span>
|
|
||||||
{{#if action.custom_category_user_field}}
|
|
||||||
{{input value=action.custom_category_user_field_key}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.action.create_topic.tags"}}</h3>
|
<label>{{i18n "admin.wizard.action.create_topic.tags"}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
|
||||||
{{tag-chooser
|
|
||||||
tags=action.tags
|
|
||||||
filterable=true
|
|
||||||
allowCreate=true
|
|
||||||
isDisabled=action.custom_tag_enabled}}
|
|
||||||
<div class="setting-gutter">
|
|
||||||
{{input type='checkbox' checked=action.custom_tag_enabled}}
|
|
||||||
<span>{{i18n 'admin.wizard.action.custom_tag.label'}}</span>
|
|
||||||
{{#if action.custom_tag_enabled}}
|
|
||||||
<div class="custom-tag">
|
|
||||||
{{combo-box
|
|
||||||
value=action.custom_tag_field
|
|
||||||
content=tagFields
|
|
||||||
nameProperty="label"
|
|
||||||
none='admin.wizard.select_field'}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if newTopicFields}}
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n "admin.wizard.action.skip_redirect.label"}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type='checkbox' checked=action.skip_redirect}}
|
{{wizard-mapper
|
||||||
<span>{{i18n 'admin.wizard.action.skip_redirect.description' type='topic'}}</span>
|
inputs=action.tags
|
||||||
|
options=(hash
|
||||||
|
tagSelection='output'
|
||||||
|
outputDefaultSelection='tag'
|
||||||
|
listSelection='output'
|
||||||
|
wizardFieldSelection=true
|
||||||
|
userFieldSelection='key,value'
|
||||||
|
context='action'
|
||||||
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if createTopic}}
|
|
||||||
<div class="setting full">
|
|
||||||
<label>{{i18n 'admin.wizard.action.add_fields' type='Topic'}}</label>
|
|
||||||
{{wizard-custom-inputs inputs=action.add_fields
|
|
||||||
valueContent=availableFields
|
|
||||||
inputKey='admin.wizard.action.topic_attr'
|
|
||||||
noneValue='admin.wizard.select_field'
|
|
||||||
allowCustomField=true}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if sendMessage}}
|
{{#if sendMessage}}
|
||||||
<div class="setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.required'}}</h3>
|
<label>{{i18n "admin.wizard.action.send_message.recipient"}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
|
||||||
{{combo-box
|
|
||||||
value=action.required
|
|
||||||
content=availableFields
|
|
||||||
nameProperty='label'
|
|
||||||
none='admin.wizard.select_field'}}
|
|
||||||
</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>
|
|
||||||
|
|
||||||
<div class="setting full">
|
<div class="setting-value">
|
||||||
<label>{{i18n "admin.wizard.action.add_fields" type='Message'}}</label>
|
{{wizard-mapper
|
||||||
{{wizard-custom-inputs inputs=action.add_fields
|
inputs=action.recipient
|
||||||
keyContent=availableFields
|
options=(hash
|
||||||
valuePlaceholder='admin.wizard.action.topic_attr'}}
|
textSelection='value,output'
|
||||||
|
wizardFieldSelection=true
|
||||||
|
userFieldSelection='key,value'
|
||||||
|
groupSelection='key,value'
|
||||||
|
userSelection='output'
|
||||||
|
outputDefaultSelection='user'
|
||||||
|
context='action'
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if updateProfile}}
|
{{#if updateProfile}}
|
||||||
<div class="setting full">
|
<div class="setting full field-mapper-setting">
|
||||||
<label>{{i18n "admin.wizard.action.add_fields" type='Profile'}}</label>
|
<div class="setting-label">
|
||||||
{{wizard-custom-inputs inputs=action.profile_updates
|
<label>{{i18n 'admin.wizard.action.update_profile.label'}}</label>
|
||||||
valueContent=profileFields
|
</div>
|
||||||
keyContent=availableFields
|
|
||||||
noneValue='admin.wizard.action.update_profile.profile_field'
|
{{wizard-mapper
|
||||||
allowCustomField=true
|
inputs=action.profile_updates
|
||||||
allowUserField=true}}
|
options=(hash
|
||||||
|
inputTypes='association'
|
||||||
|
textSelection='value'
|
||||||
|
userFieldSelection='key'
|
||||||
|
wizardFieldSelection='value'
|
||||||
|
keyDefaultSelection='userField'
|
||||||
|
context='action'
|
||||||
|
)}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if sendToApi}}
|
{{#if sendToApi}}
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.action.send_to_api.api"}}</h3>
|
<label>{{i18n "admin.wizard.action.send_to_api.api"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{combo-box
|
||||||
value=action.api
|
value=action.api
|
||||||
content=availableApis
|
content=availableApis
|
||||||
isDisabled=action.custom_title_enabled
|
onChange=(action (mut action.api))
|
||||||
none='admin.wizard.action.send_to_api.select_an_api'}}
|
options=(hash
|
||||||
|
isDisabled=action.custom_title_enabled
|
||||||
|
none='admin.wizard.action.send_to_api.select_an_api'
|
||||||
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.action.send_to_api.endpoint"}}</h3>
|
<label>{{i18n "admin.wizard.action.send_to_api.endpoint"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{combo-box
|
||||||
value=action.api_endpoint
|
value=action.api_endpoint
|
||||||
content=availableEndpoints
|
content=availableEndpoints
|
||||||
isDisabled=apiEmpty
|
onChange=(action (mut action.api_endpoint))
|
||||||
none='admin.wizard.action.send_to_api.select_an_endpoint'}}
|
options=(hash
|
||||||
|
isDisabled=apiEmpty
|
||||||
|
none='admin.wizard.action.send_to_api.select_an_endpoint'
|
||||||
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting api-body">
|
<div class="setting full">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.action.send_to_api.body"}}</h3>
|
<label>{{i18n "admin.wizard.action.send_to_api.body"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
<label>{{i18n 'admin.wizard.action.post_builder.user_fields'}}{{builderUserFields}}</label>
|
{{wizard-text-editor
|
||||||
<label>{{i18n 'admin.wizard.action.post_builder.wizard_fields'}}{{builderWizardFields}}</label>
|
value=action.api_body
|
||||||
{{textarea value=action.api_body
|
previewEnabled=false
|
||||||
placeholder=(i18n 'admin.wizard.action.interpolate_fields')}}
|
barEnabled=false
|
||||||
|
wizardFields=wizardFields
|
||||||
|
placeholder='admin.wizard.action.send_to_api.body_placeholder'}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if addToGroup}}
|
{{#if addToGroup}}
|
||||||
<div class="setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.action.add_to_group.group_selection"}}</h3>
|
<label>{{i18n "admin.wizard.group"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{wizard-mapper
|
||||||
value=action.group_id
|
inputs=action.group
|
||||||
content=availableFields
|
options=(hash
|
||||||
isDisabled=action.custom_group_enabled
|
textSelection='value,output'
|
||||||
nameProperty="label"
|
wizardFieldSelection='key,value,assignment'
|
||||||
none='admin.wizard.select_field'}}
|
userFieldSelection='key,value,assignment'
|
||||||
<div class="setting-gutter">
|
groupSelection='value,output'
|
||||||
{{input type='checkbox' checked=action.custom_group_enabled}}
|
outputDefaultSelection='group'
|
||||||
<span>{{i18n 'admin.wizard.action.add_to_group.custom_group'}}</span>
|
context='action'
|
||||||
{{#if action.custom_group_enabled}}
|
)}}
|
||||||
{{input value=action.group_id}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -276,18 +238,88 @@
|
||||||
{{#if routeTo}}
|
{{#if routeTo}}
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n "admin.wizard.action.route_to.url"}}</h3>
|
<label>{{i18n "admin.wizard.action.route_to.url"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input value=action.url}}
|
{{input value=action.url}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting">
|
{{/if}}
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n "admin.wizard.action.route_to.code"}}</h3>
|
{{#if hasAdvanced}}
|
||||||
</div>
|
{{wizard-advanced-toggle showAdvanced=action.showAdvanced}}
|
||||||
<div class="setting-value">
|
|
||||||
{{input value=action.code}}
|
{{#if action.showAdvanced}}
|
||||||
</div>
|
<div class="advanced-settings">
|
||||||
</div>
|
|
||||||
|
{{#if hasCustomFields}}
|
||||||
|
<div class="setting full field-mapper-setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.action.custom_fields.label'}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{wizard-mapper
|
||||||
|
inputs=action.custom_fields
|
||||||
|
options=(hash
|
||||||
|
inputTypes='association'
|
||||||
|
wizardFieldSelection='value'
|
||||||
|
userFieldSelection='value'
|
||||||
|
keyPlaceholder='admin.wizard.action.custom_fields.key'
|
||||||
|
context='action'
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if sendMessage}}
|
||||||
|
<div class="setting full field-mapper-setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.required'}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{wizard-mapper
|
||||||
|
inputs=action.required
|
||||||
|
options=(hash
|
||||||
|
textSelection='value'
|
||||||
|
wizardFieldSelection=true
|
||||||
|
userFieldSelection=true
|
||||||
|
groupSelection=true
|
||||||
|
context='action'
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showSkipRedirect}}
|
||||||
|
<div class="setting full">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.action.skip_redirect.label"}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input type='checkbox' checked=action.skip_redirect}}
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{{i18n 'admin.wizard.action.skip_redirect.description' type='topic'}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if routeTo}}
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n "admin.wizard.action.route_to.code"}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input value=action.code}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -1,158 +1,165 @@
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.id'}}</h3>
|
<label>{{i18n 'admin.wizard.field.label'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input name="id" value=field.id placeholderKey="admin.wizard.id_placeholder" disabled=disableId}}
|
{{input name="label" value=field.label}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.key'}}</h3>
|
<label>{{i18n 'admin.wizard.field.required'}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input name="key" value=field.key placeholderKey="admin.wizard.key_placeholder"}}
|
<span>{{i18n 'admin.wizard.field.required_label'}}</span>
|
||||||
|
{{input type='checkbox' checked=field.required}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.field.label'}}</h3>
|
<label>{{i18n 'admin.wizard.field.description'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input name="label" value=field.label placeholder=(i18n "admin.wizard.custom_text_placeholder")}}
|
{{textarea name="description" value=field.description}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.field.description'}}</h3>
|
<label>{{i18n 'admin.wizard.field.image'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{textarea name="description" value=field.description placeholder=(i18n "admin.wizard.custom_text_placeholder")}}
|
{{image-uploader
|
||||||
|
imageUrl=field.image
|
||||||
|
onUploadDone=(action "imageUploadDone")
|
||||||
|
onUploadDeleted=(action "imageUploadDeleted")
|
||||||
|
type="wizard-step"
|
||||||
|
class="no-repeat contain-image"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.field.image'}}</h3>
|
<label>{{i18n 'admin.wizard.type'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
|
||||||
{{input name="image" value=field.image placeholderKey="admin.wizard.field.image_placeholder"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.type'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{combo-box
|
||||||
value=field.type
|
value=field.type
|
||||||
content=types
|
content=fieldTypes
|
||||||
none="admin.wizard.field.type"}}
|
onChange=(action (mut field.type))
|
||||||
|
options=(hash
|
||||||
|
none="admin.wizard.field.type"
|
||||||
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting">
|
{{#if showMinLength}}
|
||||||
<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 isInput}}
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.field.min_length'}}</h3>
|
<label>{{i18n 'admin.wizard.field.min_length'}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type="number" name="min_length" value=field.min_length placeholder=(i18n 'admin.wizard.field.min_length_placeholder')}}
|
{{input
|
||||||
|
type="number"
|
||||||
|
name="min_length"
|
||||||
|
value=field.min_length
|
||||||
|
class="small"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if isDropdown}}
|
|
||||||
<div class="wizard-dropdown-choices">
|
|
||||||
<div class="wizard-header small underline">
|
|
||||||
{{i18n 'admin.wizard.field.choices_label'}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{combo-box
|
|
||||||
value=field.choices_type
|
|
||||||
content=choicesTypes
|
|
||||||
none="admin.wizard.field.choices_type"}}
|
|
||||||
|
|
||||||
{{#if choicesTranslation}}
|
|
||||||
<div class="wizard-header small">
|
|
||||||
{{i18n 'admin.wizard.field.choices_translation'}}
|
|
||||||
</div>
|
|
||||||
{{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'}}
|
|
||||||
<div class="wizard-header small">
|
|
||||||
{{i18n 'admin.wizard.field.choices_preset.filter'}}
|
|
||||||
</div>
|
|
||||||
{{wizard-custom-inputs inputs=field.choices_filters}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if choicesCustom}}
|
|
||||||
<div class="wizard-header small">
|
|
||||||
{{i18n 'admin.wizard.field.choices_custom'}}
|
|
||||||
</div>
|
|
||||||
{{wizard-custom-inputs inputs=field.choices}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="wizard-header small">
|
|
||||||
{{i18n 'admin.wizard.field.dropdown_none'}}
|
|
||||||
</div>
|
|
||||||
{{input name="dropdown_none" value=field.dropdown_none placeholder=(i18n 'admin.wizard.field.dropdown_none_placeholder')}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if isUpload}}
|
{{#if isUpload}}
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.field.file_types'}}</h3>
|
<label>{{i18n 'admin.wizard.field.file_types'}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input value=field.file_types}}
|
{{input value=field.file_types class="medium"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if isCategoryOrTag}}
|
{{#if showLimit}}
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.field.limit'}}</h3>
|
<label>{{i18n 'admin.wizard.field.limit'}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type="number" value=field.limit}}
|
{{input type="number" value=field.limit class="small"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if isCategory}}
|
{{#if showPrefill}}
|
||||||
<div class="setting">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.field.property'}}</h3>
|
<label>{{i18n 'admin.wizard.field.prefill'}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{wizard-mapper
|
||||||
content=categoryPropertyTypes
|
inputs=field.prefill
|
||||||
value=field.property}}
|
options=prefillOptions}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showContent}}
|
||||||
|
<div class="setting full field-mapper-setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.field.content'}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{wizard-mapper
|
||||||
|
inputs=field.content
|
||||||
|
options=contentOptions}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{wizard-advanced-toggle showAdvanced=field.showAdvanced}}
|
||||||
|
|
||||||
|
{{#if field.showAdvanced}}
|
||||||
|
<div class="advanced-settings">
|
||||||
|
|
||||||
|
{{#if isCategory}}
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.field.property'}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
{{combo-box
|
||||||
|
value=field.property
|
||||||
|
content=categoryPropertyTypes
|
||||||
|
onChange=(action (mut field.property))
|
||||||
|
options=(hash
|
||||||
|
none='admin.wizard.selector.placeholder.property'
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.translation'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value medium">
|
||||||
|
{{input
|
||||||
|
name="key"
|
||||||
|
value=field.key
|
||||||
|
class="medium"
|
||||||
|
placeholderKey="admin.wizard.translation_placeholder"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
<div class="key">
|
|
||||||
{{#if keyContent}}
|
|
||||||
{{combo-box value=input.key content=keyContent nameProperty="label" none=noneKey}}
|
|
||||||
{{else}}
|
|
||||||
{{input type="text" value=input.key placeholder=(i18n inputKey)}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="connector">
|
|
||||||
{{#if connectorContent}}
|
|
||||||
{{combo-box value=input.connector
|
|
||||||
content=connectorContent
|
|
||||||
nameProperty="label"
|
|
||||||
none=connectorNone}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if connectorKey}}
|
|
||||||
{{i18n connectorKey}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="value">
|
|
||||||
{{#if valueContent}}
|
|
||||||
{{combo-box value=input.value
|
|
||||||
content=valueContent
|
|
||||||
nameProperty="label"
|
|
||||||
none=noneValue
|
|
||||||
isDisabled=valueDisabled}}
|
|
||||||
{{else}}
|
|
||||||
{{input type="text" value=input.value placeholder=(i18n valuePlaceholder)}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if allowCustomField}}
|
|
||||||
<div class="text-divider">
|
|
||||||
<span>{{i18n 'admin.wizard.or'}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{input type="text"
|
|
||||||
value=input.value_custom
|
|
||||||
placeholder=(i18n 'admin.wizard.custom_value_placeholder')
|
|
||||||
disabled=customDisabled}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if allowUserField}}
|
|
||||||
<div class="text-divider">
|
|
||||||
<span>{{i18n 'admin.wizard.or'}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{combo-box value=input.user_field
|
|
||||||
content=userFields
|
|
||||||
none='admin.wizard.user_field_placeholder'}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{d-button action=remove actionParam=input icon='times' class='remove'}}
|
|
|
@ -1,15 +0,0 @@
|
||||||
{{#each inputs as |input|}}
|
|
||||||
{{wizard-custom-input input=input
|
|
||||||
valueContent=valueContent
|
|
||||||
keyContent=keyContent
|
|
||||||
connectorContent=connectorContent
|
|
||||||
connectorKey=connectorKey
|
|
||||||
noneValue=noneValue
|
|
||||||
valuePlaceholder=valuePlaceholder
|
|
||||||
allowCustomField=allowCustomField
|
|
||||||
allowUserField=allowUserField
|
|
||||||
remove=(action 'remove')}}
|
|
||||||
{{/each}}
|
|
||||||
<div class="add-custom-input">
|
|
||||||
{{d-button action='add' label='admin.wizard.add' icon='plus'}}
|
|
||||||
</div>
|
|
|
@ -1,91 +1,108 @@
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.id'}}</h3>
|
<label>{{i18n 'admin.wizard.step.title'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input name="id" value=step.id placeholderKey="admin.wizard.id_placeholder" disabled=disableId}}
|
{{input
|
||||||
</div>
|
name="title"
|
||||||
</div>
|
value=step.title}}
|
||||||
|
|
||||||
<div class="setting">
|
|
||||||
<div class="setting-label">
|
|
||||||
<h3>{{i18n 'admin.wizard.key'}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="setting-value">
|
|
||||||
{{input name="key" value=step.key placeholderKey="admin.wizard.key_placeholder"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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.custom_text_placeholder"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>
|
</div>
|
||||||
|
|
||||||
<div class="setting full">
|
<div class="setting full">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.step.description'}}</h3>
|
<label>{{i18n 'admin.wizard.step.banner'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{d-editor value=step.raw_description placeholder="admin.wizard.custom_text_placeholder"}}
|
{{image-uploader
|
||||||
|
imageUrl=step.banner
|
||||||
|
onUploadDone=(action "bannerUploadDone")
|
||||||
|
onUploadDeleted=(action "bannerUploadDeleted")
|
||||||
|
type="wizard-banner"
|
||||||
|
class="no-repeat contain-image"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting required-data full">
|
<div class="setting full">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.step.required_data.label'}}</h3>
|
<label>{{i18n 'admin.wizard.step.description'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{wizard-custom-inputs inputs=step.required_data
|
{{wizard-text-editor
|
||||||
inputKey='admin.wizard.step.required_data.key'
|
value=step.raw_description
|
||||||
valueContent=requiredContent
|
wizardFields=descriptionWizardFields}}
|
||||||
connectorContent=requiredConnectorContent}}
|
</div>
|
||||||
{{#if step.required_data}}
|
</div>
|
||||||
<div class="required-data-message">
|
|
||||||
<div class="label">
|
{{wizard-advanced-toggle showAdvanced=step.showAdvanced}}
|
||||||
{{i18n 'admin.wizard.step.required_data.not_permitted_message'}}
|
|
||||||
</div>
|
{{#if step.showAdvanced}}
|
||||||
{{input value=step.required_data_message}}
|
<div class="advanced-settings">
|
||||||
|
|
||||||
|
<div class="setting full field-mapper-setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.step.required_data.label'}}</label>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
<div class="setting-value">
|
||||||
</div>
|
{{wizard-mapper
|
||||||
</div>
|
inputs=step.required_data
|
||||||
|
options=(hash
|
||||||
|
inputTypes='validation'
|
||||||
|
inputConnector='and'
|
||||||
|
wizardFieldSelection='value'
|
||||||
|
userFieldSelection='value'
|
||||||
|
keyPlaceholder="admin.wizard.submission_key"
|
||||||
|
context='step'
|
||||||
|
)}}
|
||||||
|
{{#if step.required_data}}
|
||||||
|
<div class="required-data-message">
|
||||||
|
<div class="label">
|
||||||
|
{{i18n 'admin.wizard.step.required_data.not_permitted_message'}}
|
||||||
|
</div>
|
||||||
|
{{input value=step.required_data_message}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="setting full">
|
<div class="setting full field-mapper-setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>{{i18n 'admin.wizard.step.permitted_params.label'}}</h3>
|
<label>{{i18n 'admin.wizard.step.permitted_params.label'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{wizard-custom-inputs inputs=step.permitted_params
|
{{wizard-mapper
|
||||||
inputKey='admin.wizard.step.permitted_params.key'
|
inputs=step.permitted_params
|
||||||
valuePlaceholder='admin.wizard.step.permitted_params.value'
|
options=(hash
|
||||||
connectorKey='admin.wizard.step.permitted_params.connector'}}
|
pairConnector='set'
|
||||||
</div>
|
inputTypes='association'
|
||||||
</div>
|
keyPlaceholder='admin.wizard.param_key'
|
||||||
|
valuePlaceholder='admin.wizard.submission_key'
|
||||||
|
context='step'
|
||||||
|
)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.translation'}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-value">
|
||||||
|
{{input
|
||||||
|
name="key"
|
||||||
|
value=step.key
|
||||||
|
placeholderKey="admin.wizard.translation_placeholder"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{wizard-links itemType="field" current=currentField items=step.fields}}
|
||||||
|
|
||||||
{{wizard-links type="field" current=currentField items=step.fields}}
|
|
||||||
{{#if currentField}}
|
{{#if currentField}}
|
||||||
{{wizard-custom-field field=currentField types=wizard.fieldTypes removeField="removeField"}}
|
{{wizard-custom-field
|
||||||
|
field=currentField
|
||||||
|
fieldTypes=fieldTypes
|
||||||
|
removeField="removeField"
|
||||||
|
wizardFields=wizardFields}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{wizard-links type="action" current=currentAction items=step.actions}}
|
|
||||||
{{#if currentAction}}
|
|
||||||
{{wizard-custom-action action=currentAction
|
|
||||||
wizard=wizard
|
|
||||||
removeAction="removeAction"
|
|
||||||
availableFields=availableFields}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<label>{{i18n 'admin.wizard.action.available_fields'}}</label>
|
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
<ul class="wizard-list-select">
|
<ul class="wizard-list-select">
|
||||||
{{#each wizards as |w|}}
|
{{#each wizards as |w|}}
|
||||||
<li>
|
<li>
|
||||||
{{input type="checkbox"
|
{{input
|
||||||
id=(dasherize w.id)
|
type="checkbox"
|
||||||
change=(action 'checkChanged')}}
|
id=(dasherize w.id)
|
||||||
{{#link-to "adminWizard" (dasherize w.id)}}
|
change=(action 'checkChanged')}}
|
||||||
|
|
||||||
|
{{#link-to "adminWizardsWizardShow" (dasherize w.id)}}
|
||||||
{{w.name}}
|
{{w.name}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
<div class="wizard-links {{type}}">
|
<div class="wizard-header medium">{{{i18n header}}}</div>
|
||||||
<div class="wizard-header medium">{{{i18n header}}}</div>
|
|
||||||
<ul>
|
<div class="link-list">
|
||||||
|
{{#if anyLinks}}
|
||||||
{{#each links as |l|}}
|
{{#each links as |l|}}
|
||||||
<li data-id='{{l.id}}'>
|
<div data-id='{{l.id}}'>
|
||||||
{{d-button action="change" actionParam=l.id translatedLabel=l.label class=l.classes}}
|
{{d-button action="change" actionParam=l.id translatedLabel=l.label class=l.classes}}
|
||||||
{{d-button action='remove' actionParam=l.id icon='times' class='remove'}}
|
{{d-button action='remove' actionParam=l.id icon='times' class='remove'}}
|
||||||
</li>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
{{/if}}
|
||||||
{{d-button action='add' label='admin.wizard.add' icon='plus'}}
|
{{d-button action='add' label='admin.wizard.add' icon='plus'}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{#if hasMultiple}}
|
||||||
|
{{combo-box
|
||||||
|
value=connector
|
||||||
|
content=connectors
|
||||||
|
onChange=(action (mut connector))}}
|
||||||
|
{{else}}
|
||||||
|
{{#if connector}}
|
||||||
|
<span class="connector-single">
|
||||||
|
{{connectorLabel}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
|
@ -0,0 +1,50 @@
|
||||||
|
{{wizard-mapper-connector
|
||||||
|
connector=input.type
|
||||||
|
connectors=inputTypes
|
||||||
|
inputTypes=true
|
||||||
|
inputType=inputType
|
||||||
|
connectorType="type"
|
||||||
|
options=options}}
|
||||||
|
|
||||||
|
{{#if hasPairs}}
|
||||||
|
<div class="mapper-pairs mapper-block">
|
||||||
|
{{#each input.pairs as |pair|}}
|
||||||
|
{{wizard-mapper-pair
|
||||||
|
pair=pair
|
||||||
|
last=pair.last
|
||||||
|
inputType=inputType
|
||||||
|
options=options
|
||||||
|
removePair=(action 'removePair')}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#if canAddPair}}
|
||||||
|
<a {{action 'addPair'}} class="add-pair">
|
||||||
|
{{d-icon 'plus'}}
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if hasOutput}}
|
||||||
|
{{#if hasPairs}}
|
||||||
|
{{wizard-mapper-connector
|
||||||
|
connector=input.output_connector
|
||||||
|
connectors=connectors
|
||||||
|
connectorType="output"
|
||||||
|
inputType=inputType
|
||||||
|
options=options}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="output mapper-block">
|
||||||
|
{{wizard-mapper-selector
|
||||||
|
selectorType='output'
|
||||||
|
inputType=input.type
|
||||||
|
value=input.output
|
||||||
|
activeType=input.output_type
|
||||||
|
options=options}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<a class="remove-input" {{action remove input}}>
|
||||||
|
{{d-icon 'times'}}
|
||||||
|
</a>
|
|
@ -0,0 +1,32 @@
|
||||||
|
<div class="key mapper-block">
|
||||||
|
{{wizard-mapper-selector
|
||||||
|
selectorType='key'
|
||||||
|
inputType=inputType
|
||||||
|
value=pair.key
|
||||||
|
activeType=pair.key_type
|
||||||
|
options=options}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{wizard-mapper-connector
|
||||||
|
connector=pair.connector
|
||||||
|
connectors=connectors
|
||||||
|
connectorType="pair"
|
||||||
|
inputType=inputType
|
||||||
|
options=options}}
|
||||||
|
|
||||||
|
<div class="value mapper-block">
|
||||||
|
{{wizard-mapper-selector
|
||||||
|
selectorType='value'
|
||||||
|
inputType=inputType
|
||||||
|
value=pair.value
|
||||||
|
activeType=pair.value_type
|
||||||
|
options=options}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if showJoin}}
|
||||||
|
<span class="join-pair">&</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showRemove}}
|
||||||
|
<a {{action removePair pair}} class="remove-pair">{{d-icon 'times'}}</a>
|
||||||
|
{{/if}}
|
|
@ -0,0 +1 @@
|
||||||
|
{{item.label}}
|
|
@ -0,0 +1,70 @@
|
||||||
|
<div class="type-selector">
|
||||||
|
{{#if hasTypes}}
|
||||||
|
<a {{action "toggleTypes"}} class="active">
|
||||||
|
{{activeTypeLabel}}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{{#if showTypes}}
|
||||||
|
<div class="selector-types">
|
||||||
|
{{#each selectorTypes as |item|}}
|
||||||
|
{{wizard-mapper-selector-type
|
||||||
|
activeType=activeType
|
||||||
|
item=item
|
||||||
|
toggle=(action 'toggleType')}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{else}}
|
||||||
|
<span>{{activeTypeLabel}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
{{#if showText}}
|
||||||
|
{{input
|
||||||
|
type="text"
|
||||||
|
value=value
|
||||||
|
placeholder=(i18n placeholderKey)}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showComboBox}}
|
||||||
|
{{combo-box
|
||||||
|
value=value
|
||||||
|
content=comboBoxContent
|
||||||
|
onChange=(action (mut value))
|
||||||
|
options=(hash
|
||||||
|
none=placeholderKey
|
||||||
|
)}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showMultiSelect}}
|
||||||
|
{{multi-select
|
||||||
|
content=multiSelectContent
|
||||||
|
value=value
|
||||||
|
onChange=(action (mut value))
|
||||||
|
options=multiSelectOptions}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showList}}
|
||||||
|
{{value-list
|
||||||
|
values=value
|
||||||
|
addKey=placeholderKey}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showTag}}
|
||||||
|
{{tag-chooser
|
||||||
|
tags=value
|
||||||
|
options=(hash
|
||||||
|
none=placeholderKey
|
||||||
|
filterable=true
|
||||||
|
)}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showUser}}
|
||||||
|
{{user-selector
|
||||||
|
includeMessageableGroups='true'
|
||||||
|
placeholderKey=placeholderKey
|
||||||
|
usernames=value
|
||||||
|
autocomplete="discourse"}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
16
assets/javascripts/discourse/templates/components/wizard-mapper.hbs
Normale Datei
16
assets/javascripts/discourse/templates/components/wizard-mapper.hbs
Normale Datei
|
@ -0,0 +1,16 @@
|
||||||
|
{{#each inputs as |input|}}
|
||||||
|
{{#if input.connector}}
|
||||||
|
{{wizard-mapper-connector connector=input.connector connectorType="input"}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{wizard-mapper-input
|
||||||
|
input=input
|
||||||
|
options=inputOptions
|
||||||
|
remove=(action 'remove')}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#if canAdd}}
|
||||||
|
<span class="add-mapper-input">
|
||||||
|
{{d-button action='add' label='admin.wizard.add' icon='plus'}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
|
@ -0,0 +1,34 @@
|
||||||
|
{{d-editor
|
||||||
|
value=value
|
||||||
|
forcePreview=forcePreview
|
||||||
|
placeholder=placeholder}}
|
||||||
|
|
||||||
|
<div class="wizard-editor-gutter">
|
||||||
|
{{#if previewEnabled}}
|
||||||
|
{{d-button
|
||||||
|
action="togglePreview"
|
||||||
|
translatedLabel=previewLabel}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if fieldsEnabled}}
|
||||||
|
{{d-button
|
||||||
|
action="togglePopover"
|
||||||
|
translatedLabel=popoverLabel}}
|
||||||
|
|
||||||
|
{{#if showPopover}}
|
||||||
|
<div class="wizard-editor-gutter-popover">
|
||||||
|
<label>
|
||||||
|
{{i18n 'admin.wizard.action.post_builder.user_fields'}}
|
||||||
|
{{userFieldList}}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{{#if hasWizardFields}}
|
||||||
|
<label>
|
||||||
|
{{i18n 'admin.wizard.action.post_builder.wizard_fields'}}
|
||||||
|
{{wizardFieldList}}
|
||||||
|
</label>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
|
@ -82,7 +82,7 @@
|
||||||
//= require discourse/components/d-button
|
//= require discourse/components/d-button
|
||||||
//= require discourse/components/composer-editor
|
//= require discourse/components/composer-editor
|
||||||
//= require discourse/components/d-editor
|
//= require discourse/components/d-editor
|
||||||
//= require discourse/components/popup-input-tip
|
//= require discourse/components/input-tip
|
||||||
//= require discourse/components/emoji-picker
|
//= require discourse/components/emoji-picker
|
||||||
//= require discourse/components/input-tip
|
//= require discourse/components/input-tip
|
||||||
//= require discourse/components/date-picker
|
//= require discourse/components/date-picker
|
||||||
|
@ -92,6 +92,7 @@
|
||||||
//= require discourse/templates/components/d-button
|
//= require discourse/templates/components/d-button
|
||||||
//= require discourse/templates/components/d-editor
|
//= require discourse/templates/components/d-editor
|
||||||
//= require discourse/templates/components/emoji-picker
|
//= require discourse/templates/components/emoji-picker
|
||||||
|
//= require discourse/templates/components/popup-input-tip
|
||||||
//= require discourse/templates/category-tag-autocomplete
|
//= require discourse/templates/category-tag-autocomplete
|
||||||
//= require discourse/templates/emoji-selector-autocomplete
|
//= require discourse/templates/emoji-selector-autocomplete
|
||||||
//= require discourse/templates/user-selector-autocomplete
|
//= require discourse/templates/user-selector-autocomplete
|
||||||
|
@ -107,7 +108,6 @@
|
||||||
//= require preload-store
|
//= require preload-store
|
||||||
//= require lodash.js
|
//= require lodash.js
|
||||||
//= require mousetrap.js
|
//= require mousetrap.js
|
||||||
//= require jquery.putcursoratend.js
|
|
||||||
//= require template_include.js
|
//= require template_include.js
|
||||||
//= require caret_position.js
|
//= require caret_position.js
|
||||||
//= require popper.js
|
//= require popper.js
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
|
import { default as computed, observes } from 'discourse-common/utils/decorators';
|
||||||
import { renderAvatar } from 'discourse/helpers/user-avatar';
|
import { renderAvatar } from 'discourse/helpers/user-avatar';
|
||||||
import userSearch from '../lib/user-search';
|
import userSearch from '../lib/user-search';
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ export default Ember.TextField.extend({
|
||||||
return usernames;
|
return usernames;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$().val(this.get('usernames')).autocomplete({
|
$(this.element).val(this.get('usernames')).autocomplete({
|
||||||
template,
|
template,
|
||||||
disabled: this.get('disabled'),
|
disabled: this.get('disabled'),
|
||||||
single: this.get('single'),
|
single: this.get('single'),
|
||||||
|
@ -121,7 +121,7 @@ export default Ember.TextField.extend({
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super();
|
this._super();
|
||||||
this.$().autocomplete('destroy');
|
$(this.element).autocomplete('destroy');
|
||||||
},
|
},
|
||||||
|
|
||||||
// THIS IS A HUGE HACK TO SUPPORT CLEARING THE INPUT
|
// THIS IS A HUGE HACK TO SUPPORT CLEARING THE INPUT
|
||||||
|
@ -129,7 +129,7 @@ export default Ember.TextField.extend({
|
||||||
_clearInput: function() {
|
_clearInput: function() {
|
||||||
if (arguments.length > 1) {
|
if (arguments.length > 1) {
|
||||||
if (Em.isEmpty(this.get("usernames"))) {
|
if (Em.isEmpty(this.get("usernames"))) {
|
||||||
this.$().parent().find("a").click();
|
$(this.element).parent().find("a").click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
assets/javascripts/wizard/components/wizard-category-selector.js.es6
Normale Datei
12
assets/javascripts/wizard/components/wizard-category-selector.js.es6
Normale Datei
|
@ -0,0 +1,12 @@
|
||||||
|
import CategorySelector from 'select-kit/components/category-selector';
|
||||||
|
import { computed } from "@ember/object";
|
||||||
|
import { makeArray } from "discourse-common/lib/helpers";
|
||||||
|
|
||||||
|
export default CategorySelector.extend({
|
||||||
|
content: computed("categories.[]", "blacklist.[]", "whitelist.[]", function() {
|
||||||
|
return this._super().filter(category => {
|
||||||
|
const whitelist = makeArray(this.whitelist);
|
||||||
|
return !whitelist.length || whitelist.indexOf(category.id) > -1;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,5 +1,5 @@
|
||||||
import ComposerEditor from 'discourse/components/composer-editor';
|
import ComposerEditor from 'discourse/components/composer-editor';
|
||||||
import { default as computed, on } from 'ember-addons/ember-computed-decorators';
|
import { default as computed, on } from 'discourse-common/utils/decorators';
|
||||||
import { findRawTemplate } from "discourse/lib/raw-templates";
|
import { findRawTemplate } from "discourse/lib/raw-templates";
|
||||||
import { throttle } from "@ember/runloop";
|
import { throttle } from "@ember/runloop";
|
||||||
import { scheduleOnce } from "@ember/runloop";
|
import { scheduleOnce } from "@ember/runloop";
|
||||||
|
@ -30,7 +30,6 @@ export default ComposerEditor.extend({
|
||||||
key: "@",
|
key: "@",
|
||||||
transformComplete: v => v.username || v.name,
|
transformComplete: v => v.username || v.name,
|
||||||
afterComplete() {
|
afterComplete() {
|
||||||
// ensures textarea scroll position is correct
|
|
||||||
scheduleOnce("afterRender", () => $input.blur().focus());
|
scheduleOnce("afterRender", () => $input.blur().focus());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,29 +1,32 @@
|
||||||
import { observes } from 'ember-addons/ember-computed-decorators';
|
import { observes } from 'discourse-common/utils/decorators';
|
||||||
import Category from 'discourse/models/category';
|
import Category from 'discourse/models/category';
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
const value = this.get('field.value');
|
const property = this.field.property || 'id';
|
||||||
|
const value = this.field.value;
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
const property = this.get('field.property') || 'id';
|
this.set('categories', [...value].reduce((result, v) => {
|
||||||
const categories = [...value].map(v => {
|
let val = property === 'id' ? Category.findById(v) : Category.findBySlug(v);
|
||||||
return property === 'id' ?
|
if (val) result.push(val);
|
||||||
Category.findById(v) :
|
return result;
|
||||||
Category.findBySlug(v);
|
}, []));
|
||||||
});
|
|
||||||
this.set('categories', categories);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes('categories')
|
@observes('categories')
|
||||||
setValue() {
|
setValue() {
|
||||||
const categories = this.get('categories');
|
const categories = (this.categories || []).filter(c => !!c);
|
||||||
|
const property = this.field.property || 'id';
|
||||||
|
|
||||||
if (categories.length) {
|
if (categories.length) {
|
||||||
const property = this.get('field.property') || 'id';
|
this.set('field.value', categories.reduce((result, c) => {
|
||||||
let value = categories.length === 1 ?
|
if (c && c[property]) {
|
||||||
categories[0][property] :
|
result.push(c[property])
|
||||||
categories.map(c => c[property]);
|
}
|
||||||
this.set('field.value', value);
|
return result;
|
||||||
|
}, []));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -1,4 +1,5 @@
|
||||||
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
|
import { default as computed, observes } from 'discourse-common/utils/decorators';
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
showPreview: false,
|
showPreview: false,
|
||||||
|
@ -6,7 +7,7 @@ export default Ember.Component.extend({
|
||||||
classNameBindings: ["showPreview:show-preview:hide-preview"],
|
classNameBindings: ["showPreview:show-preview:hide-preview"],
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this.set('composer', Ember.Object.create({
|
this.set('composer', EmberObject.create({
|
||||||
loading: false,
|
loading: false,
|
||||||
reply: this.get('field.value')
|
reply: this.get('field.value')
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -10,7 +10,7 @@ export default Ember.Component.extend({
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super();
|
this._super();
|
||||||
|
|
||||||
const $upload = this.$();
|
const $upload = $(this.element);
|
||||||
|
|
||||||
const id = this.get("field.id");
|
const id = this.get("field.id");
|
||||||
|
|
||||||
|
|
17
assets/javascripts/wizard/components/wizard-group-selector.js.es6
Normale Datei
17
assets/javascripts/wizard/components/wizard-group-selector.js.es6
Normale Datei
|
@ -0,0 +1,17 @@
|
||||||
|
import ComboBox from 'select-kit/components/combo-box';
|
||||||
|
import { computed } from "@ember/object";
|
||||||
|
import { makeArray } from "discourse-common/lib/helpers";
|
||||||
|
|
||||||
|
export default ComboBox.extend({
|
||||||
|
content: computed("groups.[]", "field.content.[]", function() {
|
||||||
|
const whitelist = makeArray(this.field.content);
|
||||||
|
return this.groups.filter(group => {
|
||||||
|
return !whitelist.length || whitelist.indexOf(group.id) > -1;
|
||||||
|
}).map(g => {
|
||||||
|
return {
|
||||||
|
id: g.id,
|
||||||
|
name: g.name
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
11
assets/javascripts/wizard/components/wizard-tag-selector.js.es6
Normale Datei
11
assets/javascripts/wizard/components/wizard-tag-selector.js.es6
Normale Datei
|
@ -0,0 +1,11 @@
|
||||||
|
import TagChooser from 'select-kit/components/tag-chooser';
|
||||||
|
import { makeArray } from "discourse-common/lib/helpers";
|
||||||
|
|
||||||
|
export default TagChooser.extend({
|
||||||
|
_transformJson(context, json) {
|
||||||
|
return this._super(context, json).filter((tag) => {
|
||||||
|
const whitelist = makeArray(context.whitelist);
|
||||||
|
return !whitelist.length || whitelist.indexOf(tag.id) > 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint no-undef: 0 */
|
/* eslint no-undef: 0 */
|
||||||
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
import computed from "discourse-common/utils/decorators";
|
||||||
import { siteDir, isRTL, isLTR } from "discourse/lib/text-direction";
|
import { siteDir, isRTL, isLTR } from "discourse/lib/text-direction";
|
||||||
|
|
||||||
export default Ember.TextField.extend({
|
export default Ember.TextField.extend({
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
import { default as computed } from 'discourse-common/utils/decorators';
|
||||||
|
import { dasherize } from "@ember/string";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'custom-routes',
|
name: 'custom-routes',
|
||||||
|
@ -19,7 +20,6 @@ export default {
|
||||||
const autocomplete = requirejs('discourse/lib/autocomplete').default;
|
const autocomplete = requirejs('discourse/lib/autocomplete').default;
|
||||||
const cook = requirejs('discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite').cook;
|
const cook = requirejs('discourse/plugins/discourse-custom-wizard/wizard/lib/text-lite').cook;
|
||||||
const Singleton = requirejs("discourse/mixins/singleton").default;
|
const Singleton = requirejs("discourse/mixins/singleton").default;
|
||||||
const WizardFieldDropdown = requirejs('wizard/components/wizard-field-dropdown').default;
|
|
||||||
const Store = requirejs("discourse/models/store").default;
|
const Store = requirejs("discourse/models/store").default;
|
||||||
const registerRawHelpers = requirejs("discourse-common/lib/raw-handlebars-helpers").registerRawHelpers;
|
const registerRawHelpers = requirejs("discourse-common/lib/raw-handlebars-helpers").registerRawHelpers;
|
||||||
const RawHandlebars = requirejs("discourse-common/lib/raw-handlebars").default;
|
const RawHandlebars = requirejs("discourse-common/lib/raw-handlebars").default;
|
||||||
|
@ -89,7 +89,15 @@ export default {
|
||||||
|
|
||||||
animateInvalidFields() {
|
animateInvalidFields() {
|
||||||
Ember.run.scheduleOnce('afterRender', () => {
|
Ember.run.scheduleOnce('afterRender', () => {
|
||||||
$('.invalid input[type=text], .invalid textarea, .invalid input[type=checkbox], .invalid .select-kit').wiggle(2, 100);
|
let $element = $('.invalid input[type=text], .invalid textarea, .invalid input[type=checkbox], .invalid .select-kit');
|
||||||
|
|
||||||
|
if ($element.length) {
|
||||||
|
$([document.documentElement, document.body]).animate({
|
||||||
|
scrollTop: $element.offset().top - 200
|
||||||
|
}, 400, function() {
|
||||||
|
$element.wiggle(2, 100);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -161,7 +169,7 @@ export default {
|
||||||
const fields = {};
|
const fields = {};
|
||||||
|
|
||||||
this.get('fields').forEach(f => {
|
this.get('fields').forEach(f => {
|
||||||
if (f.type !== 'text-only') {
|
if (f.type !== 'text_only') {
|
||||||
fields[f.id] = f.value;
|
fields[f.id] = f.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -171,6 +179,7 @@ export default {
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
data: { fields }
|
data: { fields }
|
||||||
}).catch(response => {
|
}).catch(response => {
|
||||||
|
console.log(response)
|
||||||
if (response && response.responseJSON && response.responseJSON.errors) {
|
if (response && response.responseJSON && response.responseJSON.errors) {
|
||||||
let wizardErrors = [];
|
let wizardErrors = [];
|
||||||
response.responseJSON.errors.forEach(err => {
|
response.responseJSON.errors.forEach(err => {
|
||||||
|
@ -185,6 +194,7 @@ export default {
|
||||||
if (wizardErrors.length) {
|
if (wizardErrors.length) {
|
||||||
this.handleWizardError(wizardErrors.join('\n'));
|
this.handleWizardError(wizardErrors.join('\n'));
|
||||||
}
|
}
|
||||||
|
this.animateInvalidFields();
|
||||||
throw response;
|
throw response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,8 +228,8 @@ export default {
|
||||||
inputComponentName: function() {
|
inputComponentName: function() {
|
||||||
const type = this.get('field.type');
|
const type = this.get('field.type');
|
||||||
const id = this.get('field.id');
|
const id = this.get('field.id');
|
||||||
if (['text-only'].includes(type)) return false;
|
if (['text_only'].includes(type)) return false;
|
||||||
return (type === 'component') ? Ember.String.dasherize(id) : `wizard-field-${type}`;
|
return dasherize((type === 'component') ? id : `wizard-field-${type}`);
|
||||||
}.property('field.type', 'field.id')
|
}.property('field.type', 'field.id')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -230,9 +240,11 @@ export default {
|
||||||
'dropdown',
|
'dropdown',
|
||||||
'tag',
|
'tag',
|
||||||
'image',
|
'image',
|
||||||
'user-selector',
|
'user_selector',
|
||||||
'text-only',
|
'text_only',
|
||||||
'composer'
|
'composer',
|
||||||
|
'category',
|
||||||
|
'group'
|
||||||
];
|
];
|
||||||
|
|
||||||
FieldModel.reopen({
|
FieldModel.reopen({
|
||||||
|
@ -256,16 +268,15 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
const val = this.get('value');
|
const val = this.get('value');
|
||||||
const type = this.get('type');
|
const type = this.get('type');
|
||||||
|
|
||||||
if (type === 'checkbox') {
|
if (type === 'checkbox') {
|
||||||
valid = val;
|
valid = val;
|
||||||
} else if (type === 'category') {
|
|
||||||
valid = val && val.toString().length > 0;
|
|
||||||
} else if (type === 'upload') {
|
} else if (type === 'upload') {
|
||||||
valid = val && val.id > 0;
|
valid = val && val.id > 0;
|
||||||
} else if (StandardFieldValidation.indexOf(type) > -1) {
|
} else if (StandardFieldValidation.indexOf(type) > -1) {
|
||||||
valid = val && val.length > 0;
|
valid = val && val.toString().length > 0;
|
||||||
} else if (type === 'url') {
|
} else if (type === 'url') {
|
||||||
valid = true
|
valid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
import { default as computed } from 'discourse-common/utils/decorators';
|
||||||
import getUrl from 'discourse-common/lib/get-url';
|
import getUrl from 'discourse-common/lib/get-url';
|
||||||
import WizardField from 'wizard/models/wizard-field';
|
import WizardField from 'wizard/models/wizard-field';
|
||||||
import { ajax } from 'wizard/lib/ajax';
|
import { ajax } from 'wizard/lib/ajax';
|
||||||
import Step from 'wizard/models/step';
|
import Step from 'wizard/models/step';
|
||||||
|
import EmberObject from "@ember/object";
|
||||||
|
|
||||||
const CustomWizard = Ember.Object.extend({
|
const CustomWizard = EmberObject.extend({
|
||||||
@computed('steps.length')
|
@computed('steps.length')
|
||||||
totalSteps: length => length,
|
totalSteps: length => length,
|
||||||
|
|
||||||
skip() {
|
skip() {
|
||||||
if (this.get('required') && (!this.get('completed') && this.get('permitted'))) return;
|
if (this.required && (!this.completed && this.permitted)) return;
|
||||||
const id = this.get('id');
|
CustomWizard.skip(this.id);
|
||||||
CustomWizard.skip(id);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ export function findCustomWizard(wizardId, params = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ajax({ url, cache: false, dataType: 'json' }).then(result => {
|
return ajax({ url, cache: false, dataType: 'json' }).then(result => {
|
||||||
const wizard = result.custom_wizard;
|
const wizard = result;
|
||||||
if (!wizard) return null;
|
if (!wizard) return null;
|
||||||
|
|
||||||
if (!wizard.completed) {
|
if (!wizard.completed) {
|
||||||
|
@ -70,7 +70,7 @@ export function findCustomWizard(wizardId, params = {}) {
|
||||||
subcatMap[c.parent_category_id] || [];
|
subcatMap[c.parent_category_id] || [];
|
||||||
subcatMap[c.parent_category_id].push(c.id);
|
subcatMap[c.parent_category_id].push(c.id);
|
||||||
}
|
}
|
||||||
return (categoriesById[c.id] = Ember.Object.create(c));
|
return (categoriesById[c.id] = EmberObject.create(c));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Associate the categories with their parents
|
// Associate the categories with their parents
|
||||||
|
|
|
@ -14,7 +14,6 @@ export default Ember.Route.extend({
|
||||||
if (model) {
|
if (model) {
|
||||||
const completed = model.get('completed');
|
const completed = model.get('completed');
|
||||||
const permitted = model.get('permitted');
|
const permitted = model.get('permitted');
|
||||||
const minTrust = model.get('min_trust');
|
|
||||||
const wizardId = model.get('id');
|
const wizardId = model.get('id');
|
||||||
const user = model.get('user');
|
const user = model.get('user');
|
||||||
const name = model.get('name');
|
const name = model.get('name');
|
||||||
|
@ -25,7 +24,6 @@ export default Ember.Route.extend({
|
||||||
name,
|
name,
|
||||||
completed,
|
completed,
|
||||||
notPermitted: !permitted,
|
notPermitted: !permitted,
|
||||||
minTrust,
|
|
||||||
wizardId
|
wizardId
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{{category-selector
|
{{wizard-category-selector
|
||||||
categories=categories
|
categories=categories
|
||||||
|
whitelist=field.content
|
||||||
maximum=field.limit
|
maximum=field.limit
|
||||||
onChange=(action (mut categories))}}
|
onChange=(action (mut categories))}}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{{combo-box elementId=field.id
|
{{combo-box
|
||||||
class=fieldClass
|
class=fieldClass
|
||||||
value=field.value
|
value=field.value
|
||||||
content=field.choices
|
content=field.content
|
||||||
none=(hash id="__none__" label=field.dropdown_none)
|
options=(hash
|
||||||
nameProperty="label"
|
none="select_kit.default_header_text"
|
||||||
tabindex="9"}}
|
)}}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{{wizard-group-selector
|
||||||
|
groups=wizard.groups
|
||||||
|
field=field
|
||||||
|
whitelist=field.content
|
||||||
|
value=field.value
|
||||||
|
onChange=(action (mut field.value))
|
||||||
|
options=(hash
|
||||||
|
none='group.select'
|
||||||
|
)}}
|
|
@ -1,7 +1,5 @@
|
||||||
<label for={{field.id}}>
|
<label for={{field.id}} class="field-label">
|
||||||
{{#if field.label}}
|
{{{field.label}}}
|
||||||
<span class='label-value'>{{{field.label}}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{{#if field.image}}
|
{{#if field.image}}
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
<h1 class='wizard-step-title'>{{cookedTitle}}</h1>
|
<h1 class='wizard-step-title'>{{cookedTitle}}</h1>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if step.description}}
|
|
||||||
<div class='wizard-step-description'>{{cookedDescription}}</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if bannerImage}}
|
{{#if bannerImage}}
|
||||||
<div class="wizard-step-banner">
|
<div class="wizard-step-banner">
|
||||||
<img src={{bannerImage}}>
|
<img src={{bannerImage}}>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if step.description}}
|
||||||
|
<div class='wizard-step-description'>{{cookedDescription}}</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#wizard-step-form step=step}}
|
{{#wizard-step-form step=step}}
|
||||||
{{#each step.fields as |field|}}
|
{{#each step.fields as |field|}}
|
||||||
{{wizard-field field=field step=step wizard=wizard}}
|
{{wizard-field field=field step=step wizard=wizard}}
|
||||||
|
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden …
In neuem Issue referenzieren