From: Bill Erickson Date: Thu, 5 Jul 2018 15:06:20 +0000 (-0400) Subject: LP#1775466 move format svc to core w/ unit tests; root inject core svcs X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=f4eea345a247f77f18dba1f6fffb5fa1d564127a;p=working%2FEvergreen.git LP#1775466 move format svc to core w/ unit tests; root inject core svcs Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/eg2/src/app/common.module.ts b/Open-ILS/src/eg2/src/app/common.module.ts index 48e19d9f0f..c83ad392bc 100644 --- a/Open-ILS/src/eg2/src/app/common.module.ts +++ b/Open-ILS/src/eg2/src/app/common.module.ts @@ -7,16 +7,13 @@ import {RouterModule} from '@angular/router'; import {FormsModule} from '@angular/forms'; import {NgbModule} from '@ng-bootstrap/ng-bootstrap'; -import {EventService} from '@eg/core/event.service'; -import {StoreService} from '@eg/core/store.service'; -import {IdlService} from '@eg/core/idl.service'; -import {NetService} from '@eg/core/net.service'; -import {AuthService} from '@eg/core/auth.service'; -import {PermService} from '@eg/core/perm.service'; -import {PcrudService} from '@eg/core/pcrud.service'; -import {OrgService} from '@eg/core/org.service'; -import {AudioService} from '@eg/share/util/audio.service'; -import {FormatService} from '@eg/share/util/format.service'; +/* +Note core services are injected into 'root'. +They do not have to be added to the providers list. +*/ + +// consider moving these to core... +import {FormatService} from '@eg/core/format.service'; import {PrintService} from '@eg/share/print/print.service'; // Globally available components @@ -65,16 +62,7 @@ export class EgCommonModule { providers: [ DatePipe, CurrencyPipe, - EventService, - StoreService, - IdlService, - NetService, - AuthService, - PermService, - PcrudService, - OrgService, PrintService, - AudioService, FormatService ] }; diff --git a/Open-ILS/src/eg2/src/app/core/auth.service.ts b/Open-ILS/src/eg2/src/app/core/auth.service.ts index 1de67dbbee..7d58dda0ef 100644 --- a/Open-ILS/src/eg2/src/app/core/auth.service.ts +++ b/Open-ILS/src/eg2/src/app/core/auth.service.ts @@ -37,7 +37,7 @@ export enum AuthWsState { VALID } -@Injectable() +@Injectable({providedIn: 'root'}) export class AuthService { private authChannel: any; diff --git a/Open-ILS/src/eg2/src/app/core/event.service.ts b/Open-ILS/src/eg2/src/app/core/event.service.ts index 638ba96376..0bbf60bdb7 100644 --- a/Open-ILS/src/eg2/src/app/core/event.service.ts +++ b/Open-ILS/src/eg2/src/app/core/event.service.ts @@ -24,7 +24,7 @@ export class EgEvent { } } -@Injectable() +@Injectable({providedIn: 'root'}) export class EventService { /** diff --git a/Open-ILS/src/eg2/src/app/core/format.service.ts b/Open-ILS/src/eg2/src/app/core/format.service.ts new file mode 100644 index 0000000000..f8bf0d908d --- /dev/null +++ b/Open-ILS/src/eg2/src/app/core/format.service.ts @@ -0,0 +1,102 @@ +import {Injectable} from '@angular/core'; +import {DatePipe, CurrencyPipe} from '@angular/common'; +import {IdlService, IdlObject} from '@eg/core/idl.service'; +import {OrgService} from '@eg/core/org.service'; + +/** + * Format IDL vield values for display. + */ + +declare var OpenSRF; + +export interface FormatParams { + value: any; + idlClass?: string; + idlField?: string; + datatype?: string; + orgField?: string; // 'shortname' || 'name' + datePlusTime?: boolean; +} + +@Injectable({providedIn: 'root'}) +export class FormatService { + + dateFormat = 'shortDate'; + dateTimeFormat = 'short'; + wsOrgTimezone: string = OpenSRF.tz; + + constructor( + private datePipe: DatePipe, + private currencyPipe: CurrencyPipe, + private idl: IdlService, + private org: OrgService + ) { + + // Create an inilne polyfill for Number.isNaN, which is + // not available in PhantomJS for unit testing. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN + if (!Number.isNaN) { + // "The following works because NaN is the only value + // in javascript which is not equal to itself." + Number.isNaN = (value: any) => { + return value !== value; + }; + } + } + + /** + * Create a human-friendly display version of any field type. + */ + transform(params: FormatParams): string { + const value = params.value; + + if ( value === undefined + || value === null + || value === '' + || Number.isNaN(value)) { + return ''; + } + + let datatype = params.datatype; + + if (!datatype) { + if (params.idlClass && params.idlField) { + datatype = this.idl.classes[params.idlClass] + .field_map[params.idlField].datatype; + } else { + // Assume it's a primitive value + return value + ''; + } + } + + switch (datatype) { + + case 'org_unit': + const orgField = params.orgField || 'shortname'; + const org = this.org.get(value); + return org ? org[orgField]() : ''; + + case 'timestamp': + const date = new Date(value); + let fmt = this.dateFormat || 'shortDate'; + if (params.datePlusTime) { + fmt = this.dateTimeFormat || 'short'; + } + return this.datePipe.transform(date, fmt); + + case 'money': + return this.currencyPipe.transform(value); + + case 'bool': + // Slightly better than a bare 't' or 'f'. + // Should probably add a global true/false string. + return Boolean( + value === 't' || value === 1 || value === '1' + ).toString(); + + default: + return value + ''; + } + } +} + diff --git a/Open-ILS/src/eg2/src/app/core/format.spec.ts b/Open-ILS/src/eg2/src/app/core/format.spec.ts new file mode 100644 index 0000000000..05991df68f --- /dev/null +++ b/Open-ILS/src/eg2/src/app/core/format.spec.ts @@ -0,0 +1,90 @@ +import {DatePipe, CurrencyPipe} from '@angular/common'; +import {IdlService} from './idl.service'; +import {EventService} from './event.service'; +import {NetService} from './net.service'; +import {AuthService} from './auth.service'; +import {PcrudService} from './pcrud.service'; +import {StoreService} from './store.service'; +import {OrgService} from './org.service'; +import {FormatService} from './format.service'; + + +describe('FormatService', () => { + + let currencyPipe: CurrencyPipe; + let datePipe: DatePipe; + let idlService: IdlService; + let netService: NetService; + let authService: AuthService; + let pcrudService: PcrudService; + let orgService: OrgService; + let evtService: EventService; + let storeService: StoreService; + let service: FormatService; + + beforeEach(() => { + currencyPipe = new CurrencyPipe('en'); + datePipe = new DatePipe('en'); + idlService = new IdlService(); + evtService = new EventService(); + storeService = new StoreService(null /* CookieService */); + netService = new NetService(evtService); + authService = new AuthService(evtService, netService, storeService); + pcrudService = new PcrudService(idlService, netService, authService); + orgService = new OrgService(netService, authService, pcrudService); + service = new FormatService( + datePipe, + currencyPipe, + idlService, + orgService + ); + }); + + const initTestData = () => { + idlService.parseIdl(); + const win: any = window; // trick TS + win._eg_mock_data.generateOrgTree(idlService, orgService); + }; + + it('should format an org unit name', () => { + initTestData(); + const str = service.transform({ + value: orgService.root(), + datatype: 'org_unit', + orgField: 'shortname' // currently the default + }); + expect(str).toBe('ROOT'); // from eg_mock.js + }); + + it('should format a date', () => { + initTestData(); + const str = service.transform({ + value: new Date(2018, 6, 5), + datatype: 'timestamp', + }); + expect(str).toBe('7/5/18'); + }); + + it('should format a date plus time', () => { + initTestData(); + const str = service.transform({ + value: new Date(2018, 6, 5, 12, 30, 1), + datatype: 'timestamp', + datePlusTime: true + }); + expect(str).toBe('7/5/18, 12:30 PM'); + }); + + + + it('should format money', () => { + initTestData(); + const str = service.transform({ + value: '12.1', + datatype: 'money' + }); + expect(str).toBe('$12.10'); + }); + +}); + diff --git a/Open-ILS/src/eg2/src/app/core/idl.service.ts b/Open-ILS/src/eg2/src/app/core/idl.service.ts index 3f9bbe8204..95a92a4d82 100644 --- a/Open-ILS/src/eg2/src/app/core/idl.service.ts +++ b/Open-ILS/src/eg2/src/app/core/idl.service.ts @@ -14,7 +14,7 @@ export interface IdlObject { [fields: string]: any; } -@Injectable() +@Injectable({providedIn: 'root'}) export class IdlService { classes: any = {}; // IDL class metadata diff --git a/Open-ILS/src/eg2/src/app/core/net.service.ts b/Open-ILS/src/eg2/src/app/core/net.service.ts index df3cb3e6e9..3c3435b215 100644 --- a/Open-ILS/src/eg2/src/app/core/net.service.ts +++ b/Open-ILS/src/eg2/src/app/core/net.service.ts @@ -68,7 +68,7 @@ export interface AuthExpiredEvent { viaExternal?: boolean; } -@Injectable() +@Injectable({providedIn: 'root'}) export class NetService { permFailed$: EventEmitter; diff --git a/Open-ILS/src/eg2/src/app/core/org.service.ts b/Open-ILS/src/eg2/src/app/core/org.service.ts index 57cbf6f26d..38faaffbaf 100644 --- a/Open-ILS/src/eg2/src/app/core/org.service.ts +++ b/Open-ILS/src/eg2/src/app/core/org.service.ts @@ -19,7 +19,7 @@ interface OrgSettingsBatch { [key: string]: any; } -@Injectable() +@Injectable({providedIn: 'root'}) export class OrgService { private orgList: IdlObject[] = []; diff --git a/Open-ILS/src/eg2/src/app/core/pcrud.service.ts b/Open-ILS/src/eg2/src/app/core/pcrud.service.ts index ea1dabc551..76ee341653 100644 --- a/Open-ILS/src/eg2/src/app/core/pcrud.service.ts +++ b/Open-ILS/src/eg2/src/app/core/pcrud.service.ts @@ -251,7 +251,7 @@ export class PcrudContext { } } -@Injectable() +@Injectable({providedIn: 'root'}) export class PcrudService { constructor( diff --git a/Open-ILS/src/eg2/src/app/core/perm.service.ts b/Open-ILS/src/eg2/src/app/core/perm.service.ts index 774c045f33..44d3c635fb 100644 --- a/Open-ILS/src/eg2/src/app/core/perm.service.ts +++ b/Open-ILS/src/eg2/src/app/core/perm.service.ts @@ -11,7 +11,7 @@ interface HasPermHereResult { [permName: string]: boolean; } -@Injectable() +@Injectable({providedIn: 'root'}) export class PermService { constructor( diff --git a/Open-ILS/src/eg2/src/app/core/store.service.ts b/Open-ILS/src/eg2/src/app/core/store.service.ts index 0a20ca82db..5a78f840f7 100644 --- a/Open-ILS/src/eg2/src/app/core/store.service.ts +++ b/Open-ILS/src/eg2/src/app/core/store.service.ts @@ -4,7 +4,7 @@ import {Injectable} from '@angular/core'; import {CookieService} from 'ngx-cookie'; -@Injectable() +@Injectable({providedIn: 'root'}) export class StoreService { // Base path for cookie-based storage. diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid.component.ts b/Open-ILS/src/eg2/src/app/share/grid/grid.component.ts index a91e3d2392..dc041349be 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid.component.ts +++ b/Open-ILS/src/eg2/src/app/share/grid/grid.component.ts @@ -4,7 +4,7 @@ import {Subscription} from 'rxjs/Subscription'; import {IdlService} from '@eg/core/idl.service'; import {OrgService} from '@eg/core/org.service'; import {StoreService} from '@eg/core/store.service'; -import {FormatService} from '@eg/share/util/format.service'; +import {FormatService} from '@eg/core/format.service'; import {GridContext, GridColumn, GridDataSource, GridRowFlairEntry} from './grid'; /** diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid.ts b/Open-ILS/src/eg2/src/app/share/grid/grid.ts index 18c580c62a..c395687379 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid.ts +++ b/Open-ILS/src/eg2/src/app/share/grid/grid.ts @@ -7,7 +7,7 @@ import {Subscription} from 'rxjs/Subscription'; import {IdlService, IdlObject} from '@eg/core/idl.service'; import {OrgService} from '@eg/core/org.service'; import {StoreService} from '@eg/core/store.service'; -import {FormatService} from '@eg/share/util/format.service'; +import {FormatService} from '@eg/core/format.service'; import {Pager} from '@eg/share/util/pager'; const MAX_ALL_ROW_COUNT = 10000; diff --git a/Open-ILS/src/eg2/src/app/share/util/format.service.ts b/Open-ILS/src/eg2/src/app/share/util/format.service.ts deleted file mode 100644 index 33d3253370..0000000000 --- a/Open-ILS/src/eg2/src/app/share/util/format.service.ts +++ /dev/null @@ -1,90 +0,0 @@ -import {Injectable} from '@angular/core'; -import {DatePipe, CurrencyPipe} from '@angular/common'; -import {IdlService, IdlObject} from '@eg/core/idl.service'; -import {OrgService} from '@eg/core/org.service'; - -/** - * Format IDL vield values for display. - */ - -declare var OpenSRF; - -export interface FormatParams { - value: any; - idlClass?: string; - idlField?: string; - datatype?: string; - orgField?: string; // 'shortname' || 'name' - datePlusTime?: boolean; -} - -@Injectable() -export class FormatService { - - dateFormat = 'shortDate'; - dateTimeFormat = 'short'; - wsOrgTimezone: string = OpenSRF.tz; - - constructor( - private datePipe: DatePipe, - private currencyPipe: CurrencyPipe, - private idl: IdlService, - private org: OrgService - ) {} - - /** - * Create a human-friendly display version of any field type. - */ - transform(params: FormatParams): string { - const value = params.value; - - if ( value === undefined - || value === null - || value === '' - || Number.isNaN(value)) { - return ''; - } - - let datatype = params.datatype; - - if (!datatype) { - if (params.idlClass && params.idlField) { - datatype = this.idl.classes[params.idlClass] - .field_map[params.idlField].datatype; - } else { - // Assume it's a primitive value - return value + ''; - } - } - - switch (datatype) { - - case 'org_unit': - const orgField = params.orgField || 'shortname'; - const org = this.org.get(value); - return org ? org[orgField]() : ''; - - case 'timestamp': - const date = new Date(value); - let fmt = this.dateFormat || 'shortDate'; - if (params.datePlusTime) { - fmt = this.dateTimeFormat || 'short'; - } - return this.datePipe.transform(date, fmt); - - case 'money': - return this.currencyPipe.transform(value); - - case 'bool': - // Slightly better than a bare 't' or 'f'. - // Should probably add a global true/false string. - return Boolean( - value === 't' || value === 1 || value === '1' - ).toString(); - - default: - return value + ''; - } - } -} - diff --git a/Open-ILS/src/eg2/src/app/staff/common.module.ts b/Open-ILS/src/eg2/src/app/staff/common.module.ts index 986a19a56b..da3bc320e1 100644 --- a/Open-ILS/src/eg2/src/app/staff/common.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/common.module.ts @@ -1,5 +1,6 @@ import {NgModule, ModuleWithProviders} from '@angular/core'; import {EgCommonModule} from '@eg/common.module'; +import {AudioService} from '@eg/share/util/audio.service'; import {StaffBannerComponent} from './share/staff-banner.component'; import {ComboboxComponent} from '@eg/share/combobox/combobox.component'; import {ComboboxEntryComponent} from '@eg/share/combobox/combobox-entry.component'; @@ -58,6 +59,7 @@ export class StaffCommonModule { ngModule: StaffCommonModule, providers: [ // Export staff-wide services AccessKeyService, + AudioService, StringService, ToastService ] diff --git a/Open-ILS/src/eg2/src/app/staff/login.component.ts b/Open-ILS/src/eg2/src/app/staff/login.component.ts index a5f2aa0a39..b8e1b95d89 100644 --- a/Open-ILS/src/eg2/src/app/staff/login.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/login.component.ts @@ -57,7 +57,11 @@ export class StaffLoginComponent implements OnInit { handleSubmit() { // post-login URL - const url: string = this.auth.redirectUrl || '/staff/splash'; + let url: string = this.auth.redirectUrl || '/staff/splash'; + + // prevent sending the user back to the login page. + if (url.startsWith('/staff/login')) { url = '/staff/splash'; } + const workstation: string = this.args.workstation; this.auth.login(this.args).then( diff --git a/Open-ILS/src/eg2/src/app/staff/resolver.service.ts b/Open-ILS/src/eg2/src/app/staff/resolver.service.ts index 254d03bd28..2b532c325d 100644 --- a/Open-ILS/src/eg2/src/app/staff/resolver.service.ts +++ b/Open-ILS/src/eg2/src/app/staff/resolver.service.ts @@ -10,7 +10,7 @@ import {NetService} from '@eg/core/net.service'; import {AuthService, AuthWsState} from '@eg/core/auth.service'; import {PermService} from '@eg/core/perm.service'; import {OrgService} from '@eg/core/org.service'; -import {FormatService} from '@eg/share/util/format.service'; +import {FormatService} from '@eg/core/format.service'; const LOGIN_PATH = '/staff/login'; const WS_MANAGE_PATH = '/staff/admin/workstation/workstations/manage'; diff --git a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html index dbcd3062c0..db47b59a7e 100644 --- a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html +++ b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html @@ -49,7 +49,7 @@ [entries]="cbEntries">
-
diff --git a/Open-ILS/src/eg2/src/test_data/eg_mock.js b/Open-ILS/src/eg2/src/test_data/eg_mock.js index 54e4eae722..3db357974f 100644 --- a/Open-ILS/src/eg2/src/test_data/eg_mock.js +++ b/Open-ILS/src/eg2/src/test_data/eg_mock.js @@ -24,6 +24,7 @@ window._eg_mock_data = { var org1 = idlService.create('aou'); org1.id(1); org1.ou_type(type1); + org1.shortname('ROOT'); var org2 = idlService.create('aou'); org2.id(2);