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) => {
diff --git a/src/app/datasources/helpers/search.service.ts b/src/app/datasources/helpers/search.service.ts
new file mode 100644
index 0000000..8cd98a7
--- /dev/null
+++ b/src/app/datasources/helpers/search.service.ts
@@ -0,0 +1,62 @@
+import * as _ from 'lodash';
+import {IXosNavigationService} from '../../core/services/navigation';
+import {IXosState} from '../../../index';
+import {IModelStoreService} from '../stores/model.store';
+import {IXosConfigHelpersService} from '../../core/services/helpers/config.helpers';
+
+export interface IXosSearchResult {
+ label: string;
+ state: string | {name: string, params: any};
+ type?: string;
+}
+
+export interface IXosSearchService {
+ search(query: string): IXosSearchResult[];
+}
+
+export class SearchService {
+ static $inject = ['$rootScope', 'NavigationService', 'ModelStore', 'ConfigHelpers'];
+ private states: IXosState[];
+
+ constructor (
+ private $rootScope: ng.IScope,
+ private NavigationService: IXosNavigationService,
+ private ModelStore: IModelStoreService,
+ private ConfigHelpers: IXosConfigHelpersService
+ ) {
+ 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');
+ });
+ }
+
+ public search(query: string): IXosSearchResult[] {
+ const routes: IXosSearchResult[] = _.filter(this.states, s => {
+ return s.label.toLowerCase().indexOf(query) > -1;
+ }).map(r => {
+ r.type = 'View';
+ return r;
+ });
+
+ const models = _.map(this.ModelStore.search(query), m => {
+ return {
+ label: m.humanReadableName ? m.humanReadableName : m.name,
+ state: this.ConfigHelpers.stateWithParamsForJs(m.modelName, m),
+ type: m.modelName
+ };
+ });
+ return routes.concat(models);
+ }
+}
diff --git a/src/app/datasources/index.ts b/src/app/datasources/index.ts
index 7a14a9a..04c58db 100644
--- a/src/app/datasources/index.ts
+++ b/src/app/datasources/index.ts
@@ -6,6 +6,7 @@
import {SynchronizerStore} from './stores/synchronizer.store';
import {ModeldefsService} from './rest/modeldefs.rest';
import {xosCore} from '../core/index';
+import {SearchService} from './helpers/search.service';
export const xosDataSources = 'xosDataSources';
@@ -13,11 +14,9 @@
.module('xosDataSources', ['ngCookies', 'ngResource', xosCore])
.service('ModelRest', ModelRest)
.service('AuthService', AuthService)
- .service('WebSocket', WebSocketEvent);
-
-angular
- .module('xosDataSources')
+ .service('WebSocket', WebSocketEvent)
.service('StoreHelpers', StoreHelpers)
.service('SynchronizerStore', SynchronizerStore)
.service('ModelStore', ModelStore)
- .service('ModelDefs', ModeldefsService);
+ .service('ModelDefs', ModeldefsService)
+ .service('SearchService', SearchService);
diff --git a/src/app/datasources/stores/model.store.ts b/src/app/datasources/stores/model.store.ts
index fdcac63..4c6c09d 100644
--- a/src/app/datasources/stores/model.store.ts
+++ b/src/app/datasources/stores/model.store.ts
@@ -1,5 +1,5 @@
/// <reference path="../../../../typings/index.d.ts"/>
-
+import * as _ from 'lodash';
import {BehaviorSubject, Observable} from 'rxjs/Rx';
import {IWSEvent, IWSEventService} from '../websocket/global';
import {IXosResourceService} from '../rest/model.rest';
@@ -7,6 +7,7 @@
export interface IModelStoreService {
query(model: string): Observable<any>;
+ search(modelName: string): any[];
}
export class ModelStore {
@@ -39,6 +40,26 @@
return this._collections[model].asObservable();
}
+ public search(modelName: string): any[] {
+ return _.reduce(Object.keys(this._collections), (results, k) => {
+ // console.log(k, this._collections[k].value)
+ const partialRes = _.filter(this._collections[k].value, i => {
+ if (i.humanReadableName) {
+ return i.humanReadableName.toLowerCase().indexOf(modelName) > -1;
+ }
+ else if (i.name) {
+ return i.name.toLowerCase().indexOf(modelName) > -1;
+ }
+ return false;
+ })
+ .map(m => {
+ m.modelName = k;
+ return m;
+ });
+ return results.concat(partialRes);
+ }, []);
+ }
+
public get(model: string, id: number) {
// TODO implement a get method
}