Populating select field in forms

Change-Id: I78306706c4ad9560286d27fa1c2879916eb07614
diff --git a/src/app/core/form/form.ts b/src/app/core/form/form.ts
index 6713fe7..34b0287 100644
--- a/src/app/core/form/form.ts
+++ b/src/app/core/form/form.ts
@@ -28,11 +28,17 @@
     // alternatively you can return an array [errorName, true|false]
 }
 
+export interface IXosFormInputOptions {
+  id: number;
+  label: string;
+}
+
 export interface IXosFormInput {
   name: string;
   label: string;
   type: string; // options are: [date, boolean, number, email, string, select],
   validators: IXosFormInputValidator;
+  options?: IXosFormInputOptions[];
 }
 
 export interface IXosFormConfig {
diff --git a/src/app/core/header/header.ts b/src/app/core/header/header.ts
index 2aef872..a7cba72 100644
--- a/src/app/core/header/header.ts
+++ b/src/app/core/header/header.ts
@@ -59,9 +59,7 @@
         }
         return list;
       }, []);
-      console.log(this.states.length);
       this.states = _.uniqBy(this.states, 'state');
-      console.log(this.states.length);
     }, 500);
 
     // listen for keypress
diff --git a/src/app/core/services/helpers/config.helpers.spec.ts b/src/app/core/services/helpers/config.helpers.spec.ts
index 28ba22b..eca43d9 100644
--- a/src/app/core/services/helpers/config.helpers.spec.ts
+++ b/src/app/core/services/helpers/config.helpers.spec.ts
@@ -2,10 +2,11 @@
 import 'angular-mocks';
 import 'angular-ui-router';
 
-import {IXosConfigHelpersService, ConfigHelpers} from './config.helpers';
+import {IXosConfigHelpersService, ConfigHelpers, IXosModelDefsField} from './config.helpers';
 import {IModeldef} from '../../../datasources/rest/modeldefs.rest';
 import {IXosTableCfg} from '../../table/table';
 import {IXosFormInput, IXosFormConfig} from '../../form/form';
+import {BehaviorSubject} from 'rxjs';
 
 let service: IXosConfigHelpersService;
 
@@ -185,5 +186,62 @@
       expect(config.inputs.length).toBe(4);
     });
   });
+
+  describe('the private methods', () => {
+    let modelStoreMock, toastr, auth;
+
+    beforeEach(angular.mock.inject((_toastr_, AuthService) => {
+      modelStoreMock = {
+        query: () => {
+          const subject = new BehaviorSubject([
+            {id: 1, humanReadableName: 'test'},
+            {id: 2, humanReadableName: 'second'}
+          ]);
+          return subject.asObservable();
+        }
+      };
+      toastr = _toastr_;
+      auth = AuthService;
+    }));
+
+    const field: IXosModelDefsField = {
+      name: 'test',
+      type: 'number',
+      relation: {
+        model: 'Test',
+        type: 'many_to_one'
+      }
+    };
+
+    describe('the populateRelated method', () => {
+      const item = {
+        test: 2
+      };
+      it('should add the formatted data to the column definition', () => {
+        service = new ConfigHelpers(toastr, auth, modelStoreMock);
+        service['populateRelated'](item, item.test, field);
+        expect(item['test-formatted']).toBe('second');
+      });
+    });
+
+    describe('the populateSelectField', () => {
+
+      const input: IXosFormInput = {
+        name: 'test',
+        label: 'Test',
+        type: 'select',
+        validators: {}
+      };
+
+      it('should add the available choice to the select', () => {
+        service = new ConfigHelpers(toastr, auth, modelStoreMock);
+        service['populateSelectField'](field, input);
+        expect(input.options).toEqual([
+          {id: 1, label: 'test'},
+          {id: 2, label: 'second'}
+        ]);
+      });
+    });
+  });
 });
 
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index b2d966a..93ae064 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -172,6 +172,17 @@
   public modelFieldToInputCfg(fields: IXosModelDefsField[]): IXosFormInput[] {
 
     return _.map(fields, f => {
+      if (f.relation) {
+        const input = {
+          name: f.name,
+          label: this.toLabel(f.name),
+          type: 'select',
+          validators: f.validators
+        };
+        this.populateSelectField(f, input);
+        return input;
+      }
+
       return {
         name: f.name,
         label: this.toLabel(f.name),
@@ -248,4 +259,14 @@
         }
       });
   }
+
+  // augment a select field with related model informations
+  private populateSelectField(field: IXosModelDefsField, input: IXosFormInput): void {
+    this.ModelStore.query(field.relation.model)
+      .subscribe(res => {
+        input.options = _.map(res, item => {
+          return {id: item.id, label: item.humanReadableName ? item.humanReadableName : item.name};
+        });
+      });
+  }
 }
diff --git a/src/app/datasources/helpers/store.helpers.spec.ts b/src/app/datasources/helpers/store.helpers.spec.ts
index 82a5e7a..4e45070 100644
--- a/src/app/datasources/helpers/store.helpers.spec.ts
+++ b/src/app/datasources/helpers/store.helpers.spec.ts
@@ -43,6 +43,11 @@
   it('should convert a core model name in an URL', () => {
     expect(service.urlFromCoreModel('Slice')).toBe('/core/slices');
     expect(service.urlFromCoreModel('Xos')).toBe('/core/xosses');
+
+    // handling exceptions
+    expect(service.urlFromCoreModel('SiteRole')).toBe('/core/site_roles');
+    expect(service.urlFromCoreModel('SliceRole')).toBe('/core/slice_roles');
+    expect(service.urlFromCoreModel('SlicePrivilege')).toBe('/core/slice_privileges');
   });
 
   describe('when updating a collection', () => {
diff --git a/src/app/datasources/helpers/store.helpers.ts b/src/app/datasources/helpers/store.helpers.ts
index aa18bd8..7792590 100644
--- a/src/app/datasources/helpers/store.helpers.ts
+++ b/src/app/datasources/helpers/store.helpers.ts
@@ -18,7 +18,15 @@
   }
 
   public urlFromCoreModel(name: string): string {
-    return `/core/${pluralize(name.toLowerCase())}`;
+    switch (name) {
+      // FIXME handling exceptions, understand why these 3 endpoints are autogenerated with an _f
+      case 'SiteRole':
+      case 'SliceRole':
+      case 'SlicePrivilege':
+        return `/core/${pluralize(name.split(/(?=[A-Z])/).map(w => w.toLowerCase()).join('_'))}`;
+      default:
+        return `/core/${pluralize(name.toLowerCase())}`;
+    }
   }
 
   public updateCollection(event: IWSEvent, subject: BehaviorSubject<any>): BehaviorSubject<any> {