Commit 45305ad8 authored by Bertrand PINEL's avatar Bertrand PINEL

First implementation dealing with relationships

parent fcc13046
......@@ -46,12 +46,12 @@ module.exports = {
addLineToFile(this, configPath, /'use strict';/, proxy);
addLineToFile(this, configPath, /when it is created/, "\t\tproxy: usingProxy(),");
let validatedFormConfig = '\t"ember-validated-form": {\n\t\tlabel: {\n\t\t\tsubmit: "label.save"\n\t\t},\n'+
'\t\tcss: {\n\t\t\tgroup: "form-group",\n\t\t\tradio: "radio",\n\t\t\tcontrol: "form-control",\n'+
'\t\t\tlabel: "col-form-label",\n\t\t\thelp: "small form-text text-danger",'+
'\n\t\t\thint: "small form-text text-muted",\n\t\t\tcheckbox: "checkbox",\n\t\t\tbutton: "btn btn-default",'+
'\n\t\t\tsubmit: "btn btn-primary",\n\t\t\tloading: "loading",\n\t\t\tvalid: "is-valid",'+
'\n\t\t\terror: "is-invalid"\n\t\t}\n\t},\n';
let validatedFormConfig = '\t\t"ember-validated-form": {\n\t\t\tlabel: {\n\t\t\t\tsubmit: "label.save"\n\t\t\t},\n'+
'\t\t\tcss: {\n\t\t\t\tgroup: "form-group",\n\t\t\t\tradio: "radio",\n\t\t\t\tcontrol: "form-control",\n'+
'\t\t\t\tlabel: "col-form-label",\n\t\t\t\thelp: "small form-text text-danger",'+
'\n\t\t\t\thint: "small form-text text-muted",\n\t\t\t\tcheckbox: "checkbox",\n\t\t\t\tbutton: "btn btn-default",'+
'\n\t\t\t\tsubmit: "btn btn-primary",\n\t\t\t\tloading: "loading",\n\t\t\t\tvalid: "is-valid",'+
'\n\t\t\t\terror: "is-invalid"\n\t\t\t}\n\t\t},\n';
addLineToFile(this, configPath, /let ENV = {/, validatedFormConfig);
// Add import of ember_aws_ehipster.css to apps.css
......
This blueprint uses the same signature as the model blueprint for defining the list of attributes of the entity and their type.
The following attribute types are supported: :array :boolean :date :object :number :string :your-custom-transform :belongs-to: :has-many:
ember model <name> <attr:type>
ember model <name> <attr:type> [<constraint>]
Generates an ember-data model.
You may generate models with as many attrs as you would like to pass. The following attribute types are supported:
<attr-name>
......@@ -27,4 +27,6 @@ The following attribute types are supported: :array :boolean :date :object :numb
name: DS.attr('string'),
price: DS.attr('number'),
misc: DS.attr()
});
\ No newline at end of file
});
Constraint can be added
\ No newline at end of file
......@@ -8,18 +8,16 @@ import { task } from "ember-concurrency";
export default Controller.extend({
isAddingEntry: false,
newEntry: EmberObject.create({<%=controllerInitEntity%>}),
<%=capitalizeEntityName%>Validations,
<%=relationshipHandling%>
<%=controllerModelTable%>
actions: {
submit() {
event.preventDefault();
let newEntity = this.store.createRecord('<%=singularEntityName%>',{<%=controllerCreateEntity%>});
newEntity.save();
this.set('addEntryModal', false).then((entry) => {
console.log("new entry of id "+entry.get('id')+" created");
});
console.log("action submit");
},
deleteRecord (record) {
console.log('record is '+ record);
......
......@@ -2,7 +2,13 @@ import Route from '@ember/routing/route';
export default Route.extend({
model() {
return this.store.findAll('<%=singularEntityName%>');
return Ember.RSVP.hash({
<%=routeLoadModels%>
});
},
setupController(controller, models) {
controller.setProperties(models);
}
});
\ No newline at end of file
......@@ -82,8 +82,10 @@ module.exports = {
entityModel: entityModel(camelizedName, options.entity.options),
mirageFactory: mirageFactory(camelizedName, options.entity.options),
mirageModel: mirageModel(camelizedName, options.entity.options),
routeLoadModels: routeLoadModels(camelizedName, options.entity.options),
controllerInitEntity: controllerInitEntity(camelizedName, options.entity.options),
controllerCreateEntity: controllerCreateEntity(camelizedName, options.entity.options),
relationshipHandling: relationshipHandling(camelizedName, options.entity.options),
controllerModelTable: controllerModelTable(camelizedName, options.entity.options),
templateEntityForm: templateEntityForm(camelizedName, options.entity.options)
};
......@@ -161,35 +163,15 @@ function addLineToFile(ctx, filePath, markerString, addedLine) {
}
};
function templateEntityForm(name, options) {
let capitalizeName = stringUtils.capitalize(name);
let form = ['{{#validated-form model = (changeset newEntry '+capitalizeName+'Validations) on-submit = (perform submitEntry) as |f|}}'];
let attributes = [];
function relationshipHandling(name, options) {
let fetchedRelations = [];
for (var prop in options) {
let type = options[prop].split(':')[0];
let targetEntity = options[prop].split(':')[1];
switch (type) {
case "string":
case "number":
form.push('{{f.input label="'+prop+'" name="'+prop+'" }}');
break;
case "boolean":
form.push('\t\t{{f.input type="checkbox" label="'+prop+'" name="'+prop+'" }}');
break;
case "date":
form.push('\t\t{{#f.input label="'+prop+'" name="'+prop+'" as |fi|}}\n' +
'\t\t\t{{pikaday-input useUTC=true format="DD/MM/YYYY" onSelection=fi.update}}\n' +
'\t\t{{/f.input}}');
break;
case 'belongs-to':
// todo How to deal with relationships
break;
case 'has-many':
// todo How to deal with relationships
fetchedRelations.push("\t"+targetEntity+"List: computed('"+prop+"', function() {\n\t\tthis.store.findAll('"+targetEntity+"');\n\t}),");
break;
default:
......@@ -197,37 +179,47 @@ function templateEntityForm(name, options) {
break;
}
}
form.push('\t\t{{f.submit class="btn btn-primary" label="Save"}}\n\t{{/validated-form}}');
return form.join('\n');
};
return fetchedRelations.join('\n');
}
function templateEntityForm2(name, options) {
let form = ['{{#bs-form formLayout="vertical" model=this onSubmit=(action "submit") as |form|}}'];
function templateEntityForm(name, options) {
let capitalizeName = stringUtils.capitalize(name);
let form = ['{{#validated-form model = (changeset newEntry '+capitalizeName+'Validations) on-submit = (perform submitEntry) as |f|}}'];
let attributes = [];
for (var prop in options) {
let type = options[prop].split(':')[0];
let targetEntity = options[prop].split(':')[1];
let optionArray = options[prop].split(':');
let type = optionArray[0];
let targetEntity = optionArray[1];
let mapBy = optionArray[2];
if (!mapBy) {
mapBy='id';
}
switch (type) {
case "string":
case "number":
form.push('{{form.element controlType="text" label=\"' + prop + '\" value=' + prop + ' onChange=(action (mut ' + prop + ')) placeholder=\"' + prop + '\"}}');
form.push('\t\t\t{{f.input label="'+prop+'" name="'+prop+'" }}');
break;
case "boolean":
form.push('{{form.element controlType="checkbox" label=\"' + prop + '\" value=' + prop + ' onChange=(action (mut ' + prop + ')) placeholder=\"' + prop + '\"}}');
form.push('\t\t\t{{f.input type="checkbox" label="'+prop+'" name="'+prop+'" }}');
break;
case "date":
form.push('<div class="row form-group"><label class="col-form-label col-md-4">' + prop +
'</label>{{pikaday-input useUTC=true format="DD/MM/YYYY" onSelection=(action (mut ' + prop + '))}}</div>');
form.push('\t\t\t{{#f.input label="'+prop+'" name="'+prop+'" as |fi|}}\n' +
'\t\t\t\t{{pikaday-input useUTC=true format="DD/MM/YYYY" onSelection=fi.update}}\n' +
'\t\t\t{{/f.input}}');
break;
case 'belongs-to':
// todo How to deal with relationships
form.push('\t\t\t{{f.input type="select" label="'+prop+'" name="'+prop+ " \n"+
'options='+inflection.pluralize(targetEntity)+' optionLabelPath="'+mapBy+'" optionValuePath="id" \n'+
'includeBlank= "Please choose..." promptIsSelectable=false}}');
break;
case 'has-many':
// todo How to deal with relationships
form.push('\t\t\t{{f.input type="select" label="'+prop+'" name="'+prop+ " multiple=true \n"+
'options='+inflection.pluralize(targetEntity)+' optionLabelPath="'+mapBy+'" optionValuePath="id" \n'+
'includeBlank= "Please choose..." promptIsSelectable=false}}');
break;
default:
......@@ -235,7 +227,7 @@ function templateEntityForm2(name, options) {
break;
}
}
form.push("{{/bs-form}}");
form.push('\t\t{{f.submit class="btn btn-primary" label="Save"}}\n\t{{/validated-form}}');
return form.join('\n');
};
......@@ -310,6 +302,30 @@ function templateEntityForm2(name, options) {
return content;
};
function routeLoadModels(name, options) {
let content = "";
let findAll = [];
// Add main object loading
findAll.push("\t\t\t"+inflection.pluralize(name)+": this.store.findAll('"+name+"')");
for (var prop in options) {
let type = options[prop].split(':')[0];
let targetEntity = options[prop].split(':')[1];
switch (type) {
case 'belongs-to':
case 'has-many':
findAll.push("\t\t\t"+inflection.pluralize(targetEntity)+": this.store.findAll('"+targetEntity+"')");
break;
default:
// do nothing
break;
}
}
content += findAll.join(',\n');
return content;
}
function controllerInitEntity(name, options) {
let attributes = [];
for (var prop in options) {
......@@ -387,9 +403,9 @@ function templateEntityForm2(name, options) {
break;
}
}
content += attributes.join('\n') + name + "TableColumns: computed(function() {\n\tvar col = A([\n";
content += attributes.join('\n') + '\n' + name + "TableColumns: computed(function() {\n\tvar col = A([\n";
content += tablecols.join(',\n') + "]);\n\tcol.pushObject({\n\t\ttitle: 'Delete',\n\t\tcomponent: 'delete-row'\n\t});\n\treturn col;\t}),\n";
content += name + "TableContent: computed(function() {\n\treturn this.get('model');\n}),";
content += name + "TableContent: computed(function() {\n\treturn this.get('"+inflection.pluralize(name)+"');\n}),";
return content;
};
......@@ -427,19 +443,31 @@ function templateEntityForm2(name, options) {
};
function entityValidation(name, options) {
let content = "import {validatePresence, validateLength} from 'ember-changeset-validations/validators';\n\n" +
let content = "import {validatePresence, validateLength, validateFormat} from 'ember-changeset-validations/validators';\n\n" +
"export default {\n";
for (var prop in options) {
let attr = options[prop].split(':')[1];
if (attr) { // there is at least one constraint
let constraints = [];
let lengthConstraint = [];
let blocks = attr.split(',');
for (var i = 0; i < blocks.length; i++) {
let constraint = blocks[i];
if (constraint.startsWith('required')) {
constraints.push('validatePresence(true)');
} else if (constraint.startsWith('minlength')) {
lengthConstraint.push('min: '+searchArgument(constraint))
} else if (constraint.startsWith('minlength')) {
lengthConstraint.push('max: '+searchArgument(constraint))
}
}
// A rule using property name just to try to be a little clever about validation..$.
if (prop.toLowerCase().includes('mail')){
constraints.push("validateFormat({ type: 'email' })")
}
if (lengthConstraint.length>0) {
constraints.push('validateLength({'+lengthConstraint.join(',')+'})');
}
if (constraints.length>0)
content += "\t" + prop + ": [" + constraints.join(',') + "],\n"
}
......@@ -448,6 +476,10 @@ function templateEntityForm2(name, options) {
return content;
}
function searchArgument(constraint) {
return constraint.substring(constraint.indexOf('§')+1);
}
function dsAttr(name, type) {
switch (type) {
case 'belongs-to':
......
......@@ -68,7 +68,7 @@ module.exports = {
validation = validations[k];
let validationRule = validation.key;
if (validation.value) {
validationRule +='§' + validation.value;
validationRule +='§'+validation.value;
}
validationRules.push(validationRule)
}
......
This diff is collapsed.
This diff is collapsed.
{
"name": "ember-aws-ehipster",
"version": "0.3.17",
"version": "0.3.21",
"description": "Attempt to build a complete web application using serverless architecture on AWS",
"keywords": [
"ember-addon",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment