[CORD-1043] Adding click handler to display models

Change-Id: I331a193afed8e3d4f1bc5699dcb4d91a7404fa07
diff --git a/conf/webpack.conf.js b/conf/webpack.conf.js
index 5506296..34c35ec 100644
--- a/conf/webpack.conf.js
+++ b/conf/webpack.conf.js
@@ -89,7 +89,7 @@
     ]
   },
   entry: {
-    indes: `./${conf.path.src('index')}`,
+    index: `./${conf.path.src('index')}`,
     loader: `./${conf.path.src('/app/style/imports/loader.scss')}`
   },
   ts: {
diff --git a/src/app/core/services/helpers/component-injector.helpers.ts b/src/app/core/services/helpers/component-injector.helpers.ts
index 908e4c7..9fc475b 100644
--- a/src/app/core/services/helpers/component-injector.helpers.ts
+++ b/src/app/core/services/helpers/component-injector.helpers.ts
@@ -47,9 +47,6 @@
     });
   }
 
-  // FIXME
-  // component are correctly injected but not persisted,
-  // if I change route they go away
   public injectComponent(target: string | JQuery, componentName: string, attributes?: any, transclude?: string, clean?: boolean) {
     let targetEl;
     if (angular.isString(target)) {
@@ -74,7 +71,10 @@
 
     if (angular.isDefined(attributes) && angular.isObject(attributes)) {
       attr = this.stringifyAttributes(attributes);
-      scope = angular.merge(scope, attributes);
+      // we cannot use angular.merge as it cast Resource to Objects
+      _.forEach(Object.keys(attributes), (k: string) => {
+        scope[k] = attributes[k];
+      });
     }
 
     const componentTag = `<${componentTagName} ${attr}>${transclude || ''}</${componentTagName}>`;
diff --git a/src/app/core/side-panel/side-panel.html b/src/app/core/side-panel/side-panel.html
index 5d06e79..890b40b 100644
--- a/src/app/core/side-panel/side-panel.html
+++ b/src/app/core/side-panel/side-panel.html
@@ -1,5 +1,4 @@
 <section class="xos-side-panel">
-    <pre>{{vm.isOpened | json}}</pre>
     <div class="row">
         <div class="col-xs-12 text-right">
             <i class="fa fa-remove" ng-click="vm.close()"></i>
diff --git a/src/app/core/side-panel/side-panel.scss b/src/app/core/side-panel/side-panel.scss
index 05f34e0..13538fe 100644
--- a/src/app/core/side-panel/side-panel.scss
+++ b/src/app/core/side-panel/side-panel.scss
@@ -7,11 +7,13 @@
     width: $side-panel-width;
     height: 100%;
     position: fixed;
-    background: $background-dark-color;
     z-index: 9999;
+    top: 0;
     right: -$side-panel-width;
+    background: $background-dark-color;
     padding: $padding;
     transition: all .5s cubic-bezier(0.215, 0.610, 0.355, 1.000);
+    overflow-y: scroll;
 
     &.open {
       right: 0;
diff --git a/src/app/core/side-panel/side-panel.service.ts b/src/app/core/side-panel/side-panel.service.ts
index 96e4162..6857f7d 100644
--- a/src/app/core/side-panel/side-panel.service.ts
+++ b/src/app/core/side-panel/side-panel.service.ts
@@ -13,6 +13,7 @@
   public sidePanelElName = 'xos-side-panel';
   public sidePanelElClass = '.xos-side-panel';
   public sidePanelEl: JQuery;
+  private hasComponentLoaded: boolean;
 
   constructor (
     private $rootScope: ng.IRootScopeService,
@@ -32,14 +33,23 @@
   };
 
   public injectComponent(componentName: string, attributes?: any, transclude?: string) {
-    this.XosComponentInjector.injectComponent('#side-panel-container', componentName, attributes, transclude, true);
-    this.open();
+    let timeout = 0;
+    if (this.hasComponentLoaded) {
+      this.removeInjectedComponents();
+      timeout = 501; // wait for panel to close and remove component
+    }
+    this.$timeout(() => {
+      this.XosComponentInjector.injectComponent('#side-panel-container', componentName, attributes, transclude, true);
+      this.hasComponentLoaded = true;
+      this.open();
+    }, timeout);
   }
 
   public removeInjectedComponents() {
     this.close();
     this.$timeout(() => {
       this.XosComponentInjector.removeInjectedComponents('#side-panel-container');
+      this.hasComponentLoaded = false;
     }, 500);
   }
 }
diff --git a/src/app/service-graph/components/fine-grained/fine-grained.component.scss b/src/app/service-graph/components/fine-grained/fine-grained.component.scss
index 56abd53..5f330ca 100644
--- a/src/app/service-graph/components/fine-grained/fine-grained.component.scss
+++ b/src/app/service-graph/components/fine-grained/fine-grained.component.scss
@@ -7,7 +7,7 @@
   // background: $color-accent;
 
   svg {
-    height: 100%;
+    height: 90%;
     width: 100%;
     background-color: $panel-filled-bg;
     border-radius: 3px;
diff --git a/src/app/service-graph/components/fine-grained/fine-grained.component.ts b/src/app/service-graph/components/fine-grained/fine-grained.component.ts
index b0f71a6..474120f 100644
--- a/src/app/service-graph/components/fine-grained/fine-grained.component.ts
+++ b/src/app/service-graph/components/fine-grained/fine-grained.component.ts
@@ -6,12 +6,16 @@
 import {XosServiceGraphConfig as config} from '../../graph.config';
 import {IXosDebouncer} from '../../../core/services/helpers/debounce.helper';
 import {IXosServiceGraph, IXosServiceGraphLink, IXosServiceGraphNode} from '../../interfaces';
+import {IXosModelDiscovererService} from '../../../datasources/helpers/model-discoverer.service';
+import {IXosSidePanelService} from '../../../core/side-panel/side-panel.service';
 
 class XosFineGrainedTenancyGraphCtrl {
   static $inject = [
     '$log',
     'XosServiceGraphStore',
-    'XosDebouncer'
+    'XosDebouncer',
+    'XosModelDiscoverer',
+    'XosSidePanel'
   ];
 
   public graph: IXosServiceGraph;
@@ -28,7 +32,9 @@
   constructor(
     private $log: ng.ILogService,
     private XosServiceGraphStore: IXosServiceGraphStore,
-    private XosDebouncer: IXosDebouncer
+    private XosDebouncer: IXosDebouncer,
+    private XosModelDiscoverer: IXosModelDiscovererService,
+    private XosSidePanel: IXosSidePanelService
   ) {
     this.handleSvg();
     this.setupForceLayout();
@@ -225,6 +231,7 @@
       .selectAll('g.node')
       .data(nodes, n => n.id);
 
+    let mouseEventsTimer, selectedModel;
     const svgDim = this.getSvgDimensions();
     const hStep = svgDim.width / (nodes.length - 1);
     const vStep = svgDim.heigth / (nodes.length - 1);
@@ -236,10 +243,30 @@
       })
       .call(this.forceLayout.drag)
       .on('mousedown', () => {
+        mouseEventsTimer = new Date().getTime();
         d3.event.stopPropagation();
       })
-      .on('mouseup', (d) => {
-        d.fixed = true;
+      .on('mouseup', (n) => {
+        mouseEventsTimer = new Date().getTime() - mouseEventsTimer;
+        n.fixed = true;
+      })
+      .on('click', (n: IXosServiceGraphNode) => {
+        if (mouseEventsTimer > 100) {
+          // it is a drag
+          return;
+        }
+        if (selectedModel === n.id) {
+          // this model is already selected, so close the panel
+          this.XosSidePanel.removeInjectedComponents();
+          selectedModel = null;
+          return;
+        }
+        selectedModel = n.id;
+        const modelName = n.model['class_names'].split(',')[0];
+        const formConfig = this.XosModelDiscoverer.get(modelName).formCfg;
+        const model = angular.copy(n.model);
+        delete model.d3Id;
+        this.XosSidePanel.injectComponent('xosForm', {config: formConfig, ngModel: model});
       });
 
     this.renderServiceNodes(entering.filter('.service'));
diff --git a/src/index.ts b/src/index.ts
index 611ae21..fa8c2ea 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -90,6 +90,7 @@
     // check the user login
     $transitions.onSuccess({ to: '**' }, (transtion) => {
       if (!AuthService.isAuthenticated()) {
+        AuthService.clearUser();
         $state.go('login');
       }
     });
@@ -112,8 +113,8 @@
     const lastQueryString = $location.search();
 
     // if the user is authenticated
+    $log.info(`[XOS] Is user authenticated? ${AuthService.isAuthenticated()}`);
     if (AuthService.isAuthenticated()) {
-      // ModelSetup.setup()
       XosModelDiscoverer.discover()
         .then((res) => {
           if (res) {
@@ -122,7 +123,6 @@
           else {
             $log.info('[XOS] Failed to load some models, moving on.');
           }
-
           // after setting up dynamic routes, redirect to previous state
           $location.path(lastRoute).search(lastQueryString);
         })
@@ -130,6 +130,10 @@
           $rootScope.$emit('xos.core.modelSetup');
         });
     }
+    else {
+      AuthService.clearUser();
+      $state.go('login');
+    }
 
     // register keyboard shortcut
     XosKeyboardShortcut.setup();
diff --git a/src/interceptors.ts b/src/interceptors.ts
index a79765e..7770f5d 100644
--- a/src/interceptors.ts
+++ b/src/interceptors.ts
@@ -45,6 +45,12 @@
       if (req.url.indexOf('.html') === -1) {
         // NOTE  force content type to be JSON
         req.headers['Content-Type'] = 'application/json';
+
+        if (req.method === 'PUT') {
+          // FIXME XosModelStore.search add this value for visualization purpose,
+          // no one should change models
+          delete req.data.modelName;
+        }
       }
       return req;
     },