Splitted form component
diff --git a/.gitignore b/.gitignore
index 3c86d00..bf493e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@
 !xos/core/static/xos.css
 .DS_Store
 xos/configurations/setup/
+migrations/
diff --git a/views/ngXosLib/gulp/ngXosHelpers.js b/views/ngXosLib/gulp/ngXosHelpers.js
index f29a646..638e665 100644
--- a/views/ngXosLib/gulp/ngXosHelpers.js
+++ b/views/ngXosLib/gulp/ngXosHelpers.js
@@ -85,6 +85,7 @@
       module: {
         glob: [
           options.xosHelperSource + '*.js',
+          options.xosHelperSource + 'services/helpers/**/*.js',
           options.xosHelperSource + 'services/*.js',
           options.xosHelperSource + 'ui_components/**/*.js'
         ],
@@ -115,9 +116,7 @@
   gulp.task('docs', ['makeDocs', 'serveDocs'], function(){
     
     var files = [
-      options.xosHelperSource + '*.js',
-      options.xosHelperSource + 'services/*.js',
-      options.xosHelperSource + 'ui_components/**/*.js'
+      options.xosHelperSource + '**/*.js'
     ];
 
     gulp.watch(files, ['makeDocs']);
diff --git a/views/ngXosLib/karma.conf.js b/views/ngXosLib/karma.conf.js
index 9d880a0..18c6f6f 100644
--- a/views/ngXosLib/karma.conf.js
+++ b/views/ngXosLib/karma.conf.js
@@ -94,7 +94,7 @@
     // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
     browsers: [
       'PhantomJS',
-      // 'Chrome'
+      'Chrome'
     ],
 
 
diff --git a/views/ngXosLib/xosHelpers/spec/ui/field.test.js b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
new file mode 100644
index 0000000..9e7a7f2
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
@@ -0,0 +1,80 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  let element, scope, isolatedScope, rootScope, compile;
+  const compileElement = () => {
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+
+    element = angular.element('<xos-field name="name" field="field" ng-model="ngModel"></xos-field>');
+    compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }
+
+  describe('The xos.helper module', function(){
+
+    describe('The xosField component', () => {
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        compile = $compile;
+        rootScope = $rootScope;
+      }));
+
+      it('should throw an error if no name is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          scope.ngModel = {
+            label: 1
+          };
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field name'));
+      }));
+
+      it('should throw an error if no field definition is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.ngModel = {
+            label: 1
+          };
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field definition'));
+      }));
+
+      it('should throw an error if no field model is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide an ng-model'));
+      }));
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/form.test.js b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
index 226a62a..7673fc8 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/form.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
@@ -9,6 +9,7 @@
 
   describe('The xos.helper module', function(){
 
+    // TODO move in separate file
     describe('The XosFormHelper service', () => {
       let service;
 
@@ -122,6 +123,16 @@
           expect(service._getFieldFormat(new Date())).toEqual('date');
           expect(service._getFieldFormat('2016-04-19T23:09:10.208092Z')).toEqual('date');
         });
+
+        it('should return array', () => {
+          expect(service._getFieldFormat([])).toEqual('array');
+          expect(service._getFieldFormat(['a', 'b'])).toEqual('array');
+        });
+
+        it('should return object', () => {
+          expect(service._getFieldFormat({})).toEqual('object');
+          expect(service._getFieldFormat({foo: 'bar'})).toEqual('object');
+        });
       });
 
       it('should convert the fields array in an empty form object', () => {
@@ -274,10 +285,11 @@
             enabled: true,
             role: 'user', //select
             a_permissions: [
-
             ],
-            o_permissions: {
-
+            object_field: {
+              string: 'bar',
+              number: 1,
+              email: 'teo@onlab.us'
             }
           };
 
@@ -292,14 +304,15 @@
           expect(isolatedScope.excludedField).toEqual(expected);
         });
 
-        it('should render 8 input field', () => {
+        xit('should render 8 input field', () => {
           // boolean are in the form model, but are not input
           expect(Object.keys(isolatedScope.formField).length).toEqual(9);
           var field = element[0].getElementsByTagName('input');
-          expect(field.length).toEqual(8);
+          expect(field.length).toEqual(10);
         });
 
         it('should render 1 boolean field', () => {
+          // console.log($(element).find('.boolean-field'));
           expect($(element).find('.boolean-field > button').length).toEqual(2)
         });
 
@@ -336,7 +349,7 @@
             expect(isolatedScope.ngModel.enabled).toEqual(false);
           });
 
-          it('should change value to false', () => {
+          it('should change value to true', () => {
             isolatedScope.ngModel.enabled = false;
             scope.$apply();
             expect(isolatedScope.ngModel.enabled).toEqual(false);
@@ -397,6 +410,10 @@
             expect(isolatedScope.testForm.age.$error.min).toBeTruthy();
           });
         });
+
+        describe('the object field', () => {
+          
+        });
       });
     });
   });
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
new file mode 100644
index 0000000..ce52272
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
@@ -0,0 +1,149 @@
+(function () {
+  
+  angular.module('xos.uiComponents')
+
+  /**
+  * @ngdoc service
+  * @name xos.uiComponents.XosFormHelpers
+  * @requires xos.uiComponents.LabelFormatter
+  * @requires xos.helpers._
+  **/
+
+  .service('XosFormHelpers', function(_, LabelFormatter){
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_isEmail
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return true if the string is an email address
+    * @param {string} text The string to be evaluated
+    * @returns {boolean} If the string match an email format
+    **/
+
+    this._isEmail = (text) => {
+      var re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
+      return re.test(text);
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_getFieldFormat
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {mixed} value The data to be evaluated
+    * @returns {string} The type of the input
+    **/
+
+    this._getFieldFormat = (value) => {
+
+      if(angular.isArray(value)){
+        return 'array';
+      }
+
+      // check if is date
+      if (_.isDate(value) || (!Number.isNaN(Date.parse(value)) && new Date(value).getTime() > 631180800000)){
+        return 'date';
+      }
+
+      // check if is boolean
+      // isNaN(false) = false, false is a number (0), true is a number (1)
+      if(typeof value  === 'boolean'){
+        return 'boolean';
+      }
+
+      // check if a string is a number
+      if(!isNaN(value) && value !== null){
+        return 'number';
+      }
+
+      // check if a string is an email
+      if(this._isEmail(value)){
+        return 'email';
+      }
+
+      // if null return string
+      if(value === null){
+        return 'string';
+      }
+
+      return typeof value;
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#buildFormStructure
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {object} modelField An object containing one property for each field of the model
+    * @param {object} customField An object containing one property for each field custom field
+    * @param {object} model The actual model on wich build the form structure (it is used to determine the type of the input)
+    * @returns {object} An object describing the form structure in the form of:
+    * ```
+    * {
+    *   'field-name': {
+    *     label: 'Label',
+    *     type: 'number', //typeof field
+    *     validators: {} // see xosForm for more details
+    *   }
+    * }
+    * ```
+    **/
+
+    this.buildFormStructure = (modelField, customField, model) => {
+
+      modelField = Object.keys(modelField).length > 0 ? modelField : customField; //if no model field are provided, check custom
+      customField = customField || {};
+
+      return _.reduce(Object.keys(modelField), (form, f) => {
+
+        form[f] = {
+          label: (customField[f] && customField[f].label) ? `${customField[f].label}:` : LabelFormatter.format(f),
+          type: (customField[f] && customField[f].type) ? customField[f].type : this._getFieldFormat(model[f]),
+          validators: (customField[f] && customField[f].validators) ? customField[f].validators : {}
+        };
+
+        if(form[f].type === 'date'){
+          model[f] = new Date(model[f]);
+        }
+
+        if(form[f].type === 'number'){
+          model[f] = parseInt(model[f], 10);
+        }
+
+        return form;
+      }, {});
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#parseModelField
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Helpers for buildFormStructure, convert a list of model properties in an object used to build the form structure, eg:
+    * ```
+    * // input:
+    * ['id', 'name'm 'mail']
+    *
+    * // output
+    * {
+    *   id: {},
+    *   name: {},
+    *   mail: {}
+    * }
+    * ```
+    * @param {array} fields An array of fields representing the model properties
+    * @returns {object} An object containing one property for each field of the model
+    **/
+
+    this.parseModelField = (fields) => {
+      return _.reduce(fields, (form, f) => {
+        form[f] = {};
+        return form;
+      }, {});
+    }
+
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/label_formatter.service.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/label_formatter.service.js
similarity index 95%
rename from views/ngXosLib/xosHelpers/src/services/label_formatter.service.js
rename to views/ngXosLib/xosHelpers/src/services/helpers/ui/label_formatter.service.js
index 3b63ecd..bb1d279 100644
--- a/views/ngXosLib/xosHelpers/src/services/label_formatter.service.js
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/label_formatter.service.js
@@ -3,7 +3,7 @@
 
   /**
   * @ngdoc service
-  * @name xos.helpers.LabelFormatter
+  * @name xos.uiComponents.LabelFormatter
   * @description This factory define a set of helper function to format label started from an object property
   **/
 
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
new file mode 100644
index 0000000..923def6
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
@@ -0,0 +1,89 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosField
+    * @restrict E
+    * @description The xos-field directive.
+    * This component decide, give a field wich kind of input it need to print.
+    * @param {string} name The field name
+    * @param {object} field The field configuration:
+    * ```
+    * {
+    *   label: 'Label',
+    *   type: 'number', //typeof field
+    *   validators: {} // see xosForm for more details
+    * }
+    * ```
+    * @param {mixed} ngModel The field value
+    */
+  .directive('xosField', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        name: '=',
+        field: '=',
+        ngModel: '='
+      },
+      template: `
+        <label>{{vm.field.label}}</label>
+            <input
+              ng-if="vm.field.type !== 'boolean' && vm.field.type !== 'object'"
+              type="{{vm.field.type}}"
+              name="{{vm.name}}"
+              class="form-control"
+              ng-model="vm.ngModel"
+              ng-minlength="vm.field.validators.minlength || 0"
+              ng-maxlength="vm.field.validators.maxlength || 2000"
+              ng-required="vm.field.validators.required || false" />
+            <span class="boolean-field" ng-if="vm.field.type === 'boolean'">
+              <button
+                class="btn btn-success"
+                ng-show="vm.ngModel"
+                ng-click="vm.ngModel = false">
+                <i class="glyphicon glyphicon-ok"></i>
+              </button>
+              <button
+                class="btn btn-danger"
+                ng-show="!vm.ngModel"
+                ng-click="vm.ngModel = true">
+                <i class="glyphicon glyphicon-remove"></i>
+              </button>
+            </span>
+            <div
+              class="panel panel-default object-field"
+              ng-if="vm.field.type == 'object' "
+              >
+              <div class="panel-heading">Panel heading without title</div>
+              <div class="panel-body">
+                Panel content
+              </div>
+            </div>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function(){
+        // console.log('Field: ', this.name, this.field.type, this.ngModel);
+        if(!this.name){
+          throw new Error('[xosField] Please provide a field name');
+        }
+        if(!this.field){
+          throw new Error('[xosField] Please provide a field definition');
+        }
+        if(!this.ngModel){
+          throw new Error('[xosField] Please provide an ng-model');
+        }
+      }
+    }
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
index 5294229..db4a2fd 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
@@ -48,6 +48,9 @@
     * ```
     * @element ANY
     * @scope
+    * @requires xos.uiComponents.directive:xosField
+    * @requires xos.uiComponents.XosFormHelpers
+    * @requires xos.helpers._
     * @example
     
     Autogenerated form
@@ -159,31 +162,7 @@
       template: `
         <ng-form name="vm.{{vm.config.formName || 'form'}}">
           <div class="form-group" ng-repeat="(name, field) in vm.formField">
-            <label>{{field.label}}</label>
-            <input
-              ng-if="field.type !== 'boolean'"
-              type="{{field.type}}"
-              name="{{name}}"
-              class="form-control"
-              ng-model="vm.ngModel[name]"
-              ng-minlength="field.validators.minlength || 0"
-              ng-maxlength="field.validators.maxlength || 2000"
-              ng-required="field.validators.required || false" />
-            <span class="boolean-field" ng-if="field.type === 'boolean'">
-              <button
-                class="btn btn-success"
-                ng-show="vm.ngModel[name]"
-                ng-click="vm.ngModel[name] = false">
-                <i class="glyphicon glyphicon-ok"></i>
-              </button>
-              <button
-                class="btn btn-danger"
-                ng-show="!vm.ngModel[name]"
-                ng-click="vm.ngModel[name] = true">
-                <i class="glyphicon glyphicon-remove"></i>
-              </button>
-            </span>
-            <!-- <pre>{{vm[vm.config.formName][name].$error | json}}</pre> -->
+            <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>
             <xos-validation errors="vm[vm.config.formName || 'form'][name].$error"></xos-validation>
           </div>
           <div class="form-group" ng-if="vm.config.actions">
@@ -233,76 +212,5 @@
 
       }
     }
-  })
-  .service('XosFormHelpers', function(_, LabelFormatter){
-
-    this._isEmail = (text) => {
-      var re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
-      return re.test(text);
-    };
-
-    this._getFieldFormat = (value) => {
-
-      // check if is date
-      if (_.isDate(value) || (!Number.isNaN(Date.parse(value)) && new Date(value).getTime() > 631180800000)){
-        return 'date';
-      }
-
-      // check if is boolean
-      // isNaN(false) = false, false is a number (0), true is a number (1)
-      if(typeof value  === 'boolean'){
-        return 'boolean';
-      }
-
-      // check if a string is a number
-      if(!isNaN(value) && value !== null){
-        return 'number';
-      }
-
-      // check if a string is an email
-      if(this._isEmail(value)){
-        return 'email';
-      }
-
-      // if null return string
-      if(value === null){
-        return 'string';
-      }
-
-      return typeof value;
-    };
-
-    this.buildFormStructure = (modelField, customField, model) => {
-
-      modelField = Object.keys(modelField).length > 0 ? modelField : customField; //if no model field are provided, check custom
-      customField = customField || {};
-
-      return _.reduce(Object.keys(modelField), (form, f) => {
-
-        form[f] = {
-          label: (customField[f] && customField[f].label) ? `${customField[f].label}:` : LabelFormatter.format(f),
-          type: (customField[f] && customField[f].type) ? customField[f].type : this._getFieldFormat(model[f]),
-          validators: (customField[f] && customField[f].validators) ? customField[f].validators : {}
-        };
-
-        if(form[f].type === 'date'){
-          model[f] = new Date(model[f]);
-        }
-
-        if(form[f].type === 'number'){
-          model[f] = parseInt(model[f], 10);
-        }
-
-        return form;
-      }, {});
-    };
-
-    this.parseModelField = (fields) => {
-      return _.reduce(fields, (form, f) => {
-        form[f] = {};
-        return form;
-      }, {});
-    }
-
-  })
+  });
 })();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
index 059f461..b3a2eec 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
@@ -249,6 +249,7 @@
             });
 
             // build form structure
+            // TODO move in a pure function for testing purposes
             props.forEach((p, i) => {
               this.formConfig.fields[p] = {
                 label: LabelFormatter.format(labels[i]).replace(':', ''),
diff --git a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
index b74ddf9..4af3680 100644
--- a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
+++ b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
@@ -27,6 +27,13 @@
         'xos.uiComponents',
       ])
       .config(config)
+
+      /**
+      * @ngdoc service
+      * @name xos.helpers._
+      * @description Wrap [lodash](https://lodash.com/docs) in an Angular Service
+      **/
+
       .factory('_', $window => $window._ );
 
   function config($httpProvider, $interpolateProvider, $resourceProvider) {
diff --git a/views/ngXosViews/subscribers/src/js/main.js b/views/ngXosViews/subscribers/src/js/main.js
index 6665b6d..957f807 100644
--- a/views/ngXosViews/subscribers/src/js/main.js
+++ b/views/ngXosViews/subscribers/src/js/main.js
@@ -25,38 +25,29 @@
     templateUrl: 'templates/subscribers-list.tpl.html',
     controller: function(Subscribers){
 
-      this.tableConfig = {
-        filter: 'field',
-        order: true,
-        pagination: {
-          pageSize: 10
-        },
-        columns: [
-          {
-            label: 'Name',
-            prop: 'humanReadableName'
-          },
-          {
-            label: 'Identity',
-            prop: 'identity',
-            type: 'object'
-          },
-          {
-            label: 'Related Info',
-            prop: 'related',
-            type: 'object'
-          }
-        ]
-      };
-
       this.smartTableConfig = {
         resource: 'Subscribers'
       };
+
+      this.formConfig = {
+        exclude: ['password', 'last_login'],
+        formName: 'sampleForm',
+        actions: [
+          {
+            label: 'Save',
+            icon: 'ok', // refers to bootstraps glyphicon
+            cb: (user) => { // receive the model
+              console.log(user);
+            },
+            class: 'success'
+          }
+        ]
+      };
       
       // retrieving user list
       Subscribers.query().$promise
       .then((users) => {
-        this.users = users;
+        this.users = users[0];
       })
       .catch((e) => {
         throw new Error(e);
diff --git a/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html b/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html
index bd14fd5..afd7178 100644
--- a/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html
+++ b/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html
@@ -1,3 +1,4 @@
-<!-- <xos-table config="vm.tableConfig" data="vm.users"></xos-table> -->
+
+<xos-form ng-model="vm.users" config="vm.formConfig"></xos-form>
 
 <xos-smart-table config="vm.smartTableConfig"></xos-smart-table>
\ No newline at end of file
diff --git a/xos/configurations/frontend/docker-compose.yml b/xos/configurations/frontend/docker-compose.yml
index 39b8faa..835eb83 100644
--- a/xos/configurations/frontend/docker-compose.yml
+++ b/xos/configurations/frontend/docker-compose.yml
@@ -20,9 +20,8 @@
         - xos_db
     volumes:
       - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config
-      - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
-      - ../../core/xoslib:/opt/xos/core/xoslib
       - ../../tosca:/opt/xos/tosca
+      - ../../core/xoslib:/opt/xos/core/xoslib
       - ../../core/static:/opt/xos/core/static
       - ../../core/dashboard:/opt/xos/core/dashboard
       - ../../core/templatetags:/opt/xos/core/templatetags
@@ -31,6 +30,5 @@
       - ../../configurations:/opt/xos/configurations
       - ../../xos:/opt/xos/xos
       - ../../api:/opt/xos/api
-      - ../../core/views:/opt/xos/core/views
       - ../../services:/opt/xos/services
 
diff --git a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
index 85670c2..47b9c11 100644
--- a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
+++ b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
@@ -241,6 +241,7 @@
             });
 
             // build form structure
+            // TODO move in a pure function for testing purposes
             props.forEach(function (p, i) {
               _this.formConfig.fields[p] = {
                 label: LabelFormatter.format(labels[i]).replace(':', ''),
@@ -1033,6 +1034,65 @@
  *
  * Visit http://guide.xosproject.org/devguide/addview/ for more information
  *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosField
+    * @restrict E
+    * @description The xos-field directive.
+    * This component decide, give a field wich kind of input it need to print.
+    * @param {string} name The field name
+    * @param {object} field The field configuration:
+    * ```
+    * {
+    *   label: 'Label',
+    *   type: 'number', //typeof field
+    *   validators: {} // see xosForm for more details
+    * }
+    * ```
+    * @param {mixed} ngModel The field value
+    */
+  .directive('xosField', function () {
+    return {
+      restrict: 'E',
+      scope: {
+        name: '=',
+        field: '=',
+        ngModel: '='
+      },
+      template: '\n        <label>{{vm.field.label}}</label>\n            <input\n              ng-if="vm.field.type !== \'boolean\' && vm.field.type !== \'object\'"\n              type="{{vm.field.type}}"\n              name="{{vm.name}}"\n              class="form-control"\n              ng-model="vm.ngModel"\n              ng-minlength="vm.field.validators.minlength || 0"\n              ng-maxlength="vm.field.validators.maxlength || 2000"\n              ng-required="vm.field.validators.required || false" />\n            <span class="boolean-field" ng-if="vm.field.type === \'boolean\'">\n              <button\n                class="btn btn-success"\n                ng-show="vm.ngModel"\n                ng-click="vm.ngModel = false">\n                <i class="glyphicon glyphicon-ok"></i>\n              </button>\n              <button\n                class="btn btn-danger"\n                ng-show="!vm.ngModel"\n                ng-click="vm.ngModel = true">\n                <i class="glyphicon glyphicon-remove"></i>\n              </button>\n            </span>\n            <div\n              class="panel panel-default object-field"\n              ng-if="vm.field.type == \'object\' "\n              >\n              <div class="panel-heading">Panel heading without title</div>\n              <div class="panel-body">\n                Panel content\n              </div>\n            </div>\n      ',
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function controller() {
+        // console.log('Field: ', this.name, this.field.type, this.ngModel);
+        if (!this.name) {
+          throw new Error('[xosField] Please provide a field name');
+        }
+        if (!this.field) {
+          throw new Error('[xosField] Please provide a field definition');
+        }
+        if (!this.ngModel) {
+          throw new Error('[xosField] Please provide an ng-model');
+        }
+      }
+    };
+  });
+})();
+//# sourceMappingURL=../../../maps/ui_components/dumbComponents/field/field.component.js.map
+
+'use strict';
+
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
  * Created by teone on 4/15/16.
  */
 
@@ -1132,8 +1192,6 @@
 
 'use strict';
 
-var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
-
 /**
  * © OpenCORD
  *
@@ -1184,6 +1242,9 @@
     * ```
     * @element ANY
     * @scope
+    * @requires xos.uiComponents.directive:xosField
+    * @requires xos.uiComponents.XosFormHelpers
+    * @requires xos.helpers._
     * @example
     
     Autogenerated form
@@ -1287,7 +1348,7 @@
         config: '=',
         ngModel: '='
       },
-      template: '\n        <ng-form name="vm.{{vm.config.formName || \'form\'}}">\n          <div class="form-group" ng-repeat="(name, field) in vm.formField">\n            <label>{{field.label}}</label>\n            <input\n              ng-if="field.type !== \'boolean\'"\n              type="{{field.type}}"\n              name="{{name}}"\n              class="form-control"\n              ng-model="vm.ngModel[name]"\n              ng-minlength="field.validators.minlength || 0"\n              ng-maxlength="field.validators.maxlength || 2000"\n              ng-required="field.validators.required || false" />\n            <span class="boolean-field" ng-if="field.type === \'boolean\'">\n              <button\n                class="btn btn-success"\n                ng-show="vm.ngModel[name]"\n                ng-click="vm.ngModel[name] = false">\n                <i class="glyphicon glyphicon-ok"></i>\n              </button>\n              <button\n                class="btn btn-danger"\n                ng-show="!vm.ngModel[name]"\n                ng-click="vm.ngModel[name] = true">\n                <i class="glyphicon glyphicon-remove"></i>\n              </button>\n            </span>\n            <!-- <pre>{{vm[vm.config.formName][name].$error | json}}</pre> -->\n            <xos-validation errors="vm[vm.config.formName || \'form\'][name].$error"></xos-validation>\n          </div>\n          <div class="form-group" ng-if="vm.config.actions">\n            <button role="button" href=""\n              ng-repeat="action in vm.config.actions"\n              ng-click="action.cb(vm.ngModel)"\n              class="btn btn-{{action.class}}"\n              title="{{action.label}}">\n              <i class="glyphicon glyphicon-{{action.icon}}"></i>\n              {{action.label}}\n            </button>\n          </div>\n        </ng-form>\n      ',
+      template: '\n        <ng-form name="vm.{{vm.config.formName || \'form\'}}">\n          <div class="form-group" ng-repeat="(name, field) in vm.formField">\n            <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>\n            <xos-validation errors="vm[vm.config.formName || \'form\'][name].$error"></xos-validation>\n          </div>\n          <div class="form-group" ng-if="vm.config.actions">\n            <button role="button" href=""\n              ng-repeat="action in vm.config.actions"\n              ng-click="action.cb(vm.ngModel)"\n              class="btn btn-{{action.class}}"\n              title="{{action.label}}">\n              <i class="glyphicon glyphicon-{{action.icon}}"></i>\n              {{action.label}}\n            </button>\n          </div>\n        </ng-form>\n      ',
       bindToController: true,
       controllerAs: 'vm',
       controller: ["$scope", "$log", "_", "XosFormHelpers", function controller($scope, $log, _, XosFormHelpers) {
@@ -1324,77 +1385,7 @@
         });
       }]
     };
-  }).service('XosFormHelpers', ["_", "LabelFormatter", function (_, LabelFormatter) {
-    var _this2 = this;
-
-    this._isEmail = function (text) {
-      var re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
-      return re.test(text);
-    };
-
-    this._getFieldFormat = function (value) {
-
-      // check if is date
-      if (_.isDate(value) || !Number.isNaN(Date.parse(value)) && new Date(value).getTime() > 631180800000) {
-        return 'date';
-      }
-
-      // check if is boolean
-      // isNaN(false) = false, false is a number (0), true is a number (1)
-      if (typeof value === 'boolean') {
-        return 'boolean';
-      }
-
-      // check if a string is a number
-      if (!isNaN(value) && value !== null) {
-        return 'number';
-      }
-
-      // check if a string is an email
-      if (_this2._isEmail(value)) {
-        return 'email';
-      }
-
-      // if null return string
-      if (value === null) {
-        return 'string';
-      }
-
-      return typeof value === 'undefined' ? 'undefined' : _typeof(value);
-    };
-
-    this.buildFormStructure = function (modelField, customField, model) {
-
-      modelField = Object.keys(modelField).length > 0 ? modelField : customField; //if no model field are provided, check custom
-      customField = customField || {};
-
-      return _.reduce(Object.keys(modelField), function (form, f) {
-
-        form[f] = {
-          label: customField[f] && customField[f].label ? customField[f].label + ':' : LabelFormatter.format(f),
-          type: customField[f] && customField[f].type ? customField[f].type : _this2._getFieldFormat(model[f]),
-          validators: customField[f] && customField[f].validators ? customField[f].validators : {}
-        };
-
-        if (form[f].type === 'date') {
-          model[f] = new Date(model[f]);
-        }
-
-        if (form[f].type === 'number') {
-          model[f] = parseInt(model[f], 10);
-        }
-
-        return form;
-      }, {});
-    };
-
-    this.parseModelField = function (fields) {
-      return _.reduce(fields, function (form, f) {
-        form[f] = {};
-        return form;
-      }, {});
-    };
-  }]);
+  });
 })();
 //# sourceMappingURL=../../../maps/ui_components/dumbComponents/form/form.component.js.map
 
@@ -1542,6 +1533,210 @@
 (function () {
   'use strict';
 
+  /**
+  * @ngdoc service
+  * @name xos.uiComponents.LabelFormatter
+  * @description This factory define a set of helper function to format label started from an object property
+  **/
+
+  angular.module('xos.uiComponents').factory('LabelFormatter', labelFormatter);
+
+  function labelFormatter() {
+
+    var _formatByUnderscore = function _formatByUnderscore(string) {
+      return string.split('_').join(' ').trim();
+    };
+
+    var _formatByUppercase = function _formatByUppercase(string) {
+      return string.split(/(?=[A-Z])/).map(function (w) {
+        return w.toLowerCase();
+      }).join(' ');
+    };
+
+    var _capitalize = function _capitalize(string) {
+      return string.slice(0, 1).toUpperCase() + string.slice(1);
+    };
+
+    var format = function format(string) {
+      string = _formatByUnderscore(string);
+      string = _formatByUppercase(string);
+
+      string = _capitalize(string).replace(/\s\s+/g, ' ') + ':';
+      return string.replace('::', ':');
+    };
+
+    return {
+      // test export
+      _formatByUnderscore: _formatByUnderscore,
+      _formatByUppercase: _formatByUppercase,
+      _capitalize: _capitalize,
+      // export to use
+      format: format
+    };
+  }
+})();
+//# sourceMappingURL=../../../maps/services/helpers/ui/label_formatter.service.js.map
+
+'use strict';
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
+
+(function () {
+
+  angular.module('xos.uiComponents')
+
+  /**
+  * @ngdoc service
+  * @name xos.uiComponents.XosFormHelpers
+  * @requires xos.uiComponents.LabelFormatter
+  * @requires xos.helpers._
+  **/
+
+  .service('XosFormHelpers', ["_", "LabelFormatter", function (_, LabelFormatter) {
+    var _this = this;
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_isEmail
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return true if the string is an email address
+    * @param {string} text The string to be evaluated
+    * @returns {boolean} If the string match an email format
+    **/
+
+    this._isEmail = function (text) {
+      var re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
+      return re.test(text);
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_getFieldFormat
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {mixed} value The data to be evaluated
+    * @returns {string} The type of the input
+    **/
+
+    this._getFieldFormat = function (value) {
+
+      if (angular.isArray(value)) {
+        return 'array';
+      }
+
+      // check if is date
+      if (_.isDate(value) || !Number.isNaN(Date.parse(value)) && new Date(value).getTime() > 631180800000) {
+        return 'date';
+      }
+
+      // check if is boolean
+      // isNaN(false) = false, false is a number (0), true is a number (1)
+      if (typeof value === 'boolean') {
+        return 'boolean';
+      }
+
+      // check if a string is a number
+      if (!isNaN(value) && value !== null) {
+        return 'number';
+      }
+
+      // check if a string is an email
+      if (_this._isEmail(value)) {
+        return 'email';
+      }
+
+      // if null return string
+      if (value === null) {
+        return 'string';
+      }
+
+      return typeof value === 'undefined' ? 'undefined' : _typeof(value);
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#buildFormStructure
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {object} modelField An object containing one property for each field of the model
+    * @param {object} customField An object containing one property for each field custom field
+    * @param {object} model The actual model on wich build the form structure (it is used to determine the type of the input)
+    * @returns {object} An object describing the form structure in the form of:
+    * ```
+    * {
+    *   'field-name': {
+    *     label: 'Label',
+    *     type: 'number', //typeof field
+    *     validators: {} // see xosForm for more details
+    *   }
+    * }
+    * ```
+    **/
+
+    this.buildFormStructure = function (modelField, customField, model) {
+
+      modelField = Object.keys(modelField).length > 0 ? modelField : customField; //if no model field are provided, check custom
+      customField = customField || {};
+
+      return _.reduce(Object.keys(modelField), function (form, f) {
+
+        form[f] = {
+          label: customField[f] && customField[f].label ? customField[f].label + ':' : LabelFormatter.format(f),
+          type: customField[f] && customField[f].type ? customField[f].type : _this._getFieldFormat(model[f]),
+          validators: customField[f] && customField[f].validators ? customField[f].validators : {}
+        };
+
+        if (form[f].type === 'date') {
+          model[f] = new Date(model[f]);
+        }
+
+        if (form[f].type === 'number') {
+          model[f] = parseInt(model[f], 10);
+        }
+
+        return form;
+      }, {});
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#parseModelField
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Helpers for buildFormStructure, convert a list of model properties in an object used to build the form structure, eg:
+    * ```
+    * // input:
+    * ['id', 'name'm 'mail']
+    *
+    * // output
+    * {
+    *   id: {},
+    *   name: {},
+    *   mail: {}
+    * }
+    * ```
+    * @param {array} fields An array of fields representing the model properties
+    * @returns {object} An object containing one property for each field of the model
+    **/
+
+    this.parseModelField = function (fields) {
+      return _.reduce(fields, function (form, f) {
+        form[f] = {};
+        return form;
+      }, {});
+    };
+  }]);
+})();
+//# sourceMappingURL=../../../maps/services/helpers/ui/form.helpers.js.map
+
+'use strict';
+
+(function () {
+  'use strict';
+
   config.$inject = ["$httpProvider", "$interpolateProvider", "$resourceProvider"];
   angular.module('bugSnag', []).factory('$exceptionHandler', function () {
     return function (exception, cause) {
@@ -1559,7 +1754,15 @@
   * @description this is the module that group all the helpers service and components for XOS
   **/
 
-  angular.module('xos.helpers', ['ngCookies', 'ngResource', 'ngAnimate', 'bugSnag', 'xos.uiComponents']).config(config).factory('_', ["$window", function ($window) {
+  angular.module('xos.helpers', ['ngCookies', 'ngResource', 'ngAnimate', 'bugSnag', 'xos.uiComponents']).config(config)
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers._
+  * @description Wrap [lodash](https://lodash.com/docs) in an Angular Service
+  **/
+
+  .factory('_', ["$window", function ($window) {
     return $window._;
   }]);
 
@@ -2208,7 +2411,7 @@
 
   /**
   * @ngdoc service
-  * @name xos.helpers.LabelFormatter
+  * @name xos.uiComponents.LabelFormatter
   * @description This factory define a set of helper function to format label started from an object property
   **/