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
providers: [
DatePipe,
CurrencyPipe,
- EventService,
- StoreService,
- IdlService,
- NetService,
- AuthService,
- PermService,
- PcrudService,
- OrgService,
PrintService,
- AudioService,
FormatService
]
};
VALID
}
-@Injectable()
+@Injectable({providedIn: 'root'})
export class AuthService {
private authChannel: any;
}
}
-@Injectable()
+@Injectable({providedIn: 'root'})
export class EventService {
/**
--- /dev/null
+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 + '';
+ }
+ }
+}
+
--- /dev/null
+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');
+ });
+
+});
+
[fields: string]: any;
}
-@Injectable()
+@Injectable({providedIn: 'root'})
export class IdlService {
classes: any = {}; // IDL class metadata
viaExternal?: boolean;
}
-@Injectable()
+@Injectable({providedIn: 'root'})
export class NetService {
permFailed$: EventEmitter<NetRequest>;
[key: string]: any;
}
-@Injectable()
+@Injectable({providedIn: 'root'})
export class OrgService {
private orgList: IdlObject[] = [];
}
}
-@Injectable()
+@Injectable({providedIn: 'root'})
export class PcrudService {
constructor(
[permName: string]: boolean;
}
-@Injectable()
+@Injectable({providedIn: 'root'})
export class PermService {
constructor(
import {Injectable} from '@angular/core';
import {CookieService} from 'ngx-cookie';
-@Injectable()
+@Injectable({providedIn: 'root'})
export class StoreService {
// Base path for cookie-based storage.
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';
/**
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;
+++ /dev/null
-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 + '';
- }
- }
-}
-
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';
ngModule: StaffCommonModule,
providers: [ // Export staff-wide services
AccessKeyService,
+ AudioService,
StringService,
ToastService
]
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(
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';
[entries]="cbEntries"></eg-combobox>
</div>
<div class="col-lg-3">
- <eg-combobox [allowFreeText]="true"
+ <eg-combobox
placeholder="Combobox with dynamic data"
[asyncDataSource]="cbAsyncSource"></eg-combobox>
</div>
var org1 = idlService.create('aou');
org1.id(1);
org1.ou_type(type1);
+ org1.shortname('ROOT');
var org2 = idlService.create('aou');
org2.id(2);