Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-22 09:20:29 +01:00
various
Dieser Commit ist enthalten in:
Ursprung
dae08e53d4
Commit
ab18769820
65 geänderte Dateien mit 995 neuen und 1011 gelöschten Zeilen
|
@ -1,7 +1,6 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { gt } from '@ember/object/computed';
|
import { gt } from '@ember/object/computed';
|
||||||
import { computed } from "@ember/object";
|
import { computed } from "@ember/object";
|
||||||
import { removeMapperClasses } from '../lib/wizard-mapper';
|
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNameBindings: [':mapper-connector', ':mapper-block', 'hasMultiple::single'],
|
classNameBindings: [':mapper-connector', ':mapper-block', 'hasMultiple::single'],
|
||||||
|
@ -10,11 +9,5 @@ export default Component.extend({
|
||||||
let key = this.connector;
|
let key = this.connector;
|
||||||
let path = this.inputTypes ? `input.${key}.name` : `connector.${key}`;
|
let path = this.inputTypes ? `input.${key}.name` : `connector.${key}`;
|
||||||
return I18n.t(`admin.wizard.${path}`);
|
return I18n.t(`admin.wizard.${path}`);
|
||||||
}),
|
})
|
||||||
|
|
||||||
actions: {
|
|
||||||
onOpen() {
|
|
||||||
removeMapperClasses(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
|
@ -2,7 +2,7 @@ import { alias, or, gt } from "@ember/object/computed";
|
||||||
import { computed } from "@ember/object";
|
import { computed } from "@ember/object";
|
||||||
import { default as discourseComputed, observes, on } from "discourse-common/utils/decorators";
|
import { default as discourseComputed, observes, on } from "discourse-common/utils/decorators";
|
||||||
import { getOwner } from 'discourse-common/lib/get-owner';
|
import { getOwner } from 'discourse-common/lib/get-owner';
|
||||||
import { defaultSelectionType, selectionTypes, removeMapperClasses } from '../lib/wizard-mapper';
|
import { defaultSelectionType, selectionTypes } from '../lib/wizard-mapper';
|
||||||
import { snakeCase } from '../lib/wizard';
|
import { snakeCase } from '../lib/wizard';
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { bind } from "@ember/runloop";
|
import { bind } from "@ember/runloop";
|
||||||
|
@ -30,6 +30,7 @@ export default Component.extend({
|
||||||
userEnabled: computed('options.userSelection', 'inputType', function() { return this.optionEnabled('userSelection') }),
|
userEnabled: computed('options.userSelection', 'inputType', function() { return this.optionEnabled('userSelection') }),
|
||||||
listEnabled: computed('options.listSelection', 'inputType', function() { return this.optionEnabled('listSelection') }),
|
listEnabled: computed('options.listSelection', 'inputType', function() { return this.optionEnabled('listSelection') }),
|
||||||
hasTypes: gt('selectorTypes.length', 1),
|
hasTypes: gt('selectorTypes.length', 1),
|
||||||
|
showTypes: false,
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
$(document).on("click", bind(this, this.documentClick));
|
$(document).on("click", bind(this, this.documentClick));
|
||||||
|
@ -41,15 +42,10 @@ export default Component.extend({
|
||||||
|
|
||||||
documentClick(e) {
|
documentClick(e) {
|
||||||
if (this._state == "destroying") return;
|
if (this._state == "destroying") return;
|
||||||
|
|
||||||
let $target = $(e.target);
|
let $target = $(e.target);
|
||||||
|
|
||||||
if (!$target.parents('.wizard-mapper .input').length) {
|
if (!$target.parents('.type-selector').length && this.showTypes) {
|
||||||
this.send('disableActive');
|
this.set('showTypes', false);
|
||||||
}
|
|
||||||
|
|
||||||
if (!$target.parents('.type-selector').length) {
|
|
||||||
this.send('hideTypes');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -80,9 +76,9 @@ export default Component.extend({
|
||||||
|
|
||||||
@discourseComputed('activeType')
|
@discourseComputed('activeType')
|
||||||
comboBoxContent(activeType) {
|
comboBoxContent(activeType) {
|
||||||
const controller = getOwner(this).lookup('controller:admin-wizard');
|
const controller = getOwner(this).lookup('controller:admin-wizards-wizard-show');
|
||||||
let content = controller[`${activeType}s`];
|
let content = controller[`${activeType}s`];
|
||||||
|
|
||||||
// you can't select the current field in the field context
|
// you can't select the current field in the field context
|
||||||
if (activeType === 'wizardField' && this.options.context === 'field') {
|
if (activeType === 'wizardField' && this.options.context === 'field') {
|
||||||
content = content.filter(field => field.id !== controller.currentField.id);
|
content = content.filter(field => field.id !== controller.currentField.id);
|
||||||
|
@ -148,34 +144,14 @@ export default Component.extend({
|
||||||
return this.activeType === type && this[`${type}Enabled`];
|
return this.activeType === type && this[`${type}Enabled`];
|
||||||
},
|
},
|
||||||
|
|
||||||
removeClasses() {
|
|
||||||
removeMapperClasses(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
toggleType(type) {
|
toggleType(type) {
|
||||||
this.set('activeType', type);
|
this.set('activeType', type);
|
||||||
this.send('hideTypes');
|
this.set('showTypes', false);
|
||||||
},
|
},
|
||||||
|
|
||||||
// jquery is used here to ensure other selectors and types disable properly
|
toggleTypes() {
|
||||||
|
this.toggleProperty('showTypes');
|
||||||
showTypes() {
|
|
||||||
this.removeClasses();
|
|
||||||
$(this.element).find('.selector-types').addClass('show');
|
|
||||||
},
|
|
||||||
|
|
||||||
hideTypes() {
|
|
||||||
$(this.element).find('.selector-types').removeClass('show');
|
|
||||||
},
|
|
||||||
|
|
||||||
enableActive() {
|
|
||||||
this.removeClasses();
|
|
||||||
$(this.element).addClass('active');
|
|
||||||
},
|
|
||||||
|
|
||||||
disableActive() {
|
|
||||||
$(this.element).removeClass('active');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
|
@ -1,5 +0,0 @@
|
||||||
import Controller from "@ember/controller";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
|
||||||
queryParams: ['refresh']
|
|
||||||
});
|
|
|
@ -8,10 +8,10 @@ import EmberObject from "@ember/object";
|
||||||
import { scheduleOnce, later } from "@ember/runloop";
|
import { scheduleOnce, later } from "@ember/runloop";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import copyText from "discourse/lib/copy-text";
|
import copyText from "discourse/lib/copy-text";
|
||||||
|
import CustomWizard from '../models/custom-wizard';
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
hasName: notEmpty('model.name'),
|
hasName: notEmpty('wizard.name'),
|
||||||
userFields: alias('model.userFields'),
|
|
||||||
|
|
||||||
@observes('currentStep')
|
@observes('currentStep')
|
||||||
resetCurrentObjects() {
|
resetCurrentObjects() {
|
||||||
|
@ -25,28 +25,29 @@ export default Controller.extend({
|
||||||
scheduleOnce('afterRender', () => ($("body").addClass('admin-wizard')));
|
scheduleOnce('afterRender', () => ($("body").addClass('admin-wizard')));
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes('model.name')
|
@observes('wizard.name')
|
||||||
setId() {
|
setId() {
|
||||||
if (!this.model.existingId) {
|
const wizard = this.wizard;
|
||||||
this.set('model.id', generateId(this.model.name));
|
if (wizard && !wizard.existingId) {
|
||||||
|
this.set('wizard.id', generateId(wizard.name));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed('model.id')
|
@discourseComputed('wizard.id')
|
||||||
wizardUrl(wizardId) {
|
wizardUrl(wizardId) {
|
||||||
return window.location.origin + '/w/' + dasherize(wizardId);
|
return window.location.origin + '/w/' + dasherize(wizardId);
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed('model.after_time_scheduled')
|
@discourseComputed('wizard.after_time_scheduled')
|
||||||
nextSessionScheduledLabel(scheduled) {
|
nextSessionScheduledLabel(scheduled) {
|
||||||
return scheduled ?
|
return scheduled ?
|
||||||
moment(scheduled).format('MMMM Do, HH:mm') :
|
moment(scheduled).format('MMMM Do, HH:mm') :
|
||||||
I18n.t('admin.wizard.after_time_time_label');
|
I18n.t('admin.wizard.after_time_time_label');
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed('currentStep.id', 'model.save_submissions', 'model.steps.@each.fields[]')
|
@discourseComputed('currentStep.id', 'wizard.save_submissions', 'wizard.steps.@each.fields[]')
|
||||||
wizardFields(currentStepId, saveSubmissions) {
|
wizardFields(currentStepId, saveSubmissions) {
|
||||||
const allSteps = this.get('model.steps');
|
const allSteps = this.get('wizard.steps');
|
||||||
let steps = allSteps;
|
let steps = allSteps;
|
||||||
let fields = [];
|
let fields = [];
|
||||||
|
|
||||||
|
@ -71,31 +72,24 @@ export default Controller.extend({
|
||||||
return fields;
|
return fields;
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
save() {
|
save() {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
saving: true,
|
saving: true,
|
||||||
error: null
|
error: null
|
||||||
});
|
});
|
||||||
|
|
||||||
const wizard = this.model;
|
const wizard = this.wizard;
|
||||||
|
const creating = this.creating;
|
||||||
|
let opts = {};
|
||||||
|
|
||||||
wizard.save().then((result) => {
|
if (creating) {
|
||||||
|
opts.create = true;
|
||||||
this.model.setProperties(
|
}
|
||||||
buildProperties(result.wizard)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.set('saving', false);
|
wizard.save(opts).then((result) => {
|
||||||
|
this.send('afterSave', result.wizard_id);
|
||||||
if (this.get('newWizard')) {
|
}).catch((result) => {
|
||||||
this.send("refreshAllWizards");
|
|
||||||
} else {
|
|
||||||
this.send("refreshWizard");
|
|
||||||
}
|
|
||||||
}).catch((result) => {
|
|
||||||
this.set('saving', false);
|
|
||||||
|
|
||||||
let errorType = 'failed';
|
let errorType = 'failed';
|
||||||
let errorParams = {};
|
let errorParams = {};
|
||||||
|
|
||||||
|
@ -107,21 +101,18 @@ export default Controller.extend({
|
||||||
this.set('error', I18n.t(`admin.wizard.error.${errorType}`, errorParams));
|
this.set('error', I18n.t(`admin.wizard.error.${errorType}`, errorParams));
|
||||||
|
|
||||||
later(() => this.set('error', null), 10000);
|
later(() => this.set('error', null), 10000);
|
||||||
});
|
}).finally(() => this.set('saving', false));
|
||||||
},
|
},
|
||||||
|
|
||||||
remove() {
|
remove() {
|
||||||
const wizard = this.get('model');
|
this.wizard.remove().then(() => this.send('afterDestroy'));
|
||||||
wizard.remove().then(() => {
|
|
||||||
this.send("refreshAllWizards");
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setNextSessionScheduled() {
|
setNextSessionScheduled() {
|
||||||
let controller = showModal('next-session-scheduled', {
|
let controller = showModal('next-session-scheduled', {
|
||||||
model: {
|
model: {
|
||||||
dateTime: this.get('model.after_time_scheduled'),
|
dateTime: this.wizard.after_time_scheduled,
|
||||||
update: (dateTime) => this.set('model.after_time_scheduled', dateTime)
|
update: (dateTime) => this.set('wizard.after_time_scheduled', dateTime)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -129,7 +120,7 @@ export default Controller.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleAdvanced() {
|
toggleAdvanced() {
|
||||||
this.toggleProperty('model.showAdvanced');
|
this.toggleProperty('wizard.showAdvanced');
|
||||||
},
|
},
|
||||||
|
|
||||||
copyUrl() {
|
copyUrl() {
|
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}`);
|
||||||
|
}
|
||||||
|
});
|
|
@ -2,14 +2,17 @@ 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('adminWizardsTransfer', { path: '/transfer', resetNamespace: true });
|
this.route('adminWizardsTransfer', { path: '/transfer', resetNamespace: true });
|
||||||
|
|
|
@ -22,12 +22,6 @@ function inputTypesContent(options = {}) {
|
||||||
mapInputTypes(selectableInputTypes);
|
mapInputTypes(selectableInputTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeMapperClasses(ctx) {
|
|
||||||
const $mapper = $(ctx.element).parents('.wizard-mapper');
|
|
||||||
$mapper.find('.selector-types').removeClass('show');
|
|
||||||
$mapper.find('.mapper-selector').removeClass('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connectors
|
// Connectors
|
||||||
|
|
||||||
const connectors = {
|
const connectors = {
|
||||||
|
@ -160,7 +154,6 @@ export {
|
||||||
defaultInputType,
|
defaultInputType,
|
||||||
defaultSelectionType,
|
defaultSelectionType,
|
||||||
defaultConnector,
|
defaultConnector,
|
||||||
removeMapperClasses,
|
|
||||||
connectorContent,
|
connectorContent,
|
||||||
inputTypesContent,
|
inputTypesContent,
|
||||||
selectionTypes,
|
selectionTypes,
|
||||||
|
|
|
@ -5,19 +5,26 @@ import { schema, listProperties, camelCase, snakeCase } from '../lib/wizard';
|
||||||
import { Promise } from "rsvp";
|
import { Promise } from "rsvp";
|
||||||
|
|
||||||
const CustomWizard = EmberObject.extend({
|
const CustomWizard = EmberObject.extend({
|
||||||
save() {
|
save(opts) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let json = this.buildJson(this, 'wizard');
|
let wizard = this.buildJson(this, 'wizard');
|
||||||
|
|
||||||
if (json.error) {
|
if (wizard.error) {
|
||||||
reject({ error: json.error });
|
reject(wizard);
|
||||||
}
|
}
|
||||||
|
|
||||||
ajax("/admin/wizards/custom/save", {
|
let data = {
|
||||||
|
wizard
|
||||||
|
};
|
||||||
|
|
||||||
|
if (opts.create) {
|
||||||
|
data.create = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ajax(`/admin/wizards/wizard/${wizard.id}`, {
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
data: {
|
contentType: "application/json",
|
||||||
wizard: JSON.stringify(json)
|
data: JSON.stringify(data)
|
||||||
}
|
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
reject(result);
|
reject(result);
|
||||||
|
@ -40,7 +47,7 @@ const CustomWizard = EmberObject.extend({
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let property of listProperties(type, objectType)) {
|
for (let property of listProperties(type, objectType)) {
|
||||||
let value = object.get(property);
|
let value = object.get(property);
|
||||||
|
|
||||||
|
@ -175,23 +182,18 @@ const CustomWizard = EmberObject.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
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(wizard => {
|
return result.wizard_list;
|
||||||
return CustomWizard.create(wizard);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
import CustomWizard from '../models/custom-wizard';
|
|
||||||
import { ajax } from 'discourse/lib/ajax';
|
|
||||||
import { selectKitContent, userProperties, generateName } from '../lib/wizard';
|
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
|
||||||
import { all } from "rsvp";
|
|
||||||
|
|
||||||
export default DiscourseRoute.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;
|
|
||||||
this.set('newWizard', wizardId === 'new');
|
|
||||||
|
|
||||||
if (this.newWizard) {
|
|
||||||
return CustomWizard.create();
|
|
||||||
} else {
|
|
||||||
const wizard = this.modelFor('admin-wizards-custom')
|
|
||||||
.findBy('id', wizardId.underscore());
|
|
||||||
|
|
||||||
if (!wizard) {
|
|
||||||
return this.transitionTo('adminWizard', 'new');
|
|
||||||
} else {
|
|
||||||
return wizard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
afterModel(model) {
|
|
||||||
return all([
|
|
||||||
this._getFieldTypes(model),
|
|
||||||
this._getThemes(model),
|
|
||||||
this._getApis(model),
|
|
||||||
this._getUserFields(model)
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
|
|
||||||
_getFieldTypes(model) {
|
|
||||||
return ajax('/admin/wizards/field-types')
|
|
||||||
.then((result) => {
|
|
||||||
model.set(
|
|
||||||
'fieldTypes',
|
|
||||||
selectKitContent([...result.types])
|
|
||||||
)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_getThemes(model) {
|
|
||||||
return ajax('/admin/themes')
|
|
||||||
.then((result) => {
|
|
||||||
model.set('themes', result.themes.map(t => {
|
|
||||||
return {
|
|
||||||
id: t.id,
|
|
||||||
name: t.name
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_getApis(model) {
|
|
||||||
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) {
|
|
||||||
model.set('userFields',
|
|
||||||
result.content.map((f) => ({
|
|
||||||
id: `user_field_${f.id}`,
|
|
||||||
name: f.name
|
|
||||||
})).concat(
|
|
||||||
userProperties.map((f) => ({
|
|
||||||
id: f,
|
|
||||||
name: generateName(f)
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
const newWizard = this.get('newWizard');
|
|
||||||
|
|
||||||
controller.setProperties({
|
|
||||||
newWizard,
|
|
||||||
model,
|
|
||||||
currentStep: model.steps[0],
|
|
||||||
currentAction: model.actions[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,22 +1,7 @@
|
||||||
import CustomWizardApi from '../models/custom-wizard-api';
|
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
export default DiscourseRoute.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,32 +0,0 @@
|
||||||
import CustomWizardApi from '../models/custom-wizard-api';
|
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
|
||||||
|
|
||||||
export default DiscourseRoute.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,27 +0,0 @@
|
||||||
import CustomWizard from '../models/custom-wizard';
|
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
|
||||||
|
|
||||||
export default DiscourseRoute.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,7 +0,0 @@
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
|
||||||
|
|
||||||
export default DiscourseRoute.extend({
|
|
||||||
redirect() {
|
|
||||||
this.transitionTo('adminWizardsCustom');
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,7 +0,0 @@
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
|
||||||
|
|
||||||
export default DiscourseRoute.extend({
|
|
||||||
redirect() {
|
|
||||||
this.transitionTo('adminWizardSubmissions', 'first');
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -2,25 +2,8 @@ import CustomWizard from '../models/custom-wizard';
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
export default DiscourseRoute.extend({
|
export default DiscourseRoute.extend({
|
||||||
beforeModel() {
|
|
||||||
const param = this.paramsFor('adminWizardSubmissions').wizard_id;
|
|
||||||
const wizards = this.modelFor('admin-wizards-submissions');
|
|
||||||
|
|
||||||
if (wizards.length && (param === 'first')) {
|
|
||||||
const wizard = wizards.get(`${param}Object`);
|
|
||||||
if (wizard) {
|
|
||||||
this.transitionTo('adminWizardSubmissions', wizard.id.dasherize());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
model(params) {
|
model(params) {
|
||||||
const wizardId = params.wizard_id;
|
return CustomWizard.submissions(params.wizardId);
|
||||||
if (wizardId && wizardId !== 'new') {
|
|
||||||
return CustomWizard.submissions(params.wizard_id);
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController(controller, model) {
|
setupController(controller, model) {
|
||||||
|
@ -43,8 +26,6 @@ export default DiscourseRoute.extend({
|
||||||
submissions.push(submission);
|
submissions.push(submission);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(model.id)
|
|
||||||
|
|
||||||
controller.setProperties({
|
controller.setProperties({
|
||||||
wizard: model.wizard,
|
wizard: model.wizard,
|
||||||
submissions,
|
submissions,
|
|
@ -1,12 +1,24 @@
|
||||||
import CustomWizard from '../models/custom-wizard';
|
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
|
||||||
export default DiscourseRoute.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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
92
assets/javascripts/discourse/routes/admin-wizards-wizard.js.es6
Normale Datei
92
assets/javascripts/discourse/routes/admin-wizards-wizard.js.es6
Normale Datei
|
@ -0,0 +1,92 @@
|
||||||
|
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/apis')
|
||||||
|
.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)
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model) {
|
||||||
|
let props = {
|
||||||
|
wizardList: model.wizard_list
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = this.paramsFor('adminWizardsWizardShow');
|
||||||
|
if (params && params.wizardId) {
|
||||||
|
props.wizardId = params.wizardId;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,27 +0,0 @@
|
||||||
<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>
|
|
|
@ -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>
|
|
|
@ -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 submissions">
|
{{outlet}}
|
||||||
{{outlet}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
<div class="admin-wizard settings">
|
{{#if wizard}}
|
||||||
<div class="wizard-header large">
|
<div class="wizard-header large">
|
||||||
{{input
|
{{input
|
||||||
name="name"
|
name="name"
|
||||||
value=model.name
|
value=wizard.name
|
||||||
placeholderKey="admin.wizard.name_placeholder"}}
|
placeholderKey="admin.wizard.name_placeholder"}}
|
||||||
|
|
||||||
<div class="wizard-url">
|
<div class="wizard-url">
|
||||||
{{#if model.name}}
|
{{#if wizard.name}}
|
||||||
<a href="{{wizardUrl}}" target="_blank">{{wizardUrl}}</a>
|
|
||||||
{{#if copiedUrl}}
|
{{#if copiedUrl}}
|
||||||
{{d-button class="btn-hover pull-right" icon="copy" label="ip_lookup.copied"}}
|
{{d-button class="btn-hover pull-right" icon="copy" label="ip_lookup.copied"}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{d-button action=(action "copyUrl") class="pull-right no-text" icon="copy"}}
|
{{d-button action=(action "copyUrl") class="pull-right no-text" icon="copy"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
<a href="{{wizardUrl}}" target="_blank">{{wizardUrl}}</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wizard-basic-details">
|
<div class="wizard-basic-details">
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input
|
{{input
|
||||||
name="background"
|
name="background"
|
||||||
value=model.background
|
value=wizard.background
|
||||||
placeholderKey="admin.wizard.background_placeholder"
|
placeholderKey="admin.wizard.background_placeholder"
|
||||||
class="small"}}
|
class="small"}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,28 +37,28 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{combo-box
|
{{combo-box
|
||||||
content=model.themes
|
content=themes
|
||||||
valueProperty='id'
|
valueProperty='id'
|
||||||
value=model.theme_id
|
value=wizard.theme_id
|
||||||
onChange=(action (mut model.theme_id))
|
onChange=(action (mut wizard.theme_id))
|
||||||
options=(hash
|
options=(hash
|
||||||
none='admin.wizard.no_theme'
|
none='admin.wizard.no_theme'
|
||||||
)}}
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wizard-header medium">
|
<div class="wizard-header medium">
|
||||||
{{i18n 'admin.wizard.label'}}
|
{{i18n 'admin.wizard.label'}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wizard-settings">
|
<div class="wizard-settings">
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n 'admin.wizard.required'}}</label>
|
<label>{{i18n 'admin.wizard.required'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type='checkbox' checked=model.required}}
|
{{input type='checkbox' checked=wizard.required}}
|
||||||
<span>{{i18n 'admin.wizard.required_label'}}</span>
|
<span>{{i18n 'admin.wizard.required_label'}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
<label>{{i18n 'admin.wizard.after_signup'}}</label>
|
<label>{{i18n 'admin.wizard.after_signup'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type='checkbox' checked=model.after_signup}}
|
{{input type='checkbox' checked=wizard.after_signup}}
|
||||||
<span>{{i18n 'admin.wizard.after_signup_label'}}</span>
|
<span>{{i18n 'admin.wizard.after_signup_label'}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
<label>{{i18n 'admin.wizard.multiple_submissions'}}</label>
|
<label>{{i18n 'admin.wizard.multiple_submissions'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type='checkbox' checked=model.multiple_submissions}}
|
{{input type='checkbox' checked=wizard.multiple_submissions}}
|
||||||
<span>{{i18n 'admin.wizard.multiple_submissions_label'}}</span>
|
<span>{{i18n 'admin.wizard.multiple_submissions_label'}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
<label>{{i18n 'admin.wizard.prompt_completion'}}</label>
|
<label>{{i18n 'admin.wizard.prompt_completion'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type='checkbox' checked=model.prompt_completion}}
|
{{input type='checkbox' checked=wizard.prompt_completion}}
|
||||||
<span>{{i18n 'admin.wizard.prompt_completion_label'}}</span>
|
<span>{{i18n 'admin.wizard.prompt_completion_label'}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
<label>{{i18n 'admin.wizard.after_time'}}</label>
|
<label>{{i18n 'admin.wizard.after_time'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type='checkbox' checked=model.after_time}}
|
{{input type='checkbox' checked=wizard.after_time}}
|
||||||
<span>{{i18n 'admin.wizard.after_time_label'}}</span>
|
<span>{{i18n 'admin.wizard.after_time_label'}}</span>
|
||||||
{{d-button
|
{{d-button
|
||||||
action='setNextSessionScheduled'
|
action='setNextSessionScheduled'
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{wizard-mapper
|
{{wizard-mapper
|
||||||
inputs=model.permitted
|
inputs=wizard.permitted
|
||||||
options=(hash
|
options=(hash
|
||||||
context='wizard'
|
context='wizard'
|
||||||
inputTypes='assignment,validation'
|
inputTypes='assignment,validation'
|
||||||
|
@ -126,9 +126,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{wizard-advanced-toggle showAdvanced=model.showAdvanced}}
|
{{wizard-advanced-toggle showAdvanced=wizard.showAdvanced}}
|
||||||
|
|
||||||
{{#if model.showAdvanced}}
|
{{#if wizard.showAdvanced}}
|
||||||
<div class="advanced-settings">
|
<div class="advanced-settings">
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
|
@ -136,7 +136,7 @@
|
||||||
<label>{{i18n 'admin.wizard.save_submissions'}}</label>
|
<label>{{i18n 'admin.wizard.save_submissions'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type='checkbox' checked=model.save_submissions}}
|
{{input type='checkbox' checked=wizard.save_submissions}}
|
||||||
<span>{{i18n 'admin.wizard.save_submissions_label'}}</span>
|
<span>{{i18n 'admin.wizard.save_submissions_label'}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
<label>{{i18n 'admin.wizard.restart_on_revisit'}}</label>
|
<label>{{i18n 'admin.wizard.restart_on_revisit'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type='checkbox' checked=model.restart_on_revisit}}
|
{{input type='checkbox' checked=wizard.restart_on_revisit}}
|
||||||
<span>{{i18n 'admin.wizard.restart_on_revisit_label'}}</span>
|
<span>{{i18n 'admin.wizard.restart_on_revisit_label'}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -158,26 +158,27 @@
|
||||||
{{wizard-links
|
{{wizard-links
|
||||||
itemType="step"
|
itemType="step"
|
||||||
current=currentStep
|
current=currentStep
|
||||||
items=model.steps}}
|
items=wizard.steps}}
|
||||||
|
|
||||||
{{#if currentStep}}
|
{{#if currentStep}}
|
||||||
{{wizard-custom-step
|
{{wizard-custom-step
|
||||||
step=currentStep
|
step=currentStep
|
||||||
wizard=model
|
wizard=wizard
|
||||||
currentField=currentField
|
currentField=currentField
|
||||||
wizardFields=wizardFields}}
|
wizardFields=wizardFields
|
||||||
|
fieldTypes=fieldTypes}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{wizard-links
|
{{wizard-links
|
||||||
itemType="action"
|
itemType="action"
|
||||||
current=currentAction
|
current=currentAction
|
||||||
items=model.actions
|
items=wizard.actions
|
||||||
generateLabels=true}}
|
generateLabels=true}}
|
||||||
|
|
||||||
{{#if currentAction}}
|
{{#if currentAction}}
|
||||||
{{wizard-custom-action
|
{{wizard-custom-action
|
||||||
action=currentAction
|
action=currentAction
|
||||||
wizard=model
|
wizard=wizard
|
||||||
removeAction="removeAction"
|
removeAction="removeAction"
|
||||||
wizardFields=wizardFields}}
|
wizardFields=wizardFields}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -187,7 +188,7 @@
|
||||||
{{i18n 'admin.wizard.save'}}
|
{{i18n 'admin.wizard.save'}}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{{#unless newWizard}}
|
{{#unless creating}}
|
||||||
<button {{action "remove"}} class='btn btn-danger remove'>
|
<button {{action "remove"}} class='btn btn-danger remove'>
|
||||||
{{d-icon "far-trash-alt"}}{{i18n 'admin.wizard.remove'}}
|
{{d-icon "far-trash-alt"}}{{i18n 'admin.wizard.remove'}}
|
||||||
</button>
|
</button>
|
||||||
|
@ -199,4 +200,4 @@
|
||||||
<span class="error">{{d-icon "times"}}{{error}}</span>
|
<span class="error">{{d-icon "times"}}{{error}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/if}}
|
32
assets/javascripts/discourse/templates/admin-wizards-wizard.hbs
Normale Datei
32
assets/javascripts/discourse/templates/admin-wizards-wizard.hbs
Normale Datei
|
@ -0,0 +1,32 @@
|
||||||
|
<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.help'}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="admin-wizard-container settings">
|
||||||
|
{{outlet}}
|
||||||
|
</div>
|
|
@ -1,5 +1,5 @@
|
||||||
{{#admin-nav}}
|
{{#admin-nav}}
|
||||||
{{nav-item route='adminWizardsCustom' label='admin.wizard.nav_label'}}
|
{{nav-item route='adminWizardsWizard' label='admin.wizard.nav_label'}}
|
||||||
{{nav-item route='adminWizardsSubmissions' label='admin.wizard.submissions.nav_label'}}
|
{{nav-item route='adminWizardsSubmissions' label='admin.wizard.submissions.nav_label'}}
|
||||||
{{#if siteSettings.wizard_api_features}}
|
{{#if siteSettings.wizard_api_features}}
|
||||||
{{nav-item route='adminWizardsApis' label='admin.wizard.api.nav_label'}}
|
{{nav-item route='adminWizardsApis' label='admin.wizard.api.nav_label'}}
|
||||||
|
@ -7,6 +7,6 @@
|
||||||
{{nav-item route='adminWizardsTransfer' label='admin.wizard.transfer.nav_label'}}
|
{{nav-item route='adminWizardsTransfer' label='admin.wizard.transfer.nav_label'}}
|
||||||
{{/admin-nav}}
|
{{/admin-nav}}
|
||||||
|
|
||||||
<div class="admin-container admin-wizard-container">
|
<div class="admin-container">
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -64,7 +64,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{input type="number" name="min_length" value=field.min_length}}
|
{{input
|
||||||
|
type="number"
|
||||||
|
name="min_length"
|
||||||
|
value=field.min_length
|
||||||
|
class="small"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -88,7 +92,7 @@
|
||||||
</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}}
|
||||||
|
@ -148,8 +152,12 @@
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n 'admin.wizard.translation'}}</label>
|
<label>{{i18n 'admin.wizard.translation'}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-value">
|
<div class="setting-value medium">
|
||||||
{{input name="key" value=field.key placeholderKey="admin.wizard.translation_placeholder"}}
|
{{input
|
||||||
|
name="key"
|
||||||
|
value=field.key
|
||||||
|
class="small"
|
||||||
|
placeholderKey="admin.wizard.translation_placeholder"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
{{#if currentField}}
|
{{#if currentField}}
|
||||||
{{wizard-custom-field
|
{{wizard-custom-field
|
||||||
field=currentField
|
field=currentField
|
||||||
fieldTypes=wizard.fieldTypes
|
fieldTypes=fieldTypes
|
||||||
removeField="removeField"
|
removeField="removeField"
|
||||||
wizardFields=wizardFields}}
|
wizardFields=wizardFields}}
|
||||||
{{/if}}
|
{{/if}}
|
|
@ -8,7 +8,7 @@
|
||||||
id=(dasherize w.id)
|
id=(dasherize w.id)
|
||||||
change=(action 'checkChanged')}}
|
change=(action 'checkChanged')}}
|
||||||
|
|
||||||
{{#link-to "adminWizard" (dasherize w.id)}}
|
{{#link-to "adminWizardsWizardShow" (dasherize w.id)}}
|
||||||
{{w.name}}
|
{{w.name}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
{{combo-box
|
{{combo-box
|
||||||
value=connector
|
value=connector
|
||||||
content=connectors
|
content=connectors
|
||||||
onChange=(action (mut connector))
|
onChange=(action (mut connector))}}
|
||||||
onOpen=(action "onOpen")}}
|
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="connector-single">
|
<span class="connector-single">
|
||||||
{{connectorLabel}}
|
{{connectorLabel}}
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
<div class="type-selector">
|
<div class="type-selector">
|
||||||
{{#if hasTypes}}
|
{{#if hasTypes}}
|
||||||
<a {{action "showTypes"}} class="active">
|
<a {{action "toggleTypes"}} class="active">
|
||||||
{{activeTypeLabel}}
|
{{activeTypeLabel}}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="selector-types">
|
{{#if showTypes}}
|
||||||
{{#each selectorTypes as |item|}}
|
<div class="selector-types">
|
||||||
{{wizard-mapper-selector-type
|
{{#each selectorTypes as |item|}}
|
||||||
activeType=activeType
|
{{wizard-mapper-selector-type
|
||||||
item=item
|
activeType=activeType
|
||||||
toggle=(action 'toggleType')}}
|
item=item
|
||||||
{{/each}}
|
toggle=(action 'toggleType')}}
|
||||||
</div>
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<span>{{activeTypeLabel}}</span>
|
<span>{{activeTypeLabel}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -22,7 +24,6 @@
|
||||||
{{input
|
{{input
|
||||||
type="text"
|
type="text"
|
||||||
value=value
|
value=value
|
||||||
click=(action 'enableActive')
|
|
||||||
placeholder=(i18n placeholderKey)}}
|
placeholder=(i18n placeholderKey)}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
@ -31,8 +32,6 @@
|
||||||
value=value
|
value=value
|
||||||
content=comboBoxContent
|
content=comboBoxContent
|
||||||
onChange=(action (mut value))
|
onChange=(action (mut value))
|
||||||
onOpen=(action "enableActive")
|
|
||||||
onClick=(action 'enableActive')
|
|
||||||
options=(hash
|
options=(hash
|
||||||
none=placeholderKey
|
none=placeholderKey
|
||||||
)}}
|
)}}
|
||||||
|
@ -43,8 +42,6 @@
|
||||||
content=multiSelectContent
|
content=multiSelectContent
|
||||||
value=value
|
value=value
|
||||||
onChange=(action (mut value))
|
onChange=(action (mut value))
|
||||||
onOpen=(action "enableActive")
|
|
||||||
onClose=(action "disableActive")
|
|
||||||
options=multiSelectOptions}}
|
options=multiSelectOptions}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
@ -58,8 +55,6 @@
|
||||||
{{tag-chooser
|
{{tag-chooser
|
||||||
tags=value
|
tags=value
|
||||||
filterable=true
|
filterable=true
|
||||||
onOpen=(action "enableActive")
|
|
||||||
onClose=(action "disableActive")
|
|
||||||
options=(hash
|
options=(hash
|
||||||
none=placeholderKey
|
none=placeholderKey
|
||||||
)}}
|
)}}
|
||||||
|
@ -70,7 +65,6 @@
|
||||||
includeMessageableGroups='true'
|
includeMessageableGroups='true'
|
||||||
placeholderKey=placeholderKey
|
placeholderKey=placeholderKey
|
||||||
usernames=value
|
usernames=value
|
||||||
autocomplete="discourse"
|
autocomplete="discourse"}}
|
||||||
click=(action "enableActive")}}
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -2,35 +2,30 @@
|
||||||
@import 'wizard-transfer';
|
@import 'wizard-transfer';
|
||||||
@import 'wizard-api';
|
@import 'wizard-api';
|
||||||
|
|
||||||
|
.admin-wizard-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-wizard-message {
|
||||||
|
background-color: $primary-low;
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
.admin-wizard-container {
|
.admin-wizard-container {
|
||||||
.row {
|
margin-top: 20px;
|
||||||
display: flex;
|
|
||||||
|
.row > .content table {
|
||||||
> .content {
|
margin-top: 0;
|
||||||
flex: 1;
|
min-width: 100%;
|
||||||
margin-top: 10px;
|
width: auto;
|
||||||
margin-left: 30px;
|
|
||||||
|
|
||||||
table {
|
|
||||||
margin-top: 0;
|
|
||||||
min-width: 100%;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-submissions {
|
|
||||||
overflow: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wizard-list {
|
|
||||||
width: 250px;
|
|
||||||
min-width: 250px;
|
|
||||||
margin-top: 10px;
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wizard-settings-parent {
|
.wizard-settings-parent {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
@ -65,25 +60,7 @@
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// style workdarounds for wizard_step_advanced site setting - to be refactored
|
.admin-wizard-container.settings .wizard-basic-details {
|
||||||
|
|
||||||
.wizard-custom-step .wizard-advanced-toggle + .wizard-links.field,
|
|
||||||
.wizard-custom-step .advanced-settings + .wizard-links.field,
|
|
||||||
.wizard-links.action {
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wizard-links.field {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// end workdarounds //
|
|
||||||
|
|
||||||
.wizard-settings > .advanced-settings > div.setting {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-wizard.settings .wizard-basic-details {
|
|
||||||
justify-content: initial;
|
justify-content: initial;
|
||||||
|
|
||||||
.setting {
|
.setting {
|
||||||
|
@ -97,23 +74,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-wizard {
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wizard-header {
|
.wizard-header {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
|
||||||
&.large {
|
&.large {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
min-height: 31px;
|
min-height: 31px;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
width: 350px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
|
@ -124,6 +98,22 @@
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wizard-url {
|
||||||
|
display: inline-flex;
|
||||||
|
margin-left: 20px;
|
||||||
|
max-width: 50%;
|
||||||
|
|
||||||
|
a {
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 1rem;
|
||||||
|
background-color: $primary-low;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.medium {
|
&.medium {
|
||||||
|
@ -138,28 +128,13 @@
|
||||||
&.underline {
|
&.underline {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-url {
|
|
||||||
display: inline-flex;
|
|
||||||
margin-left: 20px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
padding: 6px 12px;
|
|
||||||
font-size: 1rem;
|
|
||||||
background-color: $primary-low;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-wizard-buttons {
|
.admin-wizard-buttons {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-wizard.settings {
|
.admin-wizard-container.settings {
|
||||||
|
|
||||||
[class~='setting'] {
|
[class~='setting'] {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
@ -208,15 +183,14 @@
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="number"] {
|
|
||||||
width: 70px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.medium {
|
input.medium {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.small {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
.uploaded-image-preview {
|
.uploaded-image-preview {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-height: 100px;
|
max-height: 100px;
|
||||||
|
@ -239,6 +213,11 @@
|
||||||
float: left;
|
float: left;
|
||||||
margin: 5px 7px 0 0;
|
margin: 5px 7px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input .select-kit, > .select-kit {
|
||||||
|
max-width: 250px !important;
|
||||||
|
min-width: 250px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.full, &.full-inline {
|
&.full, &.full-inline {
|
||||||
|
@ -255,7 +234,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.uploaded-image-preview {
|
.uploaded-image-preview {
|
||||||
max-height: 170px;
|
max-height: 200px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +272,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-custom-action > [class~='setting']:last-of-type {
|
.wizard-custom-action > [class~='setting']:first-of-type {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +307,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.d-editor-input {
|
.d-editor-input {
|
||||||
min-height: 130px;
|
min-height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.d-editor-container {
|
.d-editor-container {
|
||||||
|
|
|
@ -100,41 +100,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mapper-input.assignment,
|
|
||||||
.mapper-input.validation,
|
|
||||||
.mapper-input.association {
|
|
||||||
.mapper-selector {
|
|
||||||
max-width: 250px;
|
|
||||||
min-width: 250px;
|
|
||||||
|
|
||||||
> input, .select-kit, .ac-wrap, .autocomplete.ac-user {
|
|
||||||
width: 250px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapper-input.conditional {
|
|
||||||
.mapper-selector {
|
|
||||||
max-width: 170px;
|
|
||||||
min-width: 170px;
|
|
||||||
|
|
||||||
&:not(.text).active .input {
|
|
||||||
width: 250px;
|
|
||||||
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.2);
|
|
||||||
position: absolute;
|
|
||||||
z-index: 300;
|
|
||||||
|
|
||||||
.select-kit, .ac-wrap, .autocomplete.ac-user, .select-kit-wrapper {
|
|
||||||
width: 250px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapper-selector {
|
.mapper-selector {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
max-width: 250px;
|
||||||
|
min-width: 250px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
> input, .select-kit, .ac-wrap, .autocomplete.ac-user {
|
||||||
|
width: 250px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
transition: all 0.1s;
|
transition: all 0.1s;
|
||||||
|
@ -170,16 +145,12 @@
|
||||||
.selector-types {
|
.selector-types {
|
||||||
box-shadow: shadow('dropdown');
|
box-shadow: shadow('dropdown');
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: none;
|
display: flex;
|
||||||
background: $secondary;
|
background: $secondary;
|
||||||
z-index: 200;
|
z-index: 200;
|
||||||
padding: 5px 7px;
|
padding: 5px 7px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border: 1px solid $primary-low;
|
border: 1px solid $primary-low;
|
||||||
|
|
||||||
&.show {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.value-list .remove-value-btn {
|
.value-list .remove-value-btn {
|
||||||
|
|
|
@ -8,11 +8,12 @@ en:
|
||||||
wizard:
|
wizard:
|
||||||
label: "Wizard"
|
label: "Wizard"
|
||||||
nav_label: "Wizards"
|
nav_label: "Wizards"
|
||||||
new: "New"
|
select: "Select a wizard"
|
||||||
|
create: "Create Wizard"
|
||||||
name: "Name"
|
name: "Name"
|
||||||
name_placeholder: "wizard name"
|
name_placeholder: "wizard name"
|
||||||
background: "Background"
|
background: "Background"
|
||||||
background_placeholder: "#hex"
|
background_placeholder: "color"
|
||||||
save_submissions: "Save"
|
save_submissions: "Save"
|
||||||
save_submissions_label: "Save wizard submissions."
|
save_submissions_label: "Save wizard submissions."
|
||||||
multiple_submissions: "Multiple"
|
multiple_submissions: "Multiple"
|
||||||
|
@ -53,6 +54,12 @@ en:
|
||||||
permitted: "Permitted"
|
permitted: "Permitted"
|
||||||
advanced: "Advanced"
|
advanced: "Advanced"
|
||||||
|
|
||||||
|
message:
|
||||||
|
select: "Select a wizard, or create a new one"
|
||||||
|
edit: "You're editing a wizard"
|
||||||
|
create: "You're creating a new wizard"
|
||||||
|
help: "Stuck? Check out the documentation"
|
||||||
|
|
||||||
editor:
|
editor:
|
||||||
show: "Show"
|
show: "Show"
|
||||||
hide: "Hide"
|
hide: "Hide"
|
||||||
|
@ -97,6 +104,7 @@ en:
|
||||||
required: "{{type}} requires {{property}}"
|
required: "{{type}} requires {{property}}"
|
||||||
invalid: "{{property}} is invalid"
|
invalid: "{{property}} is invalid"
|
||||||
dependent: "{{property}} is dependent on {{dependent}}"
|
dependent: "{{property}} is dependent on {{dependent}}"
|
||||||
|
conflict: "{{type}} with {{property}} '{{value}}' already exists"
|
||||||
|
|
||||||
step:
|
step:
|
||||||
header: "Steps"
|
header: "Steps"
|
||||||
|
|
|
@ -12,25 +12,26 @@ Discourse::Application.routes.append do
|
||||||
|
|
||||||
scope module: 'custom_wizard', constraints: AdminConstraint.new do
|
scope module: 'custom_wizard', constraints: AdminConstraint.new do
|
||||||
get 'admin/wizards' => 'admin#index'
|
get 'admin/wizards' => 'admin#index'
|
||||||
get 'admin/wizards/field-types' => 'admin#field_types'
|
|
||||||
get 'admin/wizards/custom' => 'admin#index'
|
get 'admin/wizards/wizard' => 'admin_wizard#index'
|
||||||
get 'admin/wizards/custom/new' => 'admin#index'
|
get 'admin/wizards/wizard/create' => 'admin#index'
|
||||||
get 'admin/wizards/custom/all' => 'admin#custom_wizards'
|
get 'admin/wizards/wizard/:wizard_id' => 'admin_wizard#show'
|
||||||
get 'admin/wizards/custom/:wizard_id' => 'admin#find_wizard'
|
put 'admin/wizards/wizard/:wizard_id' => 'admin_wizard#save'
|
||||||
get 'admin/wizards/custom/:wizard_id' => 'admin#find_wizard'
|
delete 'admin/wizards/wizard/:wizard_id' => 'admin_wizard#remove'
|
||||||
put 'admin/wizards/custom/save' => 'admin#save'
|
|
||||||
delete 'admin/wizards/custom/remove' => 'admin#remove'
|
get 'admin/wizards/submissions' => 'admin_submissions#index'
|
||||||
get 'admin/wizards/submissions' => 'admin#index'
|
get 'admin/wizards/submissions/:wizard_id' => 'admin_submissions#show'
|
||||||
get 'admin/wizards/submissions/:wizard_id' => 'admin#submissions'
|
get 'admin/wizards/submissions/:wizard_id/download' => 'admin_submissions#download'
|
||||||
get 'admin/wizards/submissions/:wizard_id/download' => 'admin#download_submissions'
|
|
||||||
get 'admin/wizards/apis' => 'api#list'
|
get 'admin/wizards/apis' => 'admin_api#list'
|
||||||
get 'admin/wizards/apis/new' => 'api#index'
|
get 'admin/wizards/apis/new' => 'admin_api#index'
|
||||||
get 'admin/wizards/apis/:name' => 'api#find'
|
get 'admin/wizards/apis/:name' => 'admin_api#find'
|
||||||
put 'admin/wizards/apis/:name' => 'api#save'
|
put 'admin/wizards/apis/:name' => 'admin_api#save'
|
||||||
delete 'admin/wizards/apis/:name' => 'api#remove'
|
delete 'admin/wizards/apis/:name' => 'admin_api#remove'
|
||||||
delete 'admin/wizards/apis/logs/:name' => 'api#clearlogs'
|
delete 'admin/wizards/apis/logs/:name' => 'admin_api#clearlogs'
|
||||||
get 'admin/wizards/apis/:name/redirect' => 'api#redirect'
|
get 'admin/wizards/apis/:name/redirect' => 'admin_api#redirect'
|
||||||
get 'admin/wizards/apis/:name/authorize' => 'api#authorize'
|
get 'admin/wizards/apis/:name/authorize' => 'admin_api#authorize'
|
||||||
|
|
||||||
get 'admin/wizards/transfer' => 'transfer#index'
|
get 'admin/wizards/transfer' => 'transfer#index'
|
||||||
get 'admin/wizards/transfer/export' => 'transfer#export'
|
get 'admin/wizards/transfer/export' => 'transfer#export'
|
||||||
post 'admin/wizards/transfer/import' => 'transfer#import'
|
post 'admin/wizards/transfer/import' => 'transfer#import'
|
||||||
|
|
|
@ -1,271 +0,0 @@
|
||||||
class CustomWizard::AdminController < ::Admin::AdminController
|
|
||||||
skip_before_action :check_xhr, only: [:download_submissions]
|
|
||||||
before_action :ensure_admin
|
|
||||||
|
|
||||||
def index
|
|
||||||
render nothing: true
|
|
||||||
end
|
|
||||||
|
|
||||||
def field_types
|
|
||||||
render json: { types: CustomWizard::Field.types }
|
|
||||||
end
|
|
||||||
|
|
||||||
def save
|
|
||||||
result = build_wizard
|
|
||||||
|
|
||||||
if result[:error]
|
|
||||||
render json: { error: result[:error] }
|
|
||||||
else
|
|
||||||
wizard = result[:wizard]
|
|
||||||
existing_wizard = result[:existing_wizard]
|
|
||||||
after_time = result[:after_time]
|
|
||||||
|
|
||||||
ActiveRecord::Base.transaction do
|
|
||||||
PluginStore.set('custom_wizard', wizard["id"], wizard)
|
|
||||||
|
|
||||||
if after_time[:enabled]
|
|
||||||
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard['id'])
|
|
||||||
Jobs.enqueue_at(after_time[:scheduled], :set_after_time_wizard, wizard_id: wizard['id'])
|
|
||||||
end
|
|
||||||
|
|
||||||
if existing_wizard && existing_wizard['after_time'] && !after_time[:enabled]
|
|
||||||
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard['id'])
|
|
||||||
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard['id'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
render json: success_json.merge(wizard: wizard)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove
|
|
||||||
params.require(:id)
|
|
||||||
|
|
||||||
wizard = PluginStore.get('custom_wizard', params[:id])
|
|
||||||
|
|
||||||
if wizard['after_time']
|
|
||||||
Jobs.cancel_scheduled_job(:set_after_time_wizard)
|
|
||||||
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard['id'])
|
|
||||||
end
|
|
||||||
|
|
||||||
PluginStore.remove('custom_wizard', params[:id])
|
|
||||||
|
|
||||||
render json: success_json
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_wizard
|
|
||||||
params.require(:wizard_id)
|
|
||||||
wizard = PluginStore.get('custom_wizard', params[:wizard_id].underscore)
|
|
||||||
render json: success_json.merge(wizard: wizard)
|
|
||||||
end
|
|
||||||
|
|
||||||
def custom_wizards
|
|
||||||
rows = PluginStoreRow.where(plugin_name: 'custom_wizard').order(:id)
|
|
||||||
wizards = [*rows].map { |r| CustomWizard::Template.new(r.value) }
|
|
||||||
render json: success_json.merge(wizards: wizards)
|
|
||||||
end
|
|
||||||
|
|
||||||
def submissions
|
|
||||||
params.require(:wizard_id)
|
|
||||||
|
|
||||||
wizard_id = params[:wizard_id].underscore
|
|
||||||
wizard = PluginStore.get('custom_wizard', wizard_id)
|
|
||||||
|
|
||||||
if wizard.present?
|
|
||||||
render json: success_json.merge(
|
|
||||||
submissions: build_submissions(wizard_id),
|
|
||||||
wizard: wizard.slice(:id, :name)
|
|
||||||
)
|
|
||||||
else
|
|
||||||
head :ok
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def download_submissions
|
|
||||||
params.require(:wizard_id)
|
|
||||||
wizard_id = params[:wizard_id].underscore
|
|
||||||
|
|
||||||
wizard = PluginStore.get('custom_wizard', wizard_id)
|
|
||||||
submissions = build_submissions(wizard_id).to_json
|
|
||||||
|
|
||||||
send_data submissions,
|
|
||||||
filename: "#{Discourse.current_hostname}-wizard-submissions-#{wizard['name']}.json",
|
|
||||||
content_type: "application/json"
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def wizard_params
|
|
||||||
params.require(:wizard)
|
|
||||||
params[:wizard]
|
|
||||||
end
|
|
||||||
|
|
||||||
def required_properties
|
|
||||||
{
|
|
||||||
wizard: ['id', 'name', 'steps'],
|
|
||||||
step: ['id'],
|
|
||||||
field: ['id', 'type'],
|
|
||||||
action: ['id', 'type']
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def dependent_properties
|
|
||||||
{
|
|
||||||
wizard: {
|
|
||||||
after_time: 'after_time_scheduled'
|
|
||||||
},
|
|
||||||
step: {},
|
|
||||||
field: {},
|
|
||||||
action: {}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_required(object, type, error)
|
|
||||||
required_properties[type].each do |property|
|
|
||||||
if object[property].blank?
|
|
||||||
error = {
|
|
||||||
type: 'required',
|
|
||||||
params: { type: type, property: property }
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
error
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_depdendent(object, type, error)
|
|
||||||
dependent_properties[type].each do |property, dependent|
|
|
||||||
if object[property] && object[dependent].blank?
|
|
||||||
error = {
|
|
||||||
type: 'dependent',
|
|
||||||
params: { property: property, dependent: dependent }
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
error
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate_wizard(wizard)
|
|
||||||
error = nil
|
|
||||||
|
|
||||||
error = check_required(wizard, :wizard, error)
|
|
||||||
error = check_depdendent(wizard, :wizard, error)
|
|
||||||
|
|
||||||
if !error
|
|
||||||
wizard['steps'].each do |step|
|
|
||||||
error = check_required(step, :step, error)
|
|
||||||
error = check_depdendent(step, :step, error)
|
|
||||||
break if error.present?
|
|
||||||
|
|
||||||
if step['fields'].present?
|
|
||||||
step['fields'].each do |field|
|
|
||||||
error = check_required(field, :field, error)
|
|
||||||
error = check_depdendent(field, :field, error)
|
|
||||||
break if error.present?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if wizard['actions'].present?
|
|
||||||
wizard['actions'].each do |action|
|
|
||||||
error = check_required(action, :action, error)
|
|
||||||
error = check_depdendent(action, :action, error)
|
|
||||||
break if error.present?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if error
|
|
||||||
{ error: error }
|
|
||||||
else
|
|
||||||
{ success: true }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate_after_time(wizard, existing_wizard)
|
|
||||||
new = false
|
|
||||||
error = nil
|
|
||||||
enabled = false
|
|
||||||
scheduled = nil
|
|
||||||
|
|
||||||
if wizard["after_time"]
|
|
||||||
enabled = true
|
|
||||||
|
|
||||||
if !wizard["after_time_scheduled"] && !existing_wizard["after_time_scheduled"]
|
|
||||||
error = 'after_time_need_time'
|
|
||||||
else
|
|
||||||
scheduled = Time.parse(wizard["after_time_scheduled"]).utc
|
|
||||||
new = false
|
|
||||||
|
|
||||||
if existing_wizard['after_time_scheduled']
|
|
||||||
new = scheduled != Time.parse(existing_wizard['after_time_scheduled']).utc
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
error = 'after_time_invalid' if new && scheduled < Time.now.utc
|
|
||||||
rescue ArgumentError
|
|
||||||
error = 'after_time_invalid'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if error
|
|
||||||
{ error: { type: error } }
|
|
||||||
else
|
|
||||||
{
|
|
||||||
new: new,
|
|
||||||
scheduled: scheduled,
|
|
||||||
enabled: enabled
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_wizard
|
|
||||||
wizard = ::JSON.parse(wizard_params)
|
|
||||||
existing_wizard = PluginStore.get('custom_wizard', wizard['id']) || {}
|
|
||||||
|
|
||||||
validation = validate_wizard(wizard)
|
|
||||||
return validation if validation[:error]
|
|
||||||
|
|
||||||
after_time = validate_after_time(wizard, existing_wizard)
|
|
||||||
return after_time if after_time[:error]
|
|
||||||
|
|
||||||
wizard['steps'].each do |step|
|
|
||||||
if step['raw_description']
|
|
||||||
step['description'] = PrettyText.cook(step['raw_description'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
result = {
|
|
||||||
wizard: wizard,
|
|
||||||
existing_wizard: existing_wizard
|
|
||||||
}
|
|
||||||
|
|
||||||
if after_time[:enabled]
|
|
||||||
result[:after_time] = after_time
|
|
||||||
end
|
|
||||||
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_submissions(wizard_id)
|
|
||||||
rows = PluginStoreRow.where(plugin_name: "#{wizard_id}_submissions").order('id DESC')
|
|
||||||
|
|
||||||
submissions = [*rows].map do |row|
|
|
||||||
value = ::JSON.parse(row.value)
|
|
||||||
|
|
||||||
if user = User.find_by(id: row.key)
|
|
||||||
username = user.username
|
|
||||||
else
|
|
||||||
username = I18n.t('admin.wizard.submissions.no_user', id: row.key)
|
|
||||||
end
|
|
||||||
|
|
||||||
value.map do |submission|
|
|
||||||
{
|
|
||||||
username: username
|
|
||||||
}.merge!(submission.except("redirect_to"))
|
|
||||||
end
|
|
||||||
end.flatten
|
|
||||||
end
|
|
||||||
end
|
|
13
controllers/custom_wizard/admin/admin.rb
Normale Datei
13
controllers/custom_wizard/admin/admin.rb
Normale Datei
|
@ -0,0 +1,13 @@
|
||||||
|
class CustomWizard::AdminController < ::Admin::AdminController
|
||||||
|
before_action :ensure_admin
|
||||||
|
|
||||||
|
def index
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_wizard
|
||||||
|
params.require(:wizard_id)
|
||||||
|
@wizard = CustomWizard::Wizard.create(params[:wizard_id].underscore)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,4 @@
|
||||||
class CustomWizard::ApiController < ::ApplicationController
|
class CustomWizard::AdminApiController < CustomWizard::AdminController
|
||||||
before_action :ensure_logged_in
|
|
||||||
before_action :ensure_admin
|
|
||||||
skip_before_action :check_xhr, only: [:redirect]
|
skip_before_action :check_xhr, only: [:redirect]
|
||||||
|
|
||||||
def index
|
def index
|
51
controllers/custom_wizard/admin/submissions.rb
Normale Datei
51
controllers/custom_wizard/admin/submissions.rb
Normale Datei
|
@ -0,0 +1,51 @@
|
||||||
|
class CustomWizard::AdminSubmissionsController < CustomWizard::AdminController
|
||||||
|
skip_before_action :check_xhr, only: [:download_submissions]
|
||||||
|
before_action :find_wizard
|
||||||
|
|
||||||
|
def index
|
||||||
|
render json: ActiveModel::ArraySerializer.new(
|
||||||
|
CustomWizard::Wizard.list,
|
||||||
|
each_serializer: CustomWizard::BasicWizardSerializer
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
if wizard = @wizard
|
||||||
|
submissions = build_submissions(wizard.id)
|
||||||
|
result[:wizard] = CustomWizard::BasicWizardSerializer.new(wizard, root: false)
|
||||||
|
result[:submissions] = submissions.as_json
|
||||||
|
end
|
||||||
|
|
||||||
|
render_json_dump(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def download
|
||||||
|
send_data build_submissions(@wizard.id).to_json,
|
||||||
|
filename: "#{Discourse.current_hostname}-wizard-submissions-#{wizard['name']}.json",
|
||||||
|
content_type: "application/json"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def build_submissions(wizard_id)
|
||||||
|
rows = PluginStoreRow.where(plugin_name: "#{wizard_id}_submissions").order('id DESC')
|
||||||
|
|
||||||
|
submissions = [*rows].map do |row|
|
||||||
|
value = ::JSON.parse(row.value)
|
||||||
|
|
||||||
|
if user = User.find_by(id: row.key)
|
||||||
|
username = user.username
|
||||||
|
else
|
||||||
|
username = I18n.t('admin.wizard.submissions.no_user', id: row.key)
|
||||||
|
end
|
||||||
|
|
||||||
|
value.map do |submission|
|
||||||
|
{
|
||||||
|
username: username
|
||||||
|
}.merge!(submission.except("redirect_to"))
|
||||||
|
end
|
||||||
|
end.flatten
|
||||||
|
end
|
||||||
|
end
|
133
controllers/custom_wizard/admin/wizard.rb
Normale Datei
133
controllers/custom_wizard/admin/wizard.rb
Normale Datei
|
@ -0,0 +1,133 @@
|
||||||
|
class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
|
before_action :find_wizard, only: [:show, :remove]
|
||||||
|
|
||||||
|
def index
|
||||||
|
render_json_dump(
|
||||||
|
wizard_list: ActiveModel::ArraySerializer.new(
|
||||||
|
CustomWizard::Wizard.list,
|
||||||
|
each_serializer: CustomWizard::BasicWizardSerializer
|
||||||
|
),
|
||||||
|
field_types: CustomWizard::Field.types
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
params.require(:wizard_id)
|
||||||
|
|
||||||
|
if data = CustomWizard::Wizard.find(params[:wizard_id].underscore)
|
||||||
|
render json: data.as_json
|
||||||
|
else
|
||||||
|
render json: { none: true }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove
|
||||||
|
CustomWizard::Wizard.remove(@wizard.id)
|
||||||
|
render json: success_json
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
opts = {}
|
||||||
|
opts[:create] = params[:create] if params[:create]
|
||||||
|
|
||||||
|
validator = CustomWizard::Validator.new(save_wizard_params.to_h, opts)
|
||||||
|
validation = validator.perform
|
||||||
|
|
||||||
|
if validation[:error]
|
||||||
|
render json: { error: validation[:error] }
|
||||||
|
else
|
||||||
|
params = validation[:wizard]
|
||||||
|
|
||||||
|
if wizard_id = CustomWizard::Wizard.save(params)
|
||||||
|
render json: success_json.merge(wizard_id: wizard_id)
|
||||||
|
else
|
||||||
|
render json: failed_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def mapped_params
|
||||||
|
[
|
||||||
|
:type,
|
||||||
|
:connector,
|
||||||
|
:output,
|
||||||
|
:output_type,
|
||||||
|
:output_connector,
|
||||||
|
pairs: [
|
||||||
|
:index,
|
||||||
|
:key,
|
||||||
|
:key_type,
|
||||||
|
:value,
|
||||||
|
:value_type,
|
||||||
|
:connector,
|
||||||
|
value: [],
|
||||||
|
key: [],
|
||||||
|
],
|
||||||
|
output: [],
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def save_wizard_params
|
||||||
|
params.require(:wizard).permit(
|
||||||
|
:id,
|
||||||
|
:name,
|
||||||
|
:background,
|
||||||
|
:save_submissions,
|
||||||
|
:multiple_submissions,
|
||||||
|
:after_signup,
|
||||||
|
:after_time,
|
||||||
|
:after_time_scheduled,
|
||||||
|
:required,
|
||||||
|
:prompt_completion,
|
||||||
|
:restart_on_revisit,
|
||||||
|
:theme_id,
|
||||||
|
permitted: mapped_params,
|
||||||
|
steps: [
|
||||||
|
:id,
|
||||||
|
:title,
|
||||||
|
:key,
|
||||||
|
:banner,
|
||||||
|
:raw_description,
|
||||||
|
:required_data_message,
|
||||||
|
required_data: mapped_params,
|
||||||
|
permitted_params: mapped_params,
|
||||||
|
fields: [
|
||||||
|
:id,
|
||||||
|
:label,
|
||||||
|
:image,
|
||||||
|
:description,
|
||||||
|
:required,
|
||||||
|
:key,
|
||||||
|
:type,
|
||||||
|
:min_length,
|
||||||
|
:file_types,
|
||||||
|
:limit,
|
||||||
|
:property,
|
||||||
|
prefill: mapped_params,
|
||||||
|
content: mapped_params
|
||||||
|
]
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
:id,
|
||||||
|
:run_after,
|
||||||
|
:type,
|
||||||
|
:code,
|
||||||
|
:skip_redirect,
|
||||||
|
:url,
|
||||||
|
title: mapped_params,
|
||||||
|
post: mapped_params,
|
||||||
|
post_builder: mapped_params,
|
||||||
|
post_template: mapped_params,
|
||||||
|
category: mapped_params,
|
||||||
|
tags: mapped_params,
|
||||||
|
custom_fields: mapped_params,
|
||||||
|
required: mapped_params,
|
||||||
|
recipient: mapped_params,
|
||||||
|
profile_updates: mapped_params,
|
||||||
|
group: mapped_params
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,7 +12,7 @@ class CustomWizard::StepsController < ::ApplicationController
|
||||||
permitted.permit!
|
permitted.permit!
|
||||||
end
|
end
|
||||||
|
|
||||||
wizard = CustomWizard::Builder.new(current_user, permitted[:wizard_id].underscore).build
|
wizard = CustomWizard::Builder.new(permitted[:wizard_id].underscore, current_user).build
|
||||||
updater = wizard.create_updater(permitted[:step_id], permitted[:fields])
|
updater = wizard.create_updater(permitted[:step_id], permitted[:fields])
|
||||||
updater.update
|
updater.update
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ class CustomWizard::TransferController < ::ApplicationController
|
||||||
failed_ids = []
|
failed_ids = []
|
||||||
|
|
||||||
jsonObject.each do |o|
|
jsonObject.each do |o|
|
||||||
if !CustomWizard::Template.new(o)
|
if !CustomWizard::Wizard.new(o)
|
||||||
failed_ids.push o['id']
|
failed_ids.push o['id']
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ class CustomWizard::WizardController < ::ApplicationController
|
||||||
helper_method :theme_ids
|
helper_method :theme_ids
|
||||||
|
|
||||||
def wizard
|
def wizard
|
||||||
CustomWizard::Template.new(PluginStore.get('custom_wizard', params[:wizard_id].underscore))
|
CustomWizard::Wizard.create(params[:wizard_id].underscore, current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def wizard_page_title
|
def wizard_page_title
|
||||||
|
@ -20,12 +20,14 @@ class CustomWizard::WizardController < ::ApplicationController
|
||||||
def index
|
def index
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
builder = CustomWizard::Builder.new(current_user, params[:wizard_id].underscore)
|
builder = CustomWizard::Builder.new(params[:wizard_id].underscore, current_user)
|
||||||
builder_opts = {}
|
|
||||||
builder_opts[:reset] = params[:reset] || builder.wizard.restart_on_revisit
|
|
||||||
|
|
||||||
if builder.wizard.present?
|
if builder.wizard.present?
|
||||||
render_serialized(builder.build(builder_opts, params), ::CustomWizardSerializer)
|
builder_opts = {}
|
||||||
|
builder_opts[:reset] = params[:reset] || builder.wizard.restart_on_revisit
|
||||||
|
built_wizard = builder.build(builder_opts, params)
|
||||||
|
|
||||||
|
render_serialized(built_wizard, ::CustomWizard::WizardSerializer, root: false)
|
||||||
else
|
else
|
||||||
render json: { error: I18n.t('wizard.none') }
|
render json: { error: I18n.t('wizard.none') }
|
||||||
end
|
end
|
||||||
|
@ -34,34 +36,28 @@ class CustomWizard::WizardController < ::ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
## clean up if user skips wizard
|
|
||||||
def skip
|
def skip
|
||||||
params.require(:wizard_id)
|
params.require(:wizard_id)
|
||||||
|
|
||||||
wizard_id = params[:wizard_id]
|
|
||||||
|
|
||||||
user = current_user
|
|
||||||
wizard_template = PluginStore.get('custom_wizard', wizard_id.underscore)
|
|
||||||
wizard = CustomWizard::Wizard.new(user, wizard_template)
|
|
||||||
|
|
||||||
if wizard.required && !wizard.completed? && wizard.permitted?
|
if wizard.required && !wizard.completed? && wizard.permitted?
|
||||||
return render json: { error: I18n.t('wizard.no_skip') }
|
return render json: { error: I18n.t('wizard.no_skip') }
|
||||||
end
|
end
|
||||||
|
|
||||||
result = success_json
|
result = success_json
|
||||||
|
user = current_user
|
||||||
|
|
||||||
if user
|
if user
|
||||||
submission = Array.wrap(PluginStore.get("#{wizard_id}_submissions", user.id)).last
|
submission = wizard.submissions.last
|
||||||
|
|
||||||
if submission && submission['redirect_to']
|
if submission && submission['redirect_to']
|
||||||
result.merge!(redirect_to: submission['redirect_to'])
|
result.merge!(redirect_to: submission['redirect_to'])
|
||||||
end
|
end
|
||||||
|
|
||||||
if submission && !wizard.save_submissions
|
if submission && !wizard.save_submissions
|
||||||
PluginStore.remove("#{wizard_id}_submissions", user.id)
|
PluginStore.remove("#{wizard.id}_submissions", user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
if user.custom_fields['redirect_to_wizard'] === wizard_id
|
if user.custom_fields['redirect_to_wizard'] === wizard.id
|
||||||
user.custom_fields.delete('redirect_to_wizard')
|
user.custom_fields.delete('redirect_to_wizard')
|
||||||
user.save_custom_fields(true)
|
user.save_custom_fields(true)
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Jobs
|
||||||
user_ids = []
|
user_ids = []
|
||||||
|
|
||||||
User.human_users.each do |user|
|
User.human_users.each do |user|
|
||||||
if CustomWizard::Wizard.set_wizard_redirect(user, args[:wizard_id])
|
if CustomWizard::Wizard.set_wizard_redirect(args[:wizard_id], user)
|
||||||
user_ids.push(user.id)
|
user_ids.push(user.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
class CustomWizard::Builder
|
class CustomWizard::Builder
|
||||||
attr_accessor :wizard, :updater, :submissions
|
attr_accessor :wizard, :updater, :submissions
|
||||||
|
|
||||||
def initialize(user=nil, wizard_id)
|
def initialize(wizard_id, user=nil)
|
||||||
template = PluginStore.get('custom_wizard', wizard_id)
|
params = CustomWizard::Wizard.find(wizard_id)
|
||||||
return if template.blank?
|
return nil if params.blank?
|
||||||
|
|
||||||
@steps = template['steps']
|
@wizard = CustomWizard::Wizard.new(params, user)
|
||||||
@actions = template['actions']
|
@steps = params['steps'] || []
|
||||||
@wizard = CustomWizard::Wizard.new(user, template)
|
@actions = params['actions'] || []
|
||||||
@submissions = Array.wrap(PluginStore.get("#{wizard_id}_submissions", user.id)) if user
|
@submissions = @wizard.submissions if user && @wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.sorted_handlers
|
def self.sorted_handlers
|
||||||
|
@ -38,13 +38,8 @@ class CustomWizard::Builder
|
||||||
end
|
end
|
||||||
|
|
||||||
def build(build_opts = {}, params = {})
|
def build(build_opts = {}, params = {})
|
||||||
|
return nil if !SiteSetting.custom_wizard_enabled || !@wizard
|
||||||
return @wizard if !SiteSetting.custom_wizard_enabled ||
|
return @wizard if !@wizard.can_access?
|
||||||
(!@wizard.multiple_submissions &&
|
|
||||||
@wizard.completed? &&
|
|
||||||
!@wizard.user.admin) ||
|
|
||||||
!@steps ||
|
|
||||||
!@wizard.permitted?
|
|
||||||
|
|
||||||
reset_submissions if build_opts[:reset]
|
reset_submissions if build_opts[:reset]
|
||||||
|
|
||||||
|
@ -150,10 +145,10 @@ class CustomWizard::Builder
|
||||||
|
|
||||||
if @actions.present?
|
if @actions.present?
|
||||||
@actions.each do |action|
|
@actions.each do |action|
|
||||||
|
|
||||||
if (action['run_after'] === updater.step.id) ||
|
if (action['run_after'] === updater.step.id) ||
|
||||||
(final_step && (!action['run_after'] || (action['run_after'] === 'wizard_completion')))
|
(final_step && (!action['run_after'] || (action['run_after'] === 'wizard_completion')))
|
||||||
|
|
||||||
CustomWizard::Action.new(
|
CustomWizard::Action.new(
|
||||||
action: action,
|
action: action,
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -189,7 +184,7 @@ class CustomWizard::Builder
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@wizard
|
@wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -213,7 +208,7 @@ class CustomWizard::Builder
|
||||||
|
|
||||||
params[:value] = prefill_field(field_template, step_template) || params[:value]
|
params[:value] = prefill_field(field_template, step_template) || params[:value]
|
||||||
|
|
||||||
if field_template['type'] === 'group'
|
if field_template['type'] === 'group' && params[:value].present?
|
||||||
params[:value] = params[:value].first
|
params[:value] = params[:value].first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -262,7 +257,7 @@ class CustomWizard::Builder
|
||||||
|
|
||||||
params[:content] = content[:result]
|
params[:content] = content[:result]
|
||||||
end
|
end
|
||||||
|
|
||||||
field = step.add_field(params)
|
field = step.add_field(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,10 @@ class CustomWizard::Mapper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def map_text(value)
|
||||||
|
interpolate(value)
|
||||||
|
end
|
||||||
|
|
||||||
def map_wizard_field(value)
|
def map_wizard_field(value)
|
||||||
data && !data.key?("submitted_at") && data[value]
|
data && !data.key?("submitted_at") && data[value]
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
class CustomWizard::Template
|
|
||||||
|
|
||||||
attr_reader :id,
|
|
||||||
:name,
|
|
||||||
:background,
|
|
||||||
:save_submissions,
|
|
||||||
:multiple_submissions,
|
|
||||||
:prompt_completion,
|
|
||||||
:restart_on_revisit,
|
|
||||||
:after_signup,
|
|
||||||
:after_time,
|
|
||||||
:after_time_scheduled,
|
|
||||||
:required,
|
|
||||||
:theme_id,
|
|
||||||
:permitted,
|
|
||||||
:steps,
|
|
||||||
:actions
|
|
||||||
|
|
||||||
def initialize(data)
|
|
||||||
data = data.is_a?(String) ? ::JSON.parse(data) : data
|
|
||||||
|
|
||||||
return nil if data.blank?
|
|
||||||
|
|
||||||
@id = data['id']
|
|
||||||
@name = data['name']
|
|
||||||
@background = data['background']
|
|
||||||
@save_submissions = data['save_submissions'] || false
|
|
||||||
@multiple_submissions = data['multiple_submissions'] || false
|
|
||||||
@prompt_completion = data['prompt_completion'] || false
|
|
||||||
@restart_on_revisit = data['restart_on_revisit'] || false
|
|
||||||
@after_signup = data['after_signup']
|
|
||||||
@after_time = data['after_time']
|
|
||||||
@after_time_scheduled = data['after_time_scheduled']
|
|
||||||
@required = data['required'] || false
|
|
||||||
@theme_id = data['theme_id']
|
|
||||||
@permitted = data['permitted'] || nil
|
|
||||||
|
|
||||||
if data['theme']
|
|
||||||
theme = Theme.find_by(name: data['theme'])
|
|
||||||
@theme_id = theme.id if theme
|
|
||||||
end
|
|
||||||
|
|
||||||
@steps = data['steps']
|
|
||||||
@actions = data['actions']
|
|
||||||
end
|
|
||||||
end
|
|
143
lib/custom_wizard/validator.rb
Normale Datei
143
lib/custom_wizard/validator.rb
Normale Datei
|
@ -0,0 +1,143 @@
|
||||||
|
class CustomWizard::Validator
|
||||||
|
|
||||||
|
def initialize(params, opts={})
|
||||||
|
@params = params
|
||||||
|
@opts = opts
|
||||||
|
@error = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform
|
||||||
|
params = @params
|
||||||
|
|
||||||
|
check_id(params, :wizard)
|
||||||
|
check_required(params, :wizard)
|
||||||
|
check_depdendent(params, :wizard)
|
||||||
|
|
||||||
|
after_time = nil
|
||||||
|
|
||||||
|
if !@error && @params[:after_time]
|
||||||
|
after_time = validate_after_time
|
||||||
|
end
|
||||||
|
|
||||||
|
if !@error
|
||||||
|
params[:steps].each do |step|
|
||||||
|
check_required(step, :step)
|
||||||
|
check_depdendent(step, :step)
|
||||||
|
break if @error.present?
|
||||||
|
|
||||||
|
if params[:fields].present?
|
||||||
|
params[:fields].each do |field|
|
||||||
|
check_required(field, :field)
|
||||||
|
check_depdendent(field, :field)
|
||||||
|
break if @error.present?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if params[:actions].present?
|
||||||
|
params[:actions].each do |action|
|
||||||
|
check_required(action, :action)
|
||||||
|
check_depdendent(action, :action)
|
||||||
|
break if @error.present?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @error
|
||||||
|
{ error: @error }
|
||||||
|
else
|
||||||
|
result = { wizard: params }
|
||||||
|
result[:after_time] = after_time if after_time
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.required
|
||||||
|
{
|
||||||
|
wizard: ['id', 'name', 'steps'],
|
||||||
|
step: ['id'],
|
||||||
|
field: ['id', 'type'],
|
||||||
|
action: ['id', 'type']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.dependent
|
||||||
|
{
|
||||||
|
wizard: {
|
||||||
|
after_time: 'after_time_scheduled'
|
||||||
|
},
|
||||||
|
step: {},
|
||||||
|
field: {},
|
||||||
|
action: {}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_required(object, type)
|
||||||
|
CustomWizard::Validator.required[type].each do |property|
|
||||||
|
if object[property].blank?
|
||||||
|
@error = {
|
||||||
|
type: 'required',
|
||||||
|
params: { type: type, property: property }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_depdendent(object, type)
|
||||||
|
CustomWizard::Validator.dependent[type].each do |property, dependent|
|
||||||
|
if object[property] && object[dependent].blank?
|
||||||
|
@error = {
|
||||||
|
type: 'dependent',
|
||||||
|
params: { property: property, dependent: dependent }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_id(object, type)
|
||||||
|
if type === :wizard && @opts[:create] && CustomWizard::Wizard.exists?(object[:id])
|
||||||
|
@error = {
|
||||||
|
type: 'conflict',
|
||||||
|
params: { type: type, property: 'id', value: object[:id] }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_after_time
|
||||||
|
if !@opts[:create]
|
||||||
|
wizard = CustomWizard::Wizard.create(params)
|
||||||
|
end
|
||||||
|
|
||||||
|
new = false
|
||||||
|
error = nil
|
||||||
|
scheduled = nil
|
||||||
|
|
||||||
|
if !@params[:after_time_scheduled] && !wizard[:after_time_scheduled]
|
||||||
|
error = 'after_time_need_time'
|
||||||
|
else
|
||||||
|
scheduled = Time.parse(@params[:after_time_scheduled]).utc
|
||||||
|
new = false
|
||||||
|
|
||||||
|
if wizard[:after_time_scheduled]
|
||||||
|
new = scheduled != Time.parse(wizard[:after_time_scheduled]).utc
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
error = 'after_time_invalid' if new && scheduled < Time.now.utc
|
||||||
|
rescue ArgumentError
|
||||||
|
error = 'after_time_invalid'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if error
|
||||||
|
@error = { type: error }
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new: new,
|
||||||
|
scheduled: scheduled
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,10 +8,10 @@ UserHistory.actions[:custom_wizard_step] = 1000
|
||||||
class CustomWizard::Wizard
|
class CustomWizard::Wizard
|
||||||
include ActiveModel::SerializerSupport
|
include ActiveModel::SerializerSupport
|
||||||
|
|
||||||
attr_reader :steps, :user
|
|
||||||
attr_accessor :id,
|
attr_accessor :id,
|
||||||
:name,
|
:name,
|
||||||
:background,
|
:background,
|
||||||
|
:theme_id,
|
||||||
:save_submissions,
|
:save_submissions,
|
||||||
:multiple_submissions,
|
:multiple_submissions,
|
||||||
:after_time,
|
:after_time,
|
||||||
|
@ -22,20 +22,38 @@ class CustomWizard::Wizard
|
||||||
:restart_on_revisit,
|
:restart_on_revisit,
|
||||||
:permitted,
|
:permitted,
|
||||||
:needs_categories,
|
:needs_categories,
|
||||||
:needs_groups
|
:needs_groups,
|
||||||
|
:steps,
|
||||||
|
:actions,
|
||||||
|
:user
|
||||||
|
|
||||||
def initialize(user=nil, attrs = {})
|
def initialize(attrs = {}, user=nil)
|
||||||
@steps = []
|
|
||||||
@user = user
|
@user = user
|
||||||
@first_step = nil
|
|
||||||
@required = false
|
@id = attrs['id']
|
||||||
|
@name = attrs['name']
|
||||||
|
@background = attrs['background']
|
||||||
|
@save_submissions = attrs['save_submissions'] || false
|
||||||
|
@multiple_submissions = attrs['multiple_submissions'] || false
|
||||||
|
@prompt_completion = attrs['prompt_completion'] || false
|
||||||
|
@restart_on_revisit = attrs['restart_on_revisit'] || false
|
||||||
|
@after_signup = attrs['after_signup']
|
||||||
|
@after_time = attrs['after_time']
|
||||||
|
@after_time_scheduled = attrs['after_time_scheduled']
|
||||||
|
@required = attrs['required'] || false
|
||||||
|
@permitted = attrs['permitted'] || nil
|
||||||
@needs_categories = false
|
@needs_categories = false
|
||||||
@needs_groups = false
|
@needs_groups = false
|
||||||
|
@theme_id = attrs['theme_id']
|
||||||
attrs.each do |key, value|
|
|
||||||
setter = "#{key}="
|
if attrs['theme']
|
||||||
send(setter, value) if respond_to?(setter.to_sym, false)
|
theme = Theme.find_by(name: attrs['theme'])
|
||||||
|
@theme_id = theme.id if theme
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@first_step = nil
|
||||||
|
@steps = []
|
||||||
|
@actions = []
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_step(step_name)
|
def create_step(step_name)
|
||||||
|
@ -44,13 +62,13 @@ class CustomWizard::Wizard
|
||||||
|
|
||||||
def append_step(step)
|
def append_step(step)
|
||||||
step = create_step(step) if step.is_a?(String)
|
step = create_step(step) if step.is_a?(String)
|
||||||
|
|
||||||
yield step if block_given?
|
yield step if block_given?
|
||||||
|
|
||||||
last_step = @steps.last
|
last_step = @steps.last
|
||||||
|
|
||||||
@steps << step
|
@steps << step
|
||||||
|
|
||||||
# If it's the first step
|
# If it's the first step
|
||||||
if @steps.size == 1
|
if @steps.size == 1
|
||||||
@first_step = step
|
@first_step = step
|
||||||
|
@ -108,7 +126,7 @@ class CustomWizard::Wizard
|
||||||
|
|
||||||
def completed?
|
def completed?
|
||||||
return nil if !@user
|
return nil if !@user
|
||||||
|
|
||||||
steps = CustomWizard::Wizard.step_ids(@id)
|
steps = CustomWizard::Wizard.step_ids(@id)
|
||||||
|
|
||||||
history = ::UserHistory.where(
|
history = ::UserHistory.where(
|
||||||
|
@ -151,6 +169,13 @@ class CustomWizard::Wizard
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_access?
|
||||||
|
return true if user.admin
|
||||||
|
return false if multiple_submissions && completed?
|
||||||
|
return false if !permitted?
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
def reset
|
def reset
|
||||||
::UserHistory.create(
|
::UserHistory.create(
|
||||||
|
@ -169,6 +194,10 @@ class CustomWizard::Wizard
|
||||||
@groups ||= ::Site.new(Guardian.new(@user)).groups
|
@groups ||= ::Site.new(Guardian.new(@user)).groups
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def submissions
|
||||||
|
Array.wrap(PluginStore.get("#{id}_submissions", @user.id))
|
||||||
|
end
|
||||||
|
|
||||||
def self.filter_records(filter)
|
def self.filter_records(filter)
|
||||||
PluginStoreRow.where("
|
PluginStoreRow.where("
|
||||||
plugin_name = 'custom_wizard' AND
|
plugin_name = 'custom_wizard' AND
|
||||||
|
@ -183,7 +212,7 @@ class CustomWizard::Wizard
|
||||||
records
|
records
|
||||||
.sort_by { |record| record.value['permitted'].present? ? 0 : 1 }
|
.sort_by { |record| record.value['permitted'].present? ? 0 : 1 }
|
||||||
.each do |record|
|
.each do |record|
|
||||||
wizard = CustomWizard::Wizard.new(user, JSON.parse(record.value))
|
wizard = CustomWizard::Wizard.new(JSON.parse(record.value), user)
|
||||||
|
|
||||||
if wizard.permitted?
|
if wizard.permitted?
|
||||||
result = wizard
|
result = wizard
|
||||||
|
@ -200,7 +229,7 @@ class CustomWizard::Wizard
|
||||||
def self.prompt_completion(user)
|
def self.prompt_completion(user)
|
||||||
if (records = filter_records('prompt_completion')).any?
|
if (records = filter_records('prompt_completion')).any?
|
||||||
records.reduce([]) do |result, record|
|
records.reduce([]) do |result, record|
|
||||||
wizard = CustomWizard::Wizard.new(user, ::JSON.parse(record.value))
|
wizard = CustomWizard::Wizard.new(::JSON.parse(record.value), user)
|
||||||
result.push(id: wizard.id, name: wizard.name) if !wizard.completed?
|
result.push(id: wizard.id, name: wizard.name) if !wizard.completed?
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
@ -247,21 +276,69 @@ class CustomWizard::Wizard
|
||||||
def self.find(wizard_id)
|
def self.find(wizard_id)
|
||||||
PluginStore.get('custom_wizard', wizard_id)
|
PluginStore.get('custom_wizard', wizard_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.list(user=nil)
|
||||||
|
PluginStoreRow.where(plugin_name: 'custom_wizard').order(:id)
|
||||||
|
.map { |record| self.new(JSON.parse(record.value), user) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.save(wizard)
|
||||||
|
existing_wizard = self.create(wizard[:id])
|
||||||
|
|
||||||
|
wizard[:steps].each do |step|
|
||||||
|
if step[:raw_description]
|
||||||
|
step[:description] = PrettyText.cook(step[:raw_description])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
wizard = wizard.slice!(:create)
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
PluginStore.set('custom_wizard', wizard[:id], wizard)
|
||||||
|
|
||||||
|
if wizard[:after_time]
|
||||||
|
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard[:id])
|
||||||
|
Jobs.enqueue_at(wizard[:after_time_scheduled], :set_after_time_wizard, wizard_id: wizard[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
if existing_wizard && existing_wizard.after_time && !wizard[:after_time]
|
||||||
|
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard[:id])
|
||||||
|
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard[:id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
wizard[:id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.remove(wizard_id)
|
||||||
|
wizard = self.create(wizard_id)
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
if wizard.after_time
|
||||||
|
Jobs.cancel_scheduled_job(:set_after_time_wizard)
|
||||||
|
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
PluginStore.remove('custom_wizard', wizard.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.exists?(wizard_id)
|
def self.exists?(wizard_id)
|
||||||
PluginStoreRow.exists?(plugin_name: 'custom_wizard', key: wizard_id)
|
PluginStoreRow.exists?(plugin_name: 'custom_wizard', key: wizard_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.create(user, wizard_id)
|
def self.create(wizard_id, user = nil)
|
||||||
CustomWizard::Wizard.new(user, self.find(wizard_id).to_h)
|
if wizard = self.find(wizard_id)
|
||||||
|
CustomWizard::Wizard.new(wizard.to_h, user)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_submission_redirect(user, wizard_id, url)
|
def self.set_submission_redirect(user, wizard_id, url)
|
||||||
PluginStore.set("#{wizard_id.underscore}_submissions", user.id, [{ redirect_to: url }])
|
PluginStore.set("#{wizard_id.underscore}_submissions", user.id, [{ redirect_to: url }])
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_wizard_redirect(user, wizard_id)
|
def self.set_wizard_redirect(wizard_id, user)
|
||||||
wizard = CustomWizard::Wizard.create(user, wizard_id)
|
wizard = CustomWizard::Wizard.create(wizard_id, user)
|
||||||
|
|
||||||
if wizard.permitted?
|
if wizard.permitted?
|
||||||
user.custom_fields['redirect_to_wizard'] = wizard_id
|
user.custom_fields['redirect_to_wizard'] = wizard_id
|
||||||
|
|
13
plugin.rb
13
plugin.rb
|
@ -44,11 +44,13 @@ after_initialize do
|
||||||
%w[
|
%w[
|
||||||
../lib/custom_wizard/engine.rb
|
../lib/custom_wizard/engine.rb
|
||||||
../config/routes.rb
|
../config/routes.rb
|
||||||
|
../controllers/custom_wizard/admin/admin.rb
|
||||||
|
../controllers/custom_wizard/admin/wizard.rb
|
||||||
|
../controllers/custom_wizard/admin/submissions.rb
|
||||||
|
../controllers/custom_wizard/admin/api.rb
|
||||||
../controllers/custom_wizard/wizard.rb
|
../controllers/custom_wizard/wizard.rb
|
||||||
../controllers/custom_wizard/steps.rb
|
../controllers/custom_wizard/steps.rb
|
||||||
../controllers/custom_wizard/admin.rb
|
|
||||||
../controllers/custom_wizard/transfer.rb
|
../controllers/custom_wizard/transfer.rb
|
||||||
../controllers/custom_wizard/api.rb
|
|
||||||
../controllers/application_controller.rb
|
../controllers/application_controller.rb
|
||||||
../controllers/extra_locales_controller.rb
|
../controllers/extra_locales_controller.rb
|
||||||
../controllers/invites_controller.rb
|
../controllers/invites_controller.rb
|
||||||
|
@ -60,7 +62,7 @@ after_initialize do
|
||||||
../lib/custom_wizard/field.rb
|
../lib/custom_wizard/field.rb
|
||||||
../lib/custom_wizard/mapper.rb
|
../lib/custom_wizard/mapper.rb
|
||||||
../lib/custom_wizard/step_updater.rb
|
../lib/custom_wizard/step_updater.rb
|
||||||
../lib/custom_wizard/template.rb
|
../lib/custom_wizard/validator.rb
|
||||||
../lib/custom_wizard/wizard.rb
|
../lib/custom_wizard/wizard.rb
|
||||||
../lib/custom_wizard/api/api.rb
|
../lib/custom_wizard/api/api.rb
|
||||||
../lib/custom_wizard/api/authorization.rb
|
../lib/custom_wizard/api/authorization.rb
|
||||||
|
@ -74,6 +76,7 @@ after_initialize do
|
||||||
../serializers/custom_wizard/api/log_serializer.rb
|
../serializers/custom_wizard/api/log_serializer.rb
|
||||||
../serializers/custom_wizard/api_serializer.rb
|
../serializers/custom_wizard/api_serializer.rb
|
||||||
../serializers/custom_wizard/basic_api_serializer.rb
|
../serializers/custom_wizard/basic_api_serializer.rb
|
||||||
|
../serializers/custom_wizard/basic_wizard_serializer.rb
|
||||||
../serializers/custom_wizard/wizard_field_serializer.rb
|
../serializers/custom_wizard/wizard_field_serializer.rb
|
||||||
../serializers/custom_wizard/wizard_step_serializer.rb
|
../serializers/custom_wizard/wizard_step_serializer.rb
|
||||||
../serializers/custom_wizard/wizard_serializer.rb
|
../serializers/custom_wizard/wizard_serializer.rb
|
||||||
|
@ -94,7 +97,7 @@ after_initialize do
|
||||||
|
|
||||||
if !wizard.completed?
|
if !wizard.completed?
|
||||||
custom_redirect = true
|
custom_redirect = true
|
||||||
CustomWizard::Wizard.set_wizard_redirect(user, wizard.id)
|
CustomWizard::Wizard.set_wizard_redirect(wizard.id, user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -115,7 +118,7 @@ after_initialize do
|
||||||
|
|
||||||
on(:user_approved) do |user|
|
on(:user_approved) do |user|
|
||||||
if wizard_id = CustomWizard::Wizard.after_signup
|
if wizard_id = CustomWizard::Wizard.after_signup
|
||||||
CustomWizard::Wizard.set_wizard_redirect(user, wizard_id)
|
CustomWizard::Wizard.set_wizard_redirect(wizard_id, user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
3
serializers/custom_wizard/basic_wizard_serializer.rb
Normale Datei
3
serializers/custom_wizard/basic_wizard_serializer.rb
Normale Datei
|
@ -0,0 +1,3 @@
|
||||||
|
class CustomWizard::BasicWizardSerializer < ::ApplicationSerializer
|
||||||
|
attributes :id, :name
|
||||||
|
end
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CustomWizardFieldSerializer < ::WizardFieldSerializer
|
class CustomWizard::FieldSerializer < ::WizardFieldSerializer
|
||||||
|
|
||||||
attributes :image,
|
attributes :image,
|
||||||
:file_types,
|
:file_types,
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CustomWizardSerializer < ::WizardSerializer
|
class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer
|
||||||
|
|
||||||
attributes :id,
|
attributes :start,
|
||||||
:name,
|
|
||||||
:background,
|
:background,
|
||||||
|
:theme_id,
|
||||||
:completed,
|
:completed,
|
||||||
:required,
|
:required,
|
||||||
:permitted,
|
:permitted,
|
||||||
:uncategorized_category_id
|
:uncategorized_category_id
|
||||||
|
|
||||||
has_one :user, serializer: ::BasicUserSerializer, embed: :objects
|
has_many :steps, serializer: ::CustomWizard::StepSerializer, embed: :objects
|
||||||
has_many :steps, serializer: ::CustomWizardStepSerializer, embed: :objects
|
has_one :user, serializer: ::BasicUserSerializer, embed: :objects
|
||||||
has_many :categories, serializer: ::BasicCategorySerializer, embed: :objects
|
has_many :categories, serializer: ::BasicCategorySerializer, embed: :objects
|
||||||
has_many :groups, serializer: ::BasicGroupSerializer, embed: :objects
|
has_many :groups, serializer: ::BasicGroupSerializer, embed: :objects
|
||||||
|
|
||||||
|
@ -28,6 +28,10 @@ class CustomWizardSerializer < ::WizardSerializer
|
||||||
def permitted
|
def permitted
|
||||||
object.permitted?
|
object.permitted?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def start
|
||||||
|
object.start.id
|
||||||
|
end
|
||||||
|
|
||||||
def include_start?
|
def include_start?
|
||||||
object.start && include_steps?
|
object.start && include_steps?
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ::CustomWizardStepSerializer < ::WizardStepSerializer
|
class CustomWizard::StepSerializer < ::WizardStepSerializer
|
||||||
|
|
||||||
attributes :permitted, :permitted_message
|
attributes :permitted, :permitted_message
|
||||||
has_many :fields, serializer: ::CustomWizardFieldSerializer, embed: :objects
|
has_many :fields, serializer: ::CustomWizard::FieldSerializer, embed: :objects
|
||||||
|
|
||||||
def title
|
def title
|
||||||
return PrettyText.cook(object.title) if object.title
|
return PrettyText.cook(object.title) if object.title
|
||||||
|
|
|
@ -17,7 +17,7 @@ describe CustomWizard::Builder do
|
||||||
|
|
||||||
def build_wizard(t = template, u = user, build_opts = {}, params = {})
|
def build_wizard(t = template, u = user, build_opts = {}, params = {})
|
||||||
CustomWizard::Wizard.add_wizard(t)
|
CustomWizard::Wizard.add_wizard(t)
|
||||||
CustomWizard::Builder.new(u, 'welcome').build(build_opts, params)
|
CustomWizard::Builder.new('welcome', u).build(build_opts, params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_submission_data(data = {})
|
def add_submission_data(data = {})
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe CustomWizardSerializer do
|
||||||
|
|
||||||
def build_wizard(t = template, u = user, build_opts = {}, params = {})
|
def build_wizard(t = template, u = user, build_opts = {}, params = {})
|
||||||
CustomWizard::Wizard.add_wizard(t)
|
CustomWizard::Wizard.add_wizard(t)
|
||||||
CustomWizard::Builder.new(u, 'welcome').build(build_opts, params)
|
CustomWizard::Builder.new('welcome', u).build(build_opts, params)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return the wizard attributes' do
|
it 'should return the wizard attributes' do
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<%= stylesheet_link_tag "wizard_custom_mobile" %>
|
<%= stylesheet_link_tag "wizard_custom_mobile" %>
|
||||||
<%= stylesheet_link_tag "wizard_locations"%>
|
<%= stylesheet_link_tag "wizard_locations"%>
|
||||||
<%= stylesheet_link_tag "wizard_events"%>
|
<%= stylesheet_link_tag "wizard_events"%>
|
||||||
<%- if theme_ids %>
|
<%- if theme_ids.present? %>
|
||||||
<%= discourse_stylesheet_link_tag (mobile_view? ? :mobile_theme : :desktop_theme) %>
|
<%= discourse_stylesheet_link_tag (mobile_view? ? :mobile_theme : :desktop_theme) %>
|
||||||
<%- end %>
|
<%- end %>
|
||||||
|
|
||||||
|
|
Laden …
In neuem Issue referenzieren