Using states in place of links

Change-Id: I026b55a9dac4ed42bfd442704fc8bdfaa63918c9
diff --git a/src/app/core/link-wrapper/link-wrapper.ts b/src/app/core/link-wrapper/link-wrapper.ts
index add8d48..0f03ecb 100644
--- a/src/app/core/link-wrapper/link-wrapper.ts
+++ b/src/app/core/link-wrapper/link-wrapper.ts
@@ -2,7 +2,7 @@
 export function xosLinkWrapper(): IDirective {
   return {
     template: `
-    <a ng-if="col.link" href="{{col.link(item)}}">
+    <a ng-if="col.link" ui-sref="{{col.link(item)}}">
       <div ng-transclude></div>
     </a>
     <div ng-transclude ng-if="!col.link"></div>
diff --git a/src/app/core/services/helpers/config.helpers.spec.ts b/src/app/core/services/helpers/config.helpers.spec.ts
index eca43d9..837491a 100644
--- a/src/app/core/services/helpers/config.helpers.spec.ts
+++ b/src/app/core/services/helpers/config.helpers.spec.ts
@@ -61,6 +61,20 @@
       })
       .value('ModelStore', {
 
+      })
+      .value('$state', {
+        get: () => {
+          return [
+            {
+              name: 'xos.core.tests',
+              data: {model: 'Test'}
+            },
+            {
+              name: 'xos.core.slices',
+              data: {model: 'Slices'}
+            }
+          ];
+        }
       });
     angular.mock.module('test');
   });
@@ -116,6 +130,30 @@
     });
   });
 
+  describe('the navigation methods', () => {
+    describe('urlFromCoreModels', () => {
+      it('should return the URL for a given model', () => {
+        expect(service.urlFromCoreModel('Test')).toBe('/core/tests');
+      });
+    });
+    describe('stateFromCoreModels', () => {
+
+      let state: ng.ui.IStateService;
+
+      beforeEach(angular.mock.inject(($state) => {
+        state = $state;
+      }));
+
+      it('should return the state for a given model', () => {
+        expect(service.stateFromCoreModel('Test')).toBe('xos.core.tests');
+      });
+
+      it('should return the state with params for a given model', () => {
+        expect(service.stateWithParams('Test', {id: 1})).toBe('xos.core.tests({id: 1})');
+      });
+    });
+  });
+
   describe('the modelFieldsToColumnsCfg method', () => {
     it('should return an array of columns', () => {
       const cols = service.modelFieldsToColumnsCfg(model.fields, 'testUrl/:id?');
@@ -188,7 +226,7 @@
   });
 
   describe('the private methods', () => {
-    let modelStoreMock, toastr, auth;
+    let modelStoreMock, toastr, auth, stateMock;
 
     beforeEach(angular.mock.inject((_toastr_, AuthService) => {
       modelStoreMock = {
@@ -202,6 +240,9 @@
       };
       toastr = _toastr_;
       auth = AuthService;
+      stateMock = {
+        get: ''
+      };
     }));
 
     const field: IXosModelDefsField = {
@@ -218,7 +259,7 @@
         test: 2
       };
       it('should add the formatted data to the column definition', () => {
-        service = new ConfigHelpers(toastr, auth, modelStoreMock);
+        service = new ConfigHelpers(stateMock, toastr, auth, modelStoreMock);
         service['populateRelated'](item, item.test, field);
         expect(item['test-formatted']).toBe('second');
       });
@@ -234,7 +275,7 @@
       };
 
       it('should add the available choice to the select', () => {
-        service = new ConfigHelpers(toastr, auth, modelStoreMock);
+        service = new ConfigHelpers(stateMock, toastr, auth, modelStoreMock);
         service['populateSelectField'](field, input);
         expect(input.options).toEqual([
           {id: 1, label: 'test'},
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index e4c10b6..fd5e8e0 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -5,6 +5,7 @@
 import {IXosFormConfig, IXosFormInput} from '../../form/form';
 import {IXosAuthService} from '../../../datasources/rest/auth.rest';
 import {IModelStoreService} from '../../../datasources/stores/model.store';
+import {IXosState} from '../../../../index';
 
 export interface IXosModelDefsField {
   name: string;
@@ -20,16 +21,19 @@
 export interface IXosConfigHelpersService {
   excluded_fields: string[];
   modelFieldsToColumnsCfg(fields: IXosModelDefsField[], baseUrl: string): IXosTableColumn[]; // TODO use a proper interface
-  modelToTableCfg(model: IModeldef, baseUrl: string): IXosTableCfg;
+  modelToTableCfg(model: IModeldef, modelName: string): IXosTableCfg;
   modelFieldToInputCfg(fields: IXosModelDefsField[]): IXosFormInput[];
   modelToFormCfg(model: IModeldef): IXosFormConfig;
   pluralize(string: string, quantity?: number, count?: boolean): string;
   toLabel(string: string, pluralize?: boolean): string;
   toLabels(string: string[], pluralize?: boolean): string[];
+  urlFromCoreModel(model: string): string;
+  stateFromCoreModel(name: string): string;
+  stateWithParams(name: string, model: any): string;
 }
 
 export class ConfigHelpers {
-  static $inject = ['toastr', 'AuthService', 'ModelStore'];
+  static $inject = ['$state', 'toastr', 'AuthService', 'ModelStore'];
 
   excluded_fields = [
     'created',
@@ -51,6 +55,7 @@
   ];
 
   constructor(
+    private $state: ng.ui.IStateService,
     private toastr: ng.toastr.IToastrService,
     private AuthService: IXosAuthService,
     private ModelStore: IModelStoreService
@@ -87,7 +92,7 @@
 
   public modelToTableCfg(model: IModeldef, baseUrl: string): IXosTableCfg {
     const cfg = {
-      columns: this.modelFieldsToColumnsCfg(model.fields, baseUrl),
+      columns: this.modelFieldsToColumnsCfg(model.fields, model.name),
       filter: 'fulltext',
       order: {field: 'id', reverse: false},
       actions: [
@@ -116,7 +121,7 @@
     return cfg;
   }
 
-  public modelFieldsToColumnsCfg(fields: IXosModelDefsField[], baseUrl: string): IXosTableColumn[] {
+  public modelFieldsToColumnsCfg(fields: IXosModelDefsField[], modelName: string): IXosTableColumn[] {
 
     const columns =  _.map(fields, (f) => {
       if (this.excluded_fields.indexOf(f.name) > -1) {
@@ -128,8 +133,9 @@
       };
 
       if (f.name === 'id' || f.name === 'name') {
+        col.link = item => this.stateWithParams(modelName, item);
         // NOTE can we find a better method to generalize the route?
-        col.link = item => `#/core${baseUrl.replace(':id?', item.id)}`;
+        // col.link = item => `#/core${baseUrl.replace(':id?', item.id)}`;
       }
 
       // if the field identify a relation, create a link
@@ -140,7 +146,8 @@
           this.populateRelated(item, item[f.name], f);
           return item[f.name];
         };
-        col.link = item => `#${this.urlFromCoreModel(f.relation.model)}/${item[f.name]}`;
+        col.link = item => this.stateWithParams(f.relation.model, item);
+        // col.link = item => `#${this.urlFromCoreModel(f.relation.model)}/${item[f.name]}`;
       }
 
       if (f.name === 'backend_status') {
@@ -166,9 +173,25 @@
   };
 
   public urlFromCoreModel(name: string): string {
+
     return `/core/${this.pluralize(name.toLowerCase())}`;
   }
 
+  public stateFromCoreModel(name: string): string {
+    const state: ng.ui.IState = _.find(this.$state.get(), (s: IXosState) => {
+      if (s.data) {
+        return s.data.model === name;
+      }
+      return false;
+    });
+    return state.name;
+  }
+
+  public stateWithParams(name: string, model: any): string {
+    const state = this.stateFromCoreModel(name);
+    return `${state}({id: ${model['id']}})`;
+  }
+
   public modelFieldToInputCfg(fields: IXosModelDefsField[]): IXosFormInput[] {
 
     return _.map(fields, (f: IXosModelDefsField) => {