0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-09 20:02:54 +01:00
Dieser Commit ist enthalten in:
Angus McLeod 2020-03-22 04:30:11 +11:00
Ursprung b8369146c7
Commit 2e6ab27ea0
50 geänderte Dateien mit 737 neuen und 284 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,25 @@
import discourseComputed from 'discourse-common/utils/decorators';
export default Ember.Component.extend({
tagName: 'a',
classNameBindings: ['type', 'active'],
@discourseComputed('type', 'activeType')
active(type, activeType) {
return type === activeType;
},
@discourseComputed('type')
label(type) {
let map = {
wizard: I18n.t('admin.wizard.label'),
user: I18n.t('users_lowercase.one'),
text: I18n.t('admin.wizard.text')
};
return map[type].toLowerCase();
},
click() {
this.toggle(this.type)
}
})

Datei anzeigen

@ -1,33 +1,16 @@
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
const ACTION_TYPES = [
{ id: 'create_topic', name: 'Create Topic' },
{ id: 'update_profile', name: 'Update Profile' },
{ id: 'send_message', name: 'Send Message' },
{ id: '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'
];
import {
default as computed,
observes
} from 'discourse-common/utils/decorators';
import {
actionTypes,
generateName,
generateSelectKitContent
} from '../lib/custom-wizard';
export default Ember.Component.extend({
classNames: 'wizard-custom-action',
types: ACTION_TYPES,
profileFields: PROFILE_FIELDS,
types: actionTypes.map(t => ({ id: t, name: generateName(t) })),
createTopic: Ember.computed.equal('action.type', 'create_topic'),
updateProfile: Ember.computed.equal('action.type', 'update_profile'),
sendMessage: Ember.computed.equal('action.type', 'send_message'),
@ -36,6 +19,7 @@ export default Ember.Component.extend({
addToGroup: Ember.computed.equal('action.type', 'add_to_group'),
routeTo: Ember.computed.equal('action.type', 'route_to'),
disableId: Ember.computed.not('action.isNew'),
groupPropertyTypes: generateSelectKitContent(['id', 'name']),
@computed('action.type')
basicTopicFields(actionType) {
@ -52,17 +36,17 @@ export default Ember.Component.extend({
return ['create_topic', 'send_message'].indexOf(actionType) > -1;
},
@computed('availableFields')
@computed('wizardFields')
builderWizardFields(fields) {
return fields.map((f) => ` w{${f.id}}`);
},
@computed('availableFields')
@computed('wizardFields')
categoryFields(fields) {
return fields.filter(f => f.type == 'category');
},
@computed('availableFields')
@computed('wizardFields')
tagFields(fields) {
return fields.filter(f => f.type == 'tag');
},

Datei anzeigen

@ -1,4 +1,4 @@
import { default as computed, observes, on } from 'ember-addons/ember-computed-decorators';
import { default as computed, observes, on } from 'discourse-common/utils/decorators';
import { generateSelectKitContent } from '../lib/custom-wizard';
export default Ember.Component.extend({

Datei anzeigen

@ -0,0 +1,46 @@
import { alias, equal } from "@ember/object/computed";
import { computed } from "@ember/object";
import {
default as discourseComputed,
observes
} from "discourse-common/utils/decorators";
export default Ember.Component.extend({
@observes('activeType')
clearValue() {
this.set('value', null);
},
@discourseComputed('customPlaceholder')
textPlaceholder(customPlaceholder) {
return customPlaceholder || 'admin.wizard.text';
},
@discourseComputed('activeType', 'userEnabled')
showUser(activeType, userEnabled) {
return activeType === 'user' && userEnabled;
},
@discourseComputed('activeType', 'wizardEnabled')
showWizard(activeType, wizardEnabled) {
return activeType === 'wizard' && wizardEnabled;
},
showText: equal('activeType', 'text'),
@discourseComputed('options.allowWizardField', 'inputType')
wizardEnabled(allowWizardField, inputType) {
return allowWizardField === true || allowWizardField === inputType;
},
@discourseComputed('options.allowUserField', 'inputType')
userEnabled(allowUserField, inputType) {
return allowUserField === true || allowUserField === inputType;
},
actions: {
toggleType(type) {
this.set('activeType', type);
}
}
})

Datei anzeigen

@ -0,0 +1,9 @@
import { connectors } from '../lib/custom-wizard';
import { gt } from "@ember/object/computed";
export default Ember.Component.extend({
classNames: 'pair',
connectorNone: 'admin.wizard.connector.none',
connectors: connectors.map(c => ({ id: c, name: I18n.t(`admin.wizard.connector.${c}`) })),
showRemove: gt('pair.index', 0)
})

Datei anzeigen

@ -1,34 +1,19 @@
import { default as computed, on } from 'ember-addons/ember-computed-decorators';
import { getOwner } from 'discourse-common/lib/get-owner';
import { newPair } from '../lib/custom-wizard';
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
};
}));
}
});
outputConnectorKey: 'admin.wizard.connector.prefill',
outputPrefixKey: 'admin.wizard.if',
actions: {
addPair() {
this.get('input.pairs').pushObject(
newPair(this.options, this.input.pairs.length)
);
},
removePair(pair) {
this.get('input.pairs').removeObject(pair);
}
}
});

Datei anzeigen

@ -1,13 +1,14 @@
import { getOwner } from 'discourse-common/lib/get-owner';
import { on } from 'discourse-common/utils/decorators';
import { newInput } from '../lib/custom-wizard';
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());
if (!this.get('inputs')) this.set('inputs', Ember.A());
this.get('inputs').pushObject(newInput(this.options));
},
remove(input) {

Datei anzeigen

@ -1,4 +1,4 @@
import { observes, default as computed } from 'ember-addons/ember-computed-decorators';
import { observes, default as computed } from 'discourse-common/utils/decorators';
export default Ember.Component.extend({
classNames: 'wizard-custom-step',
@ -16,9 +16,9 @@ export default Ember.Component.extend({
});
},
@computed('availableFields', 'wizard.steps')
requiredContent(availableFields, steps) {
let content = availableFields;
@computed('wizardFields', 'wizard.steps')
requiredContent(wizardFields, steps) {
let content = wizardFields;
let actions = [];
steps.forEach(s => {
@ -37,19 +37,8 @@ export default Ember.Component.extend({
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) {
wizardFields(currentStepId, saveSubmissions) {
const allSteps = this.get('wizard.steps');
let steps = allSteps;
let fields = [];

Datei anzeigen

@ -1,5 +1,5 @@
import { ajax } from 'discourse/lib/ajax';
import { default as computed } from 'ember-addons/ember-computed-decorators';
import { default as computed } from 'discourse-common/utils/decorators';
export default Ember.Component.extend({
classNames: ['container', 'import'],

Datei anzeigen

@ -1,4 +1,4 @@
import { default as computed, on, observes } from 'ember-addons/ember-computed-decorators';
import { default as computed, on, observes } from 'discourse-common/utils/decorators';
export default Ember.Component.extend({
classNames: 'wizard-links',

Datei anzeigen

@ -1,3 +1,3 @@
{{#if currentUser.admin}}
{{nav-item route='adminWizards' label='admin.wizard.label'}}
{{nav-item route='adminWizards' label='admin.wizard.nav'}}
{{/if}}

Datei anzeigen

@ -1,4 +1,4 @@
import { default as computed } from 'ember-addons/ember-computed-decorators';
import { default as computed } from 'discourse-common/utils/decorators';
import showModal from 'discourse/lib/show-modal';
export default Ember.Controller.extend({

Datei anzeigen

@ -1,7 +1,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 'ember-addons/ember-computed-decorators';
import { default as computed } from 'discourse-common/utils/decorators';
import { generateSelectKitContent } from '../lib/custom-wizard';
export default Ember.Controller.extend({

Datei anzeigen

@ -1,4 +1,4 @@
import { default as computed } from 'ember-addons/ember-computed-decorators';
import { default as computed } from 'discourse-common/utils/decorators';
export default Ember.Controller.extend({
title: 'admin.wizard.after_time_modal.title',

Datei anzeigen

@ -2,4 +2,74 @@ function generateSelectKitContent(content) {
return content.map(i => ({id: i, name: i}))
}
export { generateSelectKitContent };
function generateName(id) {
return id.replace(/[_\-]+/g, ' ')
.toLowerCase()
.replace(/(^\w|\b\w)/g, (m) => m.toUpperCase())
}
const profileFields = [
'name',
'user_avatar',
'date_of_birth',
'title',
'locale',
'location',
'website',
'bio_raw',
'profile_background',
'card_background',
'theme_id'
];
const connectors = [
'equal'
]
const actionTypes = [
'create_topic',
'update_profile',
'create_topic',
'update_profile',
'send_message',
'send_to_api',
'add_to_group',
'route_to',
'open_composer'
];
function newInput(options = {}) {
let params = {
pairs: Ember.A([newPair(options, 0)])
}
if (options.hasOutput) {
params['output'] = '';
params['output_type'] = 'text';
}
return Ember.Object.create(params);
}
function newPair(options = {}, index) {
let params = {
index,
key: '',
key_type: 'text',
value: '',
value_type: 'text',
connector: 'equal'
}
return Ember.Object.create(params);
}
export {
generateSelectKitContent,
profileFields,
actionTypes,
generateName,
connectors,
newInput,
newPair
};

Datei anzeigen

@ -1,7 +1,8 @@
import { ajax } from 'discourse/lib/ajax';
import { default as computed } from 'ember-addons/ember-computed-decorators';
import { default as computed } from 'discourse-common/utils/decorators';
import EmberObject from "@ember/object";
const CustomWizardApi = Discourse.Model.extend({
const CustomWizardApi = EmberObject.extend({
@computed('name')
redirectUri(name) {
let nameParam = name.toString().dasherize();

Datei anzeigen

@ -1,4 +1,5 @@
import { ajax } from 'discourse/lib/ajax';
import EmberObject from "@ember/object";
const wizardProperties = [
'name',
@ -15,7 +16,7 @@ const wizardProperties = [
'theme_id'
];
const CustomWizard = Discourse.Model.extend({
const CustomWizard = EmberObject.extend({
save() {
return new Ember.RSVP.Promise((resolve, reject) => {

Datei anzeigen

@ -1,6 +1,7 @@
import CustomWizard from '../models/custom-wizard';
import DiscourseRoute from "discourse/routes/discourse";
export default Discourse.Route.extend({
export default DiscourseRoute.extend({
model(params) {
return CustomWizard.submissions(params.wizard_id);
},

Datei anzeigen

@ -1,8 +1,13 @@
import CustomWizard from '../models/custom-wizard';
import { ajax } from 'discourse/lib/ajax';
import { generateSelectKitContent } from '../lib/custom-wizard';
import {
generateSelectKitContent,
profileFields,
generateName
} from '../lib/custom-wizard';
import DiscourseRoute from "discourse/routes/discourse";
export default Discourse.Route.extend({
export default DiscourseRoute.extend({
beforeModel() {
const param = this.paramsFor('adminWizard').wizard_id;
const wizards = this.modelFor('admin-wizards-custom');
@ -35,7 +40,8 @@ export default Discourse.Route.extend({
return Ember.RSVP.all([
this._getFieldTypes(model),
this._getThemes(model),
this._getApis(model)
this._getApis(model),
this._getUserFields(model)
]);
},
@ -59,6 +65,20 @@ export default Discourse.Route.extend({
return ajax('/admin/wizards/apis')
.then((result) => model.set('apis', result));
},
_getUserFields(model) {
return this.store.findAll('user-field').then((result) => {
if (result && result.content) {
let userContent = result.content.map((f) => {
return { id: `user_field_${f.id}`, name: f.name};
});
let profileContent = profileFields.map((f) => {
return { id: f, name: generateName(f) };
});
model.set('userFields', userContent.concat(profileContent));
}
});
},
setupController(controller, model) {
const newWizard = this.get('newWizard');

Datei anzeigen

@ -1,6 +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: {
refresh_list: {
refreshModel: true

Datei anzeigen

@ -1,6 +1,7 @@
import CustomWizardApi from '../models/custom-wizard-api';
import DiscourseRoute from "discourse/routes/discourse";
export default Discourse.Route.extend({
export default DiscourseRoute.extend({
model() {
return CustomWizardApi.list();
},

Datei anzeigen

@ -1,4 +1,6 @@
export default Discourse.Route.extend({
import DiscourseRoute from "discourse/routes/discourse";
export default DiscourseRoute.extend({
redirect() {
this.transitionTo('adminWizard', 'first');
}

Datei anzeigen

@ -1,6 +1,7 @@
import CustomWizard from '../models/custom-wizard';
import DiscourseRoute from "discourse/routes/discourse";
export default Discourse.Route.extend({
export default DiscourseRoute.extend({
model() {
return CustomWizard.all();
},

Datei anzeigen

@ -1,4 +1,6 @@
export default Discourse.Route.extend({
import DiscourseRoute from "discourse/routes/discourse";
export default DiscourseRoute.extend({
redirect() {
this.transitionTo('adminWizardsCustom');
}

Datei anzeigen

@ -1,6 +1,7 @@
import CustomWizard from '../models/custom-wizard';
import DiscourseRoute from "discourse/routes/discourse";
export default Discourse.Route.extend({
export default DiscourseRoute.extend({
model() {
return CustomWizard.all();
},

Datei anzeigen

@ -1,6 +1,7 @@
import CustomWizard from '../models/custom-wizard';
import DiscourseRoute from "discourse/routes/discourse";
export default Discourse.Route.extend({
export default DiscourseRoute.extend({
model() {
return CustomWizard.all();
}

Datei anzeigen

@ -0,0 +1 @@
{{label}}

Datei anzeigen

@ -27,7 +27,7 @@
<div class="setting-value">
{{combo-box
value=action.title
content=availableFields
content=wizardFields
nameProperty="label"
isDisabled=action.custom_title_enabled
none='admin.wizard.select_field'}}
@ -48,7 +48,7 @@
<div class="setting-value">
{{combo-box
value=action.post
content=availableFields
content=wizardFields
nameProperty='label'
isDisabled=action.post_builder
none='admin.wizard.select_field'}}
@ -65,9 +65,10 @@
<h3>{{i18n 'admin.wizard.action.post_builder.label'}}</h3>
</div>
<div class="setting-value editor">
{{d-editor value=action.post_template
placeholder='admin.wizard.action.interpolate_fields'
classNames='post-builder-editor'}}
{{d-editor
value=action.post_template
placeholder='admin.wizard.action.interpolate_fields'
classNames='post-builder-editor'}}
<div>
<label>{{i18n 'admin.wizard.action.post_builder.user_fields'}}{{builderUserFields}}</label>
<label>{{i18n 'admin.wizard.action.post_builder.wizard_fields'}}{{builderWizardFields}}</label>
@ -119,12 +120,14 @@
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.create_topic.tags"}}</h3>
</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>
@ -157,11 +160,13 @@
{{#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}}
{{wizard-custom-inputs
inputs=action.add_fields
userFields=userFields
wizardFields=wizardFields
options=(hash
allowWizardField=true
)}}
</div>
{{/if}}
@ -170,43 +175,49 @@
<div class="setting-label">
<h3>{{i18n 'admin.wizard.required'}}</h3>
</div>
<div class="setting-value">
{{combo-box
value=action.required
content=availableFields
content=wizardFields
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"}}
{{user-selector
single="true"
includeMentionableGroups="true"
usernames=action.username
allowedUsers="true"}}
</div>
</div>
<div class="setting full">
<label>{{i18n "admin.wizard.action.add_fields" type='Message'}}</label>
{{wizard-custom-inputs inputs=action.add_fields
keyContent=availableFields
valuePlaceholder='admin.wizard.action.topic_attr'}}
{{wizard-custom-inputs
inputs=action.add_fields
userFields=userFields
wizardFields=wizardFields}}
</div>
{{/if}}
{{#if updateProfile}}
<div class="setting full">
<label>{{i18n "admin.wizard.action.add_fields" type='Profile'}}</label>
{{wizard-custom-inputs inputs=action.profile_updates
valueContent=profileFields
keyContent=availableFields
noneValue='admin.wizard.action.update_profile.profile_field'
allowCustomField=true
allowUserField=true}}
{{wizard-custom-inputs
inputs=action.profile_updates
userFields=userFields
wizardFields=wizardFields
options=(hash
allowWizardField=true
allowUserField=true
)}}
</div>
{{/if}}
@ -244,8 +255,9 @@
<div class="setting-value">
<label>{{i18n 'admin.wizard.action.post_builder.user_fields'}}{{builderUserFields}}</label>
<label>{{i18n 'admin.wizard.action.post_builder.wizard_fields'}}{{builderWizardFields}}</label>
{{textarea value=action.api_body
placeholder=(i18n 'admin.wizard.action.interpolate_fields')}}
{{textarea
value=action.api_body
placeholder=(i18n 'admin.wizard.action.interpolate_fields')}}
</div>
</div>
{{/if}}
@ -257,20 +269,36 @@
</div>
<div class="setting-value">
{{combo-box
value=action.group_id
content=availableFields
isDisabled=action.custom_group_enabled
value=action.value
content=wizardFields
isDisabled=action.custom
nameProperty="label"
none='admin.wizard.select_field'}}
<div class="setting-gutter">
{{input type='checkbox' checked=action.custom_group_enabled}}
<span>{{i18n 'admin.wizard.action.add_to_group.custom_group'}}</span>
{{#if action.custom_group_enabled}}
{{input value=action.group_id}}
{{input value=action.custom}}
{{/if}}
</div>
</div>
</div>
<div class="setting">
<div class="setting-label">
<h3>{{i18n "admin.wizard.action.add_to_group.property"}}</h3>
</div>
<div class="setting-value">
{{combo-box
value=action.property
content=groupPropertyTypes
options=(hash
none='admin.wizard.select_property'
)}}
</div>
</div>
{{/if}}
{{#if routeTo}}

Datei anzeigen

@ -98,7 +98,10 @@
<div class="wizard-header small">
{{i18n 'admin.wizard.field.choices_custom'}}
</div>
{{wizard-custom-inputs inputs=field.choices}}
{{wizard-custom-inputs
inputs=field.choices
userFields=userFields
wizardFields=wizardFields}}
{{/if}}
<div class="wizard-header small">
@ -138,7 +141,28 @@
<div class="setting-value">
{{combo-box
content=categoryPropertyTypes
value=field.property}}
value=field.property
options=(hash
none='admin.wizard.select_property'
)}}
</div>
</div>
{{/if}}
<div class="setting full">
<div class="setting-label">
<h3>{{i18n 'admin.wizard.field.prefill'}}</h3>
</div>
<div class="setting-value">
{{wizard-custom-inputs
inputs=field.prefill
userFields=userFields
wizardFields=wizardFields
options=(hash
hasOutput=true
enableConnectors=true
allowWizardField=true
allowUserField=true
)}}
</div>
</div>

Datei anzeigen

@ -0,0 +1,47 @@
<div class="type-selector">
{{input-type-toggle
activeType=activeType
type='text'
toggle=(action 'toggleType')}}
{{#if wizardEnabled}}
{{input-type-toggle
activeType=activeType
type='wizard'
toggle=(action 'toggleType')}}
{{/if}}
{{#if userEnabled}}
{{input-type-toggle
activeType=activeType
type='user'
toggle=(action 'toggleType')}}
{{/if}}
</div>
<div class="input">
{{#if showText}}
{{input
type="text"
value=value
placeholder=(i18n textPlaceholder)}}
{{/if}}
{{#if showWizard}}
{{combo-box
value=value
content=wizardFields
options=(hash
none='admin.wizard.wizard_field'
)}}
{{/if}}
{{#if showUser}}
{{combo-box
value=value
content=userFields
options=(hash
none='admin.wizard.user_field'
)}}
{{/if}}
</div>

Datei anzeigen

@ -0,0 +1,42 @@
<div class="key input-block">
{{wizard-custom-input-chooser
inputType='key'
userFields=userFields
wizardFields=wizardFields
value=pair.key
activeType=pair.key_type
customPlaceholder=keyPlaceholder
options=options}}
</div>
<div class="connector">
{{#if options.enableConnectors}}
{{combo-box
value=pair.connector
content=connectors
options=(hash
none=connectorNone
)}}
{{/if}}
{{#if connectorKey}}
<span class="key-connector">
{{i18n connectorKey}}
</span>
{{/if}}
</div>
<div class="value input-block">
{{wizard-custom-input-chooser
inputType='value'
userFields=userFields
wizardFields=wizardFields
value=pair.value
activeType=pair.value_type
customPlaceholder=valuePlaceholder
options=options}}
</div>
{{#if showRemove}}
<a {{action removePair pair}} class="remove-pair">{{d-icon 'minus'}}</a>
{{/if}}

Datei anzeigen

@ -1,55 +1,50 @@
<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>
{{#if options.hasOutput}}
{{#if outputPrefixKey}}
<div class="prefix">
<span>{{i18n outputPrefixKey}}</span>
</div>
{{input type="text"
value=input.value_custom
placeholder=(i18n 'admin.wizard.custom_value_placeholder')
disabled=customDisabled}}
{{/if}}
{{/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'}}
<div class="pairs">
{{#each input.pairs as |pair|}}
{{wizard-custom-input-pair
pair=pair
keyPlaceholder=keyPlaceholder
valuePlaceholder=valuePlaceholder
userFields=userFields
wizardFields=wizardFields
options=options
removePair=(action 'removePair')}}
{{/each}}
{{#if options.hasOutput}}
<a {{action 'addPair'}} class="add-pair">{{d-icon 'plus'}}</a>
{{/if}}
</div>
{{d-button action=remove actionParam=input icon='times' class='remove'}}
{{#if options.hasOutput}}
<div class="connector">
{{#if outputConnectorKey}}
<span class="output-connector">
{{i18n outputConnectorKey}}
</span>
{{/if}}
</div>
<div class="output input-block">
{{wizard-custom-input-chooser
inputType='output'
userFields=userFields
wizardFields=wizardFields
value=input.output
activeType=input.output_type
customPlaceholder=outputPlaceholder
options=options}}
</div>
{{/if}}
{{d-button
action=remove
actionParam=input
icon='times'
class='remove-input'}}

Datei anzeigen

@ -1,15 +1,16 @@
{{#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')}}
{{wizard-custom-input
input=input
userFields=userFields
wizardFields=wizardFields
keyPlaceholder=keyPlaceholder
valuePlaceholder=valuePlaceholder
connectorContent=connectorContent
connectorKey=connectorKey
options=options
remove=(action 'remove')}}
{{/each}}
<div class="add-custom-input">
{{d-button action='add' label='admin.wizard.add' icon='plus'}}
</div>
</div>

Datei anzeigen

@ -39,7 +39,9 @@
<h3>{{i18n 'admin.wizard.step.description'}}</h3>
</div>
<div class="setting-value">
{{d-editor value=step.raw_description placeholder="admin.wizard.custom_text_placeholder"}}
{{d-editor
value=step.raw_description
placeholder="admin.wizard.custom_text_placeholder"}}
</div>
</div>
@ -48,10 +50,16 @@
<h3>{{i18n 'admin.wizard.step.required_data.label'}}</h3>
</div>
<div class="setting-value">
{{wizard-custom-inputs inputs=step.required_data
inputKey='admin.wizard.step.required_data.key'
valueContent=requiredContent
connectorContent=requiredConnectorContent}}
{{wizard-custom-inputs
inputs=step.required_data
userFields=userFields
wizardFields=wizardFields
keyPlaceholder="admin.wizard.submission_key"
options=(hash
enableConnectors=true
allowWizardField='value'
allowUserField='value'
)}}
{{#if step.required_data}}
<div class="required-data-message">
<div class="label">
@ -68,24 +76,36 @@
<h3>{{i18n 'admin.wizard.step.permitted_params.label'}}</h3>
</div>
<div class="setting-value">
{{wizard-custom-inputs inputs=step.permitted_params
inputKey='admin.wizard.step.permitted_params.key'
valuePlaceholder='admin.wizard.step.permitted_params.value'
connectorKey='admin.wizard.step.permitted_params.connector'}}
{{wizard-custom-inputs
inputs=step.permitted_params
userFields=userFields
wizardFields=wizardFields
keyPlaceholder='admin.wizard.param_key'
valuePlaceholder='admin.wizard.submission_key'
connectorKey='admin.wizard.step.permitted_params.connector'}}
</div>
</div>
{{wizard-links type="field" current=currentField items=step.fields}}
{{#if currentField}}
{{wizard-custom-field field=currentField types=wizard.fieldTypes removeField="removeField"}}
{{wizard-custom-field
field=currentField
types=wizard.fieldTypes
removeField="removeField"
userFields=wizard.userFields
wizardFields=wizardFields}}
{{/if}}
{{wizard-links type="action" current=currentAction items=step.actions}}
{{#if currentAction}}
{{wizard-custom-action action=currentAction
wizard=wizard
removeAction="removeAction"
availableFields=availableFields}}
{{wizard-custom-action
action=currentAction
wizard=wizard
removeAction="removeAction"
wizardFields=wizardFields
userFields=wizard.userFields}}
{{/if}}
<label>{{i18n 'admin.wizard.action.available_fields'}}</label>

Datei anzeigen

@ -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 userSearch from '../lib/user-search';

Datei anzeigen

@ -1,5 +1,5 @@
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 { throttle } from "@ember/runloop";
import { scheduleOnce } from "@ember/runloop";

Datei anzeigen

@ -1,4 +1,4 @@
import { observes } from 'ember-addons/ember-computed-decorators';
import { observes } from 'discourse-common/utils/decorators';
import Category from 'discourse/models/category';
export default Ember.Component.extend({

Datei anzeigen

@ -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';
export default Ember.Component.extend({
showPreview: false,

Datei anzeigen

@ -0,0 +1,5 @@
export default Ember.Component.extend({
didInsertElement() {
console.log(this.field)
}
})

Datei anzeigen

@ -1,6 +1,6 @@
/* 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";
export default Ember.TextField.extend({

Datei anzeigen

@ -1,4 +1,4 @@
import { default as computed } from 'ember-addons/ember-computed-decorators';
import { default as computed } from 'discourse-common/utils/decorators';
export default {
name: 'custom-routes',
@ -227,7 +227,8 @@ export default {
'image',
'user-selector',
'text-only',
'composer'
'composer',
'group'
];
FieldModel.reopen({

Datei anzeigen

@ -1,4 +1,4 @@
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 WizardField from 'wizard/models/wizard-field';
import { ajax } from 'wizard/lib/ajax';

Datei anzeigen

@ -0,0 +1,7 @@
{{combo-box
content=wizard.groups
value=field.value
onChange=(action (mut field.value))
options=(hash
none='group.select'
)}}

Datei anzeigen

@ -872,3 +872,7 @@ input.input-location, div.input-location {
}
}
}
.select-kit.combo-box.group-dropdown {
min-width: 220px;
}

Datei anzeigen

@ -52,7 +52,6 @@
}
button {
margin-top: 5px;
display: block;
}
@ -88,11 +87,6 @@
margin-bottom: 5px;
}
}
.custom-input .remove {
margin-left: 10px;
margin-top: 0;
}
}
}
@ -194,11 +188,45 @@
.custom-input {
display: flex;
align-items: center;
align-items: flex-start;
margin-bottom: 10px;
position: relative;
.type-selector a {
color: $primary;
margin-right: 10px;
&.active {
color: $tertiary;
text-decoration: underline;
}
}
.pairs {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.add-pair {
margin-top: 4px;
}
.remove-pair {
position: absolute;
top: 25px;
right: -30px;
}
}
.pair {
display: flex;
align-items: flex-end;
position: relative;
margin-bottom: 5px;
}
.d-icon {
margin: 0 auto;
text-align: center;
}
@ -210,18 +238,38 @@
background-color: $primary-low;
border-color: #ddd;
}
.select-kit {
width: 232px !important;
.input-block, .select-kit, input {
width: 150px;
min-width: 150px;
}
.remove {
margin: 0 auto;
align-self: flex-start;
button.remove-input {
margin: 21px 0 0 10px;
}
.connector {
margin: 0 10px;
.select-kit {
min-width: 50px;
}
.key-connector {
padding-bottom: 5px;
display: inline-block;
}
.output-connector {
margin-top: 25px;
display: inline-block;
}
}
.prefix {
position: absolute;
left: -20px;
top: 24px;
}
}

Datei anzeigen

@ -6,7 +6,8 @@ en:
admin_js:
admin:
wizard:
label: "Wizards"
label: "Wizard"
nav: "Wizards"
new: "New"
custom_label: "Custom"
submissions_label: "Submissions"
@ -46,17 +47,30 @@ en:
url: "Url"
key: "Key"
or: "Or"
if: "if"
value: "Value"
output: "Output"
property: "Property"
text: "text"
profile: "profile"
id: "Id"
id_placeholder: "Underscored. Cannot be changed."
key_placeholder: "Translation key"
custom_text_placeholder: "Overrides translation"
custom_field_placeholder: "Custom Field"
custom_value_placeholder: "Custom Value"
user_field_placeholder: "User Field"
type: "Type"
none: "Make a selection"
user_field: "User Field"
wizard_field: "Wizard Field"
select_field: "Select Field"
select_property: "Select Property"
profile_field: "Profile Field"
submission_key: 'submission key'
param_key: 'param'
connector:
none: "op"
prefill: "prefill"
equal: "="
error:
name_required: "Wizards must have a name."
steps_required: "Wizards must have at least one step."
@ -68,6 +82,7 @@ en:
field:
need_choices: "All dropdowns need choices."
choices_label_empty: "Custom choice labels cannot be empty."
step:
header: "Steps"
title: "Title"
@ -76,15 +91,11 @@ en:
description: "Description"
required_data:
label: "Required Data"
key: 'Submission key'
connector:
equals: "Equals"
not_permitted_message: "Message shown when required data not present"
permitted_params:
label: "Permitted Params"
key: 'Param'
value: 'Submission key'
connector: "Save as"
connector: "save as"
field:
type: "Choose a type"
header: "Fields"
@ -110,6 +121,8 @@ en:
category: "Category"
limit: "Limit"
property: "Property"
prefill: "Prefill"
action:
header: "Actions<sup>*</sup>"
include: "Include Fields"
@ -132,7 +145,6 @@ en:
tags: "Tags"
update_profile:
label: "Update Profile"
profile_field: "Profile Field"
post_builder:
checkbox: "Post Builder"
label: "Builder"
@ -142,8 +154,9 @@ en:
add_to_group:
label: "Add to Group"
group: "Group"
group_selection: "Group Selection"
custom_group: "Custom Group"
group_selection: "Field"
custom_group: "Custom"
property: "Property"
route_to:
label: "Route To"
url: "Url"
@ -151,7 +164,6 @@ en:
custom_title: "Custom Title"
custom_category:
label: "Custom Category"
wizard_field: "Wizard Field"
user_field: "User Field"
custom_tag:
label: "Custom Tag"
@ -230,6 +242,9 @@ en:
file_size_error: "The file must be JSON and 512kb or less"
wizard_js:
group:
select: "Select a group"
location:
name:
title: "Name (optional)"

Datei anzeigen

@ -44,6 +44,9 @@ class CustomWizard::Builder
USER_FIELDS = ['name', 'username', 'email', 'date_of_birth', 'title', 'locale']
PROFILE_FIELDS = ['location', 'website', 'bio_raw', 'profile_background', 'card_background']
OPERATORS = {
'equal': '=='
}
def self.fill_placeholders(string, user, data)
result = string.gsub(/u\{(.*?)\}/) do |match|
@ -99,8 +102,9 @@ class CustomWizard::Builder
permitted_data = {}
permitted_params.each do |p|
params_key = p['key'].to_sym
submission_key = p['value'].to_sym
pair = p['pairs'].first
params_key = pair['key'].to_sym
submission_key = pair['value'].to_sym
permitted_data[submission_key] = params[params_key] if params[params_key]
end
@ -110,21 +114,32 @@ class CustomWizard::Builder
end
end
if required_data = step_template['required_data']
if !@submissions.last && required_data.present?
step.permitted = false
next
end
required_data.each do |rd|
if rd['connector'] === 'equals'
step.permitted = @submissions.last[rd['key']] == @submissions.last[rd['value']]
if (required_data = step_template['required_data']).present?
has_required_data = true
pairs =
required_data.each do |required|
required['pairs'].each do |pair|
if pair['key'].blank? || pair['value'].blank?
has_required_data = false
end
end
end
if !step.permitted
step.permitted_message = step_template['required_data_message'] if step_template['required_data_message']
next
if has_required_data
if !@submissions.last
step.permitted = false
else
required_data.each do |required|
pairs = required['pairs'].map { |p| p['value'] = @submissions.last[p['value']] }
step.permitted = false unless validate_pairs(pairs)
end
end
if !step.permitted
step.permitted_message = step_template['required_data_message'] if step_template['required_data_message']
next
end
end
end
@ -217,18 +232,7 @@ class CustomWizard::Builder
params[:value] = submission[field_template['id']] if submission[field_template['id']]
end
## If a field updates a profile field, load the current value
if step_template['actions'] && step_template['actions'].any?
profile_actions = step_template['actions'].select { |a| a['type'] === 'update_profile' }
if profile_actions.any?
profile_actions.each do |action|
if update = action['profile_updates'].select { |u| u['key'] === field_template['id'] }.first
params[:value] = prefill_profile_field(update) || params[:value]
end
end
end
end
params[:value] = prefill_field(field_template, step_template) || params[:value]
if field_template['type'] === 'checkbox'
params[:value] = standardise_boolean(params[:value])
@ -253,6 +257,8 @@ class CustomWizard::Builder
if field_template['type'] === 'group'
@wizard.needs_groups = true
end
puts "ADDING FIELD: #{params.inspect}"
field = step.add_field(params)
@ -260,24 +266,81 @@ class CustomWizard::Builder
build_dropdown_list(field, field_template)
end
end
def prefill_field(field_template, step_template)
if (prefill = field_template['prefill']).present?
output = nil
prefill.each do |item|
puts "PREFIL: #{item.inspect}"
if validate_pairs(item['pairs'])
puts "OUTPUT: #{get_field(item['output'], item['output_type'])}"
output = get_field(item['output'], item['output_type'])
end
end
output
else
actions = step_template['actions']
if actions && actions.any?
profile_actions = actions.select { |a| a['type'] === 'update_profile' } || []
def prefill_profile_field(update)
attribute = update['value']
custom_field = update['value_custom']
user_field = update['user_field']
profile_actions.each do |action|
update = action['profile_updates'].select { |u| u['key'] === field_template['id'] }.first
get_user_field(update['value']) if update
end
end
end
end
def validate_pairs(pairs)
failed = false
pairs.each do |pair|
puts "PAIR: #{pair.inspect}"
key = get_field(pair['key'], pair['key_type'])
value = get_field(pair['value'], pair['value_type'])
puts "KEY VALUE: #{key.inspect}; #{value.inspect}"
failed = true unless key.public_send(get_operator(pair['connector']), value)
end
!failed
end
def get_operator(connector)
OPERATORS[connector] || '=='
end
def get_field(value, type)
method = "get_#{type}_field"
if self.respond_to?(method)
self.send(method, value)
else
value
end
end
def get_wizard_field(value)
@submissions.last &&
!@submissions.last.key?("submitted_at") &&
@submissions.last[value]
end
if user_field || custom_field
UserCustomField.where(user_id: @wizard.user.id, name: user_field || custom_field).pluck(:value).first
elsif UserProfile.column_names.include? attribute
UserProfile.find_by(user_id: @wizard.user.id).send(attribute)
elsif User.column_names.include? attribute
User.find(@wizard.user.id).send(attribute)
def get_user_field(value)
puts "GETTING USER FIELD: #{value.inspect}"
if value.include?('user_field_')
UserCustomField.where(user_id: @wizard.user.id, name: value).pluck(:value).first
elsif UserProfile.column_names.include? value
UserProfile.find_by(user_id: @wizard.user.id).send(value)
elsif User.column_names.include? value
User.find(@wizard.user.id).send(value)
end
end
def build_dropdown_list(field, template)
field.dropdown_none = template['dropdown_none'] if template['dropdown_none']
self.send("build_dropdown_#{template['choices_type']}", field, template)
method = "build_dropdown_#{template['choices_type']}"
self.send(method, field, template) if self.respond_to?(method)
end
def build_dropdown_custom(field, template)
@ -552,8 +615,8 @@ class CustomWizard::Builder
end
def add_to_group(user, action, data)
if group_id = data[action['group_id']]
if group = Group.find(group_id)
if value = data[action['value']]
if group = Group.where("#{action['property']} = '#{value}'").first
group.add(user)
end
end

Datei anzeigen

@ -1,6 +1,6 @@
class CustomWizard::Field
def self.types
@types ||= ['checkbox', 'composer', 'dropdown', 'tag', 'category', 'image', 'text', 'textarea', 'text-only', 'upload', 'user-selector']
@types ||= ['checkbox', 'composer', 'dropdown', 'tag', 'category', 'group', 'image', 'text', 'textarea', 'text-only', 'upload', 'user-selector']
end
def self.require_assets

Datei anzeigen

@ -21,7 +21,8 @@ class CustomWizard::Wizard
:required,
:prompt_completion,
:restart_on_revisit,
:needs_categories
:needs_categories,
:needs_groups
def initialize(user=nil, attrs = {})
@steps = []
@ -29,6 +30,7 @@ class CustomWizard::Wizard
@first_step = nil
@required = false
@needs_categories = false
@needs_groups = false
attrs.each do |key, value|
setter = "#{key}="
@ -140,6 +142,10 @@ class CustomWizard::Wizard
def categories
@categories ||= ::Site.new(Guardian.new(@user)).categories
end
def groups
@groups ||= ::Site.new(Guardian.new(@user)).groups
end
def self.after_signup
rows = PluginStoreRow.where(plugin_name: 'custom_wizard')

Datei anzeigen

@ -14,6 +14,7 @@ class CustomWizardSerializer < ::WizardSerializer
has_one :user, serializer: ::BasicUserSerializer, embed: :objects
has_many :steps, serializer: ::CustomWizardStepSerializer, embed: :objects
has_many :categories, serializer: ::BasicCategorySerializer, embed: :objects
has_many :groups, serializer: ::BasicGroupSerializer, embed: :objects
def completed
object.completed?
@ -41,6 +42,10 @@ class CustomWizardSerializer < ::WizardSerializer
object.needs_categories
end
def include_groups?
object.needs_groups
end
def uncategorized_category_id
SiteSetting.uncategorized_category_id
end