Started xosForm component
diff --git a/views/ngXosLib/bower.json b/views/ngXosLib/bower.json
index 3726b85..18ee79e 100644
--- a/views/ngXosLib/bower.json
+++ b/views/ngXosLib/bower.json
@@ -19,7 +19,8 @@
     "angular-resource": "1.4.7",
     "ng-lodash": "0.3.0",
     "angular-cookies": "1.4.7",
-    "angular-animate": "1.4.7"
+    "angular-animate": "1.4.7",
+    "lodash": "~4.11.1"
   },
   "devDependencies": {
     "angular-mocks": "1.4.7"
diff --git a/views/ngXosLib/generator-xos/app/templates/bower.json b/views/ngXosLib/generator-xos/app/templates/bower.json
index 721e2de..9336a98 100644
--- a/views/ngXosLib/generator-xos/app/templates/bower.json
+++ b/views/ngXosLib/generator-xos/app/templates/bower.json
@@ -24,7 +24,7 @@
     "angular-cookies": "1.4.7",
     "angular-animate": "1.4.7",
     "angular-resource": "1.4.7",
-    "ng-lodash": "0.3.0",
+    "lodash": "~4.11.1",
     "bootstrap-css": "3.3.6"
   }
 }
diff --git a/views/ngXosLib/generator-xos/app/templates/src/js/main.js b/views/ngXosLib/generator-xos/app/templates/src/js/main.js
index 9c0e259..8e209b8 100644
--- a/views/ngXosLib/generator-xos/app/templates/src/js/main.js
+++ b/views/ngXosLib/generator-xos/app/templates/src/js/main.js
@@ -3,7 +3,6 @@
 angular.module('xos.<%= name %>', [
   'ngResource',
   'ngCookies',
-  'ngLodash',
   'ui.router',
   'xos.helpers'
 ])
diff --git a/views/ngXosLib/karma.conf.js b/views/ngXosLib/karma.conf.js
index b602d66..0a78683 100644
--- a/views/ngXosLib/karma.conf.js
+++ b/views/ngXosLib/karma.conf.js
@@ -12,7 +12,6 @@
 });
 
 var files = bowerComponents.concat([
-  'api/**/*.js',
   'xosHelpers/src/**/*.module.js',
   'xosHelpers/src/**/*.js',
   'xosHelpers/spec/**/*.test.js'
diff --git a/views/ngXosLib/xosHelpers/spec/label_formatter.test.js b/views/ngXosLib/xosHelpers/spec/label_formatter.test.js
new file mode 100644
index 0000000..8a0b90d
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/label_formatter.test.js
@@ -0,0 +1,38 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The label formatter service', () => {
+
+      let service;
+
+      // load the application module
+      beforeEach(module('xos.helpers'));
+
+      // inject the cartService
+      beforeEach(inject(function (_LabelFormatter_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _LabelFormatter_;
+      }));
+
+      it('should replace underscores in a string', () => {
+        expect(service._formatByUnderscore('my_test')).toEqual('my test');
+        expect(service._formatByUnderscore('_test')).toEqual('test');
+      });
+
+      it('should split a camel case string', () => {
+        expect(service._formatByUppercase('myTest')).toEqual('my test');
+      });
+
+      it('should capitalize a string', () => {
+        expect(service._capitalize('my test')).toEqual('My test');
+      });
+
+      it('should format an object property to a label', () => {
+        expect(service.format('myWeird_String')).toEqual('My weird string:');
+      });
+
+    });
+  });
+
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/log.test.js b/views/ngXosLib/xosHelpers/spec/log.test.js
new file mode 100644
index 0000000..aa5c737
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/log.test.js
@@ -0,0 +1,55 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/18/16.
+ */
+
+// TODO write tests for log
+
+(function () {
+  'use strict';
+
+  xdescribe('The xos.helper module', function(){
+
+    let log;
+
+    // beforeEach(module('xos.helpers'));
+
+    var mockLog;
+
+    beforeEach(function() {
+      mockLog = jasmine.createSpyObj('logMock', ['info']);
+    });
+
+    beforeEach(function() {
+      angular.mock.module('xos.helpers', function($injector, $provide) {
+        $provide.value('$log', mockLog);
+        $provide.decorator('$log', $injector.get('logDecorator'));
+      });
+    });
+
+    // beforeEach(inject(($log) => {
+    //   log = $log;
+    //   log.reset();
+    // }));
+
+    describe('The log decorator', () => {
+      it('should not print anything', inject(($log) => {
+        // spyOn(log, 'info');
+        $log.info('test');
+        // expect(mockLog.info).not.toHaveBeenCalled();
+      }));
+
+      xdescribe('if logging is enabled', () => {
+        beforeEach(() => {
+          window.location.href += '?debug=true'
+        });
+
+        it('should should log', () => {
+          log.info('test');
+          console.log(log.info.logs);
+        });
+      });
+    });
+  });
+})();
diff --git a/views/ngXosLib/xosHelpers/spec/ui/form.test.js b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
new file mode 100644
index 0000000..4cd3fec
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
@@ -0,0 +1,213 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/18/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+
+    describe('The XosFormHelper service', () => {
+      let service;
+
+      let fields = [
+        'id',
+        'name',
+        'active',
+        'created',
+        'custom'
+      ];
+
+      let modelField = {
+        id: {},
+        name: {},
+        active: {},
+        created: {},
+        custom: {}
+      };
+
+      let model = {
+        id: 1,
+        name: 'test',
+        active: true,
+        created: '2016-04-18T23:44:16.883181Z',
+        custom: 'MyCustomValue'
+      };
+
+      let customField = {
+        custom: {
+          label: 'Custom Label',
+          type: 'number',
+          validators: {}
+        }
+      };
+
+      let formObject = {
+        id: {
+          label: 'Id:',
+          type: 'number',
+          validators: {}
+        },
+        name: {
+          label: 'Name:',
+          type: 'string',
+          validators: {}
+        },
+        active: {
+          label: 'Active:',
+          type: 'boolean',
+          validators: {}
+        },
+        created: {
+          label: 'Created:',
+          type: 'date',
+          validators: {}
+        },
+        custom: {
+          label: 'Custom Label:',
+          type: 'number',
+          validators: {}
+        }
+      };
+
+      // load the application module
+      beforeEach(module('xos.helpers'));
+
+      // inject the cartService
+      beforeEach(inject(function (_XosFormHelpers_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _XosFormHelpers_;
+      }));
+
+      describe('the _getFieldFormat method', () => {
+        xit('should return string', () => {
+          expect(service._getFieldFormat('string')).toEqual('string');
+        });
+        it('should return number', () => {
+          expect(service._getFieldFormat(1)).toEqual('number');
+          expect(service._getFieldFormat('1')).toEqual('number');
+        });
+        xit('should return boolean', () => {
+          expect(service._getFieldFormat(false)).toEqual('boolean');
+          expect(service._getFieldFormat(true)).toEqual('boolean');
+        });
+
+        it('should return date', () => {
+          expect(service._getFieldFormat('2016-04-19T23:09:1092Z')).toEqual('string');
+          expect(service._getFieldFormat(new Date())).toEqual('date');
+          expect(service._getFieldFormat('2016-04-19T23:09:10.208092Z')).toEqual('date');
+        });
+      });
+
+      xit('should convert the fields array in an empty form object', () => {
+        expect(service.parseModelField(fields)).toEqual(modelField);
+      });
+
+      xit('should combine modelField and customField in a form object', () => {
+        expect(service.buildFormStructure(modelField, customField, model)).toEqual(formObject);
+      });
+    });
+
+    xdescribe('The xos-form component', () => {
+
+      let element, scope, isolatedScope;
+
+      beforeEach(module('xos.helpers'));
+
+      it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          $compile(angular.element('<xos-form></xos-form>'))($rootScope);
+          $rootScope.$digest();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide a configuration via the "config" attribute'));
+      }));
+
+      it('should throw an error if no actions is specified', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          let scope = $rootScope.$new();
+          scope.config = 'green';
+          $compile(angular.element('<xos-form config="config"></xos-form>'))(scope);
+          $rootScope.$digest();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide an action list in the configuration'));
+      }));
+
+      describe('when correctly configured', () => {
+        
+        let cb = jasmine.createSpy('callback');
+
+        beforeEach(inject(($compile, $rootScope) => {
+
+
+          scope = $rootScope.$new();
+
+          scope.config = {
+            exclude: ['excludedField'],
+            actions: [
+              {
+                label: 'Save',
+                icon: 'ok', // refers to bootstraps glyphicon
+                cb: cb,
+                class: 'success'
+              }
+            ],
+            fields: [
+              {
+                first_name: {
+                  label: 'Custom Label'
+                }
+              }
+            ]
+          };
+
+          scope.model = {
+            id: 1,
+            first_name: 'Jhon',
+            last_name: 'Snow',
+            age: 25,
+            birthDate: '2016-04-18T23:44:16.883181Z',
+            enabled: true,
+            role: 'user', //select
+            a_permissions: [
+
+            ],
+            o_permissions: {
+
+            }
+          };
+
+          element = angular.element(`<xos-form config="config" ng-model="model"></xos-form>`);
+          $compile(element)(scope);
+          scope.$digest();
+          isolatedScope = element.isolateScope().vm;
+        }));
+
+        it('should add excluded properties to the list', () => {
+          let expected = ['id', 'validators', 'created', 'updated', 'deleted', 'backend_status', 'excludedField'];
+          expect(isolatedScope.excludedField).toEqual(expected);
+        });
+
+        it('should render 8 field', () => {
+          expect(isolatedScope.formField.length).toEqual(8);
+          var field = element[0].getElementsByTagName('input');
+          expect(field.length).toEqual(8);
+        });
+
+        it('when clicking on action should invoke callback', () => {
+          var link = element[0].getElementsByTagName('button')[0];
+          link.click();
+          expect(cb).toHaveBeenCalledWith(scope.model);
+        });
+
+        it('should set a custom label', () => {
+          let nameField = element[0].getElementsByClassName('form-group')[0];
+          let label = angular.element(nameField.getElementsByTagName('label')[0]).text()
+          expect(label).toEqual('Custom Label:');
+        });
+      });
+
+    });
+  });
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/label_formatter.service.js b/views/ngXosLib/xosHelpers/src/services/label_formatter.service.js
new file mode 100644
index 0000000..1eb2796
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/label_formatter.service.js
@@ -0,0 +1,38 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.LabelFormatter
+  * @description This factory define a set of helper function to format label started from an object property
+  **/
+
+  angular
+      .module('xos.helpers')
+      .factory('LabelFormatter', labelFormatter);
+
+  function labelFormatter() {
+
+    const _formatByUnderscore = string => string.split('_').join(' ').trim();
+
+    const _formatByUppercase = string => string.split(/(?=[A-Z])/).map(w => w.toLowerCase()).join(' ');
+
+    const _capitalize = string => string.slice(0, 1).toUpperCase() + string.slice(1);
+
+    const format = (string) => {
+      string = _formatByUnderscore(string);
+      string = _formatByUppercase(string);
+
+      return _capitalize(string).replace(/\s\s+/g, ' ') + ':';
+    };
+
+    return {
+      // test export
+      _formatByUnderscore: _formatByUnderscore,
+      _formatByUppercase: _formatByUppercase,
+      _capitalize: _capitalize,
+      // export to use
+      format: format
+    };
+  }
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/log.decorator.js b/views/ngXosLib/xosHelpers/src/services/log.decorator.js
new file mode 100644
index 0000000..382f78e
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/log.decorator.js
@@ -0,0 +1,40 @@
+// TODO write tests for log
+
+angular.module('xos.helpers')
+.config([ '$provide', function( $provide )
+{
+  // Use the `decorator` solution to substitute or attach behaviors to
+  // original service instance; @see angular-mocks for more examples....
+
+  $provide.decorator( '$log', [ '$delegate', function( $delegate )
+  {
+
+    const isLogEnabled = () => {
+      return window.location.href.indexOf('debug=true') >= 0;
+    }
+    // Save the original $log.debug()
+    let debugFn = $delegate.info;
+
+    // create the replacement function
+    const replacement = (fn) => {
+      return function(){
+        if(!isLogEnabled()){
+          console.log('logging is disabled');
+          return;
+        }
+        let args    = [].slice.call(arguments);
+        let now     = new Date();
+
+        // Prepend timestamp
+        args[0] = `[${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}] ${args[0]}`;
+
+        // Call the original with the output prepended with formatted timestamp
+        fn.apply(null, args)
+      };
+    };
+
+    $delegate.info = replacement(debugFn);
+
+    return $delegate;
+  }]);
+}]);
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/table/alert.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/alert.component.js
similarity index 100%
rename from views/ngXosLib/xosHelpers/src/ui_components/table/alert.component.js
rename to views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/alert.component.js
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form.component.js
new file mode 100644
index 0000000..f33c639
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form.component.js
@@ -0,0 +1,154 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/18/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosForm
+    * @restrict E
+    * @description The xos-form directive
+    * @param {Object} config The configuration object
+    * ```
+    * {
+    *   exclude: ['id', 'validators', 'created', 'updated', 'deleted'], //field to be skipped in the form, the provide values are concatenated
+    *   actions: [ // define the form buttons with related callback
+    *     {
+            label: 'save',
+            icon: 'ok', // refers to bootstraps glyphicon
+            cb: (user) => { // receive the model
+              console.log(user);
+            },
+            class: 'success'
+          }
+    *   ]
+    * }
+    * ```
+    * @element ANY
+    * @scope
+    * @example
+  <example module="sampleAlert1">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleAlert1', ['xos.uiComponents'])
+      .controller('SampleCtrl1', function(){
+        this.config1 = {
+          exclude: ['password', 'last_login']
+        };
+      });
+    </file>
+  </example>
+
+  **/
+
+  .directive('xosForm', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '=',
+        ngModel: '='
+      },
+      template: `
+        <ng-form name="vm.config.formName || 'form'">
+          <div class="form-group" ng-repeat="field in vm.formField">
+            <label>{{vm.formatLabel(field.label)}}</label>
+            <input type="text" name="" class="form-control" ng-model="vm.ngModel[field]"/>
+          </div>
+          <div class="form-group" ng-if="vm.config.actions">
+            <button href=""
+              ng-repeat="action in vm.config.actions"
+              ng-click="action.cb(vm.ngModel)"
+              class="btn btn-{{action.class}}"
+              title="{{action.label}}">
+              <i class="glyphicon glyphicon-{{action.icon}}"></i>
+              {{action.label}}
+            </button>
+          </div>
+        </ng-form>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($scope, $log, _, LabelFormatter, XosFormHelpers){
+
+        if(!this.config){
+          throw new Error('[xosForm] Please provide a configuration via the "config" attribute');
+        }
+
+        if(!this.config.actions){
+          throw new Error('[xosForm] Please provide an action list in the configuration');
+        }
+
+        this.formatLabel = LabelFormatter.format;
+
+        this.excludedField = ['id', 'validators', 'created', 'updated', 'deleted', 'backend_status'];
+        if(this.config && this.config.exclude){
+          this.excludedField = this.excludedField.concat(this.config.exclude);
+        }
+
+
+        this.formField = [];
+        $scope.$watch(() => this.ngModel, (model) => {
+          if(!model){
+            return;
+          }
+          this.formField = XosFormHelpers.buildFormStructure(_.difference(Object.keys(model), this.excludedField));
+        });
+
+      }
+    }
+  })
+  .service('XosFormHelpers', function(_, LabelFormatter){
+
+    this._getFieldFormat = (value) => {
+
+      // check if is date
+      if (_.isDate(value)){
+        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)){
+        return 'number';
+      }
+
+      return typeof value;
+    };
+
+    this.buildFormStructure = (modelField, customField, model) => {
+      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: {}
+        };
+        return form;
+      }, {});
+    };
+
+    this.parseModelField = (fields) => {
+      return _.reduce(fields, (form, f) => {
+        form[f] = {};
+        return form;
+      }, {});
+    }
+
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/table/pagination.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/pagination.component.js
similarity index 100%
rename from views/ngXosLib/xosHelpers/src/ui_components/table/pagination.component.js
rename to views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/pagination.component.js
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/table/table.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table.component.js
similarity index 98%
rename from views/ngXosLib/xosHelpers/src/ui_components/table/table.component.js
rename to views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table.component.js
index daca484..02ce30c 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/table/table.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table.component.js
@@ -249,9 +249,9 @@
               </xos-pagination>
           </div>
           <div ng-show="vm.data.length == 0 || !vm.data">
-            <div class="alert alert-info">
+             <xos-alert config="{type: 'info'}">
               No data to show.
-            </div>
+            </xos-alert>
           </div>
         `,
         bindToController: true,
diff --git a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
index d7cd958..49e2a9e 100644
--- a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
+++ b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
@@ -23,9 +23,10 @@
         'ngCookies',
         'ngResource',
         'bugSnag',
-        'xos.uiComponents'
+        'xos.uiComponents',
       ])
-      .config(config);
+      .config(config)
+      .factory('_', $window => $window._ );
 
   function config($httpProvider, $interpolateProvider, $resourceProvider) {
     $httpProvider.interceptors.push('SetCSRFToken');