Simplified form

Change-Id: Ib4b17823be86e18bd5e83679cde7fc95a4f8bac1
diff --git a/src/app/core/services/helpers/config.helpers.spec.ts b/src/app/core/services/helpers/config.helpers.spec.ts
index 432bd7e..beec2e0 100644
--- a/src/app/core/services/helpers/config.helpers.spec.ts
+++ b/src/app/core/services/helpers/config.helpers.spec.ts
@@ -6,6 +6,7 @@
 import {xosCore} from '../../index';
 import {IModeldef} from '../../../datasources/rest/modeldefs.rest';
 import {IXosTableCfg} from '../../table/table';
+import {IXosFormInput, IXosFormConfig} from '../../form/form';
 
 let service: IXosConfigHelpersService;
 
@@ -20,12 +21,24 @@
     {
       type: 'string',
       name: 'name',
-      validators: {}
+      validators: {
+        required: true
+      }
     },
     {
       type: 'string',
       name: 'something',
-      validators: {}
+      validators: {
+        maxlength: 30
+      }
+    },
+    {
+      type: 'number',
+      name: 'else',
+      validators: {
+        min: 20,
+        max: 40
+      }
     },
     {
       type: 'date',
@@ -51,6 +64,7 @@
       expect(service.pluralize('test', 1)).toEqual('test');
       expect(service.pluralize('xos')).toEqual('xosses');
       expect(service.pluralize('slice')).toEqual('slices');
+      expect(service.pluralize('Slice', 1)).toEqual('Slice');
     });
 
     it('should preprend count to string', () => {
@@ -104,7 +118,11 @@
       expect(cols[2].prop).toBe('something');
       expect(cols[2].link).not.toBeDefined();
 
-      expect(cols[3]).not.toBeDefined();
+      expect(cols[3].label).toBe('Else');
+      expect(cols[3].prop).toBe('else');
+      expect(cols[3].link).not.toBeDefined();
+
+      expect(cols[4]).not.toBeDefined();
     });
   });
 
@@ -118,8 +136,47 @@
     });
   });
 
+  describe('the modelFieldToInputConfig', () => {
+    it('should return an array of inputs', () => {
+      const inputs: IXosFormInput[] = service.modelFieldToInputCfg(model.fields);
+      expect(inputs[0].name).toBe('id');
+      expect(inputs[0].type).toBe('number');
+      expect(inputs[0].label).toBe('Id');
+
+      expect(inputs[1].name).toBe('name');
+      expect(inputs[1].type).toBe('string');
+      expect(inputs[1].label).toBe('Name');
+      expect(inputs[1].validators.required).toBe(true);
+
+      expect(inputs[2].name).toBe('something');
+      expect(inputs[2].type).toBe('string');
+      expect(inputs[2].label).toBe('Something');
+      expect(inputs[2].validators.maxlength).toBe(30);
+
+      expect(inputs[3].name).toBe('else');
+      expect(inputs[3].type).toBe('number');
+      expect(inputs[3].label).toBe('Else');
+      expect(inputs[3].validators.min).toBe(20);
+      expect(inputs[3].validators.max).toBe(40);
+    });
+  });
+
+  describe('the modelToFormCfg method', () => {
+    it('should return a form config', () => {
+      const config: IXosFormConfig = service.modelToFormCfg(model);
+      expect(config.formName).toBe('TestForm');
+      expect(config.actions.length).toBe(1);
+      expect(config.actions[0].label).toBe('Save');
+      expect(config.actions[0].class).toBe('success');
+      expect(config.actions[0].icon).toBe('ok');
+      expect(config.actions[0].cb).toBeDefined();
+      expect(config.inputs.length).toBe(4);
+    });
+  });
+
   it('should convert a core model name in an URL', () => {
     expect(service.urlFromCoreModel('Slice')).toBe('/core/slices');
     expect(service.urlFromCoreModel('Xos')).toBe('/core/xosses');
   });
 });
+
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index fc836e7..6b89856 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -2,6 +2,7 @@
 import * as pluralize from 'pluralize';
 import {IXosTableColumn, IXosTableCfg} from '../../table/table';
 import {IModeldef} from '../../../datasources/rest/modeldefs.rest';
+import {IXosFormConfig, IXosFormInput} from '../../form/form';
 
 export interface IXosModelDefsField {
   name: string;
@@ -11,8 +12,10 @@
 
 export interface IXosConfigHelpersService {
   excluded_fields: string[];
-  modelToTableCfg(model: IModeldef, baseUrl: string): IXosTableCfg;
   modelFieldsToColumnsCfg(fields: IXosModelDefsField[], baseUrl: string): IXosTableColumn[]; // TODO use a proper interface
+  modelToTableCfg(model: IModeldef, baseUrl: string): IXosTableCfg;
+  modelFieldToInputCfg(fields: IXosModelDefsField[]): IXosFormInput[];
+  modelToFormCfg(model: IModeldef): IXosFormConfig;
   pluralize(string: string, quantity?: number, count?: boolean): string;
   toLabel(string: string, pluralize?: boolean): string;
   toLabels(string: string[], pluralize?: boolean): string[];
@@ -35,7 +38,9 @@
     'omf_friendly',
     'enabled',
     'validators',
-    'password'
+    'password',
+    'backend_need_delete',
+    'backend_need_reap'
   ];
 
   constructor(
@@ -43,6 +48,7 @@
   ) {
     pluralize.addIrregularRule('xos', 'xosses');
     pluralize.addPluralRule(/slice$/i, 'slices');
+    pluralize.addSingularRule(/slice$/i, 'slice');
   }
 
   public pluralize(string: string, quantity?: number, count?: boolean): string {
@@ -143,6 +149,41 @@
     return `/core/${this.pluralize(name.toLowerCase())}`;
   }
 
+  public modelFieldToInputCfg(fields: IXosModelDefsField[]): IXosFormInput[] {
+
+    return _.map(fields, f => {
+      return {
+        name: f.name,
+        label: this.toLabel(f.name),
+        type: f.type,
+        validators: f.validators
+      };
+    })
+      .filter(f => this.excluded_fields.indexOf(f.name) === -1);
+  }
+
+  public modelToFormCfg(model: IModeldef): IXosFormConfig {
+    return {
+      formName: `${model.name}Form`,
+      exclude: ['backend_status'],
+      actions: [{
+        label: 'Save',
+        class: 'success',
+        icon: 'ok',
+        cb: (item, form) => {
+          item.$save()
+            .then(res => {
+              this.toastr.success(`${item.name} succesfully saved`);
+            })
+            .catch(err => {
+              this.toastr.error(`Error while saving ${item.name}`);
+            });
+        }
+      }],
+      inputs: this.modelFieldToInputCfg(model.fields)
+    };
+  }
+
   private fromCamelCase(string: string): string {
     return string.split(/(?=[A-Z])/).map(w => w.toLowerCase()).join(' ');
   }
@@ -159,4 +200,3 @@
     return string.slice(0, 1).toUpperCase() + string.slice(1);
   }
 }
-