Searching for models into client cache

Change-Id: Ib65b1565153040684083fbc21a59e8c8365628fd
diff --git a/src/app/core/header/header.html b/src/app/core/header/header.html
index 5025258..c0bebe2 100644
--- a/src/app/core/header/header.html
+++ b/src/app/core/header/header.html
@@ -1,23 +1,13 @@
-<!--<header class="header">-->
-  <!--<p class="header-title">-->
-    <!--<a href="#/" target="_blank">-->
-      <!--{{vm.title}}-->
-    <!--</a>-->
-  <!--</p>-->
-  <!--<p class="header-date notification">-->
-    <!--<i ng-if="vm.newNotifications.length > 0" class="badge"></i>-->
-    <!--<i class="fa fa-bell" ng-click="vm.showNotification = !vm.showNotification"></i>-->
-    <!--<div class="notification-panel" ng-show="vm.showNotification">-->
-      <!--<ul>-->
-        <!--<li ng-repeat="n in vm.notifications track by $index" ng-click="vm.viewNotification(n)" ng-class="{viewed: n.viewed}">-->
-          <!--<b>{{n.model}}</b><br>-->
-          <!--<i>{{n.msg.object.name}} status is {{n.msg.object.backend_status}}</i>-->
-        <!--</li>-->
-      <!--</ul>-->
-    <!--</div>-->
-  <!--</p>-->
-<!--</header>-->
-
+<!-- Custom template for Typeahead -->
+<script type="text/ng-template" id="customTemplate.html">
+  <a>
+    <span ng-bind-html="match.label.label | uibTypeaheadHighlight:query"></span>
+    <code class="pull-right">
+      {{match.label.type}}
+    </code>
+  </a>
+</script>
+<!-- END Custom template for Typeahead -->
 
 <!-- Header -->
 <nav class="navbar navbar-default navbar-fixed-top">
@@ -40,7 +30,8 @@
           placeholder="Navigate routes (press 'f' to select)"
           style="width: 275px"
           ng-model="vm.query"
-          uib-typeahead="state.label for state in vm.states | filter:$viewValue | limitTo:8"
+          uib-typeahead="state for state in vm.search($viewValue) | limitTo:30"
+          typeahead-template-url="customTemplate.html"
           typeahead-on-select="vm.routeSelected($item, $model, $label)">
       </form>
       <ul class="nav navbar-nav navbar-right">
diff --git a/src/app/core/header/header.scss b/src/app/core/header/header.scss
index 263740c..ca97ae2 100644
--- a/src/app/core/header/header.scss
+++ b/src/app/core/header/header.scss
@@ -18,4 +18,27 @@
   .navbar-default {
     background: #2a2d35 !important;
   }
+
+  .dropdown-menu {
+    background: #2a2d35 !important;
+    min-width: 275px;
+    max-height: 600px;
+    overflow-y: scroll;
+
+    .active > a {
+      border-left: 6px solid #f6a821;
+      background: #494b54;
+      color: #fff !important;
+    }
+
+    a {
+      color: #c0c4c8 !important;
+      display: block;
+      width: 100%;
+    }
+
+    a:hover {
+      background: #494b54 !important;
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/app/core/header/header.spec.ts b/src/app/core/header/header.spec.ts
index 62fa368..0bd6877 100644
--- a/src/app/core/header/header.spec.ts
+++ b/src/app/core/header/header.spec.ts
@@ -54,7 +54,8 @@
       .value('NavigationService', {})
       .value('StyleConfig', {
         logo: 'cord-logo.png',
-      });
+      })
+      .value('SearchService', {});
 
     angular.mock.module('xosHeader');
   });
diff --git a/src/app/core/header/header.ts b/src/app/core/header/header.ts
index 0a98494..620aecd 100644
--- a/src/app/core/header/header.ts
+++ b/src/app/core/header/header.ts
@@ -4,23 +4,24 @@
 import {IXosAuthService} from '../../datasources/rest/auth.rest';
 import {IXosNavigationService, IXosNavigationRoute} from '../services/navigation';
 import {IStateService} from 'angular-ui-router';
-import * as _ from 'lodash';
 import * as $ from 'jquery';
 import {IXosStyleConfig} from '../../../index';
+import {IXosSearchService, IXosSearchResult} from '../../datasources/helpers/search.service';
 
 export interface INotification extends IWSEvent {
   viewed?: boolean;
 }
 
 class HeaderController {
-  static $inject = ['$scope', '$rootScope', '$state', 'AuthService', 'SynchronizerStore', 'toastr', 'toastrConfig', 'NavigationService', 'StyleConfig'];
+  static $inject = ['$scope', '$rootScope', '$state', 'AuthService', 'SynchronizerStore', 'toastr', 'toastrConfig', 'NavigationService', 'StyleConfig', 'SearchService'];
   public notifications: INotification[] = [];
   public newNotifications: INotification[] = [];
   public version: string;
   public userEmail: string;
-  public routeSelected: (route: IXosNavigationRoute) => void;
+  public routeSelected: (route: IXosSearchResult) => void;
   public states: IXosNavigationRoute[];
   public query: string;
+  public search: (query: string) => any[];
 
   constructor(
     private $scope: angular.IScope,
@@ -31,7 +32,8 @@
     private toastr: ng.toastr.IToastrService,
     private toastrConfig: ng.toastr.IToastrConfig,
     private NavigationService: IXosNavigationService,
-    private StyleConfig: IXosStyleConfig
+    private StyleConfig: IXosStyleConfig,
+    private SearchService: IXosSearchService
   ) {
     this.version = require('../../../../package.json').version;
     angular.extend(this.toastrConfig, {
@@ -46,33 +48,30 @@
       // tapToDismiss: false
     });
 
-    this.$rootScope.$on('xos.core.modelSetup', () => {
-      this.states = this.NavigationService.query().reduce((list, state) => {
-        // if it does not have child (otherwise it is abstract)
-        if (!state.children || state.children.length === 0) {
-          list.push(state);
-        }
-        // else push child
-        if (state.children && state.children.length > 0) {
-          state.children.forEach(c => {
-            list.push(c);
-          });
-        }
-        return list;
-      }, []);
-      this.states = _.uniqBy(this.states, 'state');
-    });
+    // this.$rootScope.$on('xos.core.modelSetup', () => {
+    //   this.states = _.uniqBy(this.states, 'state');
+    // });
+
+    this.search = (query: string) => {
+      return this.SearchService.search(query);
+    };
 
     // listen for keypress
     $(document).on('keyup', (e) => {
       if (e.key === 'f') {
         $('.navbar-form input').focus();
       }
+      // console.log(this.SearchService.getStates());
     });
 
     // redirect to selected page
-    this.routeSelected = (item: IXosNavigationRoute) => {
-      this.$state.go(item.state);
+    this.routeSelected = (item: IXosSearchResult) => {
+      if (angular.isString(item.state)) {
+        this.$state.go(item.state);
+      }
+      else {
+        this.$state.go(item.state.name, item.state.params);
+      }
       this.query = null;
     };
 
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index fd5e8e0..d0fbed9 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -30,6 +30,7 @@
   urlFromCoreModel(model: string): string;
   stateFromCoreModel(name: string): string;
   stateWithParams(name: string, model: any): string;
+  stateWithParamsForJs(name: string, model: any): any;
 }
 
 export class ConfigHelpers {
@@ -192,6 +193,12 @@
     return `${state}({id: ${model['id']}})`;
   }
 
+  public stateWithParamsForJs(name: string, model: any): any {
+    // TODO test and interface
+    const state = this.stateFromCoreModel(name);
+    return {name: state, params: {id: model.id}};
+  }
+
   public modelFieldToInputCfg(fields: IXosModelDefsField[]): IXosFormInput[] {
 
     return _.map(fields, (f: IXosModelDefsField) => {