lp1857911 Statistical Categories UI port user/mrisher/lp1857911-stat-cat
authorMike Risher <mrisher@catalyte.io>
Tue, 31 Dec 2019 19:51:37 +0000 (19:51 +0000)
committerMike Risher <mrisher@catalyte.io>
Wed, 15 Jan 2020 00:10:50 +0000 (00:10 +0000)
This UI allows editing copy statistical categories (stat cats), patron
statistical categories, and their entries. They are filtered by location.
This port opens a new page when editing deleting or adding entries.

Signed-off-by: Mike Risher <mrisher@catalyte.io>
 Changes to be committed:
modified:   Open-ILS/examples/fm_IDL.xml
modified:   Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html
modified:   Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts
new file:   Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.component.html
new file:   Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.component.ts
new file:   Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.module.ts
new file:   Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.html
new file:   Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.ts
new file:   Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_routing.module.ts

Open-ILS/examples/fm_IDL.xml
Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html
Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts
Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.module.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_routing.module.ts [new file with mode: 0644]

index bb01086..39fd77b 100644 (file)
@@ -6905,7 +6905,10 @@ SELECT  usr,
                </links>
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
+                               <create permission="CREATE_PATRON_STAT_CAT" context_field="owner"/>
                                <retrieve permission="STAFF_LOGIN" global_required="true"/>
+                               <update permission="UPDATE_PATRON_STAT_CAT" context_field="owner"/>
+                               <delete permission="DELETE_PATRON_STAT_CAT" context_field="owner"/>
                        </actions>
                </permacrud>
        </class>
@@ -7228,7 +7231,7 @@ SELECT  usr,
                        </actions>
                </permacrud>
        </class>
-       <class id="actsce" controller="open-ils.cstore" oils_obj:fieldmapper="actor::stat_cat_entry" oils_persist:tablename="actor.stat_cat_entry" reporter:label="User Stat Cat Entry">
+       <class id="actsce" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::stat_cat_entry" oils_persist:tablename="actor.stat_cat_entry" reporter:label="User Stat Cat Entry">
                <fields oils_persist:primary="id" oils_persist:sequence="actor.stat_cat_entry_id_seq">
                        <field reporter:label="Entry ID" name="id" reporter:datatype="id" />
                        <field reporter:label="Entry Owner" name="owner" reporter:datatype="link"/>
@@ -7241,8 +7244,22 @@ SELECT  usr,
                        <link field="owner" reltype="has_a" key="id" map="" class="aou"/>
                        <link field="default_entries" reltype="has_many" key="stat_cat_entry" map="" class="actsced"/>
                </links>
+               <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+               <actions>
+                               <create permission="CREATE_PATRON_STAT_CAT_ENTRY">
+                                       <context link="stat_cat" field="owner"/>
+                               </create>
+                               <retrieve permission="STAFF_LOGIN" global_required="true"/>
+                               <update permission="UPDATE_PATRON_STAT_CAT_ENTRY">
+                                       <context link="stat_cat" field="owner"/>
+                               </update>
+                               <delete permission="DELETE_PATRON_STAT_CAT_ENTRY">
+                                       <context link="stat_cat" field="owner"/>
+                               </delete>
+                       </actions>
+               </permacrud>
        </class>
-       <class id="actsced" controller="open-ils.cstore" oils_obj:fieldmapper="actor::stat_cat_entry_default" oils_persist:tablename="actor.stat_cat_entry_default" reporter:label="User Stat Cat Default Entry">
+       <class id="actsced" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::stat_cat_entry_default" oils_persist:tablename="actor.stat_cat_entry_default" reporter:label="User Stat Cat Default Entry">
                <fields oils_persist:primary="id" oils_persist:sequence="actor.stat_cat_entry_default_id_seq">
                        <field reporter:label="Default Entry ID" name="id" reporter:datatype="id" />
                        <field reporter:label="Default Entry Value" name="stat_cat_entry" reporter:datatype="link"/>
@@ -7254,6 +7271,20 @@ SELECT  usr,
                        <link field="owner" reltype="has_a" key="id" map="" class="aou"/>
                        <link field="stat_cat_entry" reltype="has_a" key="id" map="" class="actsce"/>
                </links>
+               <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+               <actions>
+                               <create permission="CREATE_PATRON_STAT_CAT_ENTRY">
+                                       <context link="stat_cat" field="owner"/>
+                               </create>
+                               <retrieve permission="STAFF_LOGIN" global_required="true"/>
+                               <update permission="UPDATE_PATRON_STAT_CAT_ENTRY">
+                                       <context link="stat_cat" field="owner"/>
+                               </update>
+                               <delete permission="DELETE_PATRON_STAT_CAT_ENTRY">
+                                       <context link="stat_cat" field="owner"/>
+                               </delete>
+                       </actions>
+               </permacrud>
        </class>
        <class id="cubi" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="container::user_bucket_item" oils_persist:tablename="container.user_bucket_item" reporter:label="User Bucket Item">
                <fields oils_persist:primary="id" oils_persist:sequence="container.user_bucket_item_id_seq">
@@ -8250,7 +8281,16 @@ SELECT  usr,
                </links>
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
+                               <create permission="CREATE_PATRON_STAT_CAT_ENTRY">
+                                       <context link="stat_cat" field="owner"/>
+                               </create>
                                <retrieve permission="STAFF_LOGIN" global_required="true"/>
+                               <update permission="UPDATE_PATRON_STAT_CAT_ENTRY">
+                                       <context link="stat_cat" field="owner"/>
+                               </update>
+                               <delete permission="DELETE_PATRON_STAT_CAT_ENTRY">
+                                       <context link="stat_cat" field="owner"/>
+                               </delete>
                        </actions>
                </permacrud>
        </class>
index e051d37..a8135d9 100644 (file)
@@ -59,7 +59,7 @@
     <eg-link-table-link i18n-label label="Standing Penalties" 
       routerLink="/staff/admin/local/config/standing_penalty"></eg-link-table-link>
     <eg-link-table-link i18n-label label="Statistical Categories Editor" 
-      url="/eg/staff/admin/local/asset/stat_cat_editor"></eg-link-table-link>
+      routerLink="/staff/admin/local/asset/stat_cat_editor"></eg-link-table-link>
     <eg-link-table-link i18n-label label="Statistical Popularity Badges" 
       routerLink="/staff/admin/local/rating/badge"></eg-link-table-link>
     <eg-link-table-link i18n-label label="Surveys" 
index 39c6be7..a9ae1c0 100644 (file)
@@ -17,6 +17,9 @@ const routes: Routes = [{
     path: 'actor/address_alert',
     component: AddressAlertComponent
 }, {
+    path: 'asset/stat_cat_editor',
+    loadChildren: '@eg/staff/admin/local/stat_cat/stat_cat.module#StatCatModule'
+}, {
     path: 'container/carousel',
     component: AdminCarouselComponent
 }, {
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.component.html
new file mode 100644 (file)
index 0000000..97307a9
--- /dev/null
@@ -0,0 +1,75 @@
+<eg-staff-banner bannerText="Statistical Category Editor" i18n-bannerText></eg-staff-banner>
+<div class="row">
+    <div class="col-lg-12">        
+        <ngb-tabset #createTabs [activeId]="currentTab"  (tabChange)="onTabChange($event)">    
+            <ngb-tab title="Copy Statistical Categories" i18n-title id="copy">
+                <ng-template ngbTabContent>
+                    <eg-fm-record-editor #copyDialog idlClass="asc"
+                    preloadLinkedValues="true" requiredFields="name,owner"
+                    hiddenFieldsList="id"></eg-fm-record-editor> 
+                    <div class="col-lg-2 offset-lg-5 mt-3 mb-3">
+                        <div class="text-center">Focus location</div>
+                        <eg-org-select i18n-placeholder #focus
+                        (onChange)="orgOnChange($event)" [initialOrgId]="selectedOrgId">
+                        </eg-org-select>
+                    </div>
+                    <eg-grid #copyGrid idlClass="asc" [dataSource]="ascDataSource"
+                    hideFields="id" (onRowActivate)="editStatCat([$event])">
+                        <eg-grid-toolbar-button label="New Copy Statistical Category" 
+                        i18n-label [action]="newStatCat"></eg-grid-toolbar-button>
+                        <eg-grid-toolbar-action label="Edit Selected" i18n-label 
+                        [action]="editStatCat"></eg-grid-toolbar-action>
+                        <eg-grid-toolbar-action label="Delete Selected" i18n-label 
+                        (onClick)="deleteStatCat($event)"></eg-grid-toolbar-action>
+                        <ng-template #copyEntriesTmpl let-row="row">
+                            <a href="staff/admin/local/asset/stat_cat_editor/copy_entries/{{row.id()}}">
+                                Edit Entries
+                            </a>
+                        </ng-template>
+                        <eg-grid-column i18n-label label="Entries"
+                        [cellTemplate]="copyEntriesTmpl">
+                        </eg-grid-column>
+                    </eg-grid>
+                </ng-template>
+            </ngb-tab>
+            <ngb-tab title="Patron Statistical Categories" i18n-title id="patron">
+                <ng-template ngbTabContent>
+                    <eg-fm-record-editor #patronDialog idlClass="actsc"
+                    preloadLinkedValues="true" requiredFields="name,owner"
+                    hiddenFieldsList="id"></eg-fm-record-editor>
+                    <div class="col-lg-2 offset-lg-5 mt-3 mb-3">
+                        <div class="text-center">Focus location</div>
+                        <eg-org-select i18n-placeholder #focus
+                        (onChange)="orgOnChange($event)" [initialOrgId]="selectedOrgId">
+                        </eg-org-select>
+                    </div>
+                    <eg-grid #patronGrid idlClass="actsc" [dataSource]="actscDataSource"
+                    (onRowActivate)="editStatCat([$event])" hideFields="id">
+                        <eg-grid-toolbar-button label="New Patron Statistical Category" 
+                        i18n-label [action]="newStatCat"></eg-grid-toolbar-button>
+                        <eg-grid-toolbar-action label="Edit Selected" i18n-label 
+                        [action]="editStatCat"></eg-grid-toolbar-action>
+                        <eg-grid-toolbar-action label="Delete Selected" i18n-label 
+                        (onClick)="deleteStatCat($event)"></eg-grid-toolbar-action>
+                        <ng-template #patronEntriesTmpl let-row="row">
+                            <a href="staff/admin/local/asset/stat_cat_editor/patron_entries/{{row.id()}}">
+                                Edit Entries
+                            </a>
+                        </ng-template>
+                        <eg-grid-column i18n-label label="Entries"
+                        [cellTemplate]="patronEntriesTmpl"></eg-grid-column>
+                    </eg-grid>
+                </ng-template>
+            </ngb-tab>
+        </ngb-tabset>
+    </div>    
+</div>
+
+<eg-string #createSuccessString i18n-text text="New record created"></eg-string>
+<eg-string #createErrString i18n-text text="Failed to create new record"></eg-string>
+<eg-string #deleteFailedString i18n-text text="Deletion failed or was not allowed">
+</eg-string>
+<eg-string #deleteSuccessString i18n-text text="Deletion succeeded"></eg-string>
+<eg-string #updateFailedString i18n-text text="Update failed or was not allowed">
+</eg-string>
+<eg-string #updateSuccessString i18n-text text="Update succeeded"></eg-string>
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.component.ts
new file mode 100644 (file)
index 0000000..3c6adad
--- /dev/null
@@ -0,0 +1,172 @@
+import {Pager} from '@eg/share/util/pager';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
+import {StringComponent} from '@eg/share/string/string.component';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {NgbTabChangeEvent} from '@ng-bootstrap/ng-bootstrap';
+import {OrgService} from '@eg/core/org.service';
+
+@Component({
+    templateUrl: './stat_cat.component.html'
+})
+
+export class StatCatComponent implements OnInit {
+    currentTab: string;
+    ascDataSource: GridDataSource = new GridDataSource();
+    actscDataSource: GridDataSource = new GridDataSource();
+
+    // currently selected org. Starting value is CONS (id 1)
+    selectedOrgId = 1;
+
+    // list of orgs to retrieve stat cats for
+    orgFamly: any;
+
+    @ViewChild('copyGrid', {static: false}) copyGrid: GridComponent;
+    @ViewChild('patronGrid', {static: false}) patronGrid: GridComponent;
+    @ViewChild('copyDialog', {static: false}) copyDialog: FmRecordEditorComponent;
+    @ViewChild('patronDialog', {static: false}) patronDialog: FmRecordEditorComponent;
+    @ViewChild('updateSuccessString', {static: false}) updateSuccessString: StringComponent;
+    @ViewChild('updateFailedString', {static: false}) updateFailedString: StringComponent;
+    @ViewChild('deleteFailedString', {static: false}) deleteFailedString: StringComponent;
+    @ViewChild('deleteSuccessString', {static: false}) deleteSuccessString: StringComponent;
+    @ViewChild('createSuccessString', {static: false}) createSuccessString: StringComponent;
+    @ViewChild('createErrString', {static: false}) createErrString: StringComponent;
+
+    constructor(
+        private pcrud: PcrudService,
+        private org: OrgService,
+        private toast: ToastService
+    ) {
+    }
+
+    ngOnInit() {
+        this.getOrgFamly();
+        this.getAscData();
+        this.getActscData();
+    }
+
+    getOrgFamly() {
+        this.orgFamly = this.org.fullPath(this.selectedOrgId);
+        this.orgFamly = this.orgFamly.map(record => {
+            return record.id();
+        });
+        return this.orgFamly;
+    }
+
+    getAscData() {
+        this.ascDataSource.getRows = (pager: Pager, sort: any[]) => {
+            const orderBy = {asc: 'id'};
+            return this.pcrud.search('asc', {owner: this.orgFamly}, orderBy);
+        };
+    }
+
+    getActscData() {
+        this.actscDataSource.getRows = (pager: Pager, sort: any[]) => {
+            const orderBy = {actsc: 'id'};
+            return this.pcrud.search('actsc', {owner: this.orgFamly}, orderBy);
+        };
+    }
+
+    editStatCat = (idlThing) => {
+        const idlString = idlThing[0].classname;
+        const lookupResponse = this.lookUpType(idlString);
+        const currentGrid = lookupResponse.currentGrid;
+        const currentDialog = lookupResponse.currentDialog;
+        currentDialog.mode = 'update';
+        currentDialog.recordId = idlThing[0].id();
+        currentDialog.open({size: 'lg'}).subscribe(
+            id => {
+                console.debug('Record editor performed action');
+                currentGrid.reload();
+            },
+            err => {
+                console.debug(err);
+            },
+            () => console.debug('Dialog closed')
+        );
+    }
+
+    onTabChange(event: NgbTabChangeEvent) {
+        this.currentTab = event.nextId;
+    }
+
+    orgOnChange = (org: IdlObject): void => {
+        this.selectedOrgId = org.id();
+        this.getOrgFamly();
+        if (this.copyGrid) {
+            this.getAscData();
+            this.copyGrid.reload();
+        }
+        if (this.patronGrid) {
+            this.getActscData();
+            this.patronGrid.reload();
+        }
+    }
+
+    deleteStatCat = (idlThings: IdlObject[]) => {
+        const idlString = idlThings[0].classname;
+        const currentGrid = this.lookUpType(idlString).currentGrid;
+        idlThings.forEach(idlThing => idlThing.isdeleted(true));
+        this.pcrud.autoApply(idlThings).subscribe(
+            val => {
+                console.debug('deleted: ' + val);
+                this.deleteSuccessString.current()
+                    .then(str => this.toast.success(str));
+                currentGrid.reload();
+            },
+            err => {
+                this.deleteFailedString.current()
+                    .then(str => this.toast.danger(str));
+            }
+        );
+    }
+
+    lookUpType = (idlString) => {
+        let currentDialog;
+        let currentGrid;
+        if (idlString === 'asc') {
+            currentGrid = this.copyGrid;
+            currentDialog = this.copyDialog;
+        } else {
+            currentGrid = this.patronGrid;
+            currentDialog = this.patronDialog;
+        }
+        return {
+            currentDialog: currentDialog,
+            currentGrid: currentGrid
+        };
+    }
+
+    newStatCat = (type: any) => {
+        let currentDialog;
+        let currentGrid;
+        if (this.currentTab === 'patron') {
+            currentGrid = this.patronGrid;
+            currentDialog = this.patronDialog;
+        } else {
+            currentGrid = this.copyGrid;
+            currentDialog = this.copyDialog;
+        }
+        currentDialog.mode = 'create';
+        currentDialog.recordId = null;
+        currentDialog.record = null;
+        currentDialog.open({size: 'lg'}).subscribe(
+            ok => {
+                this.createSuccessString.current()
+                    .then(str => this.toast.success(str));
+                currentGrid.reload();
+            },
+            rejection => {
+                if (!rejection.dismissed) {
+                    this.createErrString.current()
+                        .then(str => this.toast.danger(str));
+                }
+            }
+        );
+    }
+
+}
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat.module.ts
new file mode 100644 (file)
index 0000000..6be786b
--- /dev/null
@@ -0,0 +1,20 @@
+import {NgModule} from '@angular/core';
+import {AdminCommonModule} from '@eg/staff/admin/common.module';
+import {StatCatComponent} from './stat_cat.component';
+import {StatCatEntriesComponent} from './stat_cat_entries.component';
+import {StatCatRoutingModule} from './stat_cat_routing.module';
+
+@NgModule({
+  declarations: [
+    StatCatComponent,
+    StatCatEntriesComponent,
+  ],
+  imports: [
+    AdminCommonModule,
+    StatCatRoutingModule,
+  ],
+  exports: [],
+  providers: []
+})
+
+export class StatCatModule {}
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.html
new file mode 100644 (file)
index 0000000..49b489e
--- /dev/null
@@ -0,0 +1,39 @@
+<eg-staff-banner bannerText="{{statCatType}} Statistical Category Entry Editor" i18n-bannerText>
+</eg-staff-banner>
+
+<eg-fm-record-editor #patronDialog idlClass="actsce" preloadLinkedValues="true" 
+requiredFields="owner,name" hiddenFieldsList="id"></eg-fm-record-editor> 
+<eg-fm-record-editor #copyDialog idlClass="asce" preloadLinkedValues="true" 
+requiredFields="owner,name" hiddenFieldsList="id"></eg-fm-record-editor> 
+
+<div *ngIf="statCatType === 'Patron'">
+    <eg-grid #patronGrid [dataSource]="patronDataSource" idlClass="actsce"
+    (onRowActivate)="editEntry([$event])" hideFields="id,stat_cat,owner">
+        <eg-grid-toolbar-button label="New Entry" i18n-label
+        [action]="createNewEntry"></eg-grid-toolbar-button>
+        <eg-grid-toolbar-action label="Edit Selected" i18n-label 
+        [action]="editEntry"></eg-grid-toolbar-action>
+        <eg-grid-toolbar-action label="Delete Selected" i18n-label 
+        (onClick)="deleteEntry($event)"></eg-grid-toolbar-action>
+    </eg-grid>
+</div>
+<div *ngIf="statCatType === 'Copy'">
+    <eg-grid #copyGrid [dataSource]="copyDataSource" idlClass="asce"
+    (onRowActivate)="editEntry([$event])" hideFields="id,stat_cat,owner">
+        <eg-grid-toolbar-button label="New Entry" i18n-label
+        [action]="createNewEntry"></eg-grid-toolbar-button>
+        <eg-grid-toolbar-action label="Edit Selected" i18n-label 
+        [action]="editEntry"></eg-grid-toolbar-action>
+        <eg-grid-toolbar-action label="Delete Selected" i18n-label 
+        (onClick)="deleteEntry($event)"></eg-grid-toolbar-action>
+    </eg-grid>
+</div>
+
+<eg-string #createSuccessString i18n-text text="New entry Added"></eg-string>
+<eg-string #createErrString i18n-text text="Failed to create new entry"></eg-string>
+<eg-string #deleteFailedString i18n-text text="Deletion failed or was not allowed">
+</eg-string>
+<eg-string #deleteSuccessString i18n-text text="Deletion succeeded"></eg-string>
+<eg-string #updateFailedString i18n-text text="Update failed or was not allowed">
+</eg-string>
+<eg-string #updateSuccessString i18n-text text="Update succeeded"></eg-string>
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.ts
new file mode 100644 (file)
index 0000000..200b73f
--- /dev/null
@@ -0,0 +1,133 @@
+import {Pager} from '@eg/share/util/pager';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
+import {StringComponent} from '@eg/share/string/string.component';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {ActivatedRoute} from '@angular/router';
+import {Router} from '@angular/router';
+
+@Component({
+    templateUrl: './stat_cat_entries.component.html'
+})
+
+export class StatCatEntriesComponent implements OnInit {
+    statCatId: number;
+    statCatType: string;
+    copyDataSource: GridDataSource = new GridDataSource();
+    patronDataSource: GridDataSource = new GridDataSource();
+
+    @ViewChild('copyGrid', {static: false}) copyGrid: GridComponent;
+    @ViewChild('patronGrid', {static: false}) patronGrid: GridComponent;
+    @ViewChild('copyDialog', {static: false}) copyDialog: FmRecordEditorComponent;
+    @ViewChild('patronDialog', {static: false}) patronDialog: FmRecordEditorComponent;
+    @ViewChild('updateSuccessString', {static: false}) updateSuccessString: StringComponent;
+    @ViewChild('updateFailedString', {static: false}) updateFailedString: StringComponent;
+    @ViewChild('deleteFailedString', {static: false}) deleteFailedString: StringComponent;
+    @ViewChild('deleteSuccessString', {static: false}) deleteSuccessString: StringComponent;
+    @ViewChild('createSuccessString', {static: false}) createSuccessString: StringComponent;
+    @ViewChild('createErrString', {static: false}) createErrString: StringComponent;
+
+    constructor(
+        private router: Router,
+        private pcrud: PcrudService,
+        private route: ActivatedRoute,
+        private toast: ToastService
+    ) {
+    }
+
+    ngOnInit() {
+        this.statCatId = parseInt(this.route.snapshot.paramMap.get('id'), 10);
+        if (this.router.url.includes('copy_entries')) {
+            this.statCatType = 'Copy';
+            this.copyDataSource.getRows = (pager: Pager, sort: any[]) => {
+                const orderBy: any = {order_by: {asce: 'id'}};
+                return this.pcrud.search('asce', {stat_cat: this.statCatId}, orderBy);
+            };
+        } else if (this.router.url.includes('patron_entries')) {
+            this.statCatType = 'Patron';
+            this.patronDataSource.getRows = (pager: Pager, sort: any[]) => {
+                const orderBy: any = {order_by: {actsce: 'id'}};
+                return this.pcrud.search('actsce', {stat_cat: this.statCatId}, orderBy);
+            };
+        } else {
+            console.debug('Error - unable to determine type of stat cat');
+        }
+    }
+
+    deleteEntry = (idlThings: IdlObject[]) => {
+        const currentGrid = this.lookupType().currentGrid;
+        idlThings.forEach(idlThing => idlThing.isdeleted(true));
+        this.pcrud.autoApply(idlThings).subscribe(
+            val => {
+                console.debug('deleted: ' + val);
+                this.deleteSuccessString.current()
+                    .then(str => this.toast.success(str));
+                currentGrid.reload();
+            },
+            err => {
+                this.deleteFailedString.current()
+                    .then(str => this.toast.danger(str));
+            }
+        );
+    }
+
+    lookupType() {
+        let currentDialog;
+        let currentGrid;
+        if (this.statCatType === 'Copy') {
+            currentGrid = this.copyGrid;
+            currentDialog = this.copyDialog;
+        } else {
+            currentGrid = this.patronGrid;
+            currentDialog = this.patronDialog;
+        }
+        return {
+            currentGrid: currentGrid,
+            currentDialog: currentDialog
+        };
+    }
+
+    createNewEntry = () => {
+        const lookupResponse = this.lookupType();
+        const currentDialog = lookupResponse.currentDialog;
+        const currentGrid = lookupResponse.currentGrid;
+        currentDialog.mode = 'create';
+        currentDialog.recordId = null;
+        currentDialog.record = null;
+        currentDialog.open({size: 'lg'}).subscribe(
+            ok => {
+                this.createSuccessString.current()
+                    .then(str => this.toast.success(str));
+                currentGrid.reload();
+            },
+            rejection => {
+                if (!rejection.dismissed) {
+                    this.createErrString.current()
+                        .then(str => this.toast.danger(str));
+                }
+            }
+        );
+    }
+
+    editEntry = (idlThing) => {
+        const lookupResponse = this.lookupType();
+        const currentDialog = lookupResponse.currentDialog;
+        const currentGrid = lookupResponse.currentGrid;
+        currentDialog.mode = 'update';
+        currentDialog.recordId = idlThing[0].id();
+        currentDialog.open({size: 'lg'}).subscribe(
+            id => {
+                console.debug('Record editor performed action');
+                currentGrid.reload();
+            },
+            err => {
+                console.debug(err);
+            },
+            () => console.debug('Dialog closed')
+        );
+    }
+}
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_routing.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_routing.module.ts
new file mode 100644 (file)
index 0000000..f2d205d
--- /dev/null
@@ -0,0 +1,22 @@
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {StatCatComponent} from './stat_cat.component';
+import {StatCatEntriesComponent} from './stat_cat_entries.component';
+
+const routes: Routes = [{
+  path: '',
+  component: StatCatComponent
+}, {
+  path: 'copy_entries/:id',
+  component: StatCatEntriesComponent
+}, {
+  path: 'patron_entries/:id',
+  component: StatCatEntriesComponent
+}];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+
+export class StatCatRoutingModule {}