Added form to smart table
diff --git a/views/ngXosLib/xosHelpers/spec/ui/smart-table.test.js b/views/ngXosLib/xosHelpers/spec/ui/smart-table.test.js
index e8cc030..bcc34e1 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/smart-table.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/smart-table.test.js
@@ -30,6 +30,9 @@
             this.query = jasmine.createSpy('query').and.callFake(() => {
               return {$promise: {then: (cb) => cb(mockData)}};
             });
+            this.delete = jasmine.createSpy('delete').and.callFake(() => {
+              return {$promise: {then: (cb) => cb({})}};
+            });
           });
 
           $provide.service('EmptyResource', function(){
@@ -62,9 +65,40 @@
       });
 
       it('should hide hidden fields', () => {
-        expect($(element).find('thead th').length).toEqual(2);
+        // the 4th field is the mocked save method
+        expect($(element).find('thead th').length).toEqual(3);
         expect($(element).find('thead th')[0]).toContainText('First name:');
         expect($(element).find('thead th')[1]).toContainText('Last name:');
+        expect($(element).find('thead th')[2]).toContainText('Actions:');
+      });
+
+      it('should delete a model', () => {
+        $(element).find('a[title="delete"]')[0].click();
+        expect(spy.delete).toHaveBeenCalledWith({id: mockData[0].id});
+        expect($(element).find('.alert')).toContainText(`MockResource with id ${mockData[0].id} successfully deleted`);
+      });
+
+      it('should show the form', () => {
+        expect($(element).find('.panel')[0]).toHaveClass('ng-hide');
+        $(element).find('a[title="details"]')[0].click();
+        expect($(element).find('.panel')).not.toHaveClass('ng-hide');
+      });
+
+      it('should save an item', () => {
+        const saveMethod = jasmine.createSpy('$save').and.callFake(() => {
+          return {then: (cb) => cb(mockData[0])};
+        });
+        let model = {
+          id: 1,
+          first_name: 'Jon',
+          last_name: 'Snow',
+          hidden_field: 'hidden',
+          $save: saveMethod
+        };
+        isolatedScope.detailedItem = model;
+        scope.$apply();
+        $(element).find('xos-form .btn.btn-success').click();
+        expect(saveMethod).toHaveBeenCalled();
       });
 
       describe('when fetching an empty collection', () => {
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Instances.js b/views/ngXosLib/xosHelpers/src/services/rest/Instances.js
new file mode 100644
index 0000000..2e74f33
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Instances.js
@@ -0,0 +1,13 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Instances
+  * @description Angular resource to fetch /api/core/instances/
+  **/
+  .service('Instances', function($resource){
+    return $resource('/api/core/instances/');
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js
index 7eb837e..745c3ca 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js
@@ -210,7 +210,7 @@
                       </a>
                     </span>
                   </th>
-                  <th ng-if="vm.config.actions">Actions</th>
+                  <th ng-if="vm.config.actions">Actions:</th>
                 </tr>
               </thead>
               <tbody ng-if="vm.config.filter == 'field'">
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 4a0ecd9..734c54b 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
@@ -28,26 +28,53 @@
         config: '='
       },
       template: `
+        <pre>{{vm.responseErr}}</pre>
         <xos-table config="vm.tableConfig" data="vm.data"></xos-table>
+        <div class="panel panel-default" ng-show="vm.detailedItem">
+          <div class="panel-heading">
+            <h3 class="panel-title">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>
+          </div>
+          <div class="panel-body">
+            <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>
+          </div>
+        </div>
+        <xos-alert config="{type: 'success', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>
+        <xos-alert config="{type: 'danger', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>
       `,
       bindToController: true,
       controllerAs: 'vm',
       controller: function($injector, LabelFormatter, _){
         
+        this.responseMsg = false;
+        this.responseErr = false;
+
         this.tableConfig = {
           columns: [
           ],
-          // actions: [
-          //   {
-          //     label: 'delete',
-          //     icon: 'remove',
-          //     cb: (user) => {
-          //       console.log(user);
-          //       // _.remove(this.users, {id: user.id});
-          //     },
-          //     color: 'red'
-          //   }
-          // ],
+          actions: [
+            {
+              label: 'delete',
+              icon: 'remove',
+              cb: (item) => {
+                this.Resource.delete({id: item.id}).$promise
+                .then(() => {
+                  console.log(this.config.resource);
+                  this.responseMsg = `${this.config.resource} with id ${item.id} successfully deleted`;
+                })
+                .catch(err => {
+                  this.responseErr = err.data.detail || `Error while deleting ${this.config.resource} with id ${item.id}`;
+                });
+              },
+              color: 'red'
+            },
+            {
+              label: 'details',
+              icon: 'search',
+              cb: (item) => {
+                this.detailedItem = item;
+              }
+            }
+          ],
           classes: 'table table-striped table-bordered table-responsive',
           filter: 'field',
           order: true,
@@ -56,6 +83,27 @@
           }
         };
 
+        this.formConfig = {
+          exclude: this.config.hiddenFields,
+          formName: `${this.config.resource}Form`,
+          actions: [
+            {
+              label: 'Save',
+              icon: 'ok',
+              cb: (item) => {
+                item.$save()
+                .then(() => {
+                  this.responseMsg = `${this.config.resource} with id ${item.id} successfully saved`;
+                })
+                .catch((err) => {
+                  this.responseErr = err.data.detail || `Error while saving ${this.config.resource} with id ${item.id}`;
+                })
+              },
+              class: 'success'
+            }
+          ]
+        }
+
         this.Resource = $injector.get(this.config.resource);
 
         this.Resource.query().$promise
@@ -71,6 +119,7 @@
             return p == 'id' || p == 'password' || p == 'validators'
           });
 
+          // TODO move out cb
           if(angular.isArray(this.config.hiddenFields)){
             props = _.difference(props, this.config.hiddenFields)
           }