beforeEach(() => {service = new EgEventService();});
const evt = {
- ilsevent: "12345",
- pid: "12345",
+ ilsevent: "12345",
+ pid: "12345",
desc: "Test Event Description",
- payload: {test : 'xyz'},
+ payload: {test : 'xyz'},
textcode: "TEST_EVENT",
- servertime: "Wed Nov 6 16:05:50 2013"
+ servertime: "Wed Nov 6 16:05:50 2013"
};
it('should parse an event object', () => {
* Access key action is peformed via .click(). hrefs, routerLinks,
* and (click) actions are all supported.
*
- * <a
- * routerLink="/staff/splash"
- * egAccessKey
+ * <a
+ * routerLink="/staff/splash"
+ * egAccessKey
* keySpec="alt+h" i18n-keySpec
- * keyDesc="My Description" 18n-keyDesc
+ * keyDesc="My Description" 18n-keyDesc
* >
*/
import {Directive, ElementRef, Input, OnInit} from '@angular/core';
// Context info to display in the accesskey info dialog
// E.g. "navbar"
@Input() keyCtx: string;
-
+
constructor(
private elm: ElementRef,
private keyService: EgAccessKeyService
this.keySpec.split(/ /).forEach(keySpec => {
this.keyService.assign({
- key: keySpec,
+ key: keySpec,
desc: this.keyDesc,
ctx: this.keyCtx,
action: () => {this.elm.nativeElement.click()}
export interface EgAccessKeyAssignment {
key: string, // keyboard command
desc: string, // human-friendly description
- ctx: string, // template context
+ ctx: string, // template context
action: Function // handler function
};
}
/**
- * Compress a set of single-fire keyboard events into single
+ * Compress a set of single-fire keyboard events into single
* string. For example: Control and 't' becomes 'ctrl+t'.
*/
compressKeys(evt: KeyboardEvent): string {
/**
* Returns a simplified key assignment list containing just
- * the key spec and the description. Useful for inspecting
+ * the key spec and the description. Useful for inspecting
* without exposing the actions.
*/
infoIze(): any[] {
constructor(private org: EgOrgService) { }
/**
- * Returns a URL query structure suitable for using with
- * router.navigate(..., {queryParams:...}).
+ * Returns a URL query structure suitable for using with
+ * router.navigate(..., {queryParams:...}).
* No navigation is performed within.
*/
- toUrlParams(context: CatalogSearchContext):
+ toUrlParams(context: CatalogSearchContext):
{[key: string]: string | string[]} {
let params = {
context.query.forEach((q, idx) => {
['query', 'fieldClass','joinOp','matchOp'].forEach(field => {
- // Propagate all array-based fields regardless of
+ // Propagate all array-based fields regardless of
// whether a value is applied to ensure correct
// correlation between values.
params[field][idx] = context[field][idx];
// CCVM filters are encoded as comma-separated lists
Object.keys(context.ccvmFilters).forEach(code => {
- if (context.ccvmFilters[code] &&
+ if (context.ccvmFilters[code] &&
context.ccvmFilters[code][0] != '') {
params[code] = context.ccvmFilters[code].join(',');
}
});
- // Each facet is a JSON encoded blob of class, name, and value
+ // Each facet is a JSON encoded blob of class, name, and value
context.facetFilters.forEach(facet => {
params.facets.push(JSON.stringify({
c : facet.facetClass,
return new Promise((resolve, reject) => {
this.net.request(
'open-ils.search', method, {
- limit : ctx.pager.limit + 1,
+ limit : ctx.pager.limit + 1,
offset : ctx.pager.offset
}, fullQuery, true
).subscribe(result => {
fetchBibSummaries(ctx: CatalogSearchContext): Promise<any> {
let promises = [];
- let depth = ctx.global ?
+ let depth = ctx.global ?
ctx.org.root().ou_type().depth() :
ctx.searchOrg.ou_type().depth();
}
return new Promise((resolve, reject) => {
- this.net.request('open-ils.search',
+ this.net.request('open-ils.search',
'open-ils.search.facet_cache.retrieve',
ctx.result.facet_key
).subscribe(facets => {
fetchCcvms(): Promise<void> {
- if (Object.keys(this.ccvmMap).length)
+ if (Object.keys(this.ccvmMap).length)
return Promise.resolve();
return new Promise((resolve, reject) => {
- this.pcrud.search('ccvm',
- {ctype : CATALOG_CCVM_FILTERS}, {},
+ this.pcrud.search('ccvm',
+ {ctype : CATALOG_CCVM_FILTERS}, {},
{atomic: true, anonymous: true}
).subscribe(list => {
this.compileCcvms(list);
});
Object.keys(this.ccvmMap).forEach(cType => {
- this.ccvmMap[cType] =
+ this.ccvmMap[cType] =
this.ccvmMap[cType].sort((a, b) => {
return a.value() < b.value() ? -1 : 1;
});
fetchCmfs(): Promise<void> {
// At the moment, we only need facet CMFs.
- if (Object.keys(this.cmfMap).length)
+ if (Object.keys(this.cmfMap).length)
return Promise.resolve();
return new Promise((resolve, reject) => {
- this.pcrud.search('cmf',
+ this.pcrud.search('cmf',
{facet_field : 't'}, {}, {atomic: true, anonymous: true}
).subscribe(
cmfs => {
getBibSummary(bibId: number, orgId?: number, depth?: number): Promise<any> {
return new Promise((resolve, reject) => {
this.unapi.getAsXmlDocument({
- target: 'bre',
- id: bibId,
- extras: '{bre.extern,holdings_xml,mra}',
- format: 'mods32',
+ target: 'bre',
+ id: bibId,
+ extras: '{bre.extern,holdings_xml,mra}',
+ format: 'mods32',
orgId: orgId,
depth: depth
}).then(xmlDoc => {
/**
* Probably don't want to require navigating the bare UNAPI
* blob in the template, plus that's quite a lot of stuff
- * to sit in the scope / watch for changes. Translate the
+ * to sit in the scope / watch for changes. Translate the
* UNAPI content into a more digestable form.
* TODO: Add display field support
*/
};
Object.keys(MODS_XPATH_AUTO).forEach(key => {
- let result = xmlDoc.evaluate(MODS_XPATH_AUTO[key], xmlDoc,
+ let result = xmlDoc.evaluate(MODS_XPATH_AUTO[key], xmlDoc,
resolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
let node = result.singleNodeValue;
if (node) response[key] = node.textContent;
});
- let result = xmlDoc.evaluate(MODS_XPATH.extern, xmlDoc,
+ let result = xmlDoc.evaluate(MODS_XPATH.extern, xmlDoc,
resolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
let node:any = result.singleNodeValue;
}
}
- result = xmlDoc.evaluate(MODS_XPATH.attributes, xmlDoc,
+ result = xmlDoc.evaluate(MODS_XPATH.attributes, xmlDoc,
resolver, XPathResult.ANY_TYPE, null);
while(node = result.iterateNext()) {
}
}
- result = xmlDoc.evaluate(MODS_XPATH.copyCounts, xmlDoc,
+ result = xmlDoc.evaluate(MODS_XPATH.copyCounts, xmlDoc,
resolver, XPathResult.ANY_TYPE, null);
while(node = result.iterateNext()) {
let counts = {};
- ['type', 'depth', 'org_unit', 'transcendant',
+ ['type', 'depth', 'org_unit', 'transcendant',
'available', 'count', 'unshadow'].forEach(field => {
counts[field] = node.getAttribute(field);
});
let ids = [];
for (
let idx = this.pager.offset;
- idx < Math.min(
- this.pager.offset + this.pager.limit,
+ idx < Math.min(
+ this.pager.offset + this.pager.limit,
this.pager.resultCount
);
idx++
/**
* Return search context to its default state, resetting search
* parameters and clearing any cached result data.
- * This does not reset global filters like limit-to-available
+ * This does not reset global filters like limit-to-available
* search-global, or search-org.
*/
reset(): void {
}
isSearchable(): boolean {
- return this.query.length
+ return this.query.length
&& this.query[0] != ''
&& this.searchOrg != null;
}
}
stripQuotes(query: string): string {
- return query.replace(/"/g, '');
+ return query.replace(/"/g, '');
}
stripAnchors(query: string): string {
- return query.replace(/[\^\$]/g, '');
+ return query.replace(/[\^\$]/g, '');
}
addQuotes(query: string): string {
query = '^' + this.stripAnchors(query) + '$';
break;
case 'starts':
- query = this.addQuotes('^' +
+ query = this.addQuotes('^' +
this.stripAnchors(this.stripQuotes(query)));
break;
}
this.onChangeAsIso = new EventEmitter<string>();
this.onChangeAsYmd = new EventEmitter<string>();
}
-
+
ngOnInit() {
if (this.initialYmd) {
this.initialDate = new Date();
this.current = {
- year: this.initialDate.getFullYear(),
- month: this.initialDate.getMonth() + 1,
+ year: this.initialDate.getFullYear(),
+ month: this.initialDate.getMonth() + 1,
day: this.initialDate.getDate()
};
}
// Create a date in the local time zone with selected YMD values.
// TODO: Consider moving this to a date service...
localDateFromYmd(ymd: string): Date {
- var parts = ymd.split('-');
+ var parts = ymd.split('-');
return new Date(
Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
}
import {Component, Input, OnInit, ViewChild, TemplateRef, EventEmitter} from '@angular/core';
import {NgbModal, NgbModalRef, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
-/**
- * Dialog base class. Handles the ngbModal logic.
- * Sub-classed component templates must have a #dialogContent selector
+/**
+ * Dialog base class. Handles the ngbModal logic.
+ * Sub-classed component templates must have a #dialogContent selector
* at the root of the template (see EgConfirmDialogComponent).
- */
+ */
@Component({
selector: 'eg-dialog',
@Input() public dialogTitle: string;
// Pointer to the dialog content template.
- @ViewChild('dialogContent')
+ @ViewChild('dialogContent')
private dialogContent: TemplateRef<any>;
// Emitted after open() is called on the ngbModal.
- // Note when overriding open(), this will not fire unless also
+ // Note when overriding open(), this will not fire unless also
// called in the overridding method.
onOpen$ = new EventEmitter<any>();
})
/**
- * Progress Dialog.
+ * Progress Dialog.
*
* // assuming a template reference...
* @ViewChild('progressDialog')
* dialog.close();
*
* Each dialog has 2 numbers, 'max' and 'value'.
- * The content of these values determines how the dialog displays.
+ * The content of these values determines how the dialog displays.
*
* There are 3 flavors:
*
* is happening, but we don't know when it will end.
*
* -- value is unset
- * indeterminate: shows a generic value-less <progress/> with no
+ * indeterminate: shows a generic value-less <progress/> with no
* clear indication of progress.
*/
export class EgProgressDialogComponent extends EgDialogComponent {
-
+
max: number;
value: number;
}
percent(): number {
- if (this.hasValue() &&
- this.hasMax() &&
+ if (this.hasValue() &&
+ this.hasMax() &&
this.max > 0 &&
this.value <= this.max)
return Math.floor((this.value / this.max) * 100);
// Set the current state of the progress bar.
update(args: {[key:string] : number}) {
- if (args.max != undefined)
+ if (args.max != undefined)
this.max = args.max;
- if (args.value != undefined)
+ if (args.value != undefined)
this.value = args.value;
}
-import {Component, OnInit, Input,
+import {Component, OnInit, Input,
Output, EventEmitter, TemplateRef} from '@angular/core';
import {EgIdlService, EgIdlObject} from '@eg/core/idl.service';
import {EgAuthService} from '@eg/core/auth.service';
interface CustomFieldTemplate {
template: TemplateRef<any>,
-
- // Allow the caller to pass in a free-form context blob to
- // be addedto the caller's custom template context, along
+
+ // Allow the caller to pass in a free-form context blob to
+ // be addedto the caller's custom template context, along
// with our stock context.
context?: {[fields: string]: any}
}
record: EgIdlObject,
// IDL field definition blob
- field: any,
+ field: any,
// additional context values passed via CustomFieldTemplate
[fields: string]: any;
selector: 'fm-record-editor',
templateUrl: './fm-editor.component.html'
})
-export class FmRecordEditorComponent
+export class FmRecordEditorComponent
extends EgDialogComponent implements OnInit {
// IDL class hint (e.g. "aou")
// TODO: allow this to be update in real time by the caller?
record: EgIdlObject;
- @Input() customFieldTemplates:
+ @Input() customFieldTemplates:
{[fieldName:string] : CustomFieldTemplate} = {};
// list of fields that should not be displayed
// list of required fields; this supplements what the IDL considers
// required
@Input() requiredFieldsList: string[] = [];
- @Input() requiredFields: string; // comma-separated string version
+ @Input() requiredFields: string; // comma-separated string version
// list of org_unit fields where a default value may be applied by
// the org-select if no value is present.
// name and the record and should return a boolean value. This
// supports cases where whether a field is required or not depends
// on the current value of another field.
- @Input() isRequiredOverride:
+ @Input() isRequiredOverride:
{[field: string] : (field: string, record: EgIdlObject) => boolean};
// IDL record display label. Defaults to the IDL label.
private modal: NgbModal, // required for passing to parent
private idl: EgIdlService,
private auth: EgAuthService,
- private pcrud: EgPcrudService) {
- super(modal)
+ private pcrud: EgPcrudService) {
+ super(modal)
}
-
+
// Avoid fetching data on init since that may lead to unnecessary
// data retrieval.
ngOnInit() {
.toPromise().then(rec => {
if (!rec) {
- return Promise.reject(`No '${this.idlClass}'
+ return Promise.reject(`No '${this.idlClass}'
record found with id ${this.recId}`);
}
this.convertDatatypesToJs();
return this.getFieldList();
});
- }
+ }
// create a new record from scratch
this.pkeyIsEditable = !('pkey_sequence' in this.idlDef);
private flattenLinkedValues(cls: string, list: EgIdlObject[]): any[] {
let idField = this.idl.classes[cls].pkey;
- let selector =
+ let selector =
this.idl.classes[cls].field_map[idField].selector || idField;
return list.map(item => {
private getFieldList(): Promise<any> {
- this.fields = this.idlDef.fields.filter(f =>
- f.virtual != 'true' &&
+ this.fields = this.idlDef.fields.filter(f =>
+ f.virtual != 'true' &&
!this.hiddenFieldsList.includes(f.name)
);
let promises = [];
this.fields.forEach(field => {
- field.readOnly = this.mode == 'view'
+ field.readOnly = this.mode == 'view'
|| this.readonlyFieldsList.includes(field.name);
- if (this.isRequiredOverride &&
+ if (this.isRequiredOverride &&
field.name in this.isRequiredOverride) {
field.isRequired = () => {
return this.isRequiredOverride[field.name](field.name, this.record);
}
} else {
field.isRequired = () => {
- return field.required ||
+ return field.required ||
this.requiredFieldsList.includes(field.name);
}
}
promises.push(
this.pcrud.retrieveAll(field.class, {}, {atomic : true})
.toPromise().then(list => {
- field.linkedValues =
+ field.linkedValues =
this.flattenLinkedValues(field.class, list);
})
);
} else if (field.datatype == 'org_unit') {
- field.orgDefaultAllowed =
+ field.orgDefaultAllowed =
this.orgDefaultAllowedList.includes(field.name);
}
return Promise.all(promises);
}
- // Returns a context object to be inserted into a custom
+ // Returns a context object to be inserted into a custom
// field template.
customTemplateFieldContext(fieldDef: any): CustomFieldContext {
return Object.assign(
import {Component, Input, OnInit, Host} from '@angular/core';
-import {EgGridContext, EgGridColumn, EgGridColumnSet,
+import {EgGridContext, EgGridColumn, EgGridColumnSet,
EgGridDataSource} from './grid';
@Component({
@Input() label: string;
@Input() flex: number;
// is this the index field?
- @Input() index: boolean;
+ @Input() index: boolean;
@Input() visible: boolean;
@Input() hidden: boolean;
@Input() sortable: boolean;
import {Component, Input, OnInit} from '@angular/core';
-import {EgGridContext, EgGridColumn, EgGridRowSelector,
+import {EgGridContext, EgGridColumn, EgGridRowSelector,
EgGridColumnSet, EgGridDataSource} from './grid';
@Component({
this.gridContext.reload();
}
- // Returns true if the provided column is sorting in the
+ // Returns true if the provided column is sorting in the
// specified direction.
isColumnSorting(col: EgGridColumn, dir: string): boolean {
let sort = this.gridContext.dataSource.sort.filter(c => c.name == col.name)[0];
import {Component, Input, OnInit, Host} from '@angular/core';
import {DomSanitizer, SafeUrl} from '@angular/platform-browser';
import {Pager} from '@eg/share/util/pager';
-import {EgGridColumn, EgGridColumnSet, EgGridToolbarButton,
+import {EgGridColumn, EgGridColumnSet, EgGridToolbarButton,
EgGridToolbarAction, EgGridContext, EgGridDataSource} from '@eg/share/grid/grid';
import {EgGridColumnWidthComponent} from './grid-column-width.component';
// the CSV download attributes / state.
setTimeout(() => {
this.csvExportUrl = null;
- this.csvExportFileName = '';
+ this.csvExportFileName = '';
this.csvExportInProgress = false;
}, 500
);
return;
- }
+ }
this.csvExportInProgress = true;
// let the file name describe the grid
this.csvExportFileName = (
- this.gridContext.mainLabel ||
- this.gridContext.persistKey ||
+ this.gridContext.mainLabel ||
+ this.gridContext.persistKey ||
'eg_grid_data'
).replace(/\s+/g, '_') + '.csv';
this.csvExportUrl = this.sanitizer.bypassSecurityTrustUrl(
(win.URL || win.webkitURL).createObjectURL(blob)
);
-
+
// Fire the 2nd click event now that the browser has
// information on how to download the CSV file.
setTimeout(() => $event.target.click());
context: EgGridContext;
onRowActivate$: EventEmitter<any>;
onRowClick$: EventEmitter<any>;
-
+
constructor(
private idl: EgIdlService,
private org: EgOrgService,
private store: EgStoreService,
private format: EgFormatService
) {
- this.context =
+ this.context =
new EgGridContext(this.idl, this.org, this.store, this.format);
this.onRowActivate$ = new EventEmitter<any>();
this.onRowClick$ = new EventEmitter<any>();
this.context.destroy();
}
- // Not using @HostListener because it only works globally.
+ // Not using @HostListener because it only works globally.
onGridKeyDown(evt: KeyboardEvent) {
switch(evt.key) {
case 'ArrowUp':
if (this.context.disableMultiSelect) {
this.context.selectOneRow(index);
} else if ($event.ctrlKey || $event.metaKey /* mac command */) {
- if (this.context.toggleSelectOneRow(index))
+ if (this.context.toggleSelectOneRow(index))
this.context.lastSelectedIndex = index;
} else if ($event.shiftKey) {
constructor(
idl: EgIdlService, org: EgOrgService,
store: EgStoreService, format: EgFormatService) {
-
+
this.idl = idl;
this.org = org;
this.store = store;
return this.getRowColumnValue(row, col);
}
- // Returns the array position of the row-by-index in the
+ // Returns the array position of the row-by-index in the
// dataSource array.
getRowPosition(index: any): number {
// for-loop for early exit
- for (let idx = 0; idx < this.dataSource.data.length; idx++) {
+ for (let idx = 0; idx < this.dataSource.data.length; idx++) {
if (index == this.getRowIndex(this.dataSource.data[idx]))
return idx;
}
}
getRowByIndex(index: any): any {
- for (let idx = 0; idx < this.dataSource.data.length; idx++) {
+ for (let idx = 0; idx < this.dataSource.data.length; idx++) {
if (index == this.getRowIndex(this.dataSource.data[idx]))
return this.dataSource.data[idx];
}
}
- // Returns all selected rows, regardless of whether they are
+ // Returns all selected rows, regardless of whether they are
// currently visible in the grid display.
getSelectedRows(): any[] {
let selected = [];
if (this.rowSelector.contains(index)) {
this.rowSelector.deselect(index);
return false;
- }
+ }
this.rowSelector.select(index);
return true;
getRowAsFlatText(row: any): any {
let flatRow = {};
this.columnSet.displayColumns().forEach(col => {
- flatRow[col.name] =
+ flatRow[col.name] =
this.getColumnTextContent(row, col);
});
return flatRow;
str = ''+str;
if (!str) return '';
str = str.replace(/\n/g, '');
- if (str.match(/\,/) || str.match(/"/)) {
+ if (str.match(/\,/) || str.match(/"/)) {
str = str.replace(/"/g, '""');
- str = '"' + str + '"';
- }
+ str = '"' + str + '"';
+ }
return str;
}
var srcIdx, targetIdx;
this.columns.forEach((c, i) => {
- if (c.name == col.name) srcIdx = i
+ if (c.name == col.name) srcIdx = i
});
targetIdx = srcIdx + diff;
// When moving a column (down) causes one or more
// visible columns to shuffle forward, our column
// moves into the slot of the last visible column.
- // Otherwise, put it into the slot directly following
+ // Otherwise, put it into the slot directly following
// the last visible column.
targetIdx = srcIdx <= lastVisible ? lastVisible : lastVisible + 1;
}
newCols.push(col);
});
- // columns which are not expressed within the saved
- // configuration are marked as non-visible and
+ // columns which are not expressed within the saved
+ // configuration are marked as non-visible and
// appended to the end of the new list of columns.
this.columns.forEach(c => {
if (conf.filter(cf => cf.name == c.name).length == 0) {
let indexes = [].concat(index);
for (let i = 0; i < indexes.length; i++) { // early exit
if (!this.indexes[indexes[i]])
- return false;
+ return false;
}
return true;
}
}
// Returns the list of selected index values.
- // in some contexts (template checkboxes) the value for an index is
+ // in some contexts (template checkboxes) the value for an index is
// set to false to deselect instead of having it removed (via deselect()).
selected() {
return Object.keys(this.indexes).filter(
import {distinctUntilChanged} from 'rxjs/operators/distinctUntilChanged';
import {merge} from 'rxjs/operators/merge';
import {filter} from 'rxjs/operators/filter';
-import {Subject} from 'rxjs/Subject';
+import {Subject} from 'rxjs/Subject';
import {EgAuthService} from '@eg/core/auth.service';
import {EgStoreService} from '@eg/core/store.service';
import {EgOrgService} from '@eg/core/org.service';
import {EgIdlObject} from '@eg/core/idl.service';
-import {NgbTypeahead, NgbTypeaheadSelectItemEvent}
+import {NgbTypeahead, NgbTypeaheadSelectItemEvent}
from '@ng-bootstrap/ng-bootstrap';
-// Use a unicode char for spacing instead of ASCII=32 so the browser
+// Use a unicode char for spacing instead of ASCII=32 so the browser
// won't collapse the nested display entries down to a single space.
-const PAD_SPACE: string = ' '; // U+2007
+const PAD_SPACE: string = ' '; // U+2007
interface OrgDisplay {
id: number;
if (ids) this.disabled = ids;
}
- // Apply an org unit value at load time.
+ // Apply an org unit value at load time.
// This will NOT result in an onChange event.
@Input() set initialOrg(org: EgIdlObject) {
if (org) this.startOrg = org;
}
- // Apply an org unit value by ID at load time.
+ // Apply an org unit value by ID at load time.
// This will NOT result in an onChange event.
@Input() set initialOrgId(id: number) {
if (id) this.startOrg = this.org.get(id);
constructor(
private auth: EgAuthService,
private store: EgStoreService,
- private org: EgOrgService
+ private org: EgOrgService
) {}
-
+
ngOnInit() {
// Apply a default org unit if desired and possible.
formatForDisplay(org: EgIdlObject): OrgDisplay {
return {
id : org.id(),
- label : PAD_SPACE.repeat(org.ou_type().depth())
+ label : PAD_SPACE.repeat(org.ou_type().depth())
+ org[this.displayField](),
disabled : false
};
// that does not need interpolation.
if (this.key) {
this.strings.register({
- key: this.key,
+ key: this.key,
resolver: (ctx:any) => this.current(ctx)
});
}
}
- // Apply the new context if provided, give our container a
+ // Apply the new context if provided, give our container a
// chance to update, then resolve with the current string.
// NOTE: talking to the native DOM element is not so great, but
// hopefully we can retire the EgString* code entirely once
}
interpolate(key: string, ctx?: any): Promise<string> {
- if (!this.strings[key])
+ if (!this.strings[key])
return Promise.reject('No Such String');
return this.strings[key].resolver(ctx);
}
}
-
+
this.dismiss(this.message);
this.message = msg;
this.timeout = setTimeout(
- () => this.dismiss(this.message),
+ () => this.dismiss(this.message),
EG_TOAST_TIMEOUT
);
}
export interface EgToastMessage {
text: string,
- style: string
+ style: string
};
@Injectable()
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
-const routes: Routes = [{
+const routes: Routes = [{
path: '',
children : [
{ path: 'workstation',
-import {Component, Input, ViewChildren,
+import {Component, Input, ViewChildren,
AfterViewInit, QueryList} from '@angular/core';
@Component({
]
})
-export class EgAdminServerModule {
+export class EgAdminServerModule {
}
let searchOrgs = this.org.fullPath(this.contextOrg, true);
let orderBy = {};
- if (sort.length)
+ if (sort.length)
orderBy = {cbt: sort[0].name + ' ' + sort[0].dir};
return this.pcrud.search('cbt', {owner : searchOrgs}, {
- offset: pager.offset,
+ offset: pager.offset,
limit: pager.limit,
order_by: orderBy
});
]
})
-export class EgAdminServerConfigModule {
+export class EgAdminServerConfigModule {
}
let searchOrgs = this.org.fullPath(this.contextOrg, true);
let orderBy = {};
- if (sort.length)
+ if (sort.length)
orderBy = {chdd: sort[0].name + ' ' + sort[0].dir};
return this.pcrud.search('chdd', {owner : searchOrgs}, {
- offset: pager.offset,
+ offset: pager.offset,
limit: pager.limit,
order_by: orderBy
});
import {BillingTypeComponent} from './billing_type.component';
import {HardDueDateComponent} from './hard_due_date.component';
-const routes: Routes = [{
+const routes: Routes = [{
path: 'billing_type',
- component: BillingTypeComponent
+ component: BillingTypeComponent
}, {
path: 'hard_due_date',
- component: HardDueDateComponent
+ component: HardDueDateComponent
}];
@NgModule({
.then(noop => this.store.getItem('eg.workstation.default'))
.then(defWs => {
this.defaultName = defWs;
- this.selectedName = this.auth.workstation() || defWs
+ this.selectedName = this.auth.workstation() || defWs
})
.then(noop => {
let rm = this.route.snapshot.paramMap.get('remove');
.then(perms => {
// Disable org units that cannot have users and any
// that this user does not have work perms for.
- this.disableOrgs =
+ this.disableOrgs =
this.org.filterList({canHaveUsers : false}, true)
.concat(this.org.filterList(
{notInList : perms.REGISTER_WORKSTATION}, true));
useNow(): void {
if (!this.selected()) return;
- this.router.navigate(['/staff/login'],
+ this.router.navigate(['/staff/login'],
{queryParams: {workstation: this.selected().name}});
}
this.store.removeItem('eg.workstation.default');
}
}
-
+
canDeleteSelected(): boolean {
return true;
}
'open-ils.actor', method,
this.auth.token(), this.newName, this.newOwner.id()
).subscribe(wsId => {
- let evt = this.evt.parse(wsId);
+ let evt = this.evt.parse(wsId);
if (evt) {
if (evt.textcode == 'WORKSTATION_NAME_EXISTS') {
this.handleCollision().then(
reject();
}
} else {
- resolve(wsId);
+ resolve(wsId);
}
});
});
]
})
-export class EgCatalogModule {
+export class EgCatalogModule {
}
defaultSearchLimit: number;
// TODO: does unapi support pref-lib for result-page copy counts?
- prefOrg: EgIdlObject;
+ prefOrg: EgIdlObject;
constructor(
private router: Router,
// Do this here so the search form and other context data are
// applied on every page, not just the search results page. The
// search results pages will handle running the actual search.
- this.searchContext =
+ this.searchContext =
this.catUrl.fromUrlParams(this.route.snapshot.queryParamMap);
this.searchContext.org = this.org; // service, not searchOrg
applySearchDefaults(): void {
if (!this.searchContext.searchOrg) {
- this.searchContext.searchOrg =
+ this.searchContext.searchOrg =
this.defaultSearchOrg || this.org.root();
}
if (!this.searchContext.isSearchable()) return;
let params = this.catUrl.toUrlParams(this.searchContext);
-
+
// Force a new search every time this method is called, even if
// it's the same as the active search. Since router navigation
// exits early when the route + params is identical, add a
private staffCat: StaffCatalogService,
) {}
- ngOnInit() {
+ ngOnInit() {
this.initDone = true;
this.collectData();
}
// copies from all branches, sorted by search/pref libs.
let copy_depth = this.staffCat.searchContext.global ?
this.org.root().ou_type().depth() :
- this.staffCat.searchContext.searchOrg.ou_type().depth();
+ this.staffCat.searchContext.searchOrg.ou_type().depth();
this.net.request(
'open-ils.search',
copy_depth,
this.pager.limit,
this.pager.offset,
- this.staffCat.prefOrg ? this.staffCat.prefOrg.id() : null
+ this.staffCat.prefOrg ? this.staffCat.prefOrg.id() : null
).subscribe(copy => {
this.copies.push(copy);
});
}
holdable(copy: any): boolean {
- return copy.holdable == 't'
- && copy.location_holdable == 't'
+ return copy.holdable == 't'
+ && copy.location_holdable == 't'
&& copy.status_holdable == 't';
}
private staffCat: StaffCatalogService,
) {}
- ngOnInit() {
+ ngOnInit() {
this.initDone = true;
this.setIndex();
}
findRecordAtIndex(index: number): Promise<number> {
// First see if the selected record sits in the current page
- // of search results.
+ // of search results.
return new Promise((resolve, reject) => {
let id = this.searchContext.resultIdAt(index);
if (id) return resolve(id);
console.debug(
'Record paginator unable to find record at index ' + index);
- // If we have to re-run the search to find the record,
+ // If we have to re-run the search to find the record,
// expand the search limit out just enough to find the
// requested record plus one more.
return this.refreshSearch(index + 2).then(
import {ActivatedRoute, ParamMap} from '@angular/router';
import {EgPcrudService} from '@eg/core/pcrud.service';
import {EgIdlObject} from '@eg/core/idl.service';
-import {CatalogSearchContext, CatalogSearchState}
+import {CatalogSearchContext, CatalogSearchState}
from '@eg/share/catalog/search-context';
import {EgCatalogService} from '@eg/share/catalog/catalog.service';
import {StaffCatalogService} from '../catalog.service';
private staffCat: StaffCatalogService
) {}
- ngOnInit() {
+ ngOnInit() {
this.searchContext = this.staffCat.searchContext;
// Watch for URL record ID changes
})
}
- loadRecord(): void {
+ loadRecord(): void {
this.searchContext = this.staffCat.searchContext;
// If a search is encoded in the URL, be sure we have the
- // relevant search
+ // relevant search
this.cat.getBibSummary(
this.recordId,
- this.searchContext.searchOrg.id(),
+ this.searchContext.searchOrg.id(),
this.searchContext.searchOrg.ou_type().depth()
- ).then(summary => {
+ ).then(summary => {
this.bibSummary = summary;
this.pcrud.search('au', {id: [summary.creator, summary.editor]})
.subscribe(user => {
export class EgCatalogResolver implements Resolve<Promise<any[]>> {
constructor(
- private router: Router,
+ private router: Router,
private store: EgStoreService,
private org: EgOrgService,
private net: EgNetService,
) {}
resolve(
- route: ActivatedRouteSnapshot,
+ route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Promise<any[]> {
console.debug('EgCatalogResolver:resolve()');
this.facetConfig = FACET_CONFIG;
}
- ngOnInit() {
+ ngOnInit() {
this.searchContext = this.staffCat.searchContext;
}
private staffCat: StaffCatalogService
) {}
- ngOnInit() {
+ ngOnInit() {
this.searchContext = this.staffCat.searchContext;
}
private staffCat: StaffCatalogService
) {}
- ngOnInit() {
+ ngOnInit() {
this.searchContext = this.staffCat.searchContext;
this.fleshHoldCount();
}
searchContext: CatalogSearchContext;
- // Cache record creator/editor since this will likely be a
+ // Cache record creator/editor since this will likely be a
// reasonably small set of data w/ lots of repitition.
userCache: {[id:number] : EgIdlObject} = {};
private staffCat: StaffCatalogService
) {}
- ngOnInit() {
+ ngOnInit() {
this.searchContext = this.staffCat.searchContext;
// Our search context is initialized on page load. Once
// ResultsComponent is active, it will not be reinitialized,
// even if the route parameters changes (unless we change the
// route reuse policy). Watch for changes here to pick up new
- // searches.
- //
+ // searches.
+ //
// This will also fire on page load.
this.route.queryParamMap.subscribe((params: ParamMap) => {
import {RecordComponent} from './record/record.component';
import {EgCatalogResolver} from './resolver.service';
-const routes: Routes = [{
+const routes: Routes = [{
path: '',
component: EgCatalogComponent,
resolve: {catResolver : EgCatalogResolver},
import {EgIdlObject} from '@eg/core/idl.service';
import {EgOrgService} from '@eg/core/org.service';
import {EgCatalogService,} from '@eg/share/catalog/catalog.service';
-import {CatalogSearchContext, CatalogSearchState}
+import {CatalogSearchContext, CatalogSearchState}
from '@eg/share/catalog/search-context';
import {StaffCatalogService} from './catalog.service';
private staffCat: StaffCatalogService
) {}
- ngOnInit() {
+ ngOnInit() {
this.ccvmMap = this.cat.ccvmMap;
this.cmfMap = this.cat.cmfMap;
this.searchContext = this.staffCat.searchContext;
- // Start with advanced search options open
+ // Start with advanced search options open
// if any filters are active.
this.showAdvancedSearch = this.hasAdvancedOptions();
import {EgStringService} from '@eg/share/string/string.service';
import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
import {EgDateSelectComponent} from '@eg/share/date-select/date-select.component';
-import {EgLinkTableComponent, EgLinkTableLinkComponent}
+import {EgLinkTableComponent, EgLinkTableLinkComponent}
from '@eg/staff/share/link-table/link-table.component';
/**
* Imports the EG common modules and adds modules common to all staff UI's.
- */
+ */
@NgModule({
declarations: [
EgOpChangeComponent,
FmRecordEditorComponent,
EgDateSelectComponent,
- EgLinkTableComponent,
+ EgLinkTableComponent,
EgLinkTableLinkComponent
],
imports: [
EgOpChangeComponent,
FmRecordEditorComponent,
EgDateSelectComponent,
- EgLinkTableComponent,
+ EgLinkTableComponent,
EgLinkTableLinkComponent
]
})
private ngLocation: Location,
private renderer: Renderer2,
private auth: EgAuthService,
- private store: EgStoreService
+ private store: EgStoreService
) {}
ngOnInit() {
[`/staff/admin/workstation/workstations/remove/${workstation}`]);
} else {
// Force reload of the app after a successful login.
- // This allows the route resolver to re-run with a
+ // This allows the route resolver to re-run with a
// valid auth token and workstation.
- window.location.href =
+ window.location.href =
this.ngLocation.prepareExternalUrl(url);
}
},
}
// Broadcast to all tabs that we're logging out.
- // Redirect to the login page, which performs the remaining
+ // Redirect to the login page, which performs the remaining
// logout duties.
logout(): void {
this.auth.broadcastLogout();
observer: Observer<any>;
constructor(
- private router: Router,
- private route: ActivatedRoute,
+ private router: Router,
+ private route: ActivatedRoute,
private ngLocation: Location,
private store: EgStoreService,
private org: EgOrgService,
) {}
resolve(
- route: ActivatedRouteSnapshot,
+ route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<any> {
console.debug('EgStaffResolver:resolve()');
let path = state.url.split('?')[0]
if (path == '/staff/login') return Observable.of(true);
- let observable: Observable<any>
+ let observable: Observable<any>
= Observable.create(o => this.observer = o);
this.auth.testAuthToken().then(
},
wsNotOk => this.handleInvalidWorkstation(path)
);
- },
+ },
hasNotPerms => {
this.observer.error(
'User does not have staff permissions');
}
);
- },
+ },
tokenNotOk => this.handleInvalidToken(state)
);
);
});
}
-
- // A page that's not the login page was requested without a
+
+ // A page that's not the login page was requested without a
// valid auth token. Send the caller back to the login page.
handleInvalidToken(state: RouterStateSnapshot): void {
console.debug('EgStaffResolver: authtoken is not valid');
this.observer.complete();
} else {
this.router.navigate([WS_MANAGE_PATH]);
- this.observer.error(`Auth session linked to no
+ this.observer.error(`Auth session linked to no
workstation or a workstation unknown to this browser`);
}
}
import {EgStaffSplashComponent} from './splash.component';
// Not using 'canActivate' because it's called before all resolvers,
-// even the parent resolver, but the resolvers parse the IDL, load settings,
+// even the parent resolver, but the resolvers parse the IDL, load settings,
// etc. Chicken, meet egg.
const routes: Routes = [{
import {RouterModule, Routes} from '@angular/router';
import {EgSandboxComponent} from './sandbox.component';
-const routes: Routes = [{
+const routes: Routes = [{
path: '',
component: EgSandboxComponent
}];
this.btSource.getRows = (pager: Pager) => {
return this.pcrud.retrieveAll('cbt', {
- offset: pager.offset,
+ offset: pager.offset,
limit: pager.limit,
order_by: {cbt: 'name'}
});
// every 250ms emit x*10 for 0-10
Observable.timer(0, 250).pipe(
- map(x => x * 10),
+ map(x => x * 10),
take(11)
).subscribe(
val => this.progressDialog.update({value: val, max: 100}),
]
})
-export class EgSandboxModule {
+export class EgSandboxModule {
}
private pcrud: EgPcrudService
) {}
- ngOnInit() {
+ ngOnInit() {
this.initDone = true;
if (this.summary) {
this.fetchBibCallNumber();
}
loadSummary(): void {
- this.cat.getBibSummary(this.recordId).then(summary => {
+ this.cat.getBibSummary(this.recordId).then(summary => {
this.summary = summary;
this.fetchBibCallNumber();
-
+
// Flesh the user data
this.pcrud.search('au', {id: [summary.creator, summary.editor]})
.subscribe(user => {
}
ngAfterViewInit() {
- // table-ize the links
+ // table-ize the links
let rowCount = Math.ceil(this.links.length / this.columnCount);
this.colWidth = Math.floor(12 / this.columnCount); // Bootstrap 12-grid
import {Component, OnInit, Input, Renderer2} from '@angular/core';
-import {EgToastService} from '@eg/share/toast/toast.service';
+import {EgToastService} from '@eg/share/toast/toast.service';
import {EgAuthService} from '@eg/core/auth.service';
import {EgDialogComponent} from '@eg/share/dialog/dialog.component';
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
templateUrl: 'op-change.component.html'
})
-export class EgOpChangeComponent
+export class EgOpChangeComponent
extends EgDialogComponent implements OnInit {
@Input() username: string;
}
login(): Promise<any> {
- if (!(this.username && this.password))
+ if (!(this.username && this.password))
return Promise.reject('Missing Params');
-
+
return this.auth.login(
- { username : this.username,
- password : this.password,
+ { username : this.username,
+ password : this.password,
workstation : this.auth.workstation(),
type : this.loginType
}, true // isOpChange
);
}
- restore(): Promise<any> {
+ restore(): Promise<any> {
return this.auth.undoOpChange().then(
ok => this.toast.success(this.successMessage),
err => this.toast.danger(this.failMessage)
@Component({
selector: 'eg-staff-banner',
- template:
+ template:
'<div class="lead alert alert-primary text-center pt-1 pb-1" role="alert">' +
'<span>{{bannerText}}</span>' +
'</div>'
if (!this.catSearchQuery) return;
this.router.navigate(
- ['/staff/catalog/search'],
+ ['/staff/catalog/search'],
{queryParams: {query : this.catSearchQuery}}
);
}
import {EgAuthService, EgAuthWsState} from '@eg/core/auth.service';
import {EgNetService} from '@eg/core/net.service';
import {EgAccessKeyService} from '@eg/share/accesskey/accesskey.service';
-import {EgAccessKeyInfoComponent}
+import {EgAccessKeyInfoComponent}
from '@eg/share/accesskey/accesskey-info.component';
const LOGIN_PATH = '/staff/login';
// Redirect to the login page on any auth timeout events.
this.net.authExpired$.subscribe(expireEvent => {
- // If the expired authtoken was identified locally (i.e.
+ // If the expired authtoken was identified locally (i.e.
// in this browser tab) notify all tabs of imminent logout.
if (!expireEvent.viaExternal) this.auth.broadcastLogout();
* Prevent the user from leaving the workstation admin page when
* they don't have a valid workstation.
*
- * This does not verify auth tokens with the server on every route,
+ * This does not verify auth tokens with the server on every route,
* because that would be overkill. This is only here to keep
* people boxed in with their authenication state was already
* known to be less then 100%.
if (url.startsWith(LOGIN_PATH)) return;
// We lost our authtoken, go back to the login page.
- if (!this.auth.token())
+ if (!this.auth.token())
this.router.navigate([LOGIN_PATH]);
// No workstation checks needed for workstation admin page.
}
/*
- @ViewChild('egAccessKeyInfo')
+ @ViewChild('egAccessKeyInfo')
private keyComponent: EgAccessKeyInfoComponent;
*/