0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-09 20:02:54 +01:00

Improve change handling structure

Dieser Commit ist enthalten in:
Angus McLeod 2020-04-20 19:41:13 +10:00
Ursprung d194a8313a
Commit 32aa7cc897
21 geänderte Dateien mit 288 neuen und 70 gelöschten Zeilen

Datei anzeigen

@ -1,11 +1,15 @@
import { default as discourseComputed, observes, on } from 'discourse-common/utils/decorators';
import { default as discourseComputed } from 'discourse-common/utils/decorators';
import { equal, empty, or } from "@ember/object/computed";
import { generateName, selectKitContent } from '../lib/wizard';
import { computed } from "@ember/object";
import wizardSchema from '../lib/wizard-schema';
import UndoChanges from '../mixins/undo-changes';
import Component from "@ember/component";
export default Component.extend({
classNames: 'wizard-custom-action',
export default Component.extend(UndoChanges, {
componentType: 'action',
classNameBindings: [':wizard-custom-action', 'visible'],
visible: computed('currentActionId', function() { return this.action.id === this.currentActionId }),
actionTypes: Object.keys(wizardSchema.action.types).map(t => ({ id: t, name: generateName(t) })),
createTopic: equal('action.type', 'create_topic'),
updateProfile: equal('action.type', 'update_profile'),

Datei anzeigen

@ -1,11 +1,14 @@
import { default as discourseComputed, observes } from 'discourse-common/utils/decorators';
import { default as discourseComputed } from 'discourse-common/utils/decorators';
import { equal, or } from "@ember/object/computed";
import { computed } from "@ember/object";
import { selectKitContent } from '../lib/wizard';
import { default as wizardSchema, setSchemaDefaults } from '../lib/wizard-schema';
import UndoChanges from '../mixins/undo-changes';
import Component from "@ember/component";
export default Component.extend({
classNames: 'wizard-custom-field',
export default Component.extend(UndoChanges, {
componentType: 'field',
classNameBindings: [':wizard-custom-field', 'visible'],
visible: computed('currentFieldId', function() { return this.field.id === this.currentFieldId }),
isDropdown: equal('field.type', 'dropdown'),
isUpload: equal('field.type', 'upload'),
isCategory: equal('field.type', 'category'),
@ -20,20 +23,6 @@ export default Component.extend({
showMinLength: or('isText', 'isTextarea', 'isUrl', 'isComposer'),
categoryPropertyTypes: selectKitContent(['id', 'slug']),
// setTypeDefaults only set defaults if the field type of a specific field
// changes, and not when switching between fields. Switching between fields also
// changes the field.type property in this component
@observes('field.id', 'field.type')
setTypeDefaults(ctx, changed) {
if (this.field.id === this.bufferedFieldId) {
setSchemaDefaults(this.field, 'field');
}
if (changed === 'field.type') {
this.set('bufferedFieldId', this.field.id);
}
},
setupTypeOutput(fieldType, options) {
const selectionType = {
category: 'category',
@ -84,7 +73,7 @@ export default Component.extend({
return this.setupTypeOutput(fieldType, options);
},
actions: {
actions: {
imageUploadDone(upload) {
this.set("field.image", upload.url);
},

Datei anzeigen

@ -1,6 +1,6 @@
import { default as discourseComputed, on, observes } from 'discourse-common/utils/decorators';
import { generateName } from '../lib/wizard';
import { default as wizardSchema, setSchemaDefaults } from '../lib/wizard-schema';
import { default as wizardSchema, setWizardDefaults } from '../lib/wizard-schema';
import { notEmpty } from "@ember/object/computed";
import { scheduleOnce, bind } from "@ember/runloop";
import EmberObject from "@ember/object";
@ -70,6 +70,10 @@ export default Component.extend({
add() {
const items = this.get('items');
const itemType = this.itemType;
let params = setWizardDefaults({}, itemType);
params.isNew = true;
let next = 1;
if (items.length) {
@ -84,11 +88,8 @@ export default Component.extend({
if (itemType === 'field') {
id = `${this.parentId}_${id}`;
}
let params = {
id,
isNew: true
};
params.id = id;
let objectArrays = wizardSchema[itemType].objectArrays;
if (objectArrays) {
@ -96,9 +97,7 @@ export default Component.extend({
params[objectArrays[objectType].property] = A();
});
};
setSchemaDefaults(params, itemType);
const newItem = EmberObject.create(params);
items.pushObject(newItem);

Datei anzeigen

@ -3,6 +3,7 @@ import { gt } from '@ember/object/computed';
import { computed } from "@ember/object";
import { defaultConnector } from '../lib/wizard-mapper';
import { later } from "@ember/runloop";
import { observes } from "discourse-common/utils/decorators";
export default Component.extend({
classNameBindings: [':mapper-connector', ':mapper-block', 'hasMultiple::single'],
@ -22,5 +23,10 @@ export default Component.extend({
);
});
}
},
@observes('connector')
updated() {
this.onUpdate('connector');
}
});

Datei anzeigen

@ -167,6 +167,11 @@ export default Component.extend({
return this.activeType === type && this[`${type}Enabled`];
},
@observes('activeType', 'value')
updated() {
this.onUpdate('selector');
},
actions: {
toggleType(type) {
this.set('activeType', type);

Datei anzeigen

@ -59,6 +59,8 @@ export default Component.extend({
this.get('inputs').pushObject(
newInput(this.inputOptions, this.inputs.length)
);
this.onUpdate(this.property, 'input');
},
remove(input) {
@ -68,6 +70,12 @@ export default Component.extend({
if (inputs.length) {
inputs[0].set('connector', null);
}
this.onUpdate(this.property, 'input');
},
inputUpdated(type) {
this.onUpdate(this.property, type);
}
}
});

Datei anzeigen

@ -79,7 +79,7 @@ function buildObject(json, type) {
Object.keys(json).forEach(prop => {
props[prop] = buildProperty(json, prop, type)
});
return EmberObject.create(props);
}
@ -162,6 +162,7 @@ function buildProperties(json) {
};
json = actionPatch(json); // to be removed - see above
props.actions = buildObjectArray(json.actions, 'action');
} else {
listProperties('wizard').forEach(prop => {

Datei anzeigen

@ -1,4 +1,4 @@
import { set } from "@ember/object";
import { set, get } from "@ember/object";
const wizard = {
basic: {
@ -194,25 +194,27 @@ if (Discourse.SiteSettings.wizard_apis_enabled) {
}
}
export function setSchemaDefaults(obj, objType) {
let objSchema = wizardSchema[objType];
let basicDefaults = objSchema.basic;
Object.keys(basicDefaults).forEach(property => {
if (basicDefaults[property]) {
set(obj, property, basicDefaults[property]);
export function setWizardDefaults(obj, itemType, opts={}) {
const objSchema = wizardSchema[itemType];
const basicDefaults = objSchema.basic;
const typeDefaults = objSchema.types[obj.type];
Object.keys(basicDefaults).forEach(property => {
let defaultValue = get(basicDefaults, property);
if (defaultValue) {
set(obj, property, defaultValue);
}
});
if (objSchema.types && obj.type) {
let typeDefaults = objSchema.types[obj.type];
if (typeDefaults) {
Object.keys(typeDefaults).forEach(property => {
if (typeDefaults.hasOwnProperty(property)) {
set(obj, property, typeDefaults[property]);
}
set(obj, property, get(typeDefaults, property));
}
});
}
return obj;
}
export default wizardSchema;

Datei anzeigen

@ -49,11 +49,23 @@ const userProperties = [
'trust_level'
];
function listProperties(type, objectType = null) {
function listProperties(type, opts={}) {
let properties = Object.keys(wizardSchema[type].basic);
if (wizardSchema[type].types && objectType) {
properties = properties.concat(Object.keys(wizardSchema[type].types[objectType]));
const types = wizardSchema[type].types;
if (types) {
let typeProperties = [];
if (opts.allTypes) {
Object.keys(types).forEach(type => {
typeProperties = typeProperties.concat(Object.keys(types[type]));
});
} else if (opts.objectType) {
typeProperties = Object.keys(types[opts.objectType]);
}
properties = properties.concat(typeProperties);
}
return properties;

Datei anzeigen

@ -0,0 +1,124 @@
import { listProperties } from '../lib/wizard';
import { default as wizardSchema } from '../lib/wizard-schema';
import { set, get } from "@ember/object";
import Mixin from "@ember/object/mixin";
import { observes } from 'discourse-common/utils/decorators';
export default Mixin.create({
didInsertElement() {
this._super(...arguments);
this.setupObservers();
const obj = this.get(this.componentType);
this.setProperties({
originalObject: JSON.parse(JSON.stringify(obj)),
undoIcon: obj.isNew ? 'times' : 'undo',
undoKey: `admin.wizard.${obj.isNew ? 'clear' : 'undo'}`
})
},
willDestroyElement() {
this._super(...arguments);
this.removeObservers();
},
removeObservers(objType=null) {
const componentType = this.componentType;
const obj = this.get(componentType);
let opts = {
objectType: objType || obj.type
}
listProperties(componentType, opts).forEach(property => {
obj.removeObserver(property, this, this.toggleUndo);
});
},
setupObservers(objType=null) {
const componentType = this.componentType;
const obj = this.get(componentType);
let opts = {
objectType: objType || obj.type
}
listProperties(componentType, opts).forEach(property => {
obj.addObserver(property, this, this.toggleUndo);
});
},
revertToOriginal(revertBasic=false) {
const original = JSON.parse(JSON.stringify(this.originalObject));
const componentType = this.componentType;
const obj = this.get(componentType);
const objSchema = wizardSchema[componentType];
const basicDefaults = objSchema.basic;
if (revertBasic) {
Object.keys(basicDefaults).forEach(property => {
let value;
if (original.hasOwnProperty(property)) {
value = get(original, property);
} else if (basicDefaults.hasOwnProperty(property)) {
value = get(basicDefaults, property);
}
set(obj, property, value);
});
}
if (objSchema.types && obj.type) {
let typeDefaults = objSchema.types[obj.type];
Object.keys(typeDefaults).forEach(property => {
let value;
if (original.type === obj.type && original.hasOwnProperty(property)) {
value = get(original, property);
} else if (typeDefaults.hasOwnProperty(property)) {
value = get(typeDefaults, property);
}
set(obj, property, value);
});
}
},
toggleUndo() {
const current = this.get(this.componentType);
const original = this.originalObject;
this.set('showUndo', !_.isEqual(current, original));
},
actions: {
undoChanges() {
const componentType = this.componentType;
const original = this.get('originalObject');
const obj = this.get(componentType);
this.removeObservers(obj.type);
this.revertToOriginal(true);
this.set('showUndo', false);
this.setupObservers(this.get(componentType).type);
},
changeType(type) {
const componentType = this.componentType;
const original = this.get('originalObject');
const obj = this.get(componentType);
this.removeObservers(obj.type);
obj.set('type', type);
this.revertToOriginal();
this.set('showUndo', type !== original.type);
this.setupObservers(type);
},
mappedFieldUpdated(property, type) {
this.get(this.componentType).notifyPropertyChange(property);
}
}
})

Datei anzeigen

@ -49,7 +49,7 @@ const CustomWizard = EmberObject.extend({
}
}
for (let property of listProperties(type, objectType)) {
for (let property of listProperties(type, { objectType })) {
let value = object.get(property);
result = this.validateValue(property, value, object, type, result);

Datei anzeigen

@ -22,7 +22,7 @@ export default DiscourseRoute.extend({
const parentModel = this.modelFor('adminWizardsWizard');
const wizard = CustomWizard.create((!model || model.create) ? {} : model);
controller.setProperties({
let props = {
wizardList: parentModel.wizard_list,
fieldTypes: selectKitContent(Object.keys(parentModel.field_types)),
userFields: parentModel.userFields,
@ -32,6 +32,8 @@ export default DiscourseRoute.extend({
currentStep: wizard.steps[0],
currentAction: wizard.actions[0],
creating: model.create
});
};
controller.setProperties(props);
}
});

Datei anzeigen

@ -175,13 +175,14 @@
items=wizard.actions
generateLabels=true}}
{{#if currentAction}}
{{#each wizard.actions as |action|}}
{{wizard-custom-action
action=currentAction
action=action
currentActionId=currentAction.id
wizard=wizard
removeAction="removeAction"
wizardFields=wizardFields}}
{{/if}}
{{/each}}
<div class='admin-wizard-buttons'>
<button {{action "save"}} disabled={{disableSave}} class='btn btn-primary'>

Datei anzeigen

@ -1,3 +1,11 @@
{{#if showUndo}}
{{d-button
action="undoChanges"
icon=undoIcon
label=undoKey
class="undo-changes"}}
{{/if}}
<div class="setting">
<div class="setting-label">
<label>{{i18n "admin.wizard.type"}}</label>
@ -7,7 +15,7 @@
{{combo-box
value=action.type
content=actionTypes
onChange=(action (mut action.type))
onChange=(action "changeType")
options=(hash
none="admin.wizard.field.type"
)}}
@ -36,6 +44,8 @@
<div class="setting-value">
{{wizard-mapper
inputs=action.title
property='title'
onUpdate=(action 'mappedFieldUpdated')
options=(hash
wizardFieldSelection=true
userFieldSelection='key,value'
@ -91,6 +101,8 @@
<div class="setting-value">
{{wizard-mapper
inputs=action.category
property='category'
onUpdate=(action 'mappedFieldUpdated')
options=(hash
textSelection='key,value'
wizardFieldSelection=true
@ -110,6 +122,8 @@
<div class="setting-value">
{{wizard-mapper
inputs=action.tags
property='tags'
onUpdate=(action 'mappedFieldUpdated')
options=(hash
tagSelection='output'
outputDefaultSelection='tag'
@ -131,6 +145,8 @@
<div class="setting-value">
{{wizard-mapper
inputs=action.recipient
property='recipient'
onUpdate=(action 'mappedFieldUpdated')
options=(hash
textSelection='value,output'
wizardFieldSelection=true
@ -152,6 +168,8 @@
{{wizard-mapper
inputs=action.profile_updates
property='profile_updates'
onUpdate=(action 'mappedFieldUpdated')
options=(hash
inputTypes='association'
textSelection='value'
@ -223,6 +241,8 @@
<div class="setting-value">
{{wizard-mapper
inputs=action.group
property='group'
onUpdate=(action 'mappedFieldUpdated')
options=(hash
textSelection='value,output'
wizardFieldSelection='key,value,assignment'
@ -262,6 +282,8 @@
<div class="setting-value">
{{wizard-mapper
inputs=action.custom_fields
property='custom_fields'
onUpdate=(action 'mappedFieldUpdated')
options=(hash
inputTypes='association'
wizardFieldSelection='value'
@ -282,6 +304,8 @@
<div class="setting-value">
{{wizard-mapper
inputs=action.required
property='required'
onUpdate=(action 'mappedFieldUpdated')
options=(hash
textSelection='value'
wizardFieldSelection=true

Datei anzeigen

@ -1,3 +1,11 @@
{{#if showUndo}}
{{d-button
action="undoChanges"
icon=undoIcon
label=undoKey
class="undo-changes"}}
{{/if}}
<div class="setting">
<div class="setting-label">
<label>{{i18n 'admin.wizard.field.label'}}</label>
@ -50,7 +58,7 @@
{{combo-box
value=field.type
content=fieldTypes
onChange=(action (mut field.type))
onChange=(action "changeType")
options=(hash
none="admin.wizard.field.type"
)}}
@ -106,6 +114,8 @@
<div class="setting-value">
{{wizard-mapper
inputs=field.prefill
property='prefill'
onUpdate=(action 'mappedFieldUpdated')
options=prefillOptions}}
</div>
</div>
@ -120,6 +130,8 @@
<div class="setting-value">
{{wizard-mapper
inputs=field.content
property='content'
onUpdate=(action 'mappedFieldUpdated')
options=contentOptions}}
</div>
</div>

Datei anzeigen

@ -102,10 +102,11 @@
items=step.fields
parentId=step.id}}
{{#if currentField}}
{{#each step.fields as |field|}}
{{wizard-custom-field
field=currentField
field=field
currentFieldId=currentField.id
fieldTypes=fieldTypes
removeField="removeField"
wizardFields=wizardFields}}
{{/if}}
{{/each}}

Datei anzeigen

@ -4,7 +4,8 @@
inputTypes=true
inputType=inputType
connectorType="type"
options=options}}
options=options
onUpdate=onUpdate}}
{{#if hasPairs}}
<div class="mapper-pairs mapper-block">
@ -14,7 +15,8 @@
last=pair.last
inputType=inputType
options=options
removePair=(action 'removePair')}}
removePair=(action 'removePair')
onUpdate=onUpdate}}
{{/each}}
{{#if canAddPair}}
@ -32,7 +34,8 @@
connectors=connectors
connectorType="output"
inputType=inputType
options=options}}
options=options
onUpdate=onUpdate}}
{{/if}}
<div class="output mapper-block">
@ -41,7 +44,8 @@
inputType=input.type
value=input.output
activeType=input.output_type
options=options}}
options=options
onUpdate=onUpdate}}
</div>
{{/if}}

Datei anzeigen

@ -4,7 +4,8 @@
inputType=inputType
value=pair.key
activeType=pair.key_type
options=options}}
options=options
onUpdate=onUpdate}}
</div>
{{wizard-mapper-connector
@ -12,7 +13,8 @@
connectors=connectors
connectorType="pair"
inputType=inputType
options=options}}
options=options
onUpdate=onUpdate}}
<div class="value mapper-block">
{{wizard-mapper-selector
@ -20,7 +22,8 @@
inputType=inputType
value=pair.value
activeType=pair.value_type
options=options}}
options=options
onUpdate=onUpdate}}
</div>
{{#if showJoin}}

Datei anzeigen

@ -1,12 +1,16 @@
{{#each inputs as |input|}}
{{#if input.connector}}
{{wizard-mapper-connector connector=input.connector connectorType="input"}}
{{wizard-mapper-connector
connector=input.connector
connectorType="input"
onUpdate=(action 'inputUpdated')}}
{{/if}}
{{wizard-mapper-input
input=input
options=inputOptions
remove=(action 'remove')}}
remove=(action 'remove')
onUpdate=(action 'inputUpdated')}}
{{/each}}
{{#if canAdd}}

Datei anzeigen

@ -82,12 +82,27 @@
}
.wizard-custom-field {
position: relative;
background: transparent;
background-color: dark-light-diff($primary, $secondary, 96%, -65%);
padding: 20px;
}
.wizard-custom-field,
.wizard-custom-action {
position: relative;
display: none;
&.visible {
display: flex;
}
.undo-changes {
position: absolute;
top: 0;
right: 0;
}
}
.admin-wizard-container.settings .wizard-basic-details {
justify-content: initial;

Datei anzeigen

@ -53,6 +53,8 @@ en:
group: "Group"
permitted: "Permitted"
advanced: "Advanced"
undo: "Undo"
clear: "Clear"
message:
select: "Select a wizard, or create a new one"