Merge branch 'master' into user/mrisher/lp1857911-stat-cat-v3
authorMike Risher <mrisher@catalyte.io>
Fri, 9 Oct 2020 20:30:01 +0000 (20:30 +0000)
committerMike Risher <mrisher@catalyte.io>
Fri, 9 Oct 2020 22:26:53 +0000 (22:26 +0000)
1  2 
Open-ILS/examples/fm_IDL.xml
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.ts
Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.html
Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_entries.component.ts
Open-ILS/src/eg2/src/app/staff/admin/local/stat_cat/stat_cat_routing.module.ts

@@@ -1476,62 -1476,62 +1476,6 @@@ Foundation, Inc., 51 Franklin Street, F
                </permacrud>
        </class>
  
--      <class id="atevdefg" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action_trigger::event_def_group" oils_persist:tablename="action_trigger.event_def_group" reporter:label="Trigger Event Definition Group" oils_persist:restrict_primary="100">
--              <fields oils_persist:primary="id" oils_persist:sequence="action_trigger.event_def_group_id_seq">
--                      <field reporter:label="Group ID" name="id" reporter:datatype="id"/>
--                      <field reporter:label="Enabled" name="active" reporter:datatype="bool"/>
--                      <field reporter:label="Owning Library" name="owner"  reporter:datatype="org_unit"/>
--                      <field reporter:label="Hook" name="hook"  reporter:datatype="link"/>
--                      <field reporter:label="Name" name="name"  reporter:datatype="text"/>
--                      <field reporter:label="Members" name="members" oils_persist:virtual="true" reporter:datatype="link"/>
--              </fields>
--              <links>
--                      <link field="owner" reltype="has_a" key="id" map="" class="aou"/>
--                      <link field="hook" reltype="has_a" key="key" map="" class="ath"/>
--                      <link field="members" reltype="has_many" key="grp" map="" class="atevdefgm"/>
--              </links>
--              <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--                      <actions>
--                              <create permission="ADMIN_TRIGGER_EVENT_DEF CREATE_TRIGGER_EVENT_DEF" context_field="owner"/>
--                              <retrieve permission="ADMIN_TRIGGER_EVENT_DEF VIEW_TRIGGER_EVENT_DEF" context_field="owner"/>
--                              <update permission="ADMIN_TRIGGER_EVENT_DEF UPDATE_TRIGGER_EVENT_DEF" context_field="owner"/>
--                              <delete permission="ADMIN_TRIGGER_EVENT_DEF DELETE_TRIGGER_EVENT_DEF" context_field="owner"/>
--                      </actions>
--              </permacrud>
--      </class>
--
--      <class id="atevdefgm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action_trigger::event_def_group_member" oils_persist:tablename="action_trigger.event_def_group_member" reporter:label="Trigger Event Definition Group Member">
--              <fields oils_persist:primary="id" oils_persist:sequence="action_trigger.event_def_group_member_id_seq">
--                      <field reporter:label="ID" name="id" reporter:datatype="id"/>
--                      <field reporter:label="Name" name="name"  reporter:datatype="text"/>
--                      <field reporter:label="Group" name="grp"  reporter:datatype="link"/>
--                      <field reporter:label="Event Definition" name="event_def"  reporter:datatype="link"/>
--                      <field reporter:label="Sortable" name="sortable" reporter:datatype="bool"/>
--                      <field reporter:label="Include Holdings" name="holdings" reporter:datatype="bool"/>
--                      <field reporter:label="Externally Processed" name="external" reporter:datatype="bool"/>
--              </fields>
--              <links>
--                      <link field="grp" reltype="has_a" key="id" map="" class="atevdefg"/>
--                      <link field="event_def" reltype="has_a" key="id" map="" class="atevdef"/>
--              </links>
--              <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--                      <actions>
--                              <create permission="ADMIN_TRIGGER_EVENT_DEF CREATE_TRIGGER_EVENT_DEF">
--                    <context link="grp" field="owner"/>
--                </create>
--                              <retrieve permission="ADMIN_TRIGGER_EVENT_DEF VIEW_TRIGGER_EVENT_DEF">
--                    <context link="grp" field="owner"/>
--                </retrieve>
--                              <update permission="ADMIN_TRIGGER_EVENT_DEF UPDATE_TRIGGER_EVENT_DEF">
--                    <context link="grp" field="owner"/>
--                </update>
--                              <delete permission="ADMIN_TRIGGER_EVENT_DEF DELETE_TRIGGER_EVENT_DEF">
--                    <context link="grp" field="owner"/>
--                </delete>
--                      </actions>
--              </permacrud>
--      </class>
--
        <class id="atev" controller="open-ils.cstore" oils_obj:fieldmapper="action_trigger::event" oils_persist:tablename="action_trigger.event" reporter:label="Trigger Event Entry">
                <fields oils_persist:primary="id" oils_persist:sequence="action_trigger.event_id_seq">
                        <field reporter:label="Event ID" name="id" reporter:datatype="id"/>
                        <link field="thesaurus" reltype="might_have" key="code" map="" class="at"/>
                </links>
        </class>
--      <class id="abl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="authority::bib_linking" oils_persist:tablename="authority.bib_linking" reporter:label="Authority-Bibliographic Record Link">
++      <class id="abl" controller="open-ils.cstore" oils_obj:fieldmapper="authority::bib_linking" oils_persist:tablename="authority.bib_linking" reporter:label="Authority-Bibliographic Record Link">
                <fields oils_persist:primary="id" oils_persist:sequence="authority.bib_linking_id_seq">
                        <field name="id" reporter:datatype="id" />
                        <field name="bib" reporter:datatype="link" />
                        <link field="bib" reltype="has_a" key="id" map="" class="bre"/>
                        <link field="authority" reltype="has_a" key="id" map="" class="are"/>
                </links>
--              <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--                      <actions>
--                              <retrieve/>
--                      </actions>
--              </permacrud>
        </class>
        <class id="ash" controller="open-ils.cstore" oils_obj:fieldmapper="authority::simple_heading" oils_persist:tablename="authority.simple_heading" reporter:label="Authority Simple Heading">
                <fields oils_persist:primary="id" oils_persist:sequence="authority.simple_heading_id_seq">
                        <field name="record" reporter:datatype="link" />
                        <field name="atag" reporter:datatype="link" />
                        <field name="value" reporter:datatype="text" />
--                      <field name="thesaurus" reporter:datatype="text" />
                </fields>
                <links>
                        <link field="record" reltype="has_a" key="id" map="" class="are"/>
              </actions>
          </permacrud>
        </class>
--    <class id="acmc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::course_module_course" oils_persist:tablename="asset.course_module_course" reporter:label="Course">
--        <fields oils_persist:primary="id" oils_persist:sequence="asset.course_module_course_id_seq">
--            <field reporter:label="ID" name="id" reporter:datatype="id" />
--            <field reporter:label="Course Name" name="name" reporter:datatype="text" oils_obj:required="true" />
--            <field reporter:label="Course Number" name="course_number" reporter:datatype="text" oils_obj:required="true" />
--            <field reporter:label="Section Number" name="section_number" reporter:datatype="text" />
--            <field reporter:label="Owning Library" name="owning_lib" reporter:datatype="link" oils_obj:required="true" />
--            <field reporter:label="Course Members" name="members" oils_persist:virtual="true" reporter:datatype="link" />
--            <field reporter:label="Course Materials" name="materials" oils_persist:virtual="true" reporter:datatype="link" />
--            <field reporter:label="Is Archived?" name="is_archived" reporter:datatype="bool" />
--                      <field reporter:label="Terms Taught" name="terms_map" oils_persist:virtual="true" reporter:datatype="link" config_field="true" />
--        </fields>
--        <links>
--            <link field="owning_lib" reltype="has_a" key="id" map="" class="aou" />
--            <link field="members" reltype="has_many" key="course" map="" class="acmcu" />
--            <link field="materials" reltype="has_many" key="course" map="" class="acmcm" />
--                      <link field="terms_map" reltype="has_many" key="course" map="" class="acmtcm" />
--        </links>
--        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--            <actions>
--                <create permission="MANAGE_RESERVES" context_field="owning_lib"/>
--                <retrieve/>
--                <update permission="MANAGE_RESERVES" context_field="owning_lib"/>
--                <delete permission="MANAGE_RESERVES" context_field="owning_lib"/>
--            </actions>
--        </permacrud>
--    </class>
--    <class id="acmcu" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::course_module_course_users" oils_persist:tablename="asset.course_module_course_users" reporter:label="Course Users">
--        <fields oils_persist:primary="id" oils_persist:sequence="asset.course_module_course_users_id_seq">
--            <field reporter:label="ID" name="id" reporter:datatype="id" />
--            <field reporter:label="Course" name="course" reporter:datatype="link" />
--            <field reporter:label="User" name="usr" reporter:datatype="link" />
--            <field reporter:label="User Role" name="usr_role" reporter:datatype="link" />
--        </fields>
--        <links>
--            <link field="course" reltype="has_a" key="id" map="" class="acmc" />
--            <link field="usr" reltype="has_a" key="id" map="" class="au" />
--            <link field="usr_role" reltype="has_a" key="id" map="" class="acmr" />
--        </links>
--        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--            <actions>
--                <create permission="MANAGE_RESERVES">
--                                      <context link="course" field="owning_lib" />
--                </create>
--                <retrieve/>
--                <update permission="MANAGE_RESERVES">
--                                      <context link="course" field="owning_lib" />
--                </update>
--                <delete permission="MANAGE_RESERVES">
--                                      <context link="course" field="owning_lib" />
--                </delete>
--            </actions>
--        </permacrud>
--    </class>
--    <class id="acmcm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::course_module_course_materials" oils_persist:tablename="asset.course_module_course_materials" reporter:label="Course Materials" oils_persist:field_safe="true">
--        <fields oils_persist:primary="id" oils_persist:sequence="asset.course_module_course_materials_id_seq">
--            <field reporter:label="ID" name="id" reporter:datatype="id" />
--            <field reporter:label="Course" name="course" reporter:datatype="link" />
--            <field reporter:label="Item" name="item" reporter:datatype="link" />
--            <field reporter:label="Record" name="record" reporter:datatype="link" />
--            <field reporter:label="Record is temporary?" name="temporary_record" reporter:datatype="bool" />
--            <field reporter:label="Item Relationship" name="relationship" reporter:datatype="text" />
--            <field reporter:label="Original Status" name="original_status" reporter:datatype="link" />
--            <field reporter:label="Original Circ Modifier" name="original_circ_modifier" reporter:datatype="link" />
--            <field reporter:label="Original Shelving Location" name="original_location" reporter:datatype="link" />
--            <field reporter:label="Original Callnumber" name="original_callnumber" reporter:datatype="link" />
--        </fields>
--        <links>
--            <link field="course" reltype="has_a" key="id" map="" class="acmc" />
--            <link field="item" reltype="has_a" key="id" map="" class="acp" />
--            <link field="record" reltype="has_a" key="id" map="" class="bre" />
--            <link field="original_callnumber" reltype="has_a" key="id" map="" class="acn" />
--            <link field="original_status" reltype="has_a" key="id" map="" class="ccs" />
--            <link field="original_circ_modifier" reltype="has_a" key="code" map="" class="ccm" />
--            <link field="original_location" reltype="has_a" key="id" map="" class="acpl" />
--        </links>
--        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--            <actions>
--                <create permission="MANAGE_RESERVES">
--                                      <context link="course" field="owning_lib" />
--                </create>
--                <retrieve/>
--                <update permission="MANAGE_RESERVES">
--                                      <context link="course" field="owning_lib" />
--                </update>
--                <delete permission="MANAGE_RESERVES">
--                                      <context link="course" field="owning_lib" />
--                </delete>
--            </actions>
--        </permacrud>
--    </class>
--      <class id="acmt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::course_module_term" oils_persist:tablename="asset.course_module_term" reporter:label="Term" oils_persist:field_safe="true">
--              <fields oils_persist:primary="id" oils_persist:sequence="asset.course_module_term_id_seq">
--                      <field reporter:label="Term ID" name="id" reporter:datatype="id" reporter:selector="name"/>
--                      <field reporter:label="Name" name="name" reporter:datatype="text" oils_persist:i18n="true" oils_obj:required="true"/>
--            <field reporter:label="Owning Library" name="owning_lib" reporter:datatype="link" oils_obj:required="true" />
--                      <field reporter:label="Start Date" name="start_date" reporter:datatype="timestamp"/>
--                      <field reporter:label="End Date" name="end_date" reporter:datatype="timestamp"/>
--                      <field reporter:label="Courses" name="courses" reporter:datatype="link" oils_persist:virtual="true"/>
--                      <field reporter:label="Course Maps" name="maps" reporter:datatype="link" oils_persist:virtual="true"/>
--              </fields>
--              <links>
--            <link field="owning_lib" reltype="has_a" key="id" map="" class="aou" />
--                      <link field="courses" reltype="has_many" key="term" map="course" class="acmtcm"/>
--                      <link field="maps" reltype="has_many" key="term" map="" class="acmtcm"/>
--              </links>
--              <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--                      <actions>
--                              <create permission="MANAGE_RESERVES" context_field="owning_lib" />
--                              <retrieve/>
--                              <update permission="MANAGE_RESERVES" context_field="owning_lib" />
--                              <delete permission="MANAGE_RESERVES" context_field="owning_lib" />
--                      </actions>
--              </permacrud>
--      </class>
--    <class id="acmtcm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::course_module_term_course_map" oils_persist:tablename="asset.course_module_term_course_map" reporter:label="Course Term Map" oils_persist:field_safe="true">
--        <fields oils_persist:primary="id" oils_persist:sequence="asset.course_module_term_course_map_id_seq">
--            <field reporter:label="Course Term Map ID" name="id" reporter:datatype="id"/>
--            <field reporter:label="Term" name="term" oils_obj:required="true" reporter:datatype="link"/>
--            <field reporter:label="Course" name="course" reporter:datatype="link" oils_obj:required="true"/>
--        </fields>
--        <links>
--            <link field="term" reltype="has_a" key="id" map="" class="acmt"/>
--            <link field="course" reltype="has_a" key="id" map="" class="acmc"/>
--        </links>
--        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--            <actions>
--                <create permission="MANAGE_RESERVES">
--                                      <context link="course" field="owning_lib" />
--                </create>
--                <retrieve/>
--                <update permission="MANAGE_RESERVES">
--                                      <context link="course" field="owning_lib" />
--                </update>
--                <delete permission="MANAGE_RESERVES">
--                                      <context link="course" field="owning_lib" />
--                </delete>
--            </actions>
--        </permacrud>
--    </class>
--      <class id="acmr" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::course_module_role" oils_persist:tablename="asset.course_module_role" reporter:label="Course Role" oils_persist:field_safe="true">
--              <fields oils_persist:primary="id" oils_persist:sequence="asset.course_module_role_id_seq">
--                      <field reporter:label="Role ID" name="id" reporter:datatype="id" reporter:selector="name"/>
--                      <field reporter:label="Name" name="name" reporter:datatype="text" oils_persist:i18n="true" oils_obj:required="true"/>
--            <field reporter:label="OPAC Viewable?" name="is_public" reporter:datatype="bool" />
--              </fields>
--              <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--                      <actions>
--                              <create permission="MANAGE_RESERVES" global_required="true" />
--                              <retrieve/>
--                              <update permission="MANAGE_RESERVES" global_required="true" />
--                              <delete permission="MANAGE_RESERVES" global_required="true" />
--                      </actions>
--              </permacrud>
--      </class>
--      
      <class id="acnc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::call_number_class" oils_persist:tablename="asset.call_number_class" reporter:label="Call number classification scheme">
          <fields oils_persist:primary="id" oils_persist:sequence="asset.call_number_class_id_seq">
              <field reporter:label="Call number class ID" name="id" reporter:datatype="id"/>
                        <field reporter:label="Preferred Suffix" name="pref_suffix" reporter:datatype="text"/>
                        <field reporter:label="Parent/Guardian" name="guardian" reporter:datatype="text"/>
                        <field reporter:label="Name Keywords" name="name_keywords" reporter:datatype="text"/>
--                      <field reporter:label="Name Keyword internal tsvector" name="name_kw_tsvector" reporter:datatype="text"/>
                        <field reporter:label="Additional Permission Groups" name="groups" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field reporter:label="Is Deleted" name="deleted" reporter:datatype="bool"/>
                        <field reporter:label="User Notes" name="notes" oils_persist:virtual="true" reporter:datatype="link"/>
              <field name="copy_active" reporter:datatype="bool" reporter:label="Sets Item Active"/>
              <field name="restrict_copy_delete" reporter:datatype="bool" reporter:label="Restrict Deletion"/>
              <field name="is_available" reporter:datatype="bool" reporter:label="Available"/>
--            <field name="hopeless_prone" reporter:datatype="bool" reporter:label="Prone to Hopeless Holds?"/>
                </fields>
                <links/>
          <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
@@@ -4853,26 -4853,26 +4633,6 @@@ SELECT  usr
              <link field="usr" reltype="has_a" key="id" map="" class="au"/>
          </links>
        </class>
--      <class id="acsp" controller="open-ils.cstore" oils_obj:fieldmapper="action::curbside" oils_persist:tablename="action.curbside" reporter:label="Curbside Appointment Slot">
--              <fields oils_persist:primary="id" oils_persist:sequence="action.curbside_id_seq">
--                      <field reporter:label="Appointment ID" name="id" reporter:datatype="id" />
--                      <field reporter:label="Patron" name="patron" reporter:datatype="link"/>
--                      <field reporter:label="Pickup Library" name="org" reporter:datatype="org_unit"/>
--                      <field reporter:label="Appointment Date/Time" name="slot" reporter:datatype="timestamp"/>
--                      <field reporter:label="Staged" name="staged" reporter:datatype="timestamp"/>
--                      <field reporter:label="Staging Staff" name="stage_staff" reporter:datatype="link"/>
--                      <field reporter:label="Arrival Date/Time" name="arrival" reporter:datatype="timestamp"/>
--                      <field reporter:label="Delivery Date/Time" name="delivered" reporter:datatype="timestamp"/>
--                      <field reporter:label="Delivery Staff" name="delivery_staff" reporter:datatype="link"/>
--                      <field reporter:label="Notes" name="notes" reporter:datatype="text"/>
--              </fields>
--              <links>
--                      <link field="org" reltype="has_a" key="id" map="" class="aou"/>
--                      <link field="patron" reltype="has_a" key="id" map="" class="au"/>
--                      <link field="stage_staff" reltype="has_a" key="id" map="" class="au"/>
--                      <link field="delivery_staff" reltype="has_a" key="id" map="" class="au"/>
--              </links>
--      </class>
        <class id="circ" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action::circulation" oils_persist:tablename="action.circulation" reporter:core="true" reporter:label="Circulation">
                <fields oils_persist:primary="id" oils_persist:sequence="money.billable_xact_id_seq">
                        <field reporter:label="Check In Library" name="checkin_lib" reporter:datatype="org_unit"/>
                </links>
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
--                              <create permission="ADMIN_BOOKING_RESERVATION" context_field="pickup_lib"/>
--                              <retrieve permission="VIEW_BOOKING_RESERVATION" context_field="pickup_lib"/>
--                              <update permission="ADMIN_BOOKING_RESERVATION" context_field="pickup_lib"/>
--                              <delete permission="ADMIN_BOOKING_RESERVATION" context_field="pickup_lib"/>
++                              <create permission="ADMIN_BOOKING_RESERVATION" global_required='true'/>
++                              <retrieve permission="STAFF_LOGIN" global_required='true'/>
++                              <update permission="ADMIN_BOOKING_RESERVATION" global_required='true'/>
++                              <delete permission="ADMIN_BOOKING_RESERVATION" global_required='true'/>
                        </actions>
                </permacrud>
        </class>
                </links>
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
--                              <create permission="ADMIN_BOOKING_RESERVATION_ATTR_MAP">
--                                      <context link="reservation" field="pickup_lib"/>
--                              </create>
--                              <retrieve permission="VIEW_BOOKING_RESERVATION_ATTR_MAP">
--                                      <context link="reservation" field="pickup_lib"/>
--                              </retrieve>
--                              <update permission="ADMIN_BOOKING_RESERVATION_ATTR_MAP">
--                                      <context link="reservation" field="pickup_lib"/>
--                              </update>
--                              <delete permission="ADMIN_BOOKING_RESERVATION_ATTR_MAP">
--                                      <context link="reservation" field="pickup_lib"/>
--                              </delete>
++                              <create permission="ADMIN_BOOKING_RESERVATION_ATTR_MAP" global_required='true'/>
++                              <retrieve permission="STAFF_LOGIN" global_required='true'/>
++                              <update permission="ADMIN_BOOKING_RESERVATION_ATTR_MAP" global_required='true'/>
++                              <delete permission="ADMIN_BOOKING_RESERVATION_ATTR_MAP" global_required='true'/>
                        </actions>
                </permacrud>
        </class>
                        <field reporter:label="Current Shelf Lib" name="current_shelf_lib" reporter:datatype="org_unit"/>
                        <field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
                        <field reporter:label="Acquisition Request" name="acq_request" reporter:datatype="link" />
--                      <field reporter:label="Hopeless Date" name="hopeless_date" reporter:datatype="timestamp"/>
                </fields>
                <links>
                        <link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
                        <field reporter:label="Is Staff Hold?" name="is_staff_hold" reporter:datatype="bool" />
                        <field reporter:label="Potential Copies" name="potential_copies" reporter:datatype="int" />
                        <field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
--                      <field reporter:label="Hopeless Date" name="hopeless_date" reporter:datatype="timestamp"/>
                </fields>
                <links>
                        <link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
                        <field reporter:label="Current Shelf Lib" name="current_shelf_lib" reporter:datatype="org_unit"/>
                        <field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
                        <field reporter:label="Acquisition Request" name="acq_request" reporter:datatype="link" />
--                      <field reporter:label="Hopeless Date" name="hopeless_date" reporter:datatype="timestamp"/>
                </fields>
                <links>
                        <link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
                        <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>
-               <actions>
 +              <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"/>
                        <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>
-               <actions>
 +              <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">
                </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>
++                              <create permission="CREATE_PATRON_STAT_CAT" context_field="owner"/>
                                <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>
++                              <update permission="UPDATE_PATRON_STAT_CAT" context_field="owner"/>
++                <delete permission="DELETE_PATRON_STAT_CAT" context_field="owner"/>
                        </actions>
                </permacrud>
        </class>
        <class id="acqpro" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::provider" oils_persist:tablename="acq.provider" reporter:label="Provider">
                <fields oils_persist:primary="id" oils_persist:sequence="acq.provider_id_seq">
                        <field reporter:label="Provider ID" name="id" reporter:datatype="id" reporter:selector='code'/>
--                      <field reporter:label="Provider Name" name="name" reporter:datatype="text" oils_obj:required="true"/>
--                      <field reporter:label="Owner" name="owner" reporter:datatype="org_unit" oils_obj:required="true"/>
--                      <field reporter:label="Currency" name="currency_type" oils_persist:primitive="string" reporter:datatype="link" oils_obj:required="true"/>
--                      <field reporter:label="Code" name="code" reporter:datatype="text" oils_obj:required="true"/>
++                      <field reporter:label="Provider Name" name="name" reporter:datatype="text" oils_persist:i18n="true" />
++                      <field reporter:label="Owner" name="owner" reporter:datatype="org_unit" />
++                      <field reporter:label="Currency" name="currency_type" oils_persist:primitive="string" reporter:datatype="link" />
++                      <field reporter:label="Code" name="code" reporter:datatype="text" />
                        <field reporter:label="Holdings Tag" name="holding_tag" reporter:datatype="text" />
                        <field reporter:label="Addresses" name="addresses" oils_persist:virtual="true" reporter:datatype="link" />
                        <field reporter:label="SAN" name="san" reporter:datatype="text" />
                        <field reporter:label="Fax Phone" name="fax_phone" reporter:datatype="text" />
                        <field reporter:label="Default Claim Policy" name="default_claim_policy" reporter:datatype="link" />
                        <field reporter:label="Default # Copies" name="default_copy_count" reporter:datatype="int" />
--                      <field reporter:label="Primary Contact" name="primary_contact" reporter:datatype="link" />
--                      <field reporter:label="Contacts" name="contacts" oils_persist:virtual="true" reporter:datatype="link" />
                        <field reporter:label="Notes" name="provider_notes" oils_persist:virtual="true" reporter:datatype="link" />
--                      <field reporter:label="Holdings Subfields" name="holdings_subfields" oils_persist:virtual="true" reporter:datatype="link" />
--                      <field reporter:label="Attribute Definitions" name="attributes" oils_persist:virtual="true" reporter:datatype="link" />
--                      <field reporter:label="EDI Accounts" name="edi_accounts" oils_persist:virtual="true" reporter:datatype="link" />
                </fields>
                <links>
                        <link field="currency_type" reltype="has_a" key="code" map="" class="acqct"/>
                        <link field="owner" reltype="has_a" key="id" map="" class="aou"/>
--                      <link field="addresses" reltype="has_many" map="" key="provider" class="acqpa"/>
--                      <link field="contacts" reltype="has_many" map="" key="provider" class="acqpc"/>
--                      <link field="edi_default" reltype="has_a" map="" key="id" class="acqedi"/>
--                      <link field="primary_contact" reltype="has_a" map="" key="id" class="acqpc"/>
++            <link field="addresses" reltype="has_many" map="" key="provider" class="acqpa"/>
++            <link field="edi_default" reltype="has_a" map="" key="id" class="acqedi"/>
                        <link field="default_claim_policy" reltype="has_a" map="" key="id" class="acqclp"/>
                        <link field="provider_notes" reltype="has_many" map="" key="provider" class="acqpron"/>
--                      <link field="holdings_subfields" reltype="has_many" map="" key="provider" class="acqphsm"/>
--                      <link field="attributes" reltype="has_many" map="" key="provider" class="acqlipad"/>
--                      <link field="edi_accounts" reltype="has_many" map="" key="provider" class="acqedi"/>
                </links>
          <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
              <actions>
        <class id="acqpa" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::provider_address" oils_persist:tablename="acq.provider_address" reporter:label="Provider Address">
                <fields oils_persist:primary="id" oils_persist:sequence="acq.provider_address_id_seq">
                        <field reporter:label="Address Type" name="address_type"  reporter:datatype="text"/>
--                      <field reporter:label="City" name="city"  reporter:datatype="text" oils_obj:required="true"/>
--                      <field reporter:label="Country" name="country"  reporter:datatype="text" oils_obj:required="true"/>
++                      <field reporter:label="City" name="city"  reporter:datatype="text"/>
++                      <field reporter:label="Country" name="country"  reporter:datatype="text"/>
                        <field reporter:label="County" name="county"  reporter:datatype="text"/>
                        <field reporter:label="ID" name="id" reporter:datatype="id"/>
                        <field reporter:label="Provider" name="provider" reporter:datatype="link"/>
--                      <field reporter:label="Post Code" name="post_code"  reporter:datatype="text" oils_obj:required="true"/>
--                      <field reporter:label="State" name="state"  reporter:datatype="text" oils_obj:required="true"/>
--                      <field reporter:label="Street 1" name="street1"  reporter:datatype="text" oils_obj:required="true"/>
++                      <field reporter:label="Post Code" name="post_code"  reporter:datatype="text"/>
++                      <field reporter:label="State" name="state"  reporter:datatype="text"/>
++                      <field reporter:label="Street 1" name="street1"  reporter:datatype="text"/>
                        <field reporter:label="Street 2" name="street2"  reporter:datatype="text"/>
                        <field reporter:label="Is Valid?" name="valid" reporter:datatype="bool"/>
                        <field reporter:label="Fax Phone" name="fax_phone" reporter:datatype="text"/>
        <class id="acqpc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::provider_contact" oils_persist:tablename="acq.provider_contact" reporter:label="Provider Contact">
                <fields oils_persist:primary="id" oils_persist:sequence="acq.provider_contact_id_seq">
                        <field reporter:label="ID" name="id" reporter:datatype="id"/>
--                      <field reporter:label="Provider" name="provider" reporter:datatype="link" oils_obj:required="true"/>
--                      <field reporter:label="Name" name="name" reporter:datatype="text" oils_obj:required="true"/>
++                      <field reporter:label="Provider" name="provider" reporter:datatype="link"/>
++                      <field reporter:label="Name" name="name" reporter:datatype="text"/>
                        <field reporter:label="Role" name="role" reporter:datatype="text"/>
                        <field reporter:label="Email" name="email" reporter:datatype="text"/>
                        <field reporter:label="Phone" name="phone" reporter:datatype="text"/>
--                      <field reporter:label="Addresses" name="addresses" oils_persist:virtual="true" reporter:datatype="link"/>
          </fields>
                <links>
--                      <link field="addresses" reltype="has_many" key="contact" map="" class="acqpca"/>
                        <link field="provider" reltype="has_a" key="id" map="" class="acqpro"/>
                </links>
          <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
        <class id="acqpca" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::provider_contact_address" oils_persist:tablename="acq.provider_contact_address" reporter:label="Provider Contact Address">
                <fields oils_persist:primary="id" oils_persist:sequence="acq.provider_contact_address_id_seq">
                        <field reporter:label="Type" name="address_type"  reporter:datatype="text"/>
--                      <field reporter:label="City" name="city"  reporter:datatype="text" oils_obj:required="true"/>
--                      <field reporter:label="Country" name="country"  reporter:datatype="text" oils_obj:required="true"/>
++                      <field reporter:label="City" name="city"  reporter:datatype="text"/>
++                      <field reporter:label="Country" name="country"  reporter:datatype="text"/>
                        <field reporter:label="County" name="county"  reporter:datatype="text"/>
                        <field reporter:label="Address ID" name="id" reporter:datatype="id" />
--                      <field reporter:label="Postal Code" name="post_code" reporter:datatype="text" oils_obj:required="true"/>
--                      <field reporter:label="State" name="state"  reporter:datatype="text" oils_obj:required="true"/>
--                      <field reporter:label="Street (1)" name="street1"  reporter:datatype="text" oils_obj:required="true"/>
++                      <field reporter:label="Postal Code" name="post_code" reporter:datatype="text"/>
++                      <field reporter:label="State" name="state"  reporter:datatype="text"/>
++                      <field reporter:label="Street (1)" name="street1"  reporter:datatype="text"/>
                        <field reporter:label="Street (2)" name="street2"  reporter:datatype="text"/>
--                      <field reporter:label="Contact" name="contact" reporter:datatype="link" oils_obj:required="true"/>
++                      <field reporter:label="Contact" name="contact" reporter:datatype="link"/>
                        <field reporter:label="Valid Address?" name="valid" reporter:datatype="bool"/>
                        <field reporter:label="Fax Phone" name="fax_phone" reporter:datatype="text"/>
                </fields>
                        <field reporter:label="Creation Time" name="create_time" reporter:datatype="timestamp" />
                        <field reporter:label="Edit Time" name="edit_time" reporter:datatype="timestamp" />
                        <field reporter:label="Provider" name="provider" reporter:datatype="link" />
--                      <field reporter:label="Status" name="state" reporter:datatype="link" />
++                      <field reporter:label="State" name="state" reporter:datatype="text" />
                        <field reporter:label="Ordering Agency" name="ordering_agency" reporter:datatype="org_unit" />
                        <field reporter:label="Creator" name="creator" reporter:datatype="link" />
                        <field reporter:label="Editor" name="editor" reporter:datatype="link" />
                        <field reporter:label="PO Items" name="po_items" oils_persist:virtual="true" reporter:datatype="link" />
                </fields>
                <links>
--                      <link field="state" reltype="has_a" key="id" map="" class="acqpostlbl"/>
                        <link field="owner" reltype="has_a" key="id" map="" class="au"/>
                        <link field="creator" reltype="has_a" key="id" map="" class="au"/>
                        <link field="editor" reltype="has_a" key="id" map="" class="au"/>
                        <field reporter:label="Create Time" name="create_time" reporter:datatype="timestamp"/>
                        <field reporter:label="Edit Time" name="edit_time" reporter:datatype="timestamp"/>
                        <field reporter:label="Provider" name="provider" reporter:datatype="link"/>
--                      <field reporter:label="Status" name="state" reporter:datatype="text"/>
++                      <field reporter:label="State" name="state" reporter:datatype="text"/>
                        <field reporter:label="Order Date" name="order_date" reporter:datatype="timestamp"/>
                        <field reporter:label="Name" name="name" reporter:datatype="text"/>
                        <field reporter:label="Cancel Reason" name="cancel_reason" reporter:datatype="link"/>
                        <field reporter:label="Evergreen Bib ID" name="eg_bib_id" reporter:datatype="link" />
                        <field reporter:label="Source Label" name="source_label" reporter:datatype="text" />
                        <field reporter:label="Expected Receive Date" name="expected_recv_time" reporter:datatype="timestamp" />
--                      <field reporter:label="Status" name="state" reporter:datatype="link" />
++                      <field reporter:label="State" name="state" reporter:datatype="text" />
                        <field reporter:label="Creator" name="creator" reporter:datatype="link" />
                        <field reporter:label="Editor" name="editor" reporter:datatype="link" />
                        <field reporter:label="Claim Policy" name="claim_policy" reporter:datatype="link" />
                        <field reporter:label="Order Summary" name="order_summary" oils_persist:virtual="true" reporter:datatype="link" />
                </fields>
                <links>
--                      <link field="state" reltype="has_a" key="id" map="" class="jubstlbl"/>
                        <link field="selector" reltype="has_a" key="id" map="" class="au"/>
                        <link field="editor" reltype="has_a" key="id" map="" class="au"/>
                        <link field="creator" reltype="has_a" key="id" map="" class="au"/>
                        <field reporter:label="MARC" name="marc" reporter:datatype="text"/>
                        <field reporter:label="Evergreen Bib ID" name="eg_bib_id" reporter:datatype="link"/>
                        <field reporter:label="Source Label" name="source_label" reporter:datatype="text"/>
--                      <field reporter:label="Status" name="state" reporter:datatype="text"/>
++                      <field reporter:label="State" name="state" reporter:datatype="text"/>
                        <field reporter:label="Claim Policy" name="claim_policy" reporter:datatype="link"/>
                        <field reporter:label="Cancel Reason" name="cancel_reason" reporter:datatype="link"/>
                        <field reporter:label="Estimated Unit Price" name="estimated_unit_price" reporter:datatype="money" />
        <class id="acqlipad" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::lineitem_provider_attr_definition" oils_persist:tablename="acq.lineitem_provider_attr_definition" reporter:label="Line Item Provider Attribute Definition">
            <fields oils_persist:primary="id" oils_persist:sequence="acq.lineitem_attr_definition_id_seq">
                <field reporter:label="Definition ID" name="id" reporter:datatype="id" />
--              <field reporter:label="Code" name="code" reporter:datatype="text"  oils_obj:required="true" />
--              <field reporter:label="Description" name="description" reporter:datatype="text" oils_persist:i18n="true" oils_obj:required="true" />
--              <field reporter:label="XPath" name="xpath" reporter:datatype="text" oils_obj:required="true" />
--              <field reporter:label="Provider" name="provider" reporter:datatype="link" oils_obj:required="true" />
++              <field reporter:label="Code" name="code" reporter:datatype="text" />
++              <field reporter:label="Description" name="description" reporter:datatype="text" oils_persist:i18n="true" />
++              <field reporter:label="XPath" name="xpath" reporter:datatype="text" />
++              <field reporter:label="Provider" name="provider" reporter:datatype="link" />
                <field reporter:label="Is Identifier?" name="ident" reporter:datatype="bool"/>
          <field reporter:label="Remove" name="remove" reporter:datatype="text" />
  
        <class id="acqphsm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::provider_holding_subfield_map" oils_persist:tablename="acq.provider_holding_subfield_map" reporter:label="Provider Holding Subfield Map">
            <fields oils_persist:primary="id" oils_persist:sequence="acq.provider_holding_subfield_map_id_seq">
                <field reporter:label="ID" name="id" reporter:datatype="id" />
--              <field reporter:label="Provider" name="provider" reporter:datatype="link" oils_obj:required="true" />
--              <field reporter:label="Name" name="name" reporter:datatype="text" oils_obj:required="true" />
--              <field reporter:label="Subfield" name="subfield" reporter:datatype="text" oils_obj:required="true" />
++              <field reporter:label="Provider" name="provider" reporter:datatype="link" />
++              <field reporter:label="Name" name="name" reporter:datatype="text" />
++              <field reporter:label="Subfield" name="subfield" reporter:datatype="text" />
            </fields>
            <links>
                <link field="provider" reltype="has_a" key="id" map="" class="acqpro"/>
        <class id="acqedi" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::edi_account" oils_persist:tablename="acq.edi_account" reporter:label="EDI Account">
                <fields oils_persist:primary="id" oils_persist:sequence="config.remote_account_id_seq"><!-- edi_account inherits from config.remote_account, hence the seq -->
                        <field name="id"            reporter:datatype="id"        reporter:label="EDI Account ID" reporter:selector="label"/>
--                      <field name="label"         reporter:datatype="text"      reporter:label="Label" oils_obj:required="true"/>
--                      <field name="host"          reporter:datatype="text"      reporter:label="Host" oils_obj:required="true"/>
++                      <field name="label"         reporter:datatype="text"      reporter:label="Label"/>
++                      <field name="host"          reporter:datatype="text"      reporter:label="Host"/>
                        <field name="username"      reporter:datatype="text"      reporter:label="Username"/>
                        <field name="password"      reporter:datatype="text"      reporter:label="Password"/>
                        <field name="account"       reporter:datatype="text"      reporter:label="Account"/>
                        <field name="path"          reporter:datatype="text"      reporter:label="Path"/>
--                      <field name="owner"         reporter:datatype="link"      reporter:label="Owner" oils_obj:required="true"/>
++                      <field name="owner"         reporter:datatype="link"      reporter:label="Owner"/>
                        <field name="last_activity" reporter:datatype="timestamp" reporter:label="Last Activity"/>
--                      <field name="provider"      reporter:datatype="link"      reporter:label="Provider" oils_obj:required="true"/>
++                      <field name="provider"      reporter:datatype="link"      reporter:label="Provider"/>
                        <field name="in_dir"        reporter:datatype="text"      reporter:label="Incoming Directory"/>
                        <field name="vendacct"      reporter:datatype="text"      reporter:label="Vendor Account Number"/>
                        <field name="vendcode"      reporter:datatype="text"      reporter:label="Vendor Assigned Code"/>
                        <field name="attr_set"      reporter:datatype="link"      reporter:label="EDI Attribute Set"/>
--                      <field name="use_attrs"     reporter:datatype="bool"      reporter:label="Use EDI Attributes" oils_obj:required="true"/>
++                      <field name="use_attrs"     reporter:datatype="bool"      reporter:label="Use EDI Attributes"/>
                </fields>
                <links>
                        <link field="provider" reltype="has_a" key="id" map="" class="acqpro"/>
                </permacrud>
        </class>
  
--      <class id="jubstlbl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::li_state_label" oils_persist:tablename="acq.li_state_label" oils_persist:readonly="true" reporter:label="Line Item State Labels" oils_persist:field_safe="true">
--              <fields oils_persist:primary="id">
--                      <field reporter:label="State ID" reporter:selector="label" name="id" reporter:datatype="text"/>
--                      <field reporter:label="State Label" name="label" oils_persist:i18n="true" reporter:datatype="text"/>
--              </fields>
--              <links/>
--              <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--                      <actions>
--                              <retrieve/>
--                      </actions>
--              </permacrud>
--      </class>
--
--      <class id="acqpostlbl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::po_state_label" oils_persist:tablename="acq.po_state_label" oils_persist:readonly="true" reporter:label="PO State Labels">
--              <fields oils_persist:primary="id">
--                      <field reporter:label="State ID" reporter:selector="label" name="id" reporter:datatype="text"/>
--                      <field reporter:label="State Label" name="label" oils_persist:i18n="true" reporter:datatype="text"/>
--              </fields>
--              <links/>
--              <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
--                      <actions>
--                              <retrieve/>
--                      </actions>
--              </permacrud>
--      </class>
--
--
        <class id="rhcrpb" controller="open-ils.cstore open-ils.pcrud open-ils.reporter-store" oils_obj:fieldmapper="reporter::hold_copy_ratio_per_bib" oils_persist:readonly="true" reporter:core="true" reporter:label="Hold/Copy Ratio per Bib">
                <oils_persist:source_definition><![CDATA[
  
@@@ -17,11 -17,7 +17,15 @@@ const routes: Routes = [
  }, {
      path: 'actor/address_alert',
      component: AddressAlertComponent
 +}, {    
 +    path: 'asset/stat_cat_editor',
 +    loadChildren: () =>
 +        import('./stat_cat/stat_cat.module').then(m => m.StatCatModule)
 +}, {
++    path: 'asset/stat_cat_editor/:tab',
++    loadChildren: () =>
++        import('./stat_cat/stat_cat.module').then(m => m.StatCatModule)
+ }, {
      path: 'container/carousel',
      component: AdminCarouselComponent
  }, {
index 2cf15f8,0000000..037497d
mode 100644,000000..100644
--- /dev/null
@@@ -1,320 -1,0 +1,330 @@@
- import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
 +import {Pager} from '@eg/share/util/pager';
 +import {GridComponent} from '@eg/share/grid/grid.component';
 +import {GridDataSource} from '@eg/share/grid/grid';
 +import {Router, ActivatedRoute, ParamMap} from '@angular/router';
 +import {IdlObject, IdlService} 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';
 +import {PermService} from '@eg/core/perm.service';
 +import {AuthService} from '@eg/core/auth.service';
-     // @ViewChild('confirmDialog') private confirmDialog: ConfirmDialogComponent;
 +
 +@Component({
 +    templateUrl: './stat_cat.component.html'
 +})
 +
 +export class StatCatComponent implements OnInit {
 +
 +    currentTab: String;
 +    ascDataSource: GridDataSource = new GridDataSource();
 +    actscDataSource: GridDataSource = new GridDataSource();
 +    selectedCopyOrg: IdlObject = this.org.get(this.auth.user().ws_ou());
 +    selectedPatronOrg: IdlObject = this.org.get(this.auth.user().ws_ou());
 +    selectedCopyOrgId: number = this.org.get(this.auth.user().ws_ou()).id();
 +    selectedPatronOrgId: number = this.org.get(this.auth.user().ws_ou()).id();
 +
 +    // list of orgs to retrieve stat cats for
 +    copyOrgFamily: any;
 +    patronOrgFamily: any;
 +
 +    // object which has all permissions data for current user
 +    userPerms: any = {};
 +
 +    // orgs that the user doesn't have permission to view.
 +    hiddenCopyOrgs: any[];
 +    hiddenPatronOrgs: any[];
 +
 +    newActsc: IdlObject;
 +    newAsc: IdlObject;
 +
-         // private router: Router,
 +    @ViewChild('copyGrid') copyGrid: GridComponent;
 +    @ViewChild('patronGrid') patronGrid: GridComponent;
 +    @ViewChild('copyDialog') copyDialog: FmRecordEditorComponent;
 +    @ViewChild('patronDialog') patronDialog: FmRecordEditorComponent;
 +    @ViewChild('updateSuccessString') updateSuccessString: StringComponent;
 +    @ViewChild('updateFailedString') updateFailedString: StringComponent;
 +    @ViewChild('deleteFailedString') deleteFailedString: StringComponent;
 +    @ViewChild('deleteSuccessString') deleteSuccessString: StringComponent;
 +    @ViewChild('createSuccessString') createSuccessString: StringComponent;
 +    @ViewChild('createErrString') createErrString: StringComponent;
 +
 +    constructor(
 +        private pcrud: PcrudService,
++        private router: Router,
 +        private route: ActivatedRoute,
 +        private org: OrgService,
 +        private idl: IdlService,
 +        private toast: ToastService,
 +        private perm: PermService,
 +        private auth: AuthService,
 +    ) {
 +    }
 +
 +    ngOnInit() {
 +        this.newActsc = this.idl.create('actsc');
 +        this.newAsc = this.idl.create('asc');
 +        this.perm.hasWorkPermAt(['CREATE_COPY_STAT_CAT', 'CREATE_PATRON_STAT_CAT',
 +            'UPDATE_PATRON_STAT_CAT', 'UPDATE_COPY_STAT_CAT', 'DELETE_COPY_STAT_CAT',
 +            'DELETE_PATRON_STAT_CAT'], true)
 +            .then(userPerms => {
 +                this.userPerms = userPerms;
 +                const allOrgs = this.org.list();
 +
 +                // View permission is the same as permission to update,
 +                // which is how it was handled in the old UI.
 +                this.hiddenCopyOrgs = allOrgs.filter(x => {
 +                    return !this.userPerms.UPDATE_COPY_STAT_CAT.includes(x.id());
 +                }).map(x => {
 +                    return x.id();
 +                });
 +                this.hiddenPatronOrgs = allOrgs.filter(x => {
 +                    return !this.userPerms.UPDATE_PATRON_STAT_CAT.includes(x.id());
 +                }).map(x => {
 +                    return x.id();
 +                });
-                 this.getOrgFamilyAndData('copy');
-                 this.copyGrid.reload();
 +                this.setCurrentPerms();
-     onTabChange(event: NgbTabChangeEvent) {
++
++                if (this.route.snapshot.paramMap.get('tab') === 'patron') {
++                    this.onTabChange({nextId: "'patron'"})
++                } else { // if null or copy
++                    this.onTabChange({nextId: "'copy'"})
++                }
 +        });
 +    }
 +
 +    disableCopyOrgs = () => this.org.filterList( { inList: this.hiddenCopyOrgs }, true);
 +
 +    disablePatronOrgs = () => this.org.filterList( { inList: this.hiddenCopyOrgs }, true);
 +
 +    setCurrentPerms() {
 +        this.userPerms.canEditCopy =
 +            this.userPerms.UPDATE_COPY_STAT_CAT.indexOf(this.selectedCopyOrgId) !== -1;
 +        this.userPerms.canEditPatron =
 +            this.userPerms.UPDATE_PATRON_STAT_CAT.indexOf(this.selectedPatronOrgId) !== -1;
 +        this.userPerms.canCreateCopy =
 +            this.userPerms.CREATE_COPY_STAT_CAT.indexOf(this.selectedCopyOrgId) !== -1;
 +        this.userPerms.canCreatePatron =
 +            this.userPerms.CREATE_PATRON_STAT_CAT.indexOf(this.selectedPatronOrgId) !== -1;
 +        this.userPerms.canDeleteCopy =
 +            this.userPerms.DELETE_COPY_STAT_CAT.indexOf(this.selectedCopyOrgId) !== -1;
 +        this.userPerms.canDeletePatron =
 +            this.userPerms.DELETE_PATRON_STAT_CAT.indexOf(this.selectedPatronOrgId) !== -1;
 +    }
 +
-         if (this.currentTab === "patron") {
++    onTabChange(event: any) {
 +        this.currentTab = event.nextId;
++        if (this.currentTab === "'patron'") {
++            this.routeToTab('patron');
 +            this.orgOnChange(this.selectedPatronOrg, 'patron');
 +        } else {
++            this.routeToTab('copy');
 +            this.orgOnChange(this.selectedCopyOrg, 'copy');
 +        }
 +    }
 +
++    routeToTab(tab: any) {
++        const url =
++            `/staff/admin/local/asset/stat_cat_editor/${tab}`;
++        this.router.navigate([url]);
++    }
++
++
 +    orgOnChange = (org: IdlObject, type): void => {
 +        this.setCurrentPerms();
 +        if (type === 'copy') {
 +            this.selectedCopyOrg = org;
 +            this.selectedCopyOrgId = org.id();
 +            this.getOrgFamilyAndData('copy');
 +            if (this.copyGrid) {
 +                this.copyGrid.reload();
 +            }
 +        } else {
 +            this.selectedPatronOrg = org;
 +            this.selectedPatronOrgId = org.id();
 +            this.getOrgFamilyAndData('patron');
 +            if (this.patronGrid) {
 +                this.patronGrid.reload();
 +            }
 +        }
 +    }
 +
 +    getOrgFamilyAndData(type) {
 +        if (type === 'copy') {
 +            this.copyOrgFamily = this.org.fullPath(this.selectedCopyOrgId)
 +            .map(record => {
 +                return record.id();
 +            });
 +            this.getAscData();
 +        } else {
 +            this.patronOrgFamily = this.org.fullPath(this.selectedPatronOrgId)
 +            .map(record => {
 +                return record.id();
 +            });
 +            this.getActscData();
 +        }
 +    }
 +
 +    getAscData() {
 +        this.ascDataSource.getRows = (pager: Pager, sort: any[]) => {
 +            const orderBy = {asc: 'id'};
 +            return this.pcrud.search('asc', {owner: this.copyOrgFamily}, orderBy);
 +        };
 +    }
 +
 +    getActscData() {
 +        this.actscDataSource.getRows = (pager: Pager, sort: any[]) => {
 +            const orderBy = {actsc: 'id'};
 +            return this.pcrud.search('actsc', {owner: this.patronOrgFamily}, orderBy);
 +        };
 +    }
 +
 +    editStatCat = (idlThing) => {
 +        const idlString = idlThing[0].classname;
 +
 +        // automatically fail if no permissions
 +        if ((!this.userPerms.canEditCopy && idlString === 'asc') ||
 +            (!this.userPerms.canEditPatron && idlString === 'actsc')) {
 +            this.updateFailedString.current()
 +                .then(str => this.toast.danger(str));
 +            return;
 +        }
 +
 +        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')
 +        );
 +    }
 +
 +    deleteStatCat = (idlThings: IdlObject[]) => {
 +        const idlString = idlThings[0].classname;
 +
 +        // automatically fail if no permissions
 +        if ((!this.userPerms.canDeleteCopy && idlString === 'asc') ||
 +            (!this.userPerms.canDeletePatron && idlString === 'actsc')) {
 +            this.deleteFailedString.current()
 +                .then(str => this.toast.danger(str));
 +            return;
 +        }
 +        
 +        // check to see if copy stat cat is in use
 +        if (idlString === 'asc') {
 +            this.checkThenDelete(idlThings, idlString)
 +        } else {
 +            this.doDelete(idlThings, idlString);
 +        }
 +    }
 +
 +    checkThenDelete = (idlThings, idlString) => {
 +        let promises: any[] = [];
 +        idlThings.forEach(idlThing => { // check one at a time to see if it's used
 +            const id = idlThing.id();
 +            let promise : any = new Promise((resolve, reject) => {
 +                this.pcrud.search('ascecm', {stat_cat: id}, {limit: 1})
 +                    .toPromise().then(
 +                    rec => {
 +                        if (rec) {
 +                            this.deleteFailedString.current()
 +                                .then(str => this.toast.danger(str));
 +                            resolve(false);
 +                        } else {
 +                            resolve(true);
 +                        }
 +                    });
 +            })
 +            promises.push(promise);
 +        });
 +        let result = Promise.all(promises);
 +        result.then(responses => {
 +            if (!responses.includes(false)) {  // only delete if none in use
 +                this.doDelete(idlThings, idlString);  
 +            }
 +        });
 +    }
 +
 +    doDelete = (idlThings: IdlObject[], idlString) => {
 +        idlThings.forEach(idlThing => {
 +            idlThing.isdeleted(true);
 +        });
 +        const currentGrid = this.lookUpType(idlString).currentGrid;
 +        this.pcrud.autoApply(idlThings).subscribe(
 +            val => {
 +                console.debug('deleted: ' + val);
 +                this.deleteSuccessString.current()
 +                    .then(str => this.toast.success(str));
 +            },
 +            err => {
 +                this.deleteFailedString.current()
 +                    .then(str => this.toast.danger(str));
 +            },
 +            () => {
 +                currentGrid.reload();
 +            }
 +        );
 +    }
 +
 +    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;
 +        let newIdlObject;
 +        if (this.currentTab === 'patron') {
 +            currentGrid = this.patronGrid;
 +            currentDialog = this.patronDialog;
 +            newIdlObject = this.idl.clone(this.newActsc);
 +            newIdlObject.owner(this.selectedPatronOrg);
 +        } else {
 +            currentGrid = this.copyGrid;
++            
 +            currentDialog = this.copyDialog;
 +            newIdlObject = this.idl.clone(this.newAsc);
 +            newIdlObject.owner(this.selectedCopyOrg);
 +        }
 +        currentDialog.mode = 'create';
 +        currentDialog.recordId = null;
 +        currentDialog.record = newIdlObject;
 +        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));
 +                }
 +            }
 +        );
 +    }
 +
 +}
index 9cb5999,0000000..5564751
mode 100644,000000..100644
--- /dev/null
@@@ -1,50 -1,0 +1,57 @@@
 +<eg-staff-banner bannerText="{{statCatType}} Statistical Category Entry Editor" 
 +    i18n-bannerText></eg-staff-banner>
 +
 +<ng-template #orgTemplate>
 +    <eg-org-select [hideOrgs]="hiddenOrgs" (onChange)="setOwner($event)" 
 +        [initialOrgId]="statCatOrgId"></eg-org-select>
 +</ng-template>
 +
 +<eg-fm-record-editor #patronDialog idlClass="actsce" 
 +    [fieldOptions]="{owner: {customTemplate: {template: orgTemplate}}}"
 +    readonlyFieldsList="stat_cat"
 +    requiredFields="value,owner" hiddenFieldsList="id"></eg-fm-record-editor>
 +<eg-fm-record-editor #copyDialog idlClass="asce" 
 +    [fieldOptions]="{owner: {customTemplate: {template: orgTemplate}}}"
 +    readonlyFieldsList="stat_cat"
 +    requiredFields="value,owner" hiddenFieldsList="id"></eg-fm-record-editor>
 +
++<div class="row justify-content-center">
++    <button class="btn btn-outline-dark mb-1 text-center" (click)="back()">
++        &#8592; Back to Stat Cats
++    </button>
++</div>
++    
++
 +<div *ngIf="statCatType === 'Copy'">
 +    <eg-grid #copyGrid [dataSource]="copyDataSource" idlClass="asce"
 +        (onRowActivate)="editEntry([$event])" hideFields="id,stat_cat">
 +        <eg-grid-toolbar-button label="New Entry" i18n-label
 +            [action]="createNewEntry" 
 +            [disabled]="!userPerms.canCreate"></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 
 +            [action]="deleteEntry"></eg-grid-toolbar-action>
 +    </eg-grid>
 +</div>
 +<div *ngIf="statCatType === 'Patron'">
 +    <eg-grid #patronGrid [dataSource]="patronDataSource" idlClass="actsce"
 +        (onRowActivate)="editEntry([$event])" hideFields="id,stat_cat">
 +        <eg-grid-toolbar-button label="New Entry" i18n-label
 +            [action]="createNewEntry" 
 +            [disabled]="!userPerms.canCreate"></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 
 +            [action]="deleteEntry"></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>
index d08b7c1,0000000..19a0f15
mode 100644,000000..100644
--- /dev/null
@@@ -1,227 -1,0 +1,235 @@@
 +import {Pager} from '@eg/share/util/pager';
 +import {GridComponent} from '@eg/share/grid/grid.component';
 +import {GridDataSource} from '@eg/share/grid/grid';
 +import {IdlService, IdlObject} from '@eg/core/idl.service';
 +import {PcrudService} from '@eg/core/pcrud.service';
 +import {OrgService} from '@eg/core/org.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';
 +import {PermService} from '@eg/core/perm.service';
 +
 +@Component({
 +    templateUrl: './stat_cat_entries.component.html'
 +})
 +
 +export class StatCatEntriesComponent implements OnInit {
 +
 +    statCatId: number; // parent stat cat id
 +    statCatOrgId: number; // parent stat cat org id
 +    statCatOrg: IdlObject; // parent stat cat org Idl
 +    hiddenOrgs: any[];  // List of invalid orgs for a new entry
 +    statCatType: 'Copy' | 'Patron';  // parent type
 +    defaultNewRecord: IdlObject;
 +    copyDataSource: GridDataSource = new GridDataSource();
 +    patronDataSource: GridDataSource = new GridDataSource();
 +    userPerms: 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 router: Router,
 +        private idl: IdlService,
 +        private pcrud: PcrudService,
 +        private route: ActivatedRoute,
 +        private toast: ToastService,
 +        private perm: PermService,
 +        private org: OrgService
 +    ) {
 +    }
 +
 +    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);
 +            };
 +            this.getParentData('asc');
 +        } 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);
 +            };
 +            this.getParentData('actsc');
 +        } else {
 +            console.debug('Error - unable to determine type of stat cat');
 +        }
 +    }
 +
++    back = () => {
++        let tab = 'copy';
++        if (this.statCatType === 'Patron') {
++            tab = 'patron';
++        }
++        this.router.navigate(['/staff/admin/local/asset/stat_cat_editor/' + tab]);
++    }
++
 +    checkPerms = () => {
 +        this.perm.hasWorkPermAt(['CREATE_COPY_STAT_CAT_ENTRY',
 +            'CREATE_PATRON_STAT_CAT_ENTRY', 'DELETE_COPY_STAT_CAT_ENTRY',
 +            'DELETE_PATRON_STAT_CAT_ENTRY', 'UPDATE_COPY_STAT_CAT_ENTRY',
 +            'UPDATE_PATRON_STAT_CAT_ENTRY'], true)
 +            .then(userPerms => {
 +            this.userPerms = userPerms;
 +            if (this.statCatType === 'Copy') {
 +                this.userPerms.canEdit =
 +                    this.userPerms.UPDATE_COPY_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
 +                this.userPerms.canCreate =
 +                    this.userPerms.CREATE_COPY_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
 +                this.userPerms.canDelete =
 +                    this.userPerms.DELETE_COPY_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
 +            } else {
 +                this.userPerms.canEdit =
 +                    this.userPerms.UPDATE_PATRON_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
 +                this.userPerms.canCreate =
 +                    this.userPerms.CREATE_PATRON_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
 +                this.userPerms.canDelete =
 +                    this.userPerms.DELETE_PATRON_STAT_CAT_ENTRY.indexOf(this.statCatOrg) !== -1;
 +            }
 +        });
 +    }
 +
 +    getParentData = (searchIdl) => {
 +        return this.pcrud.search(searchIdl, {id: this.statCatId}, {}
 +        ).subscribe(rec => {
 +            this.statCatOrg = rec.owner();
 +            this.statCatOrgId = rec.owner();
 +            this.checkPerms();
 +            const allOrgIds = this.org.list().map(x => x.id());
 +            const statCatDescendantIds = this.org.descendants(rec.owner(), true);
 +            this.hiddenOrgs = allOrgIds.filter(org => {
 +                return !statCatDescendantIds.includes(org);
 +            });
 +            return rec;
 +        });
 +    }
 +
 +    setOwner(e): void {
 +        this.defaultNewRecord.owner(e);
 +    }
 +
 +    lookupType() {
 +        let currentDialog;
 +        let currentGrid;
 +        let newIdl;
 +        if (this.statCatType === 'Copy') {
 +            currentGrid = this.copyGrid;
 +            currentDialog = this.copyDialog;
 +            newIdl = 'asce';
 +        } else {
 +            currentGrid = this.patronGrid;
 +            currentDialog = this.patronDialog;
 +            newIdl = 'actsce';
 +        }
 +        return {
 +            currentGrid: currentGrid,
 +            currentDialog: currentDialog,
 +            newIdl: newIdl
 +        };
 +    }
 +
 +    createNewEntry = () => {
 +        // automatically fail if no permissions
 +        if (!this.userPerms.canCreate) {
 +            this.createErrString.current()
 +                .then(str => this.toast.danger(str));
 +            return;
 +        }
 +
 +        const lookupResponse = this.lookupType();
 +        const currentDialog = lookupResponse.currentDialog;
 +        const currentGrid = lookupResponse.currentGrid;
 +        this.defaultNewRecord = this.idl.create(lookupResponse.newIdl);
 +
 +        // pre-populate new record with the current stat_cat and org
 +        this.defaultNewRecord.owner(this.statCatOrg);
 +        this.defaultNewRecord.stat_cat(this.statCatId);
 +        currentDialog.mode = 'create';
 +        currentDialog.recordId = null;
 +        currentDialog.record = this.defaultNewRecord;
 +        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) => {
 +        // automatically fail if no permissions
 +        if (!this.userPerms.canEdit) {
 +            this.updateFailedString.current()
 +                .then(str => this.toast.danger(str));
 +            return;
 +        }
 +
 +        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 => {
 +                this.updateSuccessString.current()
 +                    .then(str => this.toast.success(str));
 +                console.debug('Record editor performed action');
 +                currentGrid.reload();
 +            },
 +            err => {
 +                console.debug(err);
 +                this.updateFailedString.current()
 +                    .then(str => this.toast.danger(str));
 +            },
 +            () => console.debug('Dialog closed')
 +        );
 +    }
 +
 +    deleteEntry = (idlThings: IdlObject[]) => {
 +        // automatically fail if no permissions
 +        if (!this.userPerms.canDelete) {
 +            this.deleteFailedString.current()
 +                .then(str => this.toast.danger(str));
 +            return;
 +        }
 +
 +        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));
 +            },
 +            err => {
 +                this.deleteFailedString.current()
 +                    .then(str => this.toast.danger(str));
 +            },
 +            () => {
 +                currentGrid.reload();
 +            }
 +        );
 +    }
 +
 +}
index f2d205d,0000000..5c7dd25
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,25 @@@
 +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: ':tab',
++  component: StatCatComponent
++}, {
 +  path: 'copy_entries/:id',
 +  component: StatCatEntriesComponent
 +}, {
 +  path: 'patron_entries/:id',
 +  component: StatCatEntriesComponent
 +}];
 +
 +@NgModule({
 +  imports: [RouterModule.forChild(routes)],
 +  exports: [RouterModule]
 +})
 +
 +export class StatCatRoutingModule {}