Merge branch 'feature/common-components'
diff --git a/views/ngXosLib/.eslintrc b/views/ngXosLib/.eslintrc
index f9a952f..cf02168 100644
--- a/views/ngXosLib/.eslintrc
+++ b/views/ngXosLib/.eslintrc
@@ -24,7 +24,6 @@
         "indent": [2, 2],
         "no-irregular-whitespace": 1,
         "eol-last": 0,
-        "max-nested-callbacks": [2, 4],
         "comma-spacing": [1, {"before": false, "after": true}],
         "no-trailing-spaces": [1, { skipBlankLines: true }],
         "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
diff --git a/views/ngXosLib/.gitignore b/views/ngXosLib/.gitignore
index 9b2df09..5df6f2d 100644
--- a/views/ngXosLib/.gitignore
+++ b/views/ngXosLib/.gitignore
@@ -1,3 +1,5 @@
 node_modules
 bower_components
-docs
\ No newline at end of file
+docs
+xosHelpers/.tmp
+xos
\ No newline at end of file
diff --git a/views/ngXosLib/README.md b/views/ngXosLib/README.md
index 3da0271..2eb73cb 100644
--- a/views/ngXosLib/README.md
+++ b/views/ngXosLib/README.md
@@ -49,6 +49,8 @@
 
 >_NOTE: for the API related service, check documentation in [Apigen](#apigen) section._
 
+To develop components inside this folder there is a particular command: `npm run dev`, this will watch the helpers file and rebuild them with sourcemaps. For this reason remember to build them when done developing.
+
 When some changes are applied to this common library it should be rebuilt with: `npm run build`
 
 ### Yo Xos
diff --git a/views/ngXosLib/generator-xos/app/templates/src/templates/users-list.tpl.html b/views/ngXosLib/generator-xos/app/templates/src/templates/users-list.tpl.html
index 03be487..fd8d208 100644
--- a/views/ngXosLib/generator-xos/app/templates/src/templates/users-list.tpl.html
+++ b/views/ngXosLib/generator-xos/app/templates/src/templates/users-list.tpl.html
@@ -1,6 +1,8 @@
 <div class="row">
-  <h1>Users List</h1>
-  <p>This is only an example view.</p>
+  <div class="col-xs-12">
+    <h1>Users List</h1>
+    <p>This is only an example view.</p>
+  </div>
 </div>
 <div class="row">
   <div class="col-xs-4">Email</div>
diff --git a/views/ngXosLib/gulp/ngXosHelpers.js b/views/ngXosLib/gulp/ngXosHelpers.js
index f833fb8..f046681 100644
--- a/views/ngXosLib/gulp/ngXosHelpers.js
+++ b/views/ngXosLib/gulp/ngXosHelpers.js
@@ -5,10 +5,34 @@
 var angularFilesort = require('gulp-angular-filesort');
 var gulpDocs = require('gulp-ngdocs');
 var del = require('del');
+var babel = require('gulp-babel');
+const sourcemaps = require('gulp-sourcemaps');
+var browserSync = require('browser-sync').create();
 
 module.exports = function(options){
-  gulp.task('helpers', function(){
-    return gulp.src([options.xosHelperSource + '**/*.js'])
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.xosHelperSource + '**/*.js')
+      .pipe(babel({
+        presets: ['es2015']
+      }))
+      .pipe(gulp.dest(options.xosHelperTmp));
+  });
+
+  gulp.task('babelDev', function(){
+    return gulp.src(options.xosHelperSource + '**/*.js')
+      .pipe(sourcemaps.init())
+      .pipe(babel({
+        presets: ['es2015']
+      }))
+      .pipe(sourcemaps.write('./maps'))
+      .pipe(gulp.dest(options.xosHelperTmp));
+  });
+
+  // build
+  gulp.task('helpers', ['babel'], function(){
+    return gulp.src([options.xosHelperTmp + '**/*.js'])
       .pipe(angularFilesort())
       .pipe(concat('ngXosHelpers.js'))
       .pipe(ngAnnotate())
@@ -16,18 +40,30 @@
       .pipe(gulp.dest(options.ngXosVendor));
   });
 
+  // build Dev (no minify, sourcemaps)
+  gulp.task('helpersDev', ['babelDev'], function(){
+    return gulp.src([options.xosHelperTmp + '**/*.js'])
+      .pipe(angularFilesort())
+      .pipe(concat('ngXosHelpers.js'))
+      .pipe(ngAnnotate())
+      .pipe(gulp.dest(options.ngXosVendor));
+  });
+
   gulp.task('cleanDocs', function(){
-    console.log(options);
     return del([options.docs + '**/*']);
   });
 
-  gulp.task('docs', ['cleanDocs'], function(){
+  gulp.task('makeDocs', ['cleanDocs'], function(){
     var ngOptions = {
       scripts: [
         'http://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js',
-        'http://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-animate.min.js'
+        'http://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-animate.min.js',
+        `${options.ngXosVendor}ngXosHelpers.js`
       ],
-      html5Mode: true,
+      styles: [
+        'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css',
+      ],
+      html5Mode: false,
       title: 'XOS Helpers documentation',
       startPage: '/module',
     }
@@ -36,7 +72,8 @@
       module: {
         glob: [
           options.xosHelperSource + '*.js',
-          options.xosHelperSource + 'services/*.js'
+          options.xosHelperSource + 'services/*.js',
+          options.xosHelperSource + 'ui_components/**/*.js'
         ],
         title: 'Module Documentation',
       },
@@ -49,4 +86,34 @@
       }
     }).pipe(gulpDocs.process(ngOptions)).pipe(gulp.dest('./docs'));
   });
+
+  gulp.task('serveDocs', function(){
+    browserSync.init({
+      server: {
+        baseDir: './docs',
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.ngXosVendor
+        }
+      }
+    });
+  });
+
+  gulp.task('docs', ['makeDocs', 'serveDocs'], function(){
+    
+    var files = [
+      options.xosHelperSource + '*.js',
+      options.xosHelperSource + 'services/*.js',
+      options.xosHelperSource + 'ui_components/**/*.js'
+    ];
+
+    gulp.watch(files, ['makeDocs']);
+
+    gulp.watch(files, function(){
+      browserSync.reload();
+    });
+  })
+
+  gulp.task('dev', function(){
+    gulp.watch(options.xosHelperSource + '**/*.js', ['helpersDev']);
+  });
 };
\ No newline at end of file
diff --git a/views/ngXosLib/gulpfile.js b/views/ngXosLib/gulpfile.js
index bb6bc5e..77a5c07 100644
--- a/views/ngXosLib/gulpfile.js
+++ b/views/ngXosLib/gulpfile.js
@@ -6,6 +6,7 @@
 var options = {
   ngXosVendor: '../../xos/core/xoslib/static/js/vendor/', //save here the minfied vendor file, this is automatically loaded in the django page
   xosHelperSource: './xosHelpers/src/',
+  xosHelperTmp: './xosHelpers/.tmp/',
   docs: './docs'
 };
 
diff --git a/views/ngXosLib/karma.conf.js b/views/ngXosLib/karma.conf.js
index 060e7dd..b602d66 100644
--- a/views/ngXosLib/karma.conf.js
+++ b/views/ngXosLib/karma.conf.js
@@ -13,7 +13,7 @@
 
 var files = bowerComponents.concat([
   'api/**/*.js',
-  'xosHelpers/src/*.module.js',
+  'xosHelpers/src/**/*.module.js',
   'xosHelpers/src/**/*.js',
   'xosHelpers/spec/**/*.test.js'
 ]);
@@ -43,7 +43,7 @@
     // preprocess matching files before serving them to the browser
     // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
     preprocessors: {
-      '**/*.test.js': ['babel']
+      'xosHelpers/**/*.js': ['babel'],
     },
 
     babelPreprocessor: {
@@ -86,7 +86,7 @@
 
     // start these browsers
     // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
-    browsers: ['PhantomJS', 'Chrome'],
+    browsers: ['PhantomJS'],
 
 
     // Continuous Integration mode
diff --git a/views/ngXosLib/package.json b/views/ngXosLib/package.json
index 486db22..9e8906c 100644
--- a/views/ngXosLib/package.json
+++ b/views/ngXosLib/package.json
@@ -7,8 +7,9 @@
     "test": "karma start",
     "apigen": "node apigen/blueprintToNgResource.js",
     "swagger": "node xos-swagger-def.js",
-    "doc": "gulp docs; cd ./docs; http-server -o -c-1",
-    "build": "gulp vendor && gulp helpers"
+    "doc": "gulp docs; cd ./docs",
+    "build": "gulp vendor && gulp helpers",
+    "dev": "gulp dev"
   },
   "author": "Matteo Scandolo",
   "license": "ISC",
@@ -24,15 +25,17 @@
   },
   "devDependencies": {
     "babel-preset-es2015": "^6.6.0",
+    "browser-sync": "^2.12.3",
     "concat": "^2.0.0",
     "del": "^2.2.0",
     "gulp": "^3.9.0",
     "gulp-angular-filesort": "^1.1.1",
+    "gulp-babel": "^6.1.2",
     "gulp-concat": "^2.6.0",
     "gulp-ng-annotate": "^1.1.0",
     "gulp-ngdocs": "^0.2.13",
+    "gulp-sourcemaps": "^1.6.0",
     "gulp-uglify": "^1.4.2",
-    "http-server": "^0.9.0",
     "jasmine-core": "^2.4.1",
     "karma": "^0.13.19",
     "karma-babel-preprocessor": "^6.0.1",
diff --git a/views/ngXosLib/xosHelpers/spec/csrftoken.test.js b/views/ngXosLib/xosHelpers/spec/csrftoken.test.js
index 200014d..8901bde 100644
--- a/views/ngXosLib/xosHelpers/spec/csrftoken.test.js
+++ b/views/ngXosLib/xosHelpers/spec/csrftoken.test.js
@@ -34,6 +34,7 @@
       httpBackend.when('POST', 'http://example.com', null, function(headers) {
         expect(headers['X-CSRFToken']).toBe(fakeToken);
         done();
+        return headers;
       }).respond(200, {name: 'example' });
 
       http.post('http://example.com');
diff --git a/views/ngXosLib/xosHelpers/spec/noHyperlinks.test.js b/views/ngXosLib/xosHelpers/spec/noHyperlinks.test.js
index 560f4dc..7b6e9d0 100644
--- a/views/ngXosLib/xosHelpers/spec/noHyperlinks.test.js
+++ b/views/ngXosLib/xosHelpers/spec/noHyperlinks.test.js
@@ -9,43 +9,43 @@
 (function () {
   'use strict';
 
-  describe('The NoHyperlinks factory', () => {
+  describe('The xos.helper module', function(){
+    describe('The NoHyperlinks factory', () => {
 
-    let httpProviderObj, httpBackend, http, noHyperlinks;
+      let httpProviderObj, noHyperlinks;
 
-    beforeEach(() => {
-      module(
-        'xos.helpers',
-        ($httpProvider) => {
-          //save our interceptor
-          httpProviderObj = $httpProvider;
-        }
-      );
+      beforeEach(() => {
+        module(
+          'xos.helpers',
+          ($httpProvider) => {
+            //save our interceptor
+            httpProviderObj = $httpProvider;
+          }
+        );
 
-      inject(function (_$httpBackend_, _$http_, _NoHyperlinks_) {
-        httpBackend = _$httpBackend_;
-        http = _$http_;
-        noHyperlinks = _NoHyperlinks_
+        inject(function (_NoHyperlinks_) {
+          noHyperlinks = _NoHyperlinks_
+        });
+
+        httpProviderObj.interceptors.push('NoHyperlinks');
+
       });
 
-      httpProviderObj.interceptors.push('NoHyperlinks');
+      it('should set NoHyperlinks interceptor', () => {
+        expect(httpProviderObj.interceptors).toContain('NoHyperlinks');
+      });
+
+      it('should attach ?no_hyperlinks=1 to the request url', () => {
+        let result = noHyperlinks.request({url: 'sample.url'});
+        expect(result.url).toEqual('sample.url?no_hyperlinks=1');
+      });
+
+      it('should NOT attach ?no_hyperlinks=1 to the request url if is HTML', () => {
+        let result = noHyperlinks.request({url: 'sample.html'});
+        expect(result.url).toEqual('sample.html');
+      });
 
     });
-
-    it('should set NoHyperlinks interceptor', () => {
-      expect(httpProviderObj.interceptors).toContain('NoHyperlinks');
-    });
-
-    it('should attach ?no_hyperlinks=1 to the request url', () => {
-      let result = noHyperlinks.request({url: 'sample.url'});
-      expect(result.url).toEqual('sample.url?no_hyperlinks=1');
-    });
-
-    it('should NOT attach ?no_hyperlinks=1 to the request url if is HTML', () => {
-      let result = noHyperlinks.request({url: 'sample.html'});
-      expect(result.url).toEqual('sample.html');
-    });
-
   });
 })();
 
diff --git a/views/ngXosLib/xosHelpers/spec/ui/alert.test.js b/views/ngXosLib/xosHelpers/spec/ui/alert.test.js
new file mode 100644
index 0000000..c67d03a
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/alert.test.js
@@ -0,0 +1,131 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xos-alert component', () => {
+
+      let element, scope, isolatedScope;
+
+      let message = 'Test Error Message';
+
+      beforeEach(module('xos.helpers'));
+
+      it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          $compile(angular.element('<xos-alert></xos-alert>'))($rootScope);
+          $rootScope.$digest();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosAlert] Please provide a configuration via the "config" attribute'));
+      }));
+
+      describe('when correctly configured', () => {
+        beforeEach(inject(($compile, $rootScope) => {
+
+          scope = $rootScope.$new();
+
+          scope.config = {
+            type: 'danger',
+            closeBtn: true
+          };
+
+          element = angular.element(`<xos-alert config="config">${message}</xos-alert>`);
+          $compile(element)(scope);
+          scope.$digest();
+          isolatedScope = element.isolateScope().vm;
+        }));
+
+        it('should transclude the message', () => {
+          let textContainer = element[0].getElementsByTagName('p')[0];
+          let text = angular.element(textContainer).text();
+          expect(text).toEqual(message)
+        });
+
+        it('should have a close button', () => {
+          let btn = element[0].getElementsByTagName('button');
+          expect(btn.length).toEqual(1);
+        });
+
+        describe('when the close button is clicked', () => {
+          it('should hide the alert', () => {
+            let btn = element[0].getElementsByTagName('button')[0];
+            btn.click();
+            let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+            expect(alert.hasClass('ng-hide')).toBeTruthy();
+          });
+        });
+
+        describe('when autoHide is set', () => {
+
+          let to;
+
+          beforeEach(inject(($compile, $rootScope, $timeout) => {
+            scope = $rootScope.$new();
+
+            scope.config = {
+              type: 'danger',
+              closeBtn: true,
+              autoHide: 500
+            };
+
+            to = $timeout;
+
+            element = angular.element(`<xos-alert config="config">${message}</xos-alert>`);
+            $compile(element)(scope);
+            scope.$digest();
+            isolatedScope = element.isolateScope().vm;
+          }));
+
+          it('should hide the alert', () => {
+            to.flush();
+            expect(isolatedScope.show).toBeFalsy();
+            let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+            expect(alert.hasClass('ng-hide')).toBeTruthy();
+          });
+        });
+
+        describe('when show is set to false', () => {
+
+          beforeEach(inject(($compile, $rootScope) => {
+            scope = $rootScope.$new();
+
+            scope.config = {
+              type: 'danger',
+              closeBtn: true
+            };
+
+            scope.show = false;
+
+            element = angular.element(`<xos-alert config="config" show="show">${message}</xos-alert>`);
+            $compile(element)(scope);
+            scope.$digest();
+            isolatedScope = element.isolateScope().vm;
+          }));
+
+          it('should hide the alert', () => {
+            let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+            expect(alert.hasClass('ng-hide')).toBeTruthy();
+          });
+
+          describe('when show is changed to true', () => {
+            beforeEach(() => {
+              scope.show = true;
+              scope.$digest();
+            });
+
+            it('should show the alert', () => {
+              let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+              expect(alert.hasClass('ng-hide')).toBeFalsy();
+            });
+          });
+        });
+
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/pagination.test.js b/views/ngXosLib/xosHelpers/spec/ui/pagination.test.js
new file mode 100644
index 0000000..a8a7482
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/pagination.test.js
@@ -0,0 +1,53 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xos-pagination component', () => {
+
+      let scope, element, isolatedScope;
+      let cb = jasmine.createSpy('callback')
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        scope = $rootScope.$new();
+
+        scope.pageSize = 2;
+
+        scope.totalElements = 5;
+
+        scope.change = cb;
+
+        element = angular.element('<xos-pagination page-size="pageSize" total-elements="totalElements" change="change"></xos-table>');
+        $compile(element)(scope);
+        scope.$digest();
+        isolatedScope = element.isolateScope().vm;
+      }));
+
+      it('should contain 3 pages', function() {
+        var li = element[0].getElementsByTagName('li');
+        expect(li.length).toEqual(5);
+      });
+
+      it('should call the change function', () => {
+        var li = element[0].getElementsByTagName('li')[3];
+        let link = li.getElementsByTagName('a')[0];
+        link.click();
+        expect(cb).toHaveBeenCalledWith(2);
+      });
+
+      describe('when elements number is less than page size', () => {
+        beforeEach(() => {
+          isolatedScope.pageSize = 10;
+          isolatedScope.totalElements = 9;
+          scope.$digest();
+        });
+
+        it('should not be rendered', () => {
+          var pagination = element[0].getElementsByClassName('pagination');
+          expect(pagination.length).toEqual(0);
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/table.test.js b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
new file mode 100644
index 0000000..50a5d72
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
@@ -0,0 +1,200 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xos-table component', () => {
+
+      beforeEach(module('xos.helpers'));
+
+      it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          $compile(angular.element('<xos-table></xos-table>'))($rootScope);
+          $rootScope.$digest();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a configuration via the "config" attribute'));
+      }));
+
+      it('should throw an error if no config columns are specified', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          let scope = $rootScope.$new();
+          scope.config = 'green';
+          $compile(angular.element('<xos-table config="config"></xos-table>'))(scope);
+          $rootScope.$digest();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a columns list in the configuration'));
+      }));
+
+      describe('when basicly configured', function() {
+        var scope, element, isolatedScope;
+
+        beforeEach(inject(function ($compile, $rootScope) {
+          scope = $rootScope.$new();
+
+          scope.config = {
+            columns: [
+              {
+                label: 'Label 1',
+                prop: 'label-1'
+              },
+              {
+                label: 'Label 2',
+                prop: 'label-2'
+              }
+            ]
+          };
+
+          scope.data = [
+            {
+              'label-1': 'Sample 1.1',
+              'label-2': 'Sample 1.2'
+            },
+            {
+              'label-1': 'Sample 2.1',
+              'label-2': 'Sample 2.2'
+            }
+          ]
+
+          element = angular.element('<xos-table config="config" data="data"></xos-table>');
+          $compile(element)(scope);
+          scope.$digest();
+          isolatedScope = element.isolateScope().vm;
+        }));
+
+        it('should contain 2 columns', function() {
+          var th = element[0].getElementsByTagName('th');
+          expect(th.length).toEqual(2);
+          expect(isolatedScope.columns.length).toEqual(2);
+        });
+
+        it('should contain 3 rows', function() {
+          var tr = element[0].getElementsByTagName('tr');
+          expect(tr.length).toEqual(3);
+        });
+
+        describe('when no data are provided', () => {
+          beforeEach(() => {
+            isolatedScope.data = [];
+            scope.$digest();
+          });
+          it('should render an alert', () => {
+            let alert = element[0].getElementsByClassName('alert');
+            let table = element[0].getElementsByTagName('table');
+            expect(alert.length).toEqual(1);
+            expect(table.length).toEqual(1);
+          });
+        });
+
+        describe('when actions are passed', () => {
+
+          let cb = jasmine.createSpy('callback')
+
+          beforeEach(() => {
+            isolatedScope.config.actions = [
+              {
+                label: 'delete',
+                icon: 'remove',
+                cb: cb,
+                color: 'red'
+              }
+            ];
+            scope.$digest();
+          });
+
+          it('should have 3 columns', () => {
+            var th = element[0].getElementsByTagName('th');
+            expect(th.length).toEqual(3);
+            expect(isolatedScope.columns.length).toEqual(2);
+          });
+
+          it('when clicking on action should invoke callback', () => {
+            var link = element[0].getElementsByTagName('a')[0];
+            link.click();
+            expect(cb).toHaveBeenCalledWith(scope.data[0]);
+          });
+        });
+
+        describe('when filter is fulltext', () => {
+          beforeEach(() => {
+            isolatedScope.config.filter = 'fulltext';
+            scope.$digest();
+          });
+
+          it('should render a text field', () => {
+            var textField = element[0].getElementsByTagName('input');
+            expect(textField.length).toEqual(1);
+          });
+
+          describe('and a value is enterd', () => {
+            beforeEach(() => {
+              isolatedScope.query = '2.2';
+              scope.$digest();
+            });
+
+            it('should contain 2 rows', function() {
+              var tr = element[0].getElementsByTagName('tr');
+              expect(tr.length).toEqual(2);
+            });
+          });
+        });
+
+        describe('when filter is field', () => {
+          beforeEach(() => {
+            isolatedScope.config.filter = 'field';
+            scope.$digest();
+          });
+
+          it('should render a text field for each column', () => {
+            var textField = element[0].getElementsByTagName('input');
+            expect(textField.length).toEqual(2);
+          });
+
+          describe('and a value is enterd', () => {
+            beforeEach(() => {
+              isolatedScope.query = {'label-1': '2.1'};
+              scope.$digest();
+            });
+
+            it('should contain 3 rows', function() {
+              var tr = element[0].getElementsByTagName('tr');
+              expect(tr.length).toEqual(3);
+            });
+          });
+        });
+
+        describe('when order is true', () => {
+          beforeEach(() => {
+            isolatedScope.config.order = true;
+            scope.$digest();
+          });
+
+          it('should render a arrows beside', () => {
+            var arrows = element[0].getElementsByTagName('i');
+            expect(arrows.length).toEqual(4);
+          });
+
+          describe('and an order is set', () => {
+            beforeEach(() => {
+              isolatedScope.orderBy = 'label-1';
+              isolatedScope.reverse = true;
+              scope.$digest();
+            });
+
+            it('should orderBy', function() {
+              var tr = element[0].getElementsByTagName('tr');
+              expect(angular.element(tr[1]).text()).toContain('Sample 2.2');
+              expect(angular.element(tr[2]).text()).toContain('Sample 1.1');
+            });
+          });
+        });
+      });
+    });
+  });
+})();
+
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/table/alert.component.js b/views/ngXosLib/xosHelpers/src/ui_components/table/alert.component.js
new file mode 100644
index 0000000..7d7a026
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/table/alert.component.js
@@ -0,0 +1,145 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosAlert
+    * @restrict E
+    * @description The xos-alert directive
+    * @param {Object} config The configuration object
+    * ```
+    * {
+    *   type: 'danger', //info, success, warning
+    *   closeBtn: true, //default false
+    *   autoHide: 3000 //delay to automatically hide the alert
+    * }
+    * ```
+    * @param {Boolean=} show Binding to show and hide the alert, default to true
+    * @element ANY
+    * @scope
+    * @example
+  <example module="sampleAlert1">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-alert config="vm.config1">
+          A sample alert message
+        </xos-alert>
+        <xos-alert config="vm.config2">
+          A sample alert message (with close button)
+        </xos-alert>
+        <xos-alert config="vm.config3">
+          A sample info message
+        </xos-alert>
+        <xos-alert config="vm.config4">
+          A sample success message
+        </xos-alert>
+        <xos-alert config="vm.config5">
+          A sample warning message
+        </xos-alert>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleAlert1', ['xos.uiComponents'])
+      .controller('SampleCtrl1', function(){
+        this.config1 = {
+          type: 'danger'
+        };
+
+        this.config2 = {
+          type: 'danger',
+          closeBtn: true
+        };
+
+        this.config3 = {
+          type: 'info'
+        };
+
+        this.config4 = {
+          type: 'success'
+        };
+
+        this.config5 = {
+          type: 'warning'
+        };
+      });
+    </file>
+  </example>
+
+  <example module="sampleAlert2">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm" class="row">
+        <div class="col-sm-4">
+          <a class="btn btn-default btn-block" ng-show="!vm.show" ng-click="vm.show = true">Show Alert</a>
+          <a class="btn btn-default btn-block" ng-show="vm.show" ng-click="vm.show = false">Hide Alert</a>
+        </div>
+        <div class="col-sm-8">
+          <xos-alert config="vm.config1" show="vm.show">
+            A sample alert message, not displayed by default.
+          </xos-alert>
+        </div>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleAlert2', ['xos.uiComponents'])
+      .controller('SampleCtrl', function(){
+        this.config1 = {
+          type: 'success'
+        };
+
+        this.show = false;
+      });
+    </file>
+  </example>
+  **/
+
+  .directive('xosAlert', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '=',
+        show: '=?'
+      },
+      template: `
+        <div class="alert alert-{{vm.config.type}}" ng-show="vm.show">
+          <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">
+            <span aria-hidden="true">&times;</span>
+          </button>
+          <p ng-transclude></p>
+        </div>
+      `,
+      transclude: true,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($timeout){
+
+        if(!this.config){
+          throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');
+        }
+
+        // default the value to true
+        this.show = this.show !== false;
+        
+        this.dismiss = () => {
+          this.show = false;
+        }
+
+        if(this.config.autoHide){
+          let to = $timeout(() => {
+            this.dismiss();
+            $timeout.cancel(to);
+          }, this.config.autoHide);
+        }
+      }
+    }
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/table/pagination.component.js b/views/ngXosLib/xosHelpers/src/ui_components/table/pagination.component.js
new file mode 100644
index 0000000..b7b1701
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/table/pagination.component.js
@@ -0,0 +1,122 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosPagination
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Number} pageSize Number of elements per page
+    * @param {Number} totalElements Number of total elements in the collection
+    * @param {Function} change The callback to be triggered on page change.
+    * * @element ANY
+    * @scope
+    * @example
+  <example module="samplePagination">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-pagination
+          page-size="vm.pageSize"
+          total-elements="vm.totalElements"
+          change="vm.change">
+        </xos-pagination>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('samplePagination', ['xos.uiComponents'])
+      .controller('SampleCtrl1', function(){
+        this.pageSize = 10;
+        this.totalElements = 35;
+        this.change = (pageNumber) => {
+          console.log(pageNumber);
+        }
+      });
+    </file>
+  </example>
+  **/
+
+  .directive('xosPagination', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        pageSize: '=',
+        totalElements: '=',
+        change: '='
+      },
+      template: `
+        <div class="row" ng-if="vm.pageList.length > 1">
+          <div class="col-xs-12 text-center">
+            <ul class="pagination">
+              <li
+                ng-click="vm.goToPage(vm.currentPage - 1)"
+                ng-class="{disabled: vm.currentPage == 0}">
+                <a href="" aria-label="Previous">
+                    <span aria-hidden="true">&laquo;</span>
+                </a>
+              </li>
+              <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">
+                <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>
+              </li>
+              <li
+                ng-click="vm.goToPage(vm.currentPage + 1)"
+                ng-class="{disabled: vm.currentPage == vm.pages - 1}">
+                <a href="" aria-label="Next">
+                    <span aria-hidden="true">&raquo;</span>
+                </a>
+              </li>
+            </ul>
+          </div>
+        </div>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($scope){
+        
+        this.currentPage = 0;
+
+        this.goToPage = (n) => {
+          if(n < 0 || n === this.pages){
+            return;
+          }
+          this.currentPage = n;
+          this.change(n);
+        }
+
+        this.createPages = (pages) => {
+          let arr = [];
+          for(var i = 0; i < pages; i++){
+            arr.push(i);
+          }
+          return arr;
+        }
+
+        // watch for data changes
+        $scope.$watch(() => this.totalElements, () => {
+          if(this.totalElements){
+            this.pages = Math.ceil(this.totalElements / this.pageSize);
+            this.pageList = this.createPages(this.pages);
+          }
+        });
+      }
+    }
+  })
+  .filter('pagination', function(){
+    return function(input, start) {
+      if(!input || !angular.isArray(input)){
+        return input;
+      }
+      start = parseInt(start, 10);
+      return input.slice(start);
+    };
+  });
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/table/table.component.js b/views/ngXosLib/xosHelpers/src/ui_components/table/table.component.js
index faeaa26..daca484 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/table/table.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/table/table.component.js
@@ -9,33 +9,276 @@
 (function () {
   'use strict';
 
-  angular.module('xos.uiComponents.table', [])
+  angular.module('xos.uiComponents')
+
+    /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosTable
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Object} config The configuration for the component.
+    * ```
+    * {
+    *   columns: [
+    *     {
+    *       label: 'Human readable name',
+    *       prop: 'Property to read in the model object'
+    *     }
+    *   ],
+    *   classes: 'table table-striped table-bordered',
+    *   actions: [ // if defined add an action column
+          {
+            label: 'delete',
+            icon: 'remove', // refers to bootstraps glyphicon
+            cb: (user) => { // receive the model
+              console.log(user);
+            },
+            color: 'red'
+          }
+        ],
+        filter: 'field', // can be by `field` or `fulltext`
+        order: true // whether to show ordering arrows
+    * }
+    * ```
+    * @param {Array} data The data that should be rendered
+    * @element ANY
+    * @scope
+    * @example
+
+  <example module="sampleTable1">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable1', ['xos.uiComponents'])
+      .controller('SampleCtrl1', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name', // column title
+              prop: 'name' // property to read in the data array
+            },
+            {
+              label: 'Last Name',
+              prop: 'lastname'
+            }
+          ]
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            lastname: 'Doe'
+          },
+          {
+            name: 'Gili',
+            lastname: 'Fereydoun'
+          }
+        ]
+      });
+    </file>
+  </example>
+
+  <example module="sampleTable2">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl2 as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable2', ['xos.uiComponents'])
+      .controller('SampleCtrl2', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name', // column title
+              prop: 'name' // property to read in the data array
+            },
+            {
+              label: 'Last Name',
+              prop: 'lastname'
+            }
+          ],
+          classes: 'table table-striped table-condensed', // table classes, default to `table table-striped table-bordered`
+          actions: [ // if defined add an action column
+            {
+              label: 'delete', // label
+              icon: 'remove', // icons, refers to bootstraps glyphicon
+              cb: (user) => { // callback, get feeded with the full object
+                console.log(user);
+              },
+              color: 'red' // icon color
+            }
+          ],
+          filter: 'field', // can be by `field` or `fulltext`
+          order: true
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            lastname: 'Doe'
+          },
+          {
+            name: 'Gili',
+            lastname: 'Fereydoun'
+          }
+        ]
+      });
+    </file>
+  </example>
+
+  <example module="sampleTable3">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl3 as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable3', ['xos.uiComponents'])
+      .controller('SampleCtrl3', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name', // column title
+              prop: 'name' // property to read in the data array
+            },
+            {
+              label: 'Last Name',
+              prop: 'lastname'
+            }
+          ],
+          pagination: {
+            pageSize: 2
+          }
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            lastname: 'Doe'
+          },
+          {
+            name: 'Gili',
+            lastname: 'Fereydoun'
+          },
+          {
+            name: 'Lucky',
+            lastname: 'Clarkson'
+          },
+          {
+            name: 'Tate',
+            lastname: 'Spalding'
+          }
+        ]
+      });
+    </file>
+  </example>
+    **/
+
     .directive('xosTable', function(){
       return {
         restrict: 'E',
         scope: {
           data: '=',
-          columns: '='
+          config: '='
         },
-        template: [
-          '<!--<pre>{{vm.data | json}}</pre>-->',
-          '<table class="table table-striped" ng-show="vm.data.length > 0">',
-            '<thead>',
-              '<tr>',
-                '<th ng-repeat="col in vm.columns">{{col}}</th>',
-              '</tr>',
-            '</thead>',
-            '<tbody>',
-              '<tr ng-repeat="item in vm.data">',
-                '<td ng-repeat="col in vm.columns">{{item[col]}}</td>',
-              '</tr>',
-            '</tbody>',
-          '</table>'
-        ].join(),
+        template: `
+          <div ng-show="vm.data.length > 0">
+            <div class="row" ng-if="vm.config.filter == 'fulltext'">
+              <div class="col-xs-12">
+                <input
+                  class="form-control"
+                  placeholder="Type to search.."
+                  type="text"
+                  ng-model="vm.query"/>
+              </div>
+            </div>
+            <table ng-class="vm.classes" ng-show="vm.data.length > 0">
+              <thead>
+                <tr>
+                  <th ng-repeat="col in vm.columns">
+                    {{col.label}}
+                    <span ng-if="vm.config.order">
+                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">
+                        <i class="glyphicon glyphicon-chevron-up"></i>
+                      </a>
+                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">
+                        <i class="glyphicon glyphicon-chevron-down"></i>
+                      </a>
+                    </span>
+                  </th>
+                  <th ng-if="vm.config.actions">Actions</th>
+                </tr>
+              </thead>
+              <tbody ng-if="vm.config.filter == 'field'">
+                <tr>
+                  <td ng-repeat="col in vm.columns">
+                    <input
+                      class="form-control"
+                      placeholder="Type to search by {{col.label}}"
+                      type="text"
+                      ng-model="vm.query[col.prop]"/>
+                  </td>
+                  <td ng-if="vm.config.actions"></td>
+                </tr>
+              </tbody>
+              <tbody>
+                <tr ng-repeat="item in vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">
+                  <td ng-repeat="col in vm.columns">{{item[col.prop]}}</td>
+                  <td ng-if="vm.config.actions">
+                    <a href=""
+                      ng-repeat="action in vm.config.actions"
+                      ng-click="action.cb(item)"
+                      title="{{action.label}}">
+                      <i
+                        class="glyphicon glyphicon-{{action.icon}}"
+                        style="color: {{action.color}};"></i>
+                    </a>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+            <xos-pagination
+              ng-if="vm.config.pagination"
+              page-size="vm.config.pagination.pageSize"
+              total-elements="vm.data.length"
+              change="vm.goToPage">
+              </xos-pagination>
+          </div>
+          <div ng-show="vm.data.length == 0 || !vm.data">
+            <div class="alert alert-info">
+              No data to show.
+            </div>
+          </div>
+        `,
         bindToController: true,
         controllerAs: 'vm',
         controller: function(){
-          console.log(this.data, this.columns);
+
+          if(!this.config){
+            throw new Error('[xosTable] Please provide a configuration via the "config" attribute');
+          }
+
+          if(!this.config.columns){
+            throw new Error('[xosTable] Please provide a columns list in the configuration');
+          }
+
+          this.columns = this.config.columns;
+          this.classes = this.config.classes || 'table table-striped table-bordered';
+
+          if(this.config.actions){
+            // TODO validate action format
+          }
+          if(this.config.pagination){
+            this.currentPage = 0;
+            this.goToPage = (n) => {
+              this.currentPage = n;
+            };
+          }
+
         }
       }
     })
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js b/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js
index 0cbe70e..bd07908 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js
@@ -9,7 +9,12 @@
 (function () {
   'use strict';
 
+  /**
+  * @ngdoc overview
+  * @name xos.uiComponents
+  * @description A collection of UI components useful for Dashboard development
+  **/
+
   angular.module('xos.uiComponents', [
-    'xos.uiComponents.table'
   ])
 })();
diff --git a/views/ngXosViews/sampleView/gulp/server.js b/views/ngXosViews/sampleView/gulp/server.js
index 13659c3..3c6a8e3 100644
--- a/views/ngXosViews/sampleView/gulp/server.js
+++ b/views/ngXosViews/sampleView/gulp/server.js
@@ -3,6 +3,7 @@
 var gulp = require('gulp');
 var browserSync = require('browser-sync').create();
 var inject = require('gulp-inject');
+var es = require('event-stream');
 var runSequence = require('run-sequence');
 var angularFilesort = require('gulp-angular-filesort');
 var babel = require('gulp-babel');
@@ -10,6 +11,7 @@
 var httpProxy = require('http-proxy');
 var del = require('del');
 var sass = require('gulp-sass');
+var debug = require('gulp-debug');
 
 const environment = process.env.NODE_ENV;
 
@@ -34,9 +36,9 @@
 });
 
 module.exports = function(options){
-
   // open in browser with sync and proxy to 0.0.0.0
   gulp.task('browser', function() {
+    console.log(options.helpers);
     browserSync.init({
       // reloadDelay: 500,
       // logLevel: 'debug',
@@ -50,13 +52,14 @@
       server: {
         baseDir: options.src,
         routes: {
-          '/xosHelpers/src': options.helpers
+          // '/xosHelpers/src': options.helpers,
+          '/xos/core/xoslib/static/js/vendor': options.helpers
         },
         middleware: function(req, res, next){
           if(
-            req.url.indexOf('/xos/') !== -1 ||
-            req.url.indexOf('/xoslib/') !== -1 ||
-            req.url.indexOf('/hpcapi/') !== -1 ||
+            // req.url.indexOf('/xos/') !== -1 ||
+            // req.url.indexOf('/xoslib/') !== -1 ||
+            // req.url.indexOf('/hpcapi/') !== -1 ||
             req.url.indexOf('/api/') !== -1
           ){
             if(conf.xoscsrftoken && conf.xossessionid){
@@ -82,6 +85,11 @@
     gulp.watch(options.css + '**/*.css', function(){
       browserSync.reload();
     });
+
+    gulp.watch(options.helpers + 'ngXosHelpers.js', function(){
+      browserSync.reload();
+    });
+    
     gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
       browserSync.reload();
     });
@@ -101,16 +109,40 @@
       .pipe(gulp.dest(options.tmp));
   });
 
+  // // inject sourceMap
+  // gulp.task('injectMaps', function(){
+  //   return gulp.src(options.src + 'index.html')
+  //     .pipe(
+  //       inject(
+  //         gulp.src([
+  //           options.helpersSourceMaps + '**/*.js.map'
+  //         ], {read: false}).pipe(debug()),
+  //         {
+  //           starttag: '<!-- inject:maps -->',
+  //           // ignorePath: [options.src, '/../../ngXosLib']
+  //         }
+  //       )
+  //     )
+  //     .pipe(gulp.dest(options.src));
+  // });
+
   // inject scripts
   gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+
+    var appScripts = gulp.src([
+      options.tmp + '**/*.js',
+      options.helpers + 'ngXosHelpers.js'
+    ])
+    .pipe(angularFilesort()).pipe(debug());
+
+    var helpersSourceMaps = gulp.src([
+      options.helpersSourceMaps + '**/*.js.map'
+    ]).pipe(debug());
+
     return gulp.src(options.src + 'index.html')
       .pipe(
         inject(
-          gulp.src([
-            options.tmp + '**/*.js',
-            options.helpers + '**/*.js' // todo add Babel here
-          ])
-          .pipe(angularFilesort()),
+          es.merge(appScripts, helpersSourceMaps),
           {
             ignorePath: [options.src, '/../../ngXosLib']
           }
diff --git a/views/ngXosViews/sampleView/gulpfile.js b/views/ngXosViews/sampleView/gulpfile.js
index 8d30660..8b50345 100644
--- a/views/ngXosViews/sampleView/gulpfile.js
+++ b/views/ngXosViews/sampleView/gulpfile.js
@@ -11,7 +11,8 @@
   tmp: 'src/.tmp',
   dist: 'dist/',
   api: '../../ngXosLib/api/',
-  helpers: '../../ngXosLib/xosHelpers/src/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  helpersSourceMaps: '../../ngXosLib/xosHelpers/.tmp/maps/',
   static: '../../../xos/core/xoslib/static/', // this is the django static folder
   dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
 };
diff --git a/views/ngXosViews/sampleView/package.json b/views/ngXosViews/sampleView/package.json
index 0ffe32c..e92f937 100644
--- a/views/ngXosViews/sampleView/package.json
+++ b/views/ngXosViews/sampleView/package.json
@@ -28,12 +28,14 @@
     "easy-mocker": "^1.2.0",
     "eslint": "^1.8.0",
     "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "event-stream": "^3.3.2",
     "gulp": "^3.9.0",
     "gulp-angular-filesort": "^1.1.1",
     "gulp-angular-templatecache": "^1.8.0",
     "gulp-babel": "^5.3.0",
     "gulp-concat": "^2.6.0",
     "gulp-concat-util": "^0.5.5",
+    "gulp-debug": "^2.1.2",
     "gulp-eslint": "^1.0.0",
     "gulp-inject": "^3.0.0",
     "gulp-minify-html": "^1.0.4",
diff --git a/views/ngXosViews/sampleView/spec/sample.test.js b/views/ngXosViews/sampleView/spec/sample.test.js
index f0db699..6005af7 100644
--- a/views/ngXosViews/sampleView/spec/sample.test.js
+++ b/views/ngXosViews/sampleView/spec/sample.test.js
@@ -15,7 +15,7 @@
       {
         email: 'teo@onlab.us',
         firstname: 'Matteo',
-        lastname: 'Scandolo' 
+        lastname: 'Scandolo'
       }
     ]);
   
diff --git a/views/ngXosViews/sampleView/src/css/main.css b/views/ngXosViews/sampleView/src/css/main.css
index afdeba7..e69de29 100644
--- a/views/ngXosViews/sampleView/src/css/main.css
+++ b/views/ngXosViews/sampleView/src/css/main.css
@@ -1,2 +0,0 @@
-#xosSampleView .row {
-  color: #d9534f; }
diff --git a/views/ngXosViews/sampleView/src/index.html b/views/ngXosViews/sampleView/src/index.html
index a925a7e..d04fc3b 100644
--- a/views/ngXosViews/sampleView/src/index.html
+++ b/views/ngXosViews/sampleView/src/index.html
@@ -21,17 +21,9 @@
 <script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
 <!-- endbower --><!-- endjs -->
 <!-- inject:js -->
-<script src="/xosHelpers/src/xosHelpers.module.js"></script>
-<script src="/xosHelpers/src/ui_components/table/table.component.js"></script>
-<script src="/xosHelpers/src/services/rest/vSG.js"></script>
-<script src="/xosHelpers/src/services/rest/vOLT.js"></script>
-<script src="/xosHelpers/src/services/rest/Users.js"></script>
-<script src="/xosHelpers/src/services/rest/Truckroll.js"></script>
-<script src="/xosHelpers/src/services/rest/Subscribers.js"></script>
-<script src="/xosHelpers/src/services/rest/ONOS-Services.js"></script>
-<script src="/xosHelpers/src/services/rest/ONOS-Apps.js"></script>
-<script src="/xosHelpers/src/ui_components/ui-components.module.js"></script>
-<script src="/xosHelpers/src/services/noHyperlinks.interceptor.js"></script>
-<script src="/xosHelpers/src/services/csrfToken.interceptor.js"></script>
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
 <script src="/.tmp/main.js"></script>
 <!-- endinject -->
+
+<!-- inject:map -->
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosViews/sampleView/src/js/main.js b/views/ngXosViews/sampleView/src/js/main.js
index 896ab77..b00aa0b 100644
--- a/views/ngXosViews/sampleView/src/js/main.js
+++ b/views/ngXosViews/sampleView/src/js/main.js
@@ -25,6 +25,46 @@
     controllerAs: 'vm',
     templateUrl: 'templates/users-list.tpl.html',
     controller: function(Users){
+
+      this.tableConfig = {
+        columns: [
+          {
+            label: 'E-Mail',
+            prop: 'email'
+          },
+          {
+            label: 'First Name',
+            prop: 'firstname'
+          },
+          {
+            label: 'Last Name',
+            prop: 'lastname'
+          }
+        ],
+        classes: 'table table-striped table-condensed',
+        actions: [
+          {
+            label: 'delete',
+            icon: 'remove',
+            cb: (user) => {
+              console.log(user);
+            },
+            color: 'red'
+          }
+        ],
+        filter: 'field',
+        order: true,
+        // pagination: {
+        //   pageSize: 6
+        // }
+      };
+
+      this.alertConfig = {
+        type: 'danger',
+        closeBtn: true
+      }
+
+
       // retrieving user list
       Users.query().$promise
       .then((users) => {
diff --git a/views/ngXosViews/sampleView/src/sass/main.scss b/views/ngXosViews/sampleView/src/sass/main.scss
index 76d5ce8..efe6cdc 100644
--- a/views/ngXosViews/sampleView/src/sass/main.scss
+++ b/views/ngXosViews/sampleView/src/sass/main.scss
@@ -1,7 +1,5 @@
 @import '../../../../style/sass/lib/_variables.scss';
 
 #xosSampleView {
-  .row {
-    color: $brand-danger;
-  }
+
 }
\ No newline at end of file
diff --git a/views/ngXosViews/sampleView/src/templates/users-list.tpl.html b/views/ngXosViews/sampleView/src/templates/users-list.tpl.html
index 03be487..c0c58cb 100644
--- a/views/ngXosViews/sampleView/src/templates/users-list.tpl.html
+++ b/views/ngXosViews/sampleView/src/templates/users-list.tpl.html
@@ -1,14 +1,14 @@
 <div class="row">
-  <h1>Users List</h1>
-  <p>This is only an example view.</p>
+  <div class="col-xs-12">
+    <h1>Users List</h1>
+    <p>This is only an example view.</p>
+  </div>
 </div>
+
+  <xos-alert config="vm.alertConfig">Alert message Here</xos-alert>
+
 <div class="row">
-  <div class="col-xs-4">Email</div>
-  <div class="col-xs-4">First Name</div>
-  <div class="col-xs-4">Last Name</div>
-</div>  
-<div class="row" ng-repeat="user in vm.users">
-  <div class="col-xs-4">{{user.email}}</div>
-  <div class="col-xs-4">{{user.firstname}}</div>
-  <div class="col-xs-4">{{user.lastname}}</div>
-</div>  
\ No newline at end of file
+  <div class="col-xs-12">
+    <xos-table data="vm.users" config="vm.tableConfig"></xos-table>
+  </div>
+</div>
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosSampleView.css b/xos/core/xoslib/static/css/xosSampleView.css
index 1a67321..e69de29 100644
--- a/xos/core/xoslib/static/css/xosSampleView.css
+++ b/xos/core/xoslib/static/css/xosSampleView.css
@@ -1 +0,0 @@
-#xosSampleView .row{color:#d9534f}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
index 23316a7..f981551 100644
--- a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
+++ b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
@@ -1 +1 @@
-!function(){"use strict";angular.module("xos.uiComponents.table",[]).directive("xosTable",function(){return{restrict:"E",scope:{data:"=",columns:"="},template:["<!--<pre>{{vm.data | json}}</pre>-->",'<table class="table table-striped" ng-show="vm.data.length > 0">',"<thead>","<tr>",'<th ng-repeat="col in vm.columns">{{col}}</th>',"</tr>","</thead>","<tbody>",'<tr ng-repeat="item in vm.data">','<td ng-repeat="col in vm.columns">{{item[col]}}</td>',"</tr>","</tbody>","</table>"].join(),bindToController:!0,controllerAs:"vm",controller:function(){console.log(this.data,this.columns)}}})}(),function(){"use strict";function e(e,r,s){e.interceptors.push("SetCSRFToken"),r.startSymbol("{$"),r.endSymbol("$}"),s.defaults.stripTrailingSlashes=!1}e.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"],console.log("XOS Helpers Module"),angular.module("bugSnag",[]).factory("$exceptionHandler",function(){return function(e,r){window.Bugsnag?Bugsnag.notifyException(e,{diagnostics:{cause:r}}):console.error(e,r,e.stack)}}),angular.module("xos.helpers",["ngCookies","ngResource","bugSnag","xos.uiComponents"]).config(e)}(),function(){"use strict";angular.module("xos.helpers").service("vSG-Collection",["$resource",function(e){return e("/api/service/vsg/")}])}(),function(){"use strict";angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(e){return e("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"})}])}(),function(){"use strict";angular.module("xos.helpers").service("Users",["$resource",function(e){return e("/api/core/users/")}])}(),function(){"use strict";angular.module("xos.helpers").service("Truckroll-Collection",["$resource",function(e){return e("/api/tenant/truckroll/:truckroll_id/",{truckroll_id:"@id"})}])}(),function(){"use strict";angular.module("xos.helpers").service("Subscribers",["$resource",function(e){return e("/api/tenant/cord/subscriber/:subscriber_id/",{subscriber_id:"@id"})}]).service("Subscriber-features",["$resource",function(e){return e("/api/tenant/cord/subscriber/:subscriber_id/features/",{subscriber_id:"@id"})}]).service("Subscriber-features-uplink_speed",["$resource",function(e){return e("/api/tenant/cord/subscriber/:subscriber_id/features/uplink_speed/",{subscriber_id:"@id"})}]).service("Subscriber-features-downlink_speed",["$resource",function(e){return e("/api/tenant/cord/subscriber/:subscriber_id/features/downlink_speed/",{subscriber_id:"@id"})}]).service("Subscriber-features-cdn",["$resource",function(e){return e("/api/tenant/cord/subscriber/:subscriber_id/features/cdn/",{subscriber_id:"@id"})}]).service("Subscriber-features-uverse",["$resource",function(e){return e("/api/tenant/cord/subscriber/:subscriber_id/features/uverse/",{subscriber_id:"@id"})}]).service("Subscriber-features-status",["$resource",function(e){return e("/api/tenant/cord/subscriber/:subscriber_id/features/status/",{subscriber_id:"@id"})}])}(),function(){"use strict";angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(e){return e("/api/service/onos/")}])}(),function(){"use strict";angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(e){return e("/api/tenant/onos/app/")}])}(),function(){"use strict";angular.module("xos.uiComponents",["xos.uiComponents.table"])}(),function(){"use strict";function e(){return{request:function(e){return-1===e.url.indexOf(".html")&&(e.url+="?no_hyperlinks=1"),e}}}angular.module("xos.helpers").factory("NoHyperlinks",e)}(),function(){"use strict";function e(e){return{request:function(r){return"GET"!==r.method&&(r.headers["X-CSRFToken"]=e.get("xoscsrftoken")),r}}}e.$inject=["$cookies"],angular.module("xos.helpers").factory("SetCSRFToken",e)}();
\ No newline at end of file
+"use strict";!function(){angular.module("xos.uiComponents",[])}(),function(){angular.module("xos.uiComponents").directive("xosTable",function(){return{restrict:"E",scope:{data:"=",config:"="},template:'\n          <div ng-show="vm.data.length > 0">\n            <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n              <div class="col-xs-12">\n                <input\n                  class="form-control"\n                  placeholder="Type to search.."\n                  type="text"\n                  ng-model="vm.query"/>\n              </div>\n            </div>\n            <table ng-class="vm.classes" ng-show="vm.data.length > 0">\n              <thead>\n                <tr>\n                  <th ng-repeat="col in vm.columns">\n                    {{col.label}}\n                    <span ng-if="vm.config.order">\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n                        <i class="glyphicon glyphicon-chevron-up"></i>\n                      </a>\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n                        <i class="glyphicon glyphicon-chevron-down"></i>\n                      </a>\n                    </span>\n                  </th>\n                  <th ng-if="vm.config.actions">Actions</th>\n                </tr>\n              </thead>\n              <tbody ng-if="vm.config.filter == \'field\'">\n                <tr>\n                  <td ng-repeat="col in vm.columns">\n                    <input\n                      class="form-control"\n                      placeholder="Type to search by {{col.label}}"\n                      type="text"\n                      ng-model="vm.query[col.prop]"/>\n                  </td>\n                  <td ng-if="vm.config.actions"></td>\n                </tr>\n              </tbody>\n              <tbody>\n                <tr ng-repeat="item in vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n                  <td ng-repeat="col in vm.columns">{{item[col.prop]}}</td>\n                  <td ng-if="vm.config.actions">\n                    <a href=""\n                      ng-repeat="action in vm.config.actions"\n                      ng-click="action.cb(item)"\n                      title="{{action.label}}">\n                      <i\n                        class="glyphicon glyphicon-{{action.icon}}"\n                        style="color: {{action.color}};"></i>\n                    </a>\n                  </td>\n                </tr>\n              </tbody>\n            </table>\n            <xos-pagination\n              ng-if="vm.config.pagination"\n              page-size="vm.config.pagination.pageSize"\n              total-elements="vm.data.length"\n              change="vm.goToPage">\n              </xos-pagination>\n          </div>\n          <div ng-show="vm.data.length == 0 || !vm.data">\n            <div class="alert alert-info">\n              No data to show.\n            </div>\n          </div>\n        ',bindToController:!0,controllerAs:"vm",controller:function(){var n=this;if(!this.config)throw new Error('[xosTable] Please provide a configuration via the "config" attribute');if(!this.config.columns)throw new Error("[xosTable] Please provide a columns list in the configuration");this.columns=this.config.columns,this.classes=this.config.classes||"table table-striped table-bordered",this.config.actions,this.config.pagination&&(this.currentPage=0,this.goToPage=function(e){n.currentPage=e})}}})}(),function(){angular.module("xos.uiComponents").directive("xosPagination",function(){return{restrict:"E",scope:{pageSize:"=",totalElements:"=",change:"="},template:'\n        <div class="row" ng-if="vm.pageList.length > 1">\n          <div class="col-xs-12 text-center">\n            <ul class="pagination">\n              <li\n                ng-click="vm.goToPage(vm.currentPage - 1)"\n                ng-class="{disabled: vm.currentPage == 0}">\n                <a href="" aria-label="Previous">\n                    <span aria-hidden="true">&laquo;</span>\n                </a>\n              </li>\n              <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n                <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n              </li>\n              <li\n                ng-click="vm.goToPage(vm.currentPage + 1)"\n                ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n                <a href="" aria-label="Next">\n                    <span aria-hidden="true">&raquo;</span>\n                </a>\n              </li>\n            </ul>\n          </div>\n        </div>\n      ',bindToController:!0,controllerAs:"vm",controller:["$scope",function(n){var e=this;this.currentPage=0,this.goToPage=function(n){0>n||n===e.pages||(e.currentPage=n,e.change(n))},this.createPages=function(n){for(var e=[],r=0;n>r;r++)e.push(r);return e},n.$watch(function(){return e.totalElements},function(){e.totalElements&&(e.pages=Math.ceil(e.totalElements/e.pageSize),e.pageList=e.createPages(e.pages))})}]}}).filter("pagination",function(){return function(n,e){return n&&angular.isArray(n)?(e=parseInt(e,10),n.slice(e)):n}})}(),function(){angular.module("xos.uiComponents").directive("xosAlert",function(){return{restrict:"E",scope:{config:"=",show:"=?"},template:'\n        <div class="alert alert-{{vm.config.type}}" ng-show="vm.show">\n          <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n            <span aria-hidden="true">&times;</span>\n          </button>\n          <p ng-transclude></p>\n        </div>\n      ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:["$timeout",function(n){var e=this;if(!this.config)throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');this.show=this.show!==!1,this.dismiss=function(){e.show=!1},this.config.autoHide&&!function(){var r=n(function(){e.dismiss(),n.cancel(r)},e.config.autoHide)}()}]}})}(),function(){function n(n,e,r){n.interceptors.push("SetCSRFToken"),e.startSymbol("{$"),e.endSymbol("$}"),r.defaults.stripTrailingSlashes=!1}n.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"],angular.module("bugSnag",[]).factory("$exceptionHandler",function(){return function(n,e){window.Bugsnag?Bugsnag.notifyException(n,{diagnostics:{cause:e}}):console.error(n,e,n.stack)}}),angular.module("xos.helpers",["ngCookies","ngResource","bugSnag","xos.uiComponents"]).config(n)}(),function(){angular.module("xos.helpers").service("vSG-Collection",["$resource",function(n){return n("/api/service/vsg/")}])}(),function(){angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(n){return n("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"})}])}(),function(){angular.module("xos.helpers").service("Users",["$resource",function(n){return n("/api/core/users/")}])}(),function(){angular.module("xos.helpers").service("Truckroll-Collection",["$resource",function(n){return n("/api/tenant/truckroll/:truckroll_id/",{truckroll_id:"@id"})}])}(),function(){angular.module("xos.helpers").service("Subscribers",["$resource",function(n){return n("/api/tenant/cord/subscriber/:subscriber_id/",{subscriber_id:"@id"})}]).service("Subscriber-features",["$resource",function(n){return n("/api/tenant/cord/subscriber/:subscriber_id/features/",{subscriber_id:"@id"})}]).service("Subscriber-features-uplink_speed",["$resource",function(n){return n("/api/tenant/cord/subscriber/:subscriber_id/features/uplink_speed/",{subscriber_id:"@id"})}]).service("Subscriber-features-downlink_speed",["$resource",function(n){return n("/api/tenant/cord/subscriber/:subscriber_id/features/downlink_speed/",{subscriber_id:"@id"})}]).service("Subscriber-features-cdn",["$resource",function(n){return n("/api/tenant/cord/subscriber/:subscriber_id/features/cdn/",{subscriber_id:"@id"})}]).service("Subscriber-features-uverse",["$resource",function(n){return n("/api/tenant/cord/subscriber/:subscriber_id/features/uverse/",{subscriber_id:"@id"})}]).service("Subscriber-features-status",["$resource",function(n){return n("/api/tenant/cord/subscriber/:subscriber_id/features/status/",{subscriber_id:"@id"})}])}(),function(){angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(n){return n("/api/service/onos/")}])}(),function(){angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(n){return n("/api/tenant/onos/app/")}])}(),function(){function n(){return{request:function(n){return-1===n.url.indexOf(".html")&&(n.url+="?no_hyperlinks=1"),n}}}angular.module("xos.helpers").factory("NoHyperlinks",n)}(),function(){function n(n){return{request:function(e){return"GET"!==e.method&&(e.headers["X-CSRFToken"]=n.get("xoscsrftoken")),e}}}n.$inject=["$cookies"],angular.module("xos.helpers").factory("SetCSRFToken",n)}();
\ No newline at end of file