Adding relations links to table
Change-Id: I5dd2d206a6da7fec163342f54f1143a7783f7758
diff --git a/src/app/core/nav/nav.spec.ts b/src/app/core/nav/nav.spec.ts
index 3c18e4d..28cd3e1 100644
--- a/src/app/core/nav/nav.spec.ts
+++ b/src/app/core/nav/nav.spec.ts
@@ -19,7 +19,9 @@
};
const AuthMock = {
- logout: jasmine.createSpy('logout')
+ logout: jasmine.createSpy('logout').and.returnValue({then: () => {
+ return;
+ }})
};
describe('Nav component', () => {
diff --git a/src/app/core/nav/nav.ts b/src/app/core/nav/nav.ts
index 31831e1..6c26635 100644
--- a/src/app/core/nav/nav.ts
+++ b/src/app/core/nav/nav.ts
@@ -56,7 +56,10 @@
}
logout() {
- this.authService.logout();
+ this.authService.logout()
+ .then(() => {
+ this.$state.go('login');
+ });
}
}
diff --git a/src/app/core/services/helpers/config.helpers.spec.ts b/src/app/core/services/helpers/config.helpers.spec.ts
index b39f444..28ba22b 100644
--- a/src/app/core/services/helpers/config.helpers.spec.ts
+++ b/src/app/core/services/helpers/config.helpers.spec.ts
@@ -57,6 +57,9 @@
getUser: () => {
return {id: 1};
}
+ })
+ .value('ModelStore', {
+
});
angular.mock.module('test');
});
@@ -182,10 +185,5 @@
expect(config.inputs.length).toBe(4);
});
});
-
- it('should convert a core model name in an URL', () => {
- expect(service.urlFromCoreModel('Slice')).toBe('/core/slices');
- expect(service.urlFromCoreModel('Xos')).toBe('/core/xosses');
- });
});
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index 1df2662..b2d966a 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -4,11 +4,17 @@
import {IModeldef} from '../../../datasources/rest/modeldefs.rest';
import {IXosFormConfig, IXosFormInput} from '../../form/form';
import {IXosAuthService} from '../../../datasources/rest/auth.rest';
+import {IModelStoreService} from '../../../datasources/stores/model.store';
export interface IXosModelDefsField {
name: string;
type: string;
validators?: any;
+ hint?: string;
+ relation?: {
+ model: string;
+ type: string;
+ };
}
export interface IXosConfigHelpersService {
@@ -20,10 +26,10 @@
pluralize(string: string, quantity?: number, count?: boolean): string;
toLabel(string: string, pluralize?: boolean): string;
toLabels(string: string[], pluralize?: boolean): string[];
- urlFromCoreModel(name: string): string;
}
export class ConfigHelpers {
+ static $inject = ['toastr', 'AuthService', 'ModelStore'];
excluded_fields = [
'created',
@@ -46,7 +52,8 @@
constructor(
private toastr: ng.toastr.IToastrService,
- private AuthService: IXosAuthService
+ private AuthService: IXosAuthService,
+ private ModelStore: IModelStoreService
) {
pluralize.addIrregularRule('xos', 'xosses');
pluralize.addPluralRule(/slice$/i, 'slices');
@@ -125,6 +132,17 @@
col.link = item => `#/core${baseUrl.replace(':id?', item.id)}`;
}
+ // if the field identify a relation, create a link
+ if (f.relation && f.relation.type === 'many_to_one') {
+ // TODO read the related model name and replace the value, use the xosTable format method?
+ col.type = 'custom';
+ col.formatter = item => {
+ this.populateRelated(item, item[f.name], f);
+ return item[f.name];
+ };
+ col.link = item => `#${this.urlFromCoreModel(f.relation.model)}/${item[f.name]}`;
+ }
+
if (f.name === 'backend_status') {
col.type = 'icon';
col.formatter = (item) => {
@@ -214,4 +232,20 @@
private capitalizeFirst(string: string): string {
return string.slice(0, 1).toUpperCase() + string.slice(1);
}
+
+ private populateRelated(item: any, fk: string, field: IXosModelDefsField): any {
+ // if the relation is not defined return
+ if (!fk || angular.isUndefined(fk) || fk === null) {
+ return;
+ }
+ this.ModelStore.query(field.relation.model)
+ .subscribe(res => {
+ if (angular.isDefined(res) && angular.isDefined(fk)) {
+ let ri = _.find(res, {id: fk});
+ if (angular.isDefined(ri)) {
+ item[`${field.name}-formatted`] = angular.isDefined(ri.name) ? ri.name : ri.humanReadableName;
+ }
+ }
+ });
+ }
}
diff --git a/src/app/core/table/table.html b/src/app/core/table/table.html
index 382dbec..788e84c 100644
--- a/src/app/core/table/table.html
+++ b/src/app/core/table/table.html
@@ -71,7 +71,8 @@
</dl>
</span>
<span ng-if="col.type === 'custom'">
- {{col.formatter(item)}}
+ {{item[col.prop + '-formatted']}}
+ <i class="ng-hide">{{col.formatter(item)}}</i>
</span>
<span ng-if="col.type === 'icon'">
<i class="fa fa-{{col.formatter(item)}}">
diff --git a/src/app/datasources/helpers/store.helpers.spec.ts b/src/app/datasources/helpers/store.helpers.spec.ts
index 1793a7c..82a5e7a 100644
--- a/src/app/datasources/helpers/store.helpers.spec.ts
+++ b/src/app/datasources/helpers/store.helpers.spec.ts
@@ -39,6 +39,12 @@
expect(service.updateCollection).toBeDefined();
});
+
+ it('should convert a core model name in an URL', () => {
+ expect(service.urlFromCoreModel('Slice')).toBe('/core/slices');
+ expect(service.urlFromCoreModel('Xos')).toBe('/core/xosses');
+ });
+
describe('when updating a collection', () => {
beforeEach(() => {
diff --git a/src/app/datasources/helpers/store.helpers.ts b/src/app/datasources/helpers/store.helpers.ts
index 1458d81..aa18bd8 100644
--- a/src/app/datasources/helpers/store.helpers.ts
+++ b/src/app/datasources/helpers/store.helpers.ts
@@ -1,22 +1,26 @@
import {BehaviorSubject} from 'rxjs';
import * as _ from 'lodash';
+import * as pluralize from 'pluralize';
import {IWSEvent} from '../websocket/global';
import {IXosResourceService} from '../rest/model.rest';
-import {IXosConfigHelpersService} from '../../core/services/helpers/config.helpers';
export interface IStoreHelpersService {
+ urlFromCoreModel(name: string): string;
updateCollection(event: IWSEvent, subject: BehaviorSubject<any>): BehaviorSubject<any>;
}
export class StoreHelpers {
- static $inject = ['ConfigHelpers', 'ModelRest'];
+ static $inject = ['ModelRest'];
constructor (
- private configHelpers: IXosConfigHelpersService,
private modelRest: IXosResourceService
) {
}
+ public urlFromCoreModel(name: string): string {
+ return `/core/${pluralize(name.toLowerCase())}`;
+ }
+
public updateCollection(event: IWSEvent, subject: BehaviorSubject<any>): BehaviorSubject<any> {
const collection: any[] = subject.value;
const index: number = _.findIndex(collection, (i) => {
@@ -27,7 +31,7 @@
const isDeleted: boolean = _.includes(event.msg.changed_fields, 'deleted');
// generate a resource for the model
- const endpoint = this.configHelpers.urlFromCoreModel(event.model);
+ const endpoint = this.urlFromCoreModel(event.model);
const resource = this.modelRest.getResource(endpoint);
const model = new resource(event.msg.object);
diff --git a/src/app/datasources/stores/model.store.ts b/src/app/datasources/stores/model.store.ts
index 21f42ac..fdcac63 100644
--- a/src/app/datasources/stores/model.store.ts
+++ b/src/app/datasources/stores/model.store.ts
@@ -4,25 +4,23 @@
import {IWSEvent, IWSEventService} from '../websocket/global';
import {IXosResourceService} from '../rest/model.rest';
import {IStoreHelpersService} from '../helpers/store.helpers';
-import {IXosConfigHelpersService} from '../../core/services/helpers/config.helpers';
export interface IModelStoreService {
query(model: string): Observable<any>;
}
export class ModelStore {
- static $inject = ['WebSocket', 'StoreHelpers', 'ModelRest', 'ConfigHelpers'];
+ static $inject = ['WebSocket', 'StoreHelpers', 'ModelRest'];
private _collections: any; // NOTE contains a map of {model: BehaviourSubject}
constructor(
private webSocket: IWSEventService,
private storeHelpers: IStoreHelpersService,
private ModelRest: IXosResourceService,
- private ConfigHelpers: IXosConfigHelpersService
) {
this._collections = {};
}
- query(model: string) {
+ public query(model: string) {
// if there isn't already an observable for that item
if (!this._collections[model]) {
this._collections[model] = new BehaviorSubject([]); // NOTE maybe this can be created when we get response from the resource
@@ -41,9 +39,13 @@
return this._collections[model].asObservable();
}
+ public get(model: string, id: number) {
+ // TODO implement a get method
+ }
+
private loadInitialData(model: string) {
// NOTE check what is the correct pattern to pluralize this
- const endpoint = this.ConfigHelpers.urlFromCoreModel(model);
+ const endpoint = this.storeHelpers.urlFromCoreModel(model);
this.ModelRest.getResource(endpoint).query().$promise
.then(
res => {
diff --git a/src/app/views/crud/crud.ts b/src/app/views/crud/crud.ts
index f3cc1fa..4c41104 100644
--- a/src/app/views/crud/crud.ts
+++ b/src/app/views/crud/crud.ts
@@ -4,6 +4,7 @@
import * as _ from 'lodash';
import {IXosFormConfig} from '../../core/form/form';
import {IXosResourceService} from '../../datasources/rest/model.rest';
+import {IStoreHelpersService} from '../../datasources/helpers/store.helpers';
export interface IXosCrudData {
model: string;
related: string[];
@@ -12,7 +13,7 @@
}
class CrudController {
- static $inject = ['$scope', '$state', '$stateParams', 'ModelStore', 'ConfigHelpers', 'ModelRest'];
+ static $inject = ['$scope', '$state', '$stateParams', 'ModelStore', 'ConfigHelpers', 'ModelRest', 'StoreHelpers'];
public data: IXosCrudData;
public tableCfg: IXosTableCfg;
@@ -31,7 +32,8 @@
private $stateParams: ng.ui.IStateParamsService,
private store: IModelStoreService,
private ConfigHelpers: IXosConfigHelpersService,
- private ModelRest: IXosResourceService
+ private ModelRest: IXosResourceService,
+ private StoreHelpers: IStoreHelpersService
) {
this.data = this.$state.current.data;
this.tableCfg = this.data.xosTableCfg;
@@ -68,7 +70,7 @@
// if it is the create page
if ($stateParams['id'] === 'add') {
// generate a resource for an empty model
- const endpoint = this.ConfigHelpers.urlFromCoreModel(this.data.model);
+ const endpoint = this.StoreHelpers.urlFromCoreModel(this.data.model);
const resource = this.ModelRest.getResource(endpoint);
this.model = new resource({});
}
diff --git a/src/index.ts b/src/index.ts
index ca6ca34..c23c075 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -29,6 +29,7 @@
import {IXosConfigHelpersService} from './app/core/services/helpers/config.helpers';
import {StyleConfig} from './app/config/style.config';
import {IXosResourceService} from './app/datasources/rest/model.rest';
+import {IXosAuthService} from './app/datasources/rest/auth.rest';
export interface IXosState extends angular.ui.IState {
data: IXosCrudData;
@@ -68,10 +69,19 @@
RuntimeStates: IRuntimeStatesService,
NavigationService: IXosNavigationService,
ConfigHelpers: IXosConfigHelpersService,
+ AuthService: IXosAuthService,
+ $transitions: any,
toastr: ng.toastr.IToastrService,
PageTitle: IXosPageTitleService
) => {
+ // check the user login
+ $transitions.onSuccess({ to: '**' }, (transtion) => {
+ if (!AuthService.getUser()) {
+ $state.go('login');
+ }
+ });
+
// save the last visited state before reload
const lastRoute = window.location.hash.replace('#', '');