0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-25 18:50:27 +01:00
Dieser Commit ist enthalten in:
Angus McLeod 2020-04-02 16:21:57 +11:00
Ursprung 694f5f1898
Commit 87a53a8c85
32 geänderte Dateien mit 600 neuen und 429 gelöschten Zeilen

Datei anzeigen

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

Datei anzeigen

@ -1,11 +1,11 @@
import { default as discourseComputed, observes } from 'discourse-common/utils/decorators';
import { equal, not, empty } from "@ember/object/computed";
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
import { equal, not, empty, or } from "@ember/object/computed";
import {
actionTypes,
generateName,
generateSelectKitContent,
profileFields
} from '../lib/custom-wizard';
} from '../lib/wizard';
export default Ember.Component.extend({
classNames: 'wizard-custom-action',
@ -19,6 +19,13 @@ export default Ember.Component.extend({
routeTo: equal('action.type', 'route_to'),
disableId: not('action.isNew'),
groupPropertyTypes: generateSelectKitContent(['id', 'name']),
hasAdvanced: or('basicTopicFields', 'routeTo'),
@on('didInsertElement')
@observes('action.type')
updateId() {
if (this.action.type) this.set('action.id', generateName(this.action.type));
},
@discourseComputed('action.type')
basicTopicFields(actionType) {

Datei anzeigen

@ -1,6 +1,6 @@
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
import { equal, not, or } from "@ember/object/computed";
import { generateSelectKitContent } from '../lib/custom-wizard';
import { generateSelectKitContent } from '../lib/wizard';
export default Ember.Component.extend({
classNames: 'wizard-custom-field',
@ -16,6 +16,7 @@ export default Ember.Component.extend({
categoryPropertyTypes: generateSelectKitContent(['id', 'slug']),
prefillEnabled: or('isCategory', 'isTag', 'isGroup'),
contentEnabled: or('isCategory', 'isTag', 'isGroup'),
hasAdvanced: or('isCategory', 'isTag', 'isGroup'),
@discourseComputed('field.type')
isInput: (type) => type === 'text' || type === 'textarea' || type === 'url',

Datei anzeigen

@ -1,5 +1,6 @@
import { observes, on, default as discourseComputed } from 'discourse-common/utils/decorators';
import { not } from "@ember/object/computed";
import EmberObject from "@ember/object";
export default Ember.Component.extend({
classNames: 'wizard-custom-step',
@ -31,7 +32,7 @@ export default Ember.Component.extend({
actions.forEach(a => {
if (a.type === 'route_to' && a.code) {
content.push(
Ember.Object.create({
EmberObject.create({
id: a.code,
label: "code (Route To)"
})

Datei anzeigen

@ -1,6 +1,7 @@
import { default as computed, on, observes } from 'discourse-common/utils/decorators';
import { notEmpty } from "@ember/object/computed";
import { scheduleOnce } from "@ember/runloop";
import EmberObject from "@ember/object";
export default Ember.Component.extend({
classNameBindings: [':wizard-links', 'type'],
@ -67,7 +68,7 @@ export default Ember.Component.extend({
params['actions'] = Ember.A();
};
const newItem = Ember.Object.create(params);
const newItem = EmberObject.create(params);
items.pushObject(newItem);
this.set('current', newItem);
},

Datei anzeigen

@ -0,0 +1,13 @@
import Component from "@ember/component";
import { lt } from '@ember/object/computed';
import { computed } from "@ember/object";
export default Component.extend({
classNameBindings: [':mapper-connector', ':mapper-block', 'single'],
single: lt('connectors.length', 2),
connectorLabel: computed(function() {
let key = this.connector;
let path = this.inputTypes ? `input.${key}.name` : `connector.${key}`;
return I18n.t(`admin.wizard.${path}`);
})
});

Datei anzeigen

@ -1,6 +1,6 @@
import { computed, set } from "@ember/object";
import { alias, equal } from "@ember/object/computed";
import { newPair, connectorContent, inputTypesContent } from '../lib/mapper';
import { newPair, connectorContent, inputTypesContent } from '../lib/wizard-mapper';
export default Ember.Component.extend({
classNameBindings: [':mapper-input', 'type'],

Datei anzeigen

@ -1,4 +1,4 @@
import { connectorContent } from '../lib/mapper';
import { connectorContent } from '../lib/wizard-mapper';
import { gt, or, alias } from "@ember/object/computed";
import { computed, observes } from "@ember/object";

Datei anzeigen

@ -2,7 +2,7 @@ import { alias } from "@ember/object/computed";
import { computed } from "@ember/object";
import { default as discourseComputed, observes } from "discourse-common/utils/decorators";
import { getOwner } from 'discourse-common/lib/get-owner';
import { defaultSelectionType } from '../lib/mapper';
import { defaultSelectionType } from '../lib/wizard-mapper';
export default Ember.Component.extend({
classNames: 'mapper-selector',

Datei anzeigen

@ -1,6 +1,6 @@
import { getOwner } from 'discourse-common/lib/get-owner';
import { on } from 'discourse-common/utils/decorators';
import { newInput } from '../lib/mapper';
import { newInput } from '../lib/wizard-mapper';
import { default as discourseComputed } from 'discourse-common/utils/decorators';
export default Ember.Component.extend({

Datei anzeigen

@ -2,7 +2,7 @@ import {
default as discourseComputed,
on
} from 'discourse-common/utils/decorators';
import { profileFields } from '../lib/custom-wizard';
import { profileFields } from '../lib/wizard';
import { scheduleOnce } from "@ember/runloop";
export default Ember.Component.extend({

Datei anzeigen

@ -1,13 +1,20 @@
import { default as discourseComputed, observes } from 'discourse-common/utils/decorators';
import { notEmpty } from "@ember/object/computed";
import showModal from 'discourse/lib/show-modal';
import { generateId } from '../lib/custom-wizard';
import { buildProperties } from '../lib/json';
import { generateId } from '../lib/wizard';
import { buildProperties } from '../lib/wizard-json';
import { dasherize } from "@ember/string";
import EmberObject from "@ember/object";
import { scheduleOnce } from "@ember/runloop";
export default Ember.Controller.extend({
hasName: notEmpty('model.name'),
init() {
this._super();
scheduleOnce('afterRender', () => ($("body").addClass('admin-wizard')));
},
@observes('model.name')
setId() {
if (!this.model.existingId) this.set('model.id', generateId(this.model.name));
@ -38,7 +45,7 @@ export default Ember.Controller.extend({
steps.forEach((s) => {
if (s.fields && s.fields.length > 0) {
let stepFields = s.fields.map((f) => {
return Ember.Object.create({
return EmberObject.create({
id: f.id,
label: `${f.id} (${s.id})`,
type: f.type
@ -98,5 +105,9 @@ export default Ember.Controller.extend({
controller.setup();
},
toggleAdvanced() {
this.toggleProperty('model.showAdvanced');
}
}
});

Datei anzeigen

@ -2,7 +2,7 @@ import { ajax } from 'discourse/lib/ajax';
import { popupAjaxError } from 'discourse/lib/ajax-error';
import CustomWizardApi from '../models/custom-wizard-api';
import { default as computed } from 'discourse-common/utils/decorators';
import { generateSelectKitContent } from '../lib/custom-wizard';
import { generateSelectKitContent } from '../lib/wizard';
export default Ember.Controller.extend({
queryParams: ['refresh_list'],

Datei anzeigen

@ -1,5 +1,4 @@
import { properties } from '../lib/custom-wizard';
import { mappedProperties } from '../lib/mapper';
import { properties, mappedProperties } from '../lib/wizard';
import EmberObject from '@ember/object';
function present(val) {
@ -152,38 +151,36 @@ function buildObject(json, type) {
}
Object.keys(json).forEach(prop => {
if (mapped(prop, type)) {
if (mapped(prop, type) && present(json[prop])) {
let inputs = [];
if (present(json[prop])) {
json[prop].forEach(inputJson => {
let input = {}
Object.keys(inputJson).forEach(inputKey => {
if (inputKey === 'pairs') {
let pairs = [];
let pairCount = inputJson.pairs.length;
json[prop].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 = pairJson;
pair.pairCount = pairCount;
inputJson.pairs.forEach(pairJson => {
let pair = pairJson;
pair.pairCount = pairCount;
pairs.push(
EmberObject.create(pair)
);
});
input.pairs = pairs;
} else {
input[inputKey] = inputJson[inputKey];
}
});
inputs.push(
EmberObject.create(input)
);
pairs.push(
EmberObject.create(pair)
);
});
input.pairs = pairs;
} else {
input[inputKey] = inputJson[inputKey];
}
});
}
inputs.push(
EmberObject.create(input)
);
});
params[prop] = Ember.A(inputs);
} else {
@ -194,6 +191,30 @@ function buildObject(json, type) {
return EmberObject.create(params);
}
function isAdvancedWizard(property, value) {
if (property === 'save_submissions' && value == false) return true;
if (property === 'restart_on_revisit' && value == true) return true;
return false;
}
function isAdvancedStep(property, value) {
return mapped(property, 'step') && present(value);
}
function isAdvancedField(params) {
if (present(params.property)) return true;
if (present(params.prefill)) return true;
if (present(params.content)) return true;
return false;
}
function isAdvancedAction(params) {
if (present(params.code)) return true;
if (present(params.custom_fields)) return true;
if (present(params.skip_redirect)) return true;
return false;
}
function buildProperties(json) {
let steps = Ember.A();
let props = {
@ -206,6 +227,10 @@ function buildProperties(json) {
properties.wizard.forEach((p) => {
props[p] = json[p];
if (isAdvancedWizard(p, json[p])) {
props.showAdvanced = true;
}
});
if (present(json.steps)) {
@ -216,15 +241,23 @@ function buildProperties(json) {
properties.step.forEach((p) => {
stepParams[p] = stepJson[p];
if (isAdvancedStep(p, stepJson[p])) {
stepParams.showAdvanced = true;
}
});
stepParams.fields = Ember.A();
if (present(stepJson.fields)) {
stepJson.fields.forEach((f) => {
stepParams.fields.pushObject(
buildObject(f, 'field')
);
let params = buildObject(f, 'field');
if (isAdvancedField(params)) {
params.showAdvanced = true;
}
stepParams.fields.pushObject(params);
});
}
@ -232,9 +265,13 @@ function buildProperties(json) {
if (present(stepJson.actions)) {
stepJson.actions.forEach((a) => {
stepParams.actions.pushObject(
buildObject(a, 'action')
);
let params = buildObject(a, 'action');
if (isAdvancedAction(params)) {
params.showAdvanced = true;
}
stepParams.actions.pushObject(params);
});
}

Datei anzeigen

@ -1,27 +1,4 @@
const mappedProperties = {
wizard: [
'permitted'
],
step: [
'required_data',
'permitted_params'
],
field: [
'choices',
'prefill',
'content'
],
action: [
'title',
'category',
'tags',
'custom_fields',
'required',
'recipient',
'profile_updates',
'group'
]
}
import EmberObject from "@ember/object";
// Inputs
@ -67,25 +44,28 @@ const connectors = {
]
}
function connectorItem(connector) {
return {
id: connector,
name: I18n.t(`admin.wizard.connector.${connector}`)
};
}
function defaultConnector(connectorType, inputType, opts = {}) {
if (opts[`${connectorType}Connector`]) return opts[`${connectorType}Connector`];
if (inputType === 'assignment') return 'set';
return connectorType === 'output' ? 'then' : 'equal';
if (inputType === 'assignment' && connectorType === 'output') return 'set';
if (inputType === 'conditional' && connectorType === 'output') return 'then';
if (inputType === 'conditional' && connectorType === 'pair') return 'equal';
if (inputType === 'pair') return 'equal';
}
function connectorContent(connectorType, inputType, opts) {
let connector = opts[`${connectorType}Connector`] || defaultConnector(connectorType, inputType, opts);
if (connector) return [connectorItem(connector)];
let connector = opts[`${connectorType}Connector`];
return connectors[connectorType].map(function(connector) {
return connectorItem(connector);
if (!connector && connectorType === 'output') {
connector = defaultConnector(connectorType, inputType, opts);
}
let content = connector ? [connector] : connectors[connectorType];
return content.map(function(item) {
return {
id: item,
name: I18n.t(`admin.wizard.connector.${item}`)
};
});
}
@ -113,6 +93,7 @@ function defaultSelectionType(inputType, options = {}) {
if (inputTypes === true ||
((typeof inputTypes === 'string') &&
inputTypes.split(',').indexOf(inputType) > -1)) {
type = t;
break;
}
@ -134,7 +115,7 @@ function newPair(inputType, options = {}) {
connector: defaultConnector('pair', inputType, options)
}
return Ember.Object.create(params);
return EmberObject.create(params);
}
function newInput(options = {}) {
@ -160,11 +141,10 @@ function newInput(options = {}) {
params['connector'] = defaultConnector('output', inputType, options);
}
return Ember.Object.create(params);
return EmberObject.create(params);
}
export {
mappedProperties,
defaultInputType,
defaultSelectionType,
connectorContent,

Datei anzeigen

@ -75,6 +75,7 @@ const actionProperties = [
'type',
'title',
'post',
'post_builder',
'post_template',
'category',
'tags',
@ -98,6 +99,31 @@ const properties = {
action: actionProperties
}
const mappedProperties = {
wizard: [
'permitted'
],
step: [
'required_data',
'permitted_params'
],
field: [
'choices',
'prefill',
'content'
],
action: [
'title',
'category',
'tags',
'custom_fields',
'required',
'recipient',
'profile_updates',
'group'
]
}
const actionTypes = [
'create_topic',
'update_profile',
@ -116,6 +142,7 @@ export {
generateId,
properties,
wizardProperties,
mappedProperties,
profileFields,
actionTypes
};

Datei anzeigen

@ -1,6 +1,6 @@
import { ajax } from 'discourse/lib/ajax';
import EmberObject from "@ember/object";
import { buildStepJson, buildJson, buildProperties } from '../lib/json';
import { buildStepJson, buildJson, buildProperties } from '../lib/wizard-json';
const CustomWizard = EmberObject.extend({
save() {
@ -34,7 +34,6 @@ const CustomWizard = EmberObject.extend({
wizard: JSON.stringify(wizardJson)
}
}).then((result) => {
console.log('result: ', result);
if (result.error) {
reject(result);
} else {

Datei anzeigen

@ -4,7 +4,7 @@ import {
generateSelectKitContent,
profileFields,
generateName
} from '../lib/custom-wizard';
} from '../lib/wizard';
import DiscourseRoute from "discourse/routes/discourse";
export default DiscourseRoute.extend({
@ -95,6 +95,7 @@ export default DiscourseRoute.extend({
setupController(controller, model) {
const newWizard = this.get('newWizard');
const steps = model.get('steps') || [];
controller.setProperties({
newWizard,
model,

Datei anzeigen

@ -48,26 +48,7 @@
</div>
<div class="wizard-settings">
<div class="setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.save_submissions'}}</label>
</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">
<label>{{i18n 'admin.wizard.multiple_submissions'}}</label>
</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">
<label>{{i18n 'admin.wizard.required'}}</label>
@ -90,11 +71,11 @@
<div class="setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.restart_on_revisit'}}</label>
<label>{{i18n 'admin.wizard.multiple_submissions'}}</label>
</div>
<div class="setting-value">
{{input type='checkbox' checked=model.restart_on_revisit}}
<span>{{i18n 'admin.wizard.restart_on_revisit_label'}}</span>
{{input type='checkbox' checked=model.multiple_submissions}}
<span>{{i18n 'admin.wizard.multiple_submissions_label'}}</span>
</div>
</div>
@ -138,7 +119,36 @@
textSelection='key,value'
)}}
</div>
</div>
{{wizard-advanced-toggle showAdvanced=model.showAdvanced}}
{{#if model.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=model.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=model.restart_on_revisit}}
<span>{{i18n 'admin.wizard.restart_on_revisit_label'}}</span>
</div>
</div>
</div>
{{/if}}
</div>
{{wizard-links type="step" current=currentStep items=model.steps}}

Datei anzeigen

@ -0,0 +1,4 @@
{{d-button
action="toggleAdvanced"
label='admin.wizard.advanced'
class=toggleClass}}

Datei anzeigen

@ -107,59 +107,7 @@
</div>
{{/if}}
{{#if newTopicFields}}
<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 basicTopicFields}}
<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
keyPlaceholder='admin.wizard.action.custom_fields.key'
options=(hash
pairConnector='set'
wizardSelection='value'
userSelection='value'
)}}
</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'
wizardSelection=true
userSelection=true
groupSelection=true
)}}
</div>
</div>
{{#if sendMessage}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n "admin.wizard.action.send_message.recipient"}}</label>
@ -172,7 +120,7 @@
hasOutput=true
textSelection='value,output'
wizardSelection=true
userSelection=true
userSelection='key,value'
groupSelection='key,value'
)}}
</div>
@ -279,14 +227,79 @@
{{input value=action.url}}
</div>
</div>
<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}}
{{#if hasAdvanced}}
{{wizard-advanced-toggle showAdvanced=action.showAdvanced}}
{{#if action.showAdvanced}}
<div class="advanced-settings">
{{#if basicTopicFields}}
<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
keyPlaceholder='admin.wizard.action.custom_fields.key'
options=(hash
pairConnector='set'
wizardSelection='value'
userSelection='value'
)}}
</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'
wizardSelection=true
userSelection=true
groupSelection=true
)}}
</div>
</div>
{{/if}}
{{#if newTopicFields}}
<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}}

Datei anzeigen

@ -125,24 +125,6 @@
</div>
{{/if}}
{{#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.select_property'
)}}
</div>
</div>
{{/if}}
{{#if isCategoryOrTag}}
<div class="setting">
<div class="setting-label">
@ -155,26 +137,52 @@
</div>
{{/if}}
{{#if prefillEnabled}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.prefill'}}</label>
</div>
<div class="setting-value">
{{wizard-mapper inputs=field.prefill options=prefillOptions}}
</div>
</div>
{{/if}}
{{#if hasAdvanced}}
{{wizard-advanced-toggle showAdvanced=field.showAdvanced}}
{{#if contentEnabled}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.content'}}</label>
{{#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.select_property'
)}}
</div>
</div>
{{/if}}
{{#if prefillEnabled}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.prefill'}}</label>
</div>
<div class="setting-value">
{{wizard-mapper inputs=field.prefill options=prefillOptions}}
</div>
</div>
{{/if}}
{{#if contentEnabled}}
<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}}
</div>
<div class="setting-value">
{{wizard-mapper inputs=field.content options=contentOptions}}
</div>
</div>
{{/if}}
{{/if}}

Datei anzeigen

@ -46,44 +46,51 @@
</div>
</div>
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.step.required_data.label'}}</label>
</div>
<div class="setting-value">
{{wizard-mapper
inputs=step.required_data
keyPlaceholder="admin.wizard.submission_key"
options=(hash
pairConnector='equal'
wizardSelection='value'
userSelection='value'
)}}
{{#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>
{{wizard-advanced-toggle showAdvanced=step.showAdvanced}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.step.permitted_params.label'}}</label>
{{#if step.showAdvanced}}
<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 class="setting-value">
{{wizard-mapper
inputs=step.required_data
keyPlaceholder="admin.wizard.submission_key"
options=(hash
wizardSelection='value'
userSelection='value'
)}}
{{#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 field-mapper-setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.step.permitted_params.label'}}</label>
</div>
<div class="setting-value">
{{wizard-mapper
inputs=step.permitted_params
keyPlaceholder='admin.wizard.param_key'
valuePlaceholder='admin.wizard.submission_key'
options=(hash
pairConnector='set'
)}}
</div>
</div>
</div>
<div class="setting-value">
{{wizard-mapper
inputs=step.permitted_params
keyPlaceholder='admin.wizard.param_key'
valuePlaceholder='admin.wizard.submission_key'
options=(hash
pairConnector='set'
)}}
</div>
</div>
{{/if}}
{{wizard-links type="field" current=currentField items=step.fields}}

Datei anzeigen

@ -0,0 +1,10 @@
{{#if single}}
<span class="connector-single">
{{connectorLabel}}
</span>
{{else}}
{{combo-box
value=connector
content=connectors
onChange=(action (mut connector))}}
{{/if}}

Datei anzeigen

@ -1,10 +1,8 @@
{{#if hasOutput}}
<div class="mapper-connector mapper-block">
{{combo-box
value=input.type
content=inputTypes
onChange=(action (mut input.type))}}
</div>
{{wizard-mapper-connector
connector=input.type
connectors=inputTypes
inputTypes=true}}
{{/if}}
{{#if hasPairs}}
@ -30,12 +28,9 @@
{{#if hasOutput}}
{{#if hasPairs}}
<div class="mapper-connector mapper-block">
{{combo-box
value=input.connector
content=connectors
onChange=(action (mut input.connector))}}
</div>
{{wizard-mapper-connector
connector=input.connector
connectors=connectors}}
{{/if}}
<div class="output mapper-block">

Datei anzeigen

@ -8,12 +8,9 @@
options=options}}
</div>
<div class="mapper-connector mapper-block">
{{combo-box
value=pair.connector
content=connectors
onChange=(action (mut pair.connector))}}
</div>
{{wizard-mapper-connector
connector=pair.connector
connectors=connectors}}
<div class="value mapper-block">
{{wizard-mapper-selector

Datei anzeigen

@ -1,4 +1,5 @@
import { default as computed, observes } from 'discourse-common/utils/decorators';
import EmberObject from "@ember/object";
export default Ember.Component.extend({
showPreview: false,
@ -6,7 +7,7 @@ export default Ember.Component.extend({
classNameBindings: ["showPreview:show-preview:hide-preview"],
didInsertElement() {
this.set('composer', Ember.Object.create({
this.set('composer', EmberObject.create({
loading: false,
reply: this.get('field.value')
}))

Datei anzeigen

@ -3,15 +3,15 @@ import getUrl from 'discourse-common/lib/get-url';
import WizardField from 'wizard/models/wizard-field';
import { ajax } from 'wizard/lib/ajax';
import Step from 'wizard/models/step';
import EmberObject from "@ember/object";
const CustomWizard = Ember.Object.extend({
const CustomWizard = EmberObject.extend({
@computed('steps.length')
totalSteps: length => length,
skip() {
if (this.get('required') && (!this.get('completed') && this.get('permitted'))) return;
const id = this.get('id');
CustomWizard.skip(id);
if (this.required && (!this.completed && this.permitted)) return;
CustomWizard.skip(this.id);
},
});
@ -70,7 +70,7 @@ export function findCustomWizard(wizardId, params = {}) {
subcatMap[c.parent_category_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

Datei anzeigen

@ -4,6 +4,12 @@
$setting-background: dark-light-diff($primary, $secondary, 96%, -65%);
body.admin-wizard {
.boxed.white {
background-color: initial;
}
}
.wizard-list {
float: left;
width: 250px;
@ -12,8 +18,8 @@ $setting-background: dark-light-diff($primary, $secondary, 96%, -65%);
.wizard-settings-parent {
margin-bottom: 30px;
padding: 30px;
background-color: $setting-background;
padding: 20px;
border: 1px solid $primary-medium;
}
.wizard-settings-group {
@ -32,10 +38,29 @@ $setting-background: dark-light-diff($primary, $secondary, 96%, -65%);
.wizard-basic-details,
.wizard-custom-field,
.wizard-custom-action {
.wizard-custom-action,
.advanced-settings {
@extend .wizard-settings-group;
}
.wizard-custom-field,
.wizard-custom-action {
position: relative;
background: transparent;
background-color: $setting-background;
padding: 20px;
}
.wizard-links {
&.action, &.field {
margin-top: 50px;
}
}
.wizard-settings > .advanced-settings > div.setting {
margin-bottom: 0;
}
.admin-wizard.settings .wizard-basic-details {
justify-content: initial;
@ -99,13 +124,18 @@ $setting-background: dark-light-diff($primary, $secondary, 96%, -65%);
.admin-wizard.settings {
margin-top: 10px;
margin-left: 30px;
[class~='setting'] {
display: inline-flex;
align-items: flex-start;
width: 48%;
margin-bottom: 30px;
padding-bottom: 0;
position: relative;
&:last-of-type {
margin-bottom: 0;
}
.setting-label {
width: 80px;
@ -144,6 +174,7 @@ $setting-background: dark-light-diff($primary, $secondary, 96%, -65%);
input[type="number"] {
width: 70px;
margin-bottom: 0;
}
input.medium {
@ -198,9 +229,8 @@ $setting-background: dark-light-diff($primary, $secondary, 96%, -65%);
display: flex;
align-items: center;
input[type='checkbox'],
span {
margin: 0 10px 0 0;
input {
margin: 0 7px 0 0;
}
button {
@ -218,6 +248,15 @@ $setting-background: dark-light-diff($primary, $secondary, 96%, -65%);
}
}
.advanced-settings {
width: 100%;
margin-top: 30px;
[class~='setting']:first-of-type {
border-top: none;
}
}
.wizard-custom-action > [class~='setting']:last-of-type {
margin-bottom: 0;
}
@ -365,11 +404,11 @@ $setting-background: dark-light-diff($primary, $secondary, 96%, -65%);
.admin-contents .wizard-submissions {
width: 100%;
display: inline-block;
margin-top: 10px;
margin-left: 30px;
table {
margin-top: 0;
position: absolute;
}
}
@ -470,3 +509,11 @@ $setting-background: dark-light-diff($primary, $secondary, 96%, -65%);
height: unset !important;
}
.wizard-advanced-toggle {
width: 100%;
}
.add-mapper-input .btn, .btn-after-time, .wizard-editor-gutter .btn {
background-color: $secondary;
border: 1px solid $primary-medium;
}

Datei anzeigen

@ -52,11 +52,6 @@
.add-mapper-input {
display: block;
.btn {
background-color: $secondary;
border: 1px solid $primary-medium;
}
}
.mapper-input + .add-mapper-input {
@ -68,23 +63,27 @@
min-width: 40px;
.select-kit .select-kit-header {
padding: 0 0.5em;
display: flex;
justify-content: center;
.caret-icon {
display: none;
}
}
&.single {
height: 28px;
background: $secondary;
border: 1px solid $primary-medium;
display: flex;
align-items: center;
justify-content: center;
}
}
.mapper-selector {
width: 100%;
max-width: 160px;
min-width: 160px;
max-width: 150px;
min-width: 150px;
input, .select-kit {
width: 160px;
width: 150px;
}
.type-selector {

Datei anzeigen

@ -60,6 +60,7 @@ en:
param_key: 'param'
group: "Group"
permitted: "Permitted"
advanced: "Advanced"
editor:
show: "Show"

Datei anzeigen

@ -20,144 +20,69 @@ class CustomWizard::Action
end
def create_topic
if action['custom_title_enabled']
title = mapper.interpolate(action['custom_title'])
else
title = data[action['title']]
end
params = basic_topic_params
if action['post_builder']
post = mapper.interpolate(action['post_template'])
else
post = data[action['post']]
end
byebug
if title
params = {
title: title,
raw: post,
skip_validations: true
}
params[:category] = action_category_id(action, data)
tags = action_tags(action, data)
params[:tags] = tags
if params[:title] && params[:raw]
params[:category] = action_category
params[:tags] = action_tags
if action['add_fields']
action['add_fields'].each do |field|
value = field['value_custom'].present? ? field['value_custom'] : data[field['value']]
key = field['key']
if key && (value.present? || value === false)
if key.include?('custom_fields')
keyArr = key.split('.')
if keyArr.length === 3
custom_key = keyArr.last
type = keyArr.first
if type === 'topic'
params[:topic_opts] ||= {}
params[:topic_opts][:custom_fields] ||= {}
params[:topic_opts][:custom_fields][custom_key] = value
elsif type === 'post'
params[:custom_fields] ||= {}
params[:custom_fields][custom_key.to_sym] = value
end
end
else
value = [*value] + [*tags] if key === 'tags'
params[key.to_sym] = value
end
end
end
end
byebug
creator = PostCreator.new(user, params)
post = creator.create
if creator.errors.present?
updater.errors.add(:create_topic, creator.errors.full_messages.join(" "))
else
unless action['skip_redirect']
data['redirect_on_complete'] = post.topic.url
end
elsif action['skip_redirect'].blank?
data['redirect_on_complete'] = post.topic.url
end
end
end
def send_message
if action['required'].present? && data[action['required']].blank?
return
end
return if action['required'].present? && data[action['required']].blank?
if action['custom_title_enabled']
title = mapper.interpolate(action['custom_title'])
else
title = data[action['title']]
end
if action['post_builder']
post = mapper.interpolate(action['post_template'])
else
post = data[action['post']]
end
if title && post
creator = PostCreator.new(user,
title: title,
raw: post,
archetype: Archetype.private_message,
target_usernames: action['username']
)
params = basic_topic_params
params[:target_usernames] = CustomWizard::Mapper.new(
inputs: action['recipient'],
data: data,
user: user,
opts: {
multiple: true
}
).output
if params[:title] && params[:raw]
params[:archetype] = Archetype.private_message
creator = PostCreator.new(user, params)
post = creator.create
if creator.errors.present?
updater.errors.add(:send_message, creator.errors.full_messages.join(" "))
else
unless action['skip_redirect']
data['redirect_on_complete'] = post.topic.url
end
elsif action['skip_redirect'].blank?
data['redirect_on_complete'] = post.topic.url
end
end
end
def update_profile
return unless action['profile_updates'].length
return unless (profile_updates = action['profile_updates']).length
attributes = {}
custom_fields = {}
attributes = { custom_fields: {} }
action['profile_updates'].each do |pu|
value = pu['value']
key = pu['key']
profile_updates.each do |pu|
pair = field['pairs'].first
field = mapper.map_field(pair['key'], pair['key_type'])
value = mapper.map_field(pair['value'], pair['value_type'])
return if data[key].blank?
if user_field || custom_field
custom_fields[user_field || custom_field] = data[key]
if field.include?("custom_field")
attributes[:custom_fields][field] = value
else
updater_key = value
if ['profile_background', 'card_background'].include?(value)
updater_key = "#{value}_upload_url"
end
attributes[updater_key.to_sym] = data[key] if updater_key
attributes[field.to_sym] = value
end
if ['user_avatar'].include?(value)
this_upload_id = data[key][:id]
user.create_user_avatar unless user.user_avatar
user.user_avatar.custom_upload_id = this_upload_id
user.uploaded_avatar_id = this_upload_id
user.save!
user.user_avatar.save!
end
end
if custom_fields.present?
attributes[:custom_fields] = custom_fields
end
if attributes.present?
@ -205,7 +130,7 @@ class CustomWizard::Action
url += "&body=#{post}"
if category_id = action_category_id
if category_id = action_category
if category = Category.find(category_id)
url += "&category=#{category.full_slug('/')}"
end
@ -249,35 +174,92 @@ class CustomWizard::Action
def route_to
url = mapper.interpolate(action['url'])
if action['code']
data[action['code']] = SecureRandom.hex(8)
url += "&#{action['code']}=#{data[action['code']]}"
end
data['route_to'] = URI.encode(url)
end
def action_category_id
if action['custom_category_enabled']
if action['custom_category_wizard_field']
data[action['category_id']]
elsif action['custom_category_user_field_key']
if action['custom_category_user_field_key'].include?('custom_fields')
field = action['custom_category_user_field_key'].split('.').last
user.custom_fields[field]
else
user.send(action['custom_category_user_field_key'])
end
end
else
action['category_id']
private
def action_category
output = CustomWizard::Mapper.new(
inputs: action['category'],
data: data,
user: user
).output
if output.is_a?(Array)
output.first
elsif output.is_a?(Integer)
output
elsif output.is_a?(String)
output.to_i
end
end
def action_tags
if action['custom_tag_enabled']
data[action['custom_tag_field']]
else
action['tags']
output = CustomWizard::Mapper.new(
inputs: action['tags'],
data: data,
user: user,
).output
if output.is_a?(Array)
output.flatten
elsif output.is_a?(Integer)
[*output]
elsif output.is_a?(String)
[*output.to_i]
end
end
def add_custom_fields(params = {})
if (custom_fields = action['custom_fields']).present?
custom_fields.each do |field|
pair = field['pairs'].first
value = mapper.map_field(pair['key'], pair['key_type'])
key = mapper.map_field(pair['value'], pair['value_type'])
if key &&
value.present? &&
(keyArr = key.split('.')).length === 2
if keyArr.first === 'topic'
params[:topic_opts] ||= {}
params[:topic_opts][:custom_fields] ||= {}
params[:topic_opts][:custom_fields][keyArr.last] = value
elsif keyArr.first === 'post'
params[:custom_fields] ||= {}
params[:custom_fields][keyArr.last.to_sym] = value
end
end
end
end
params
end
def basic_topic_params
params = {
skip_validations: true
}
params[:title] = CustomWizard::Mapper.new(
inputs: action['title'],
data: data,
user: user
).output
params[:raw] = action['post_builder'] ?
mapper.interpolate(action['post_template']) :
data[action['post']]
params = add_custom_fields(params)
params
end
end