Dashboard and nginx fixes

Change-Id: I4ee34b24779f929f41852d4662018caead860ab6
diff --git a/Dockerfile b/Dockerfile
index 4b1df3d..8dd7ce4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -25,4 +25,5 @@
 RUN npm run build
 
 # Override nginx configutaion
-RUN mv ${CODE_SOURCE}/nginx.conf /etc/nginx/conf.d/default.conf
\ No newline at end of file
+RUN mv ${CODE_SOURCE}/nginx.conf /etc/nginx/conf.d/default.conf
+#RUN service nginx restart
\ No newline at end of file
diff --git a/README.md b/README.md
index 18837b9..7b369a6 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,39 @@
 # XOS GUI
 
-This is the new XOS UI
+**Experimental Feature**
+
+This UI is currently hidden behind a flag and at the current state it is guaranteed as working only from the `frontend` config.
+#### Setup the correct environment:
+- Clone `opencord` using `repo` 
+```
+repo init -u https://gerrit.opencord.org/manifest
+repo sync
+```
+- Download XOS patch to enable Redis notifications (waiting for the release to merge it)
+```
+cd orchestration/xos
+git review -d 1852
+```
+
+#### Start the system
+
+A vagrant VM is provided to make your life easier, so:
+```
+cd orchestration/service-profile/frontend
+vagrant up frontend
+vagrant ssh frontend # password is vagrant
+cd service-profile/frontend
+make local_containers
+make
+make experimental-ui
+```
+The new UI is now accessible at `http://<your-ip>` on port `80`
+
+If you want to create some slices to have some data:
+```
+make slices
+```
+
 
 # Development
 
@@ -16,5 +49,23 @@
 - `NODE_ENV`: to configure the app constants (eg: `dev`, `production`)
 - `BRAND`: to configure style constants (eg: `cord`, `opencloud`)
 
+# Test
 
+To commands come with the project:
+- `npm run test:auto` to watch source files and run test anytime they change, useful for development
+- `npm test` to run test once, this is the command triggered by Jenkins
 
+## Emulate a Synchronizer notification
+
+```
+redis-cli -h xos.dev
+ 
+# In progress
+PUBLISH Slice "{\"pk\": 19, \"object\": {\"id\": 19,\"name\": \"mysite_test_redis\", \"backend_status\": \"0 - In Progress\"}, \"changed_fields\": [\"updated\", \"backend_status\"]}"
+ 
+# Succes
+PUBLISH Slice "{\"pk\": 19, \"object\": {\"id\": 19,\"name\": \"mysite_test_redis\", \"backend_status\": \"1 - Success\"}, \"changed_fields\": [\"updated\", \"backend_status\"]}"
+ 
+# Error
+PUBLISH Slice "{\"pk\": 19, \"object\": {\"id\": 19,\"name\": \"mysite_test_redis\", \"backend_status\": \"2 - Error\"}, \"changed_fields\": [\"updated\", \"backend_status\"]}"
+```
diff --git a/conf/webpack-dist.conf.js b/conf/webpack-dist.conf.js
index 59bb335..1ee1855 100644
--- a/conf/webpack-dist.conf.js
+++ b/conf/webpack-dist.conf.js
@@ -34,7 +34,9 @@
       {
         test: /.html$/,
         loaders: [
-          'html'
+          'html?' + JSON.stringify({
+            attrs: ["img:src", "img:ng-src"]
+          })
         ]
       },
       {
diff --git a/conf/webpack-test.conf.js b/conf/webpack-test.conf.js
index d3303ba..a87e383 100644
--- a/conf/webpack-test.conf.js
+++ b/conf/webpack-test.conf.js
@@ -25,7 +25,9 @@
       {
         test: /.html$/,
         loaders: [
-          'html'
+          'html?' + JSON.stringify({
+            attrs: ["img:src", "img:ng-src"]
+          })
         ]
       },
       {
diff --git a/nginx.conf b/nginx.conf
index 659bb61..4506b59 100644
--- a/nginx.conf
+++ b/nginx.conf
@@ -11,10 +11,12 @@
     }
 
     location /api {
+        resolver 127.0.0.1 valid=30s;
         proxy_pass http://xos-rest-gw:3000;
     }
 
     location /socket.io {
+        resolver 127.0.0.1 valid=30s;
         proxy_pass http://xos-rest-gw:3000;
     }
 }
\ No newline at end of file
diff --git a/src/app/core/header/header.ts b/src/app/core/header/header.ts
index efaa385..849767f 100644
--- a/src/app/core/header/header.ts
+++ b/src/app/core/header/header.ts
@@ -35,7 +35,7 @@
       // tapToDismiss: false
     });
 
-    this.userEmail = this.authService.getUser().email;
+    this.userEmail = this.authService.getUser() ? this.authService.getUser().email : '';
 
     this.syncStore.query()
       .subscribe(
diff --git a/src/app/core/nav/nav.scss b/src/app/core/nav/nav.scss
index 7646cd9..ef3020b 100644
--- a/src/app/core/nav/nav.scss
+++ b/src/app/core/nav/nav.scss
@@ -1,5 +1,18 @@
 xos-nav {
+  .navigation {
+    max-height: 100%;
+    display: block;
+    overflow-y: scroll;
+
+    nav {
+      margin-bottom: 200px;
+    }
+  }
+
   .nav-info {
+    position: fixed !important;
+    bottom: 0;
+    width: 200px;
     .row + .row:last-child {
       margin-top: 20px;
     }
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index f9b76f0..599edaf 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -30,7 +30,8 @@
     'no_policy',
     'omf_friendly',
     'enabled',
-    'validators'
+    'validators',
+    'password'
   ];
 
   constructor() {
diff --git a/src/app/core/table/table.html b/src/app/core/table/table.html
index 23b5a2f..382dbec 100644
--- a/src/app/core/table/table.html
+++ b/src/app/core/table/table.html
@@ -8,19 +8,20 @@
                     ng-model="vm.query"/>
         </div>
     </div>
-    <table ng-class="vm.classes">
+    <div class="table-responsive">
+        <table ng-class="vm.classes">
         <thead>
         <tr>
             <th ng-repeat="col in vm.columns">
                 {{col.label}}
-                <span ng-if="vm.config.order">
+                <div ng-if="vm.config.order">
                     <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">
                       <i class="fa fa-chevron-up"></i>
                     </a>
                     <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">
                       <i class="fa fa-chevron-down"></i>
                     </a>
-                  </span>
+                </div>
             </th>
             <th ng-if="vm.config.actions">Actions:</th>
         </tr>
@@ -90,6 +91,7 @@
         </tr>
         </tbody>
     </table>
+    </div>
 <!--</div>-->
 <!--<div ng-show="(vm.data.length == 0 || !vm.data) && vm.loader == false">-->
     <!--<xos-alert config="{type: 'info'}">-->
diff --git a/src/app/core/table/table.scss b/src/app/core/table/table.scss
index fbf6ee7..a2af05e 100644
--- a/src/app/core/table/table.scss
+++ b/src/app/core/table/table.scss
@@ -1,7 +1,10 @@
+xos-table {
+  .row + .table-responsive {
+    margin-top: 10px;
+  }
+}
+
 table {
-  width: 100%;
-  max-width: 100%;
-  margin-bottom: 20px;
   border-collapse: collapse !important;
   background: darken(grey, 20);
   border: 1px solid darken(grey, 35);
diff --git a/src/app/core/table/table.ts b/src/app/core/table/table.ts
index dba740e..1ed258d 100644
--- a/src/app/core/table/table.ts
+++ b/src/app/core/table/table.ts
@@ -22,13 +22,15 @@
 }
 
 interface IXosTableCgfOrder {
-  reverse: boolean;
+  reverse?: boolean;
   field: string;
 }
 
 export interface IXosTableCfg {
   columns: any[];
-  order?: IXosTableCgfOrder; // | boolean;
+  order?: IXosTableCgfOrder;
+  filter?: string;
+  actions?: any[]; // TODO create interface
 }
 
 class TableCtrl {
diff --git a/src/app/datasources/rest/auth.rest.ts b/src/app/datasources/rest/auth.rest.ts
index e7a593c..f963799 100644
--- a/src/app/datasources/rest/auth.rest.ts
+++ b/src/app/datasources/rest/auth.rest.ts
@@ -21,7 +21,8 @@
 export interface IXosAuthService {
   login(data: IAuthRequestData): Promise<any>;
   logout(): Promise<any>;
-  getUser(): IXosUser;
+  getUser(): any; // NOTE how to define return user || false ???
+  isAuthenticated(): boolean;
 }
 export class AuthService {
 
@@ -67,6 +68,16 @@
   }
 
   public getUser(): IXosUser {
-    return JSON.parse(this.$cookies.get('xosuser'));
+    const user = this.$cookies.get('xosuser');
+    if (angular.isDefined(user)) {
+      return JSON.parse(user);
+    }
+    return;
+  }
+
+  public isAuthenticated(): boolean {
+    const token = this.$cookies.get('xoscsrftoken');
+    const session = this.$cookies.get('xossessionid');
+    return angular.isDefined(token) && angular.isDefined(session);
   }
 }
diff --git a/src/app/datasources/rest/model.rest.ts b/src/app/datasources/rest/model.rest.ts
index 908ca0f..eca4221 100644
--- a/src/app/datasources/rest/model.rest.ts
+++ b/src/app/datasources/rest/model.rest.ts
@@ -16,6 +16,6 @@
   }
 
   public getResource(url: string): ng.resource.IResourceClass<ng.resource.IResource<any>> {
-    return this.resource = this.$resource(`${AppConfig.apiEndpoint}${url}/:id`);
+    return this.resource = this.$resource(`${AppConfig.apiEndpoint}${url}/:id`, {id: '@id'});
   }
 }
diff --git a/src/app/datasources/stores/model.store.ts b/src/app/datasources/stores/model.store.ts
index fa3ab06..0839cc7 100644
--- a/src/app/datasources/stores/model.store.ts
+++ b/src/app/datasources/stores/model.store.ts
@@ -18,6 +18,8 @@
     private ModelRest: IXosResourceService
   ) {
   }
+  // FIXME if called multiple time (for different collection),
+  // it return the same observable while it should return different ones
 
   query(model: string) {
     this.loadInitialData(model);
diff --git a/src/app/views/dashboard/dashboard.html b/src/app/views/dashboard/dashboard.html
new file mode 100644
index 0000000..de4c358
--- /dev/null
+++ b/src/app/views/dashboard/dashboard.html
@@ -0,0 +1,42 @@
+<section class="content">
+    <div class="container-fluid">
+        <!--<h1>Dashboard</h1>-->
+        <div class="row">
+            <div class="col-xs-4">
+                <div class="panel panel-filled">
+                    <div class="panel-body text-center">
+                        <h2 class="m-b-none">
+                            {{vm.nodes}}
+                            <!--<span class="slight"><i class="fa fa-play fa-rotate-270 text-warning"> </i> +20%</span>-->
+                        </h2>
+                        <h4>Nodes</h4>
+                        <!--<div class="small">% New Sessions</div>-->
+                        <!--<div class="slight m-t-sm"><i class="fa fa-clock-o"> </i> Updated: <span class="c-white">10:22pm</span></div>-->
+                    </div>
+                </div>
+            </div>
+
+            <div class="col-xs-4">
+                <div class="panel panel-filled">
+                    <div class="panel-body text-center">
+                        <h2 class="m-b-none">
+                            {{vm.slices}}
+                        </h2>
+                        <h4>Slices</h4>
+                    </div>
+                </div>
+            </div>
+
+            <div class="col-xs-4">
+                <div class="panel panel-filled">
+                    <div class="panel-body text-center">
+                        <h2 class="m-b-none">
+                            {{vm.instances}}
+                        </h2>
+                        <h4>Instances</h4>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</section>
\ No newline at end of file
diff --git a/src/app/views/dashboard/dashboard.ts b/src/app/views/dashboard/dashboard.ts
new file mode 100644
index 0000000..776acf6
--- /dev/null
+++ b/src/app/views/dashboard/dashboard.ts
@@ -0,0 +1,46 @@
+import {IModelStoreService} from '../../datasources/stores/model.store';
+import {IXosAuthService} from '../../datasources/rest/auth.rest';
+class DashboardController {
+  static $inject = ['$state', 'ModelStore', 'AuthService'];
+
+  public nodes: number;
+  public slices: number;
+  public instances: number;
+
+  constructor(
+    private $state: ng.ui.IStateService,
+    private store: IModelStoreService,
+    private auth: IXosAuthService
+  ) {
+
+    if (!this.auth.isAuthenticated()) {
+      this.$state.go('login');
+    }
+    else {
+      // this.store.query('node')
+      //   .subscribe((event) => {
+      //     console.log(`node`, event);
+      //     this.nodes = event.length;
+      // });
+      this.store.query('slice')
+        .subscribe((event) => {
+          // console.log('slice', event);
+          this.slices = event.length;
+      });
+      // this.store.query('instance')
+      //   .subscribe((event) => {
+      //     console.log('isntance', event);
+      //     this.instances = event.length;
+      // });
+      this.instances = 0;
+      this.nodes = 2;
+      this.slices = 3;
+    }
+  }
+}
+
+export const xosDashboard: angular.IComponentOptions = {
+  template: require('./dashboard.html'),
+  controllerAs: 'vm',
+  controller: DashboardController
+};
diff --git a/src/app/views/index.ts b/src/app/views/index.ts
index 495e2a4..ee87ef9 100644
--- a/src/app/views/index.ts
+++ b/src/app/views/index.ts
@@ -1,8 +1,10 @@
 import {xosCore} from '../core/index';
 import {xosCrud} from './crud/crud';
+import {xosDashboard} from './dashboard/dashboard';
 
 export const xosViews = 'xosViews';
 
 angular
   .module('xosViews', [xosCore])
-  .component('xosCrud', xosCrud);
+  .component('xosCrud', xosCrud)
+  .component('xosDashboard', xosDashboard);
diff --git a/src/index.ts b/src/index.ts
index 48244ef..4ba1f3d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -90,7 +90,20 @@
               model: m.name,
               related: m.relations,
               xosTableCfg: {
-                columns: ConfigHelpers.modeldefToTableCfg(m.fields, stateUrl)
+                columns: ConfigHelpers.modeldefToTableCfg(m.fields, stateUrl),
+                filter: 'fulltext',
+                order: {field: 'id', reverse: false}, // TODO understand dynamic interfaces
+                actions: [
+                  {
+                    label: 'delete',
+                    icon: 'remove',
+                    color: 'red',
+                    cb: (item) => {
+                      console.log(item);
+                      item.$delete();
+                    }
+                  }
+                ]
               },
               // TODO add form config
             }
diff --git a/src/interceptors.ts b/src/interceptors.ts
index 57f79f2..ef765c0 100644
--- a/src/interceptors.ts
+++ b/src/interceptors.ts
@@ -33,7 +33,7 @@
       if (!$cookies.get('xoscsrftoken') || !$cookies.get('xossessionid')) {
         return req;
       }
-      // req.headers['X-CSRFToken'] = $cookies.get('xoscsrftoken');
+      req.headers['X-CSRFToken'] = $cookies.get('xoscsrftoken');
       req.headers['x-csrftoken'] = $cookies.get('xoscsrftoken');
       req.headers['x-sessionid'] = $cookies.get('xossessionid');
       return req;
diff --git a/src/routes.ts b/src/routes.ts
index e972d22..3e9274e 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -18,7 +18,7 @@
     .state('xos.dashboard', {
       url: '',
       parent: 'xos',
-      template: '<h1>Dashboard</h1>'
+      template: '<xos-dashboard></xos-dashboard>'
     })
     .state('xos.core', {
       url: 'core',