From b06dee7bb498f623f48603baa1b1132d9bd1a627 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Fri, 15 May 2020 15:11:06 -0400 Subject: [PATCH] LP1879335 Manage Authorities Angular Port Migrates the Manage Authorities interface from Dojo to Angular. In addition to the existing functionality, the UI contains additional authority record data and it's now possible to jump to a list of linked bib records. Includes release notes. Signed-off-by: Bill Erickson Signed-off-by: Galen Charlton --- Open-ILS/examples/fm_IDL.xml | 1 + .../app/staff/cat/authority/authority.module.ts | 14 ++- .../app/staff/cat/authority/browse.component.html | 94 ++++++++++++++++ .../app/staff/cat/authority/browse.component.ts | 123 +++++++++++++++++++++ .../src/app/staff/cat/authority/browse.service.ts | 81 ++++++++++++++ .../app/staff/cat/authority/manage.component.html | 35 ++++++ .../app/staff/cat/authority/manage.component.ts | 67 +++++++++++ .../cat/authority/merge-dialog.component.html | 42 +++++++ .../staff/cat/authority/merge-dialog.component.ts | 74 +++++++++++++ .../src/app/staff/cat/authority/routing.module.ts | 11 ++ Open-ILS/src/eg2/src/app/staff/nav.component.html | 2 +- .../staff/share/bib-list/bib-list.component.html | 31 ++++++ .../app/staff/share/bib-list/bib-list.component.ts | 78 +++++++++++++ .../app/staff/share/bib-list/bib-list.module.ts | 20 ++++ .../lib/OpenILS/Application/Search/Authority.pm | 89 +++++++++++++++ Open-ILS/src/sql/Pg/950.data.seed-values.sql | 12 ++ .../upgrade/XXXX.data.manage-authority-grids.sql | 20 ++++ Open-ILS/src/templates/staff/navbar.tt2 | 2 +- .../Cataloging/manage-auths-ang.adoc | 7 ++ 19 files changed, 799 insertions(+), 4 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/staff/cat/authority/browse.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/cat/authority/browse.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/cat/authority/browse.service.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/cat/authority/merge-dialog.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/cat/authority/merge-dialog.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.module.ts create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.manage-authority-grids.sql create mode 100644 docs/RELEASE_NOTES_NEXT/Cataloging/manage-auths-ang.adoc diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index 520f6e6beb..60e4bea34e 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -2772,6 +2772,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/authority.module.ts b/Open-ILS/src/eg2/src/app/staff/cat/authority/authority.module.ts index ded954a9c7..f29b20c6f4 100644 --- a/Open-ILS/src/eg2/src/app/staff/cat/authority/authority.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/cat/authority/authority.module.ts @@ -4,18 +4,28 @@ import {CommonWidgetsModule} from '@eg/share/common-widgets.module'; import {AuthorityRoutingModule} from './routing.module'; import {MarcEditModule} from '@eg/staff/share/marc-edit/marc-edit.module'; import {AuthorityMarcEditComponent} from './marc-edit.component'; +import {BrowseAuthorityComponent} from './browse.component'; +import {ManageAuthorityComponent} from './manage.component'; +import {AuthorityMergeDialogComponent} from './merge-dialog.component'; +import {BrowseService} from './browse.service'; +import {BibListModule} from '@eg/staff/share/bib-list/bib-list.module'; @NgModule({ declarations: [ - AuthorityMarcEditComponent + AuthorityMarcEditComponent, + BrowseAuthorityComponent, + ManageAuthorityComponent, + AuthorityMergeDialogComponent ], imports: [ StaffCommonModule, CommonWidgetsModule, MarcEditModule, - AuthorityRoutingModule + AuthorityRoutingModule, + BibListModule ], providers: [ + BrowseService ] }) diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/browse.component.html b/Open-ILS/src/eg2/src/app/staff/cat/authority/browse.component.html new file mode 100644 index 0000000000..94a0f5388c --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/cat/authority/browse.component.html @@ -0,0 +1,94 @@ + + + + + + + +
+
+
+
+ Search Term +
+ +
+
+
+
+
+ Authority Type +
+ + + +
+
+
+
+
+ + + + +
+
+
+ + + + {{row.heading}} + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/browse.component.ts b/Open-ILS/src/eg2/src/app/staff/cat/authority/browse.component.ts new file mode 100644 index 0000000000..8f6dc1e22f --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/cat/authority/browse.component.ts @@ -0,0 +1,123 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {Observable, empty} from 'rxjs'; +import {map, switchMap} from 'rxjs/operators'; +import {IdlObject} from '@eg/core/idl.service'; +import {Pager} from '@eg/share/util/pager'; +import {NetService} from '@eg/core/net.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {OrgService} from '@eg/core/org.service'; +import {GridComponent} from '@eg/share/grid/grid.component'; +import {GridContext, GridDataSource, GridCellTextGenerator, + GridRowFlairEntry} from '@eg/share/grid/grid'; +import {ComboboxEntry, ComboboxComponent} from '@eg/share/combobox/combobox.component'; +import {BrowseService} from './browse.service'; +import {StringComponent} from '@eg/share/string/string.component'; +import {AuthorityMergeDialogComponent} from './merge-dialog.component'; + +/* Find, merge, and edit authority records */ + +@Component({ + templateUrl: 'browse.component.html', + styles: [`#offset-input { width: 4em; }`] +}) +export class BrowseAuthorityComponent implements OnInit { + + authorityAxis: ComboboxEntry; + dataSource: GridDataSource; + cellTextGenerator: GridCellTextGenerator; + + rowFlairCallback: (row: any) => GridRowFlairEntry; + + @ViewChild('grid', {static: false}) grid: GridComponent; + @ViewChild('axisCbox', {static: false}) axisCbox: ComboboxComponent; + @ViewChild('rowSelected', {static: false}) rowSelected: StringComponent; + @ViewChild('mergeDialog', {static: false}) + mergeDialog: AuthorityMergeDialogComponent; + + constructor( + private net: NetService, + private org: OrgService, + private pcrud: PcrudService, + public browse: BrowseService + ) {} + + ngOnInit() { + this.browse.fetchAxes(); + this.setupGrid(); + } + + setupGrid() { + this.dataSource = new GridDataSource(); + + this.dataSource.getRows = + (pager: Pager, sort: any): Observable => { + + if (this.authorityAxis) { + this.browse.authorityAxis = this.authorityAxis.id; + + } else { + // Our browse service may have cached search params + if (this.browse.authorityAxis) { + this.axisCbox.selectedId = this.browse.authorityAxis; + this.authorityAxis = this.axisCbox.selected; + } else { + return empty(); + } + } + + return this.browse.loadAuthorities(); + }; + + this.cellTextGenerator = { + heading: row => row.heading + }; + + this.rowFlairCallback = (row: any): GridRowFlairEntry => { + const flair = {icon: null, title: null}; + if (this.browse.markedForMerge[row.authority.id()]) { + flair.icon = 'merge_type'; + flair.title = this.rowSelected.text; + } + return flair; + }; + } + + + markForMerge(rows: any[]) { + rows.forEach(row => + this.browse.markedForMerge[row.authority.id()] = row); + } + + unMarkForMerge(rows: any[]) { + rows.forEach(row => + delete this.browse.markedForMerge[row.authority.id()]); + } + + clearMergeSelection() { + this.browse.markedForMerge = {}; + } + + search(offset?: number, isNew?: boolean) { + if (offset) { + this.browse.searchOffset += offset; + } else if (isNew) { + this.browse.searchOffset = 0; + } + this.grid.reload(); + } + + openMergeDialog() { + const rows = Object.values(this.browse.markedForMerge); + if (rows.length > 0) { + this.mergeDialog.authData = rows; + this.mergeDialog.open({size: 'lg'}).subscribe(success => { + if (success) { + this.clearMergeSelection(); + this.search(); + } + }); + } + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/browse.service.ts b/Open-ILS/src/eg2/src/app/staff/cat/authority/browse.service.ts new file mode 100644 index 0000000000..83701c1a25 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/cat/authority/browse.service.ts @@ -0,0 +1,81 @@ +import {Injectable} from '@angular/core'; +import {Observable, empty} from 'rxjs'; +import {map, switchMap} from 'rxjs/operators'; +import {IdlObject} from '@eg/core/idl.service'; +import {Pager} from '@eg/share/util/pager'; +import {NetService} from '@eg/core/net.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {OrgService} from '@eg/core/org.service'; +import {ComboboxEntry} from '@eg/share/combobox/combobox.component'; + +/* Browse APIS and state maintenance */ + +@Injectable() +export class BrowseService { + + // Grid paging is disabled in this UI to support browsing in + // both directions. Define our own paging trackers. + pageSize = 15; + searchOffset = 0; + + searchTerm: string; + authorityAxis: string; + authorityAxes: ComboboxEntry[]; + markedForMerge: {[id: number]: boolean} = {}; + + constructor( + private net: NetService, + private org: OrgService, + private pcrud: PcrudService + ) {} + + fetchAxes(): Promise { + if (this.authorityAxes) { + return Promise.resolve(this.authorityAxes); + } + + this.pcrud.retrieveAll('aba', {}, {atomic: true}) + .pipe(map(axes => { + this.authorityAxes = axes + .map(axis => ({id: axis.code(), label: axis.name()})) + .sort((a1, a2) => a1.label < a2.label ? -1 : 1); + })).toPromise(); + + } + + loadAuthorities(): Observable { + + if (!this.searchTerm || !this.authorityAxis) { + return empty(); + } + + return this.net.request( + 'open-ils.supercat', + 'open-ils.supercat.authority.browse.by_axis', + this.authorityAxis, this.searchTerm, + this.pageSize, this.searchOffset + + ).pipe(switchMap(authIds => { + + return this.net.request( + 'open-ils.search', + 'open-ils.search.authority.main_entry', authIds + ); + + })).pipe(map(authMeta => { + + const oOrg = this.org.get(authMeta.authority.owner()); + + return { + authority: authMeta.authority, + link_count: authMeta.linked_bibs.length, + heading: authMeta.heading, + thesaurus: authMeta.thesaurus, + thesaurus_code: authMeta.thesaurus_code, + owner: oOrg ? oOrg.shortname() : '' + }; + })); + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.html b/Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.html new file mode 100644 index 0000000000..37bb7ecf02 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.html @@ -0,0 +1,35 @@ + + + + + + + + +
+ +
+
+
+ + +
+ + +
+
+
+
+ + diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.ts b/Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.ts new file mode 100644 index 0000000000..1234e76e0e --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.ts @@ -0,0 +1,67 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {Router, ActivatedRoute, ParamMap} from '@angular/router'; +import {Observable, empty} from 'rxjs'; +import {map, switchMap} from 'rxjs/operators'; +import {NgbTabset, NgbTabChangeEvent} from '@ng-bootstrap/ng-bootstrap'; +import {IdlObject} from '@eg/core/idl.service'; +import {Pager} from '@eg/share/util/pager'; +import {NetService} from '@eg/core/net.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {OrgService} from '@eg/core/org.service'; +import {ComboboxEntry} from '@eg/share/combobox/combobox.component'; + +/* Find, merge, and edit authority records */ + +@Component({ + templateUrl: 'manage.component.html' +}) +export class ManageAuthorityComponent implements OnInit { + + authId: number; + authTab = 'bibs'; + authMeta: any; + + constructor( + private router: Router, + private route: ActivatedRoute, + private net: NetService, + private org: OrgService, + private pcrud: PcrudService + ) { + } + + ngOnInit() { + this.route.paramMap.subscribe((params: ParamMap) => { + this.authTab = params.get('tab') || 'bibs'; + const id = +params.get('id'); + + if (id !== this.authId) { + this.authId = id; + + this.net.request( + 'open-ils.search', + 'open-ils.search.authority.main_entry', this.authId + ).subscribe(meta => this.authMeta = meta); + } + }); + } + + // Changing a tab in the UI means changing the route. + // Changing the route ultimately results in changing the tab. + beforeTabChange(evt: NgbTabChangeEvent) { + + // prevent tab changing until after route navigation + evt.preventDefault(); + + this.authTab = evt.nextId; + this.routeToTab(); + } + + routeToTab() { + const url = + `/staff/cat/authority/manage/${this.authId}/${this.authTab}`; + this.router.navigate([url]); + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/merge-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/cat/authority/merge-dialog.component.html new file mode 100644 index 0000000000..cccf2eee0b --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/cat/authority/merge-dialog.component.html @@ -0,0 +1,42 @@ + + + + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/merge-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/cat/authority/merge-dialog.component.ts new file mode 100644 index 0000000000..526121e46a --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/cat/authority/merge-dialog.component.ts @@ -0,0 +1,74 @@ +import {Component, OnInit, Input, ViewChild} from '@angular/core'; +import {NetService} from '@eg/core/net.service'; +import {EventService} from '@eg/core/event.service'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {AuthService} from '@eg/core/auth.service'; +import {DialogComponent} from '@eg/share/dialog/dialog.component'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {StringComponent} from '@eg/share/string/string.component'; + +/** + * Dialog for merging authority records. + */ + +@Component({ + selector: 'eg-authority-merge-dialog', + templateUrl: 'merge-dialog.component.html' +}) + +export class AuthorityMergeDialogComponent + extends DialogComponent implements OnInit { + + // Rows passed from the authority browse grid. + @Input() authData: any[] = []; + + leadRecord: number; + + @ViewChild('successMsg', {static: true}) + private successMsg: StringComponent; + + @ViewChild('errorMsg', {static: true}) + private errorMsg: StringComponent; + + constructor( + private modal: NgbModal, // required for passing to parent + private toast: ToastService, + private net: NetService, + private evt: EventService, + private auth: AuthService) { + super(modal); // required for subclassing + } + + ngOnInit() { + this.onOpen$.subscribe(_ => { + if (this.authData.length > 0) { + this.leadRecord = this.authData[0].authority.id(); + } + }); + } + + merge() { + + const list = this.authData + .map(data => data.authority.id()) + .filter(id => id !== this.leadRecord); + + this.net.request('open-ils.cat', + 'open-ils.cat.authority.records.merge', + this.auth.token(), this.leadRecord, list) + .subscribe(resp => { + const evt = this.evt.parse(resp); + + if (evt) { + this.errorMsg.current().then(str => this.toast.warning(str)); + this.close(false); + } else { + this.successMsg.current().then(str => this.toast.success(str)); + this.close(true); + } + }); + } +} + + + diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/cat/authority/routing.module.ts index cd6b3a138f..b3fcf36447 100644 --- a/Open-ILS/src/eg2/src/app/staff/cat/authority/routing.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/cat/authority/routing.module.ts @@ -1,6 +1,8 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; import {AuthorityMarcEditComponent} from './marc-edit.component'; +import {BrowseAuthorityComponent} from './browse.component'; +import {ManageAuthorityComponent} from './manage.component'; const routes: Routes = [{ path: 'edit', @@ -8,6 +10,15 @@ const routes: Routes = [{ }, { path: 'edit/:id', component: AuthorityMarcEditComponent + }, { + path: 'browse', + component: BrowseAuthorityComponent + }, { + path: 'manage/:id/:tab', + component: ManageAuthorityComponent + }, { + path: 'manage/:id/:tab', + component: ManageAuthorityComponent }]; @NgModule({ diff --git a/Open-ILS/src/eg2/src/app/staff/nav.component.html b/Open-ILS/src/eg2/src/app/staff/nav.component.html index ad4a3d8088..a36ce00386 100644 --- a/Open-ILS/src/eg2/src/app/staff/nav.component.html +++ b/Open-ILS/src/eg2/src/app/staff/nav.component.html @@ -216,7 +216,7 @@ Link Checker - + Manage Authorities diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.component.html b/Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.component.html new file mode 100644 index 0000000000..6c0ffca6ae --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.component.html @@ -0,0 +1,31 @@ + + + {{row.title()}} + + + + + + + + + + + + + + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.component.ts b/Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.component.ts new file mode 100644 index 0000000000..19faff39b1 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.component.ts @@ -0,0 +1,78 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {Observable, empty} from 'rxjs'; +import {map, switchMap} from 'rxjs/operators'; +import {IdlObject} from '@eg/core/idl.service'; +import {Pager} from '@eg/share/util/pager'; +import {NetService} from '@eg/core/net.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {OrgService} from '@eg/core/org.service'; +import {GridComponent} from '@eg/share/grid/grid.component'; +import {GridContext, GridDataSource, GridCellTextGenerator} from '@eg/share/grid/grid'; +import {ComboboxEntry} from '@eg/share/combobox/combobox.component'; + + +/* Grid of bib records and associated actions. */ + +@Component({ + templateUrl: 'bib-list.component.html', + selector: 'eg-bib-list' +}) +export class BibListComponent implements OnInit { + + // Display bibs linked to this authority record. + @Input() bibIds: number[]; + @Input() gridPersistKey: string; + + dataSource: GridDataSource; + cellTextGenerator: GridCellTextGenerator; + + @ViewChild('grid', {static: false}) grid: GridComponent; + + constructor( + private net: NetService, + private org: OrgService, + private pcrud: PcrudService + ) { + } + + ngOnInit() { + this.dataSource = new GridDataSource(); + + this.dataSource.getRows = (pager: Pager, sort: any): Observable => { + + if (this.bibIds) { + return this.loadIds(pager, sort); + } + + return empty(); + }; + + this.cellTextGenerator = { + title: row => row.title + }; + } + + loadIds(pager: Pager, sort: any): Observable { + if (this.bibIds.length === 0) { + return empty(); + } + + const orderBy: any = {rmsr: 'title'}; + if (sort.length) { + orderBy.rmsr = sort[0].name + ' ' + sort[0].dir; + } + + return this.pcrud.search('rmsr', {id: this.bibIds}, { + order_by: orderBy, + limit: pager.limit, + offset: pager.offset, + flesh: 2, + flesh_fields: { + rmsr: ['biblio_record'], + bre: ['creator', 'editor'] + } + }); + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.module.ts b/Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.module.ts new file mode 100644 index 0000000000..3767156e92 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/share/bib-list/bib-list.module.ts @@ -0,0 +1,20 @@ +import {NgModule} from '@angular/core'; +import {StaffCommonModule} from '@eg/staff/common.module'; +import {BibListComponent} from './bib-list.component'; + +@NgModule({ + declarations: [ + BibListComponent + ], + imports: [ + StaffCommonModule + ], + exports: [ + BibListComponent + ], + providers: [ + ] +}) + +export class BibListModule {} + diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Authority.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Authority.pm index 2e90ae23b3..57ec61dcb6 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Authority.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Authority.pm @@ -4,6 +4,9 @@ use strict; use warnings; use OpenILS::Utils::Fieldmapper; use OpenILS::Application::AppUtils; +use MARC::Record; +use MARC::File::XML (BinaryEncoding => 'UTF-8'); +use MARC::Charset; use XML::LibXML; use XML::LibXSLT; use OpenILS::Utils::CStoreEditor q/:funcs/; @@ -338,6 +341,92 @@ sub crossref_authority_batch2 { return $response; } +__PACKAGE__->register_method( + method => "authority_main_entry", + api_name => "open-ils.search.authority.main_entry", + stream => 1, + signature => { + desc => q/ + Returns the main entry details for one or more authority + records plus a few other details. + /, + params => [ + {desc => 'Authority IDs', type => 'number or array'} + ], + return => { + desc => q/ + Stream of authority metadata objects. + { authority: are_object, + heading: heading_text, + thesaurus: short_code, + thesaurus_code: code, + control_set: control_set_object, + linked_bibs: [id1, id2, ...] + } + /, + type => 'object' + } + } +); + +sub authority_main_entry { + my ($self, $client, $auth_ids) = @_; + + $auth_ids = [$auth_ids] unless ref $auth_ids; + + my $e = new_editor(); + + for my $auth_id (@$auth_ids) { + + my $rec = $e->retrieve_authority_record_entry([ + $auth_id, { + flesh => 1, + flesh_fields => {are => [qw/control_set bib_links creator/]} + } + ]) or return $e->event; + + my $response = { + authority => $rec, + control_set => $rec->control_set, + linked_bibs => [ map {$_->bib} @{$rec->bib_links} ] + }; + + # Extract the heading and thesaurus. + # In theory this data has already been extracted in the DB, but + # using authority.simple_heading results in data that varies + # quite a bit from the previous authority manage interface. I + # took the MARC parsing approach because it matches the logic + # (and results) of the previous UI. + + my $marc = MARC::Record->new_from_xml($rec->marc); + my $heading_field = $marc->field('1..'); + $response->{heading} = $heading_field->as_string if $heading_field; + + my $field_008 = $marc->field('008'); + if ($field_008) { + + # Extract the 1-char thesaurus code from the 008. + my $thes = substr($field_008->data, 11, 1); + + if (defined $thes) { + $response->{thesaurus} = $thes; + + if ($thes ne 'z') { # 'z' ('Other') maps to many entries + my $thesaurus = $e->search_authority_thesaurus( + {short_code => $thes})->[0]; + + $response->{thesaurus_code} = $thesaurus->code if $thesaurus; + } + } + } + + $rec->clear_marc; + $client->respond($response); + } + + return undef; +} + 1; 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 fe6de394fa..18564980f4 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -20520,6 +20520,18 @@ VALUES ( 'Default org unit for patron search', 'cwst', 'label' ) +), ( + 'eg.grid.cat.authority.browse', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.cat.authority.browse', + 'Grid Config: eg.grid.cat.authority.browse', + 'cwst', 'label') +), ( + 'eg.grid.cat.authority.manage.bibs', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.cat.authority.manage.bibs', + 'Grid Config: eg.grid.cat.authority.manage.bibs', + 'cwst', 'label') ); INSERT INTO config.workstation_setting_type diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.manage-authority-grids.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.manage-authority-grids.sql new file mode 100644 index 0000000000..4236704eef --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.manage-authority-grids.sql @@ -0,0 +1,20 @@ +BEGIN; + +-- SELECT evergreen.upgrade_deps_block_check('TODO', :eg_version); + +INSERT INTO config.workstation_setting_type (name, grp, datatype, label) +VALUES ( + 'eg.grid.cat.authority.browse', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.cat.authority.browse', + 'Grid Config: eg.grid.cat.authority.browse', + 'cwst', 'label') +), ( + 'eg.grid.cat.authority.manage.bibs', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.cat.authority.manage.bibs', + 'Grid Config: eg.grid.cat.authority.manage.bibs', + 'cwst', 'label') +); + +COMMIT; diff --git a/Open-ILS/src/templates/staff/navbar.tt2 b/Open-ILS/src/templates/staff/navbar.tt2 index 6ccd5b4253..48b808f414 100644 --- a/Open-ILS/src/templates/staff/navbar.tt2 +++ b/Open-ILS/src/templates/staff/navbar.tt2 @@ -335,7 +335,7 @@
  • - + [% l('Manage Authorities') %] diff --git a/docs/RELEASE_NOTES_NEXT/Cataloging/manage-auths-ang.adoc b/docs/RELEASE_NOTES_NEXT/Cataloging/manage-auths-ang.adoc new file mode 100644 index 0000000000..a044ea5853 --- /dev/null +++ b/docs/RELEASE_NOTES_NEXT/Cataloging/manage-auths-ang.adoc @@ -0,0 +1,7 @@ +Manage Authorities Angular Port +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The Cataloging => 'Manage Authorities' interface has been ported to Angular. + +New functionality includes displaying additional authority data, like create +and edit dates, etc. It's also possible to view the list of linked bib +records. -- 2.11.0