From eaa880793622f231c2cb9590c0e661db6371e174 Mon Sep 17 00:00:00 2001 From: Mike Rylander Date: Mon, 22 Mar 2021 16:00:55 -0400 Subject: [PATCH] LP#1207533: item-oriented Triggered Event Log Building on the previous commit from Jason Etheridge, this adds an Angular reimplementation of the item-oriented TEL variant. In addition, it separates the grid settings persist key and creates the YAOUSen needed to save those grid settings. Because these interfaces make use of the flattener service to drive grid construction and data retrieval, staff will have to have the appropriate VIEW_USER permission to be able to see patron related data in the item-oriented grid. Funding for these interfaces comes from PaILS, for the patron-oriented interface, and from ECDI, for the item-oriented one. Signed-off-by: Mike Rylander Signed-off-by: Dawn Dale Signed-off-by: Chris Sharp --- Open-ILS/examples/fm_IDL.xml | 8 +- .../circ/item/event-log/event-grid.component.html | 14 +++ .../circ/item/event-log/event-grid.component.ts | 129 +++++++++++++++++++++ .../circ/item/event-log/event-log.component.html | 20 ++++ .../circ/item/event-log/event-log.component.ts | 29 +++++ .../staff/circ/item/event-log/event-log.module.ts | 19 +++ .../staff/circ/item/event-log/routing.module.ts | 19 +++ .../eg2/src/app/staff/circ/item/routing.module.ts | 16 +++ .../patron/event-log/event-grid.component.html | 7 +- .../circ/patron/event-log/event-grid.component.ts | 5 +- .../src/eg2/src/app/staff/circ/routing.module.ts | 4 + .../lib/OpenILS/Application/Trigger/Event.pm | 65 ++++++----- Open-ILS/src/sql/Pg/040.schema.asset.sql | 8 +- Open-ILS/src/sql/Pg/400.schema.action_trigger.sql | 9 +- Open-ILS/src/sql/Pg/950.data.seed-values.sql | 23 +++- .../ZZZZ.schema.item_triggered_event_log.sql | 85 ++++++++++++++ Open-ILS/src/templates/staff/cat/item/t_view.tt2 | 2 +- .../web/js/ui/default/staff/cat/catalog/app.js | 3 +- Open-ILS/web/js/ui/default/staff/cat/item/app.js | 8 +- .../js/ui/default/staff/circ/patron/items_out.js | 7 +- .../Circulation/ItemTriggeredEventsLog.adoc | 5 + 21 files changed, 431 insertions(+), 54 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-grid.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-grid.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.module.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/circ/item/event-log/routing.module.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/circ/item/routing.module.ts create mode 100644 Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.item_triggered_event_log.sql create mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/ItemTriggeredEventsLog.adoc diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index fc20984373..0f0dff8a4f 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -1457,6 +1457,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + @@ -1554,6 +1555,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + @@ -1563,6 +1565,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + @@ -1696,6 +1699,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA atev.context_user, atev.context_library, atev.context_bib, + atev.context_item, rssr.title, rssr.author FROM action_trigger.event atev @@ -1736,6 +1740,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + @@ -1749,10 +1754,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + - + diff --git a/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-grid.component.html b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-grid.component.html new file mode 100644 index 0000000000..80f6227ce5 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-grid.component.html @@ -0,0 +1,14 @@ + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-grid.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-grid.component.ts new file mode 100644 index 0000000000..063d2cda3b --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-grid.component.ts @@ -0,0 +1,129 @@ +import {Component, EventEmitter, Input, Output, OnChanges, OnInit, ViewChild} from '@angular/core'; +import {Router} from '@angular/router'; +import {Observable, from, of} from 'rxjs'; +import {map, tap, switchMap, mergeMap} from 'rxjs/operators'; +import {AuthService} from '@eg/core/auth.service'; +import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component'; +import {FormatService} from '@eg/core/format.service'; +import {GridComponent} from '@eg/share/grid/grid.component'; +import {GridDataSource} from '@eg/share/grid/grid'; +import {IdlService, IdlObject} from '@eg/core/idl.service'; +import {EventService} from '@eg/core/event.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {Pager} from '@eg/share/util/pager'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {NetService} from '@eg/core/net.service'; +import {OrgService} from '@eg/core/org.service'; +import {BibRecordService, BibRecordSummary} from '@eg/share/catalog/bib-record.service'; + +// A filterable grid of A/T events for circ or ahr hook core types + +@Component({ + selector: 'eg-item-event-grid', + templateUrl: './event-grid.component.html' +}) + +export class ItemEventGridComponent implements OnChanges, OnInit { + + @Input() item: number; + @Input() event_type: string; + + gridSource: GridDataSource; + numRowsSelected: number; + + act_on_events: (action: string, rows: IdlObject[]) => void; + noRowSelected: (rows: IdlObject[]) => boolean; + + @ViewChild('grid', { static: true }) grid: GridComponent; + + constructor( + private idl: IdlService, + private auth: AuthService, + private bib: BibRecordService, + private format: FormatService, + private pcrud: PcrudService, + private router: Router, + private toast: ToastService, + private net: NetService, + private evt: EventService, + private org: OrgService + ) { + + } + + ngOnInit() { + this.gridSource = new GridDataSource(); + + this.gridSource.getRows = (pager: Pager, sort: any[]): Observable => { + // TODO: why is this getting called twice on page load? + + const orderBy: any = {atoul: 'id'}; + if (sort.length) { + orderBy.atoul = sort[0].name + ' ' + sort[0].dir; + } + + // base query to grab everything + const base: Object = {}; + base[this.idl.classes['atoul'].pkey] = {'!=' : null}; + base['context_item'] = (this.item ? this.item : {'>' : 0}) + + // circs or holds? + if (this.event_type == 'circ') { + base['target_circ'] = { '>' : 0 } + } else { + base['target_hold'] = { '>' : 0 } + } + + const query: any = new Array(); + query.push(base); + + // and add any filters + Object.keys(this.gridSource.filters).forEach(key => { + Object.keys(this.gridSource.filters[key]).forEach(key2 => { + query.push(this.gridSource.filters[key][key2]); + }); + }); + + return this.pcrud.search('atoul', + query, { + flesh: 3, + flesh_fields: { + atoul: ['context_user','context_item'], + au: ['card'] + }, + offset: pager.offset, + limit: pager.limit, + order_by: orderBy + }); + }; + + this.act_on_events = (action: string, rows: IdlObject[]) => { + this.net.request( + 'open-ils.actor', + 'open-ils.actor.user.event.' + action + '.batch', + this.auth.token(), rows.map( event => event.id() ) + ).subscribe( + (res) => { + if (this.evt.parse(res)) { + console.error('parsed error response',res); + } else { + console.log('success',res); + } + }, + (err) => { + console.error('error',err); + }, + () => { + console.log('finis'); + this.grid.reload(); + } + ); + } + + this.noRowSelected = (rows: IdlObject[]) => (rows.length == 0); + } + + ngOnChanges() { this.reloadGrid(); } + + reloadGrid() { this.grid.reload(); } +} diff --git a/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.component.html b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.component.html new file mode 100644 index 0000000000..8b3c707f5d --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.component.html @@ -0,0 +1,20 @@ + + + + + + +
diff --git a/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.component.ts new file mode 100644 index 0000000000..2916ba82c5 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.component.ts @@ -0,0 +1,29 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {NetService} from '@eg/core/net.service'; +import {AuthService} from '@eg/core/auth.service'; +import {ItemEventGridComponent} from './event-grid.component'; + +@Component({ + templateUrl: 'event-log.component.html' +}) + +export class ItemEventLogComponent implements OnInit { + itemId: number; + + @ViewChild('itemEventGrid', { static: true }) itemEventGrid: ItemEventGridComponent; + + constructor( + private route: ActivatedRoute, + private net: NetService, + private auth: AuthService + ) {} + + ngOnInit() { + // Note: if this is not supplied, the grid will show recent events + // across all items, which may be a neat feature... + this.itemId = +this.route.snapshot.paramMap.get('item'); + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.module.ts b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.module.ts new file mode 100644 index 0000000000..67e1d5956d --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/event-log.module.ts @@ -0,0 +1,19 @@ +import {NgModule} from '@angular/core'; +import {StaffCommonModule} from '@eg/staff/common.module'; +import {ItemEventLogRoutingModule} from './routing.module'; +import {ItemEventGridComponent} from './event-grid.component'; +import {ItemEventLogComponent} from './event-log.component'; + +@NgModule({ + declarations: [ + ItemEventGridComponent, + ItemEventLogComponent + ], + imports: [ + StaffCommonModule, + ItemEventLogRoutingModule, + ], +}) + +export class ItemEventLogModule {} + diff --git a/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/routing.module.ts new file mode 100644 index 0000000000..fdb2ccf508 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/circ/item/event-log/routing.module.ts @@ -0,0 +1,19 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; +import {ItemEventLogComponent} from './event-log.component'; + +const routes: Routes = [ + { path: '', + component: ItemEventLogComponent + }, + { path: ':item', + component: ItemEventLogComponent + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) + +export class ItemEventLogRoutingModule {} diff --git a/Open-ILS/src/eg2/src/app/staff/circ/item/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/circ/item/routing.module.ts new file mode 100644 index 0000000000..e8045a981c --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/circ/item/routing.module.ts @@ -0,0 +1,16 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; + +const routes: Routes = [ + { path: 'event-log', + loadChildren: () => + import('./event-log/event-log.module').then(m => m.ItemEventLogModule) + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) + +export class CircItemRoutingModule {} diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/event-log/event-grid.component.html b/Open-ILS/src/eg2/src/app/staff/circ/patron/event-log/event-grid.component.html index 0605678258..f6e404e80d 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/event-log/event-grid.component.html +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/event-log/event-grid.component.html @@ -1,15 +1,14 @@ + persistKey="patron.event_grid"> - - + diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/event-log/event-grid.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/event-log/event-grid.component.ts index 385754e2f1..083b1a4b25 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/event-log/event-grid.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/event-log/event-grid.component.ts @@ -88,9 +88,8 @@ export class EventGridComponent implements OnChanges, OnInit { query, { flesh: 3, flesh_fields: { - atoul: ['target_circ', 'target_hold'], - circ: ['target_copy'], - ahr: ['current_copy'] + atoul: ['context_item', 'context_user'], + au: ['card'] }, offset: pager.offset, limit: pager.limit, diff --git a/Open-ILS/src/eg2/src/app/staff/circ/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/circ/routing.module.ts index fae4330cb4..49cd79aa96 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/routing.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/routing.module.ts @@ -5,6 +5,10 @@ const routes: Routes = [ { path: 'patron', loadChildren: () => import('./patron/routing.module').then(m => m.CircPatronRoutingModule) + }, + { path: 'item', + loadChildren: () => + import('./item/routing.module').then(m => m.CircItemRoutingModule) } ]; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Event.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Event.pm index 66df9c9785..419bd7f458 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Event.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Event.pm @@ -525,38 +525,47 @@ sub build_environment { if ($self->event->event_def->context_usr_path) { my @usr_path = split(/\./, $self->event->event_def->context_usr_path); $self->_object_by_path( $self->target, undef, [qw/context usr/], \@usr_path ); + } - if ($self->event->event_def->context_bib_path) { - my @bib_path = split(/\./, $self->event->event_def->context_bib_path); - $self->_object_by_path( $self->target, undef, [qw/context bib/], \@bib_path ); - if (ref $self->environment->{context}->{bib} eq 'ARRAY') { - $self->environment->{context}->{bib} = $self->environment->{context}->{bib}->[0]; - } - if ($self->environment->{context}->{bib}->isa('Fieldmapper::biblio::record_entry')) { - $self->environment->{context}->{bib} = $self->environment->{context}->{bib}->id; - } elsif ($self->environment->{context}->{bib}->isa('Fieldmapper::reporter::hold_request_record')) { - $self->environment->{context}->{bib} = $self->environment->{context}->{bib}->bib_record; - } + if ($self->event->event_def->context_bib_path) { + my @bib_path = split(/\./, $self->event->event_def->context_bib_path); + $self->_object_by_path( $self->target, undef, [qw/context bib/], \@bib_path ); + if (ref $self->environment->{context}->{bib} eq 'ARRAY') { + $self->environment->{context}->{bib} = $self->environment->{context}->{bib}->[0]; } - - if ($self->event->event_def->context_library_path) { - my @library_path = split(/\./, $self->event->event_def->context_library_path); - $self->_object_by_path( $self->target, undef, [qw/context org/], \@library_path ); - } else { - $self->_object_by_path( $self->event->event_def, undef, [qw/context org/], ['owner'] ); + if ($self->environment->{context}->{bib}->isa('Fieldmapper::biblio::record_entry')) { + $self->environment->{context}->{bib} = $self->environment->{context}->{bib}->id; + } elsif ($self->environment->{context}->{bib}->isa('Fieldmapper::reporter::hold_request_record')) { + $self->environment->{context}->{bib} = $self->environment->{context}->{bib}->bib_record; } - $self->update_state( - $self->event->state, { - 'context_user' => $self->environment->{context}->{usr} - ? $self->environment->{context}->{usr}->id - : undef, - 'context_library' => $self->environment->{context}->{org} - ? $self->environment->{context}->{org}->id - : undef, - 'context_bib' => $self->environment->{context}->{bib} - } - ); } + + if ($self->event->event_def->context_library_path) { + my @library_path = split(/\./, $self->event->event_def->context_library_path); + $self->_object_by_path( $self->target, undef, [qw/context org/], \@library_path ); + } else { + $self->_object_by_path( $self->event->event_def, undef, [qw/context org/], ['owner'] ); + } + + if ($self->event->event_def->context_item_path) { + my @item_path = split(/\./, $self->event->event_def->context_item_path); + $self->_object_by_path( $self->target, undef, [qw/context item/], \@item_path ); + } + + $self->update_state( + $self->event->state, { + 'context_item' => $self->environment->{context}->{item} + ? $self->environment->{context}->{item}->id + : undef, + 'context_user' => $self->environment->{context}->{usr} + ? $self->environment->{context}->{usr}->id + : undef, + 'context_library' => $self->environment->{context}->{org} + ? $self->environment->{context}->{org}->id + : undef, + 'context_bib' => $self->environment->{context}->{bib} + } + ); $self->environment->{complete} = 1; } otherwise { diff --git a/Open-ILS/src/sql/Pg/040.schema.asset.sql b/Open-ILS/src/sql/Pg/040.schema.asset.sql index f1455306f5..2002113b99 100644 --- a/Open-ILS/src/sql/Pg/040.schema.asset.sql +++ b/Open-ILS/src/sql/Pg/040.schema.asset.sql @@ -952,9 +952,11 @@ DECLARE copy_id BIGINT; BEGIN EXECUTE 'SELECT ($1).' || quote_ident(TG_ARGV[0]) INTO copy_id USING NEW; - PERFORM * FROM asset.copy WHERE id = copy_id; - IF NOT FOUND THEN - RAISE EXCEPTION 'Key (%.%=%) does not exist in asset.copy', TG_TABLE_SCHEMA, TG_TABLE_NAME, copy_id; + IF copy_id IS NOT NULL THEN + PERFORM * FROM asset.copy WHERE id = copy_id; + IF NOT FOUND THEN + RAISE EXCEPTION 'Key (%.%=%) does not exist in asset.copy', TG_TABLE_SCHEMA, TG_TABLE_NAME, copy_id; + END IF; END IF; RETURN NULL; END; diff --git a/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql b/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql index 80e4f8de89..3a0816a07c 100644 --- a/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql +++ b/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql @@ -200,6 +200,7 @@ CREATE TABLE action_trigger.event_definition ( context_usr_path TEXT, -- for optimizing action_trigger.event context_library_path TEXT, -- ''' context_bib_path TEXT, -- ''' + context_item_path TEXT, -- ''' message_template TEXT, message_usr_path TEXT, @@ -282,7 +283,8 @@ CREATE TABLE action_trigger.event ( async_output BIGINT REFERENCES action_trigger.event_output (id), context_user INT REFERENCES actor.usr (id), context_library INT REFERENCES actor.org_unit (id), - context_bib BIGINT REFERENCES biblio.record_entry (id) + context_bib BIGINT REFERENCES biblio.record_entry (id), + context_item BIGINT ); CREATE INDEX atev_target_def_idx ON action_trigger.event (target,event_def); CREATE INDEX atev_def_state ON action_trigger.event (event_def,state); @@ -291,6 +293,11 @@ CREATE INDEX atev_async_output ON action_trigger.event (async_output); CREATE INDEX atev_error_output ON action_trigger.event (error_output); CREATE INDEX atev_context_user ON action_trigger.event (context_user); CREATE INDEX atev_context_library ON action_trigger.event (context_library); +CREATE INDEX atev_context_item ON action_trigger.event (context_item); + +CREATE TRIGGER action_trigger_event_context_item_fkey_trig + AFTER INSERT OR UPDATE ON action_trigger.event + FOR EACH ROW EXECUTE PROCEDURE evergreen.fake_fkey_tgr('context_item'); CREATE TABLE action_trigger.event_params ( id BIGSERIAL PRIMARY KEY, diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index 3ec8dc6128..bb3edfc890 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -17558,7 +17558,8 @@ UPDATE SET context_usr_path = 'usr', context_library_path = 'circ_lib', - context_bib_path = 'target_copy.call_number.record' + context_bib_path = 'target_copy.call_number.record', + context_item_path = 'target_copy' WHERE hook IN ( SELECT key FROM action_trigger.hook WHERE core_type = 'circ' @@ -17570,7 +17571,8 @@ UPDATE SET context_usr_path = 'usr', context_library_path = 'pickup_lib', - context_bib_path = 'bib_rec' + context_bib_path = 'bib_rec', + context_item_path = 'current_copy' WHERE hook IN ( SELECT key FROM action_trigger.hook WHERE core_type = 'ahr' @@ -21754,7 +21756,22 @@ VALUES ( 'eg.staff.catalog.results.show_more', 'Show more details in Angular staff catalog', 'cwst', 'label' - ) +); + +INSERT INTO config.workstation_setting_type + (name, grp, datatype, label) +VALUES ( + 'eg.grid.item.event_grid', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.item.event_grid', + 'Grid Config: item.event_grid', + 'cwst', 'label') +), ( + 'eg.grid.patron.event_grid', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.patron.event_grid', + 'Grid Config: patron.event_grid', + 'cwst', 'label') ); INSERT INTO config.org_unit_setting_type diff --git a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.item_triggered_event_log.sql b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.item_triggered_event_log.sql new file mode 100644 index 0000000000..57882a373a --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.item_triggered_event_log.sql @@ -0,0 +1,85 @@ +BEGIN; + +SELECT evergreen.upgrade_deps_block_check('ZZZZ', :eg_version); + +INSERT INTO config.workstation_setting_type + (name, grp, datatype, label) +VALUES ( + 'eg.grid.item.event_grid', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.item.event_grid', + 'Grid Config: item.event_grid', + 'cwst', 'label') +), ( + 'eg.grid.patron.event_grid', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.patron.event_grid', + 'Grid Config: patron.event_grid', + 'cwst', 'label') +); + +DROP TRIGGER IF EXISTS action_trigger_event_context_item_trig ON action_trigger.event; + +-- Create a NULLABLE version of the fake-copy-fkey trigger function. +CREATE OR REPLACE FUNCTION evergreen.fake_fkey_tgr () RETURNS TRIGGER AS $F$ +DECLARE + copy_id BIGINT; +BEGIN + EXECUTE 'SELECT ($1).' || quote_ident(TG_ARGV[0]) INTO copy_id USING NEW; + IF copy_id IS NOT NULL THEN + PERFORM * FROM asset.copy WHERE id = copy_id; + IF NOT FOUND THEN + RAISE EXCEPTION 'Key (%.%=%) does not exist in asset.copy', TG_TABLE_SCHEMA, TG_TABLE_NAME, copy_id; + END IF; + END IF; + RETURN NULL; +END; +$F$ LANGUAGE PLPGSQL; + + +-- context_item_path TEXT, -- for optimizing action_trigger.event +ALTER TABLE action_trigger.event_definition ADD COLUMN context_item_path TEXT; + +-- context_item BIGINT REFERENCES asset.copy (id) +ALTER TABLE action_trigger.event ADD COLUMN context_item BIGINT; +CREATE INDEX atev_context_item ON action_trigger.event (context_item); + +UPDATE + action_trigger.event_definition +SET + context_item_path = 'target_copy' +WHERE + hook IN ( + SELECT key FROM action_trigger.hook WHERE core_type = 'circ' + ) +; + +UPDATE + action_trigger.event_definition +SET + context_item_path = 'current_copy' +WHERE + hook IN ( + SELECT key FROM action_trigger.hook WHERE core_type = 'ahr' + ) +; + +-- Retroactively setting context_item on existing rows in action_trigger.event: +-- This is not done by default because it'll likely take a long time depending on the Evergreen +-- installation. You may want to do this out-of-band with the upgrade if you want to do this at all. +-- +-- \pset format unaligned +-- \t +-- \o update_action_trigger_events_for_circs.sql +-- SELECT 'UPDATE action_trigger.event e SET context_item = c.target_copy FROM action.circulation cWHERE c.id = e.target AND e.id = ' || e.id || ' RETURNING ' || e.id || ';' FROM action_trigger.event e, action.circulation c WHERE e.target = c.id AND e.event_def IN (SELECT id FROM action_trigger.event_definition WHERE hook in (SELECT key FROM action_trigger.hook WHERE core_type = 'circ')) ORDER BY e.id DESC; +-- \o +-- \o update_action_trigger_events_for_holds.sql +-- SELECT 'UPDATE action_trigger.event e SET context_item = h.current_copy FROM action.hold_request h WHERE h.id = e.target AND e.id = ' || e.id || ' RETURNING ' || e.id || ';' FROM action_trigger.event e, action.hold_request h WHERE e.target = h.id AND e.event_def IN (SELECT id FROM action_trigger.event_definition WHERE hook in (SELECT key FROM action_trigger.hook WHERE core_type = 'ahr')) ORDER BY e.id DESC; +-- \o + +COMMIT; + +CREATE TRIGGER action_trigger_event_context_item_trig + AFTER INSERT OR UPDATE ON action_trigger.event + FOR EACH ROW EXECUTE PROCEDURE evergreen.fake_fkey_tgr('context_item'); + diff --git a/Open-ILS/src/templates/staff/cat/item/t_view.tt2 b/Open-ILS/src/templates/staff/cat/item/t_view.tt2 index bf9eaa4817..47b369a4a1 100644 --- a/Open-ILS/src/templates/staff/cat/item/t_view.tt2 +++ b/Open-ILS/src/templates/staff/cat/item/t_view.tt2 @@ -21,7 +21,7 @@ [% l('Cataloging Info') %]
  • - [% l('Triggered Events') %] + [% l('Triggered Events') %]
  • [% l('Course Info') %] diff --git a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js index 5789dba3ec..ecd0936ed2 100644 --- a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js +++ b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js @@ -1658,8 +1658,7 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e angular.forEach( gatherSelectedHoldingsIds(), function (cid) { - var url = egCore.env.basePath + - 'cat/item/' + cid + '/triggered_events'; + var url = '/eg2/staff/circ/item/event-log/' + cid; $timeout(function() { $window.open(url, '_blank') }); } ); diff --git a/Open-ILS/web/js/ui/default/staff/cat/item/app.js b/Open-ILS/web/js/ui/default/staff/cat/item/app.js index 7e4c618566..8e21e25994 100644 --- a/Open-ILS/web/js/ui/default/staff/cat/item/app.js +++ b/Open-ILS/web/js/ui/default/staff/cat/item/app.js @@ -161,7 +161,7 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD } $scope.show_triggered_events = function() { - $location.path('/cat/item/' + $scope.args.copyId + '/triggered_events'); + window.open('/eg2/staff/circ/item/event-log/' + $scope.args.copyId, '_blank'); } $scope.show_item_holds = function() { @@ -469,7 +469,7 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD $scope.context.show_triggered_events = function() { var item = copyGrid.selectedItems()[0]; if (item) - $location.path('/cat/item/' + item.id + '/triggered_events'); + window.open('/eg2/staff/circ/item/event-log/' + item.id, '_blank'); } function gatherSelectedRecordIds () { @@ -613,7 +613,7 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD $scope.selectedHoldingsItemStatusTgrEvt= function() { var item = copyGrid.selectedItems()[0]; if (item) - $location.path('/cat/item/' + item.id + '/triggered_events'); + window.open('/eg2/staff/circ/item/event-log/' + item.id, '_blank'); } $scope.selectedHoldingsItemStatusHolds= function() { @@ -1320,7 +1320,7 @@ console.debug($scope.copy_alert_count); } $scope.context.show_triggered_events = function() { - $location.path('/cat/item/' + copyId + '/triggered_events'); + window.open('/eg2/staff/circ/item/event-log/' + copyId, '_blank'); } loadCopy().then(loadTabData); diff --git a/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js b/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js index 16c04c9d62..db0489d8e0 100644 --- a/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js +++ b/Open-ILS/web/js/ui/default/staff/circ/patron/items_out.js @@ -476,11 +476,10 @@ function($scope , $q , $routeParams , $timeout , egCore , egUser , patronSvc , $scope.show_triggered_events = function(items) { var focus = items.length == 1; angular.forEach(items, function(item) { - var url = egCore.env.basePath + - '/cat/item/' + - item.target_copy().id() + - '/triggered_events'; + var url = '/eg2/staff/circ/item/event-log/' + + item.target_copy().id(); $timeout(function() { var x = $window.open(url, '_blank'); if (focus) x.focus() }); + }); } diff --git a/docs/RELEASE_NOTES_NEXT/Circulation/ItemTriggeredEventsLog.adoc b/docs/RELEASE_NOTES_NEXT/Circulation/ItemTriggeredEventsLog.adoc new file mode 100644 index 0000000000..e95fa47b77 --- /dev/null +++ b/docs/RELEASE_NOTES_NEXT/Circulation/ItemTriggeredEventsLog.adoc @@ -0,0 +1,5 @@ +New Item Triggered Events Log +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A reimplementation of the Item Triggered Events Log interface, building +on the Patron Triggered Events Log Angular reimplemenation. -- 2.11.0