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 {BibListModule} from '@eg/staff/share/bib-list/bib-list.module';
@NgModule({
declarations: [
AuthorityMarcEditComponent,
+ BrowseAuthorityComponent,
ManageAuthorityComponent
],
imports: [
StaffCommonModule,
CommonWidgetsModule,
MarcEditModule,
- AuthorityRoutingModule
+ AuthorityRoutingModule,
+ BibListModule
],
providers: [
]
--- /dev/null
+<eg-staff-banner bannerText="Manage Authority Records" i18n-bannerText>
+</eg-staff-banner>
+
+<div class="row form-inline mb-3">
+ <div class="col-lg-3">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text" id="search-term" i18n>Search Term</span>
+ </div>
+ <input type="text" class="form-control" placeholder="Search Term"
+ i18n-placeholder aria-describedby="search-term"
+ (keyup.enter)="search()" [(ngModel)]="searchTerm">
+ </div>
+ </div>
+ <div class="col-lg-5">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text" id="auth-axis" i18n>Authority Type</span>
+ </div>
+ <eg-combobox #axisCbox [(ngModel)]="authorityAxis"
+ [entries]="authorityAxes" (onChange)="search()">
+ </eg-combobox>
+ <button class="btn btn-outline-dark ml-2" (click)="search()" i18n>Submit</button>
+ </div>
+ </div>
+ <div class="col-lg-4 d-flex">
+ <div class="flex-1"></div><!-- push right -->
+ <div class="form-inline">
+ <button class="btn btn-outline-dark ml-2" (click)="search(-1)" i18n>Previous</button>
+ <label for='offset-input' class="form-control ml-2" i18n>Page</label>
+ <input class="form-control" type="number"
+ [(ngModel)]="searchOffset" id="offset-input" (change)="search()"/>
+ <button class="btn btn-outline-dark ml-2" (click)="search(1)" i18n>Next</button>
+ </div>
+ </div>
+</div>
+
+<ng-template #headingTemplate let-row="row">
+ <a routerLink="/staff/cat/authority/manage/{{row.authority.id()}}/bibs"
+ i18n-title title="Manage Authority {{row.authority.id()}}">
+ {{row.heading}}
+ </a>
+</ng-template>
+
+<eg-grid #grid [dataSource]="dataSource" [disablePaging]="true"
+ [cellTextGenerator]="cellTextGenerator" persistKey="cat.authority.browse">
+ <eg-grid-column name="id" label="ID" path="authority.id" i18n-label
+ [index]="true" flex="1"></eg-grid-column>
+ <eg-grid-column name="link_count" label="Linked Bibs"
+ i18n-label flex="1"></eg-grid-column>
+ <eg-grid-column name="heading" label="Heading" i18n-label flex="3"
+ [cellTemplate]="headingTemplate"></eg-grid-column>
+ <eg-grid-column name="control_set" path="authority.control_set.name"
+ label="Control Set" i18n-label flex="1"></eg-grid-column>
+ <eg-grid-column name="thesaurus" label="Thesaurus" i18n-label flex="1"></eg-grid-column>
+ <eg-grid-column name="thesaurus_code" label="Thesaurus Code"
+ i18n-label flex="1"></eg-grid-column>
+ <eg-grid-column name="creator" label="Creator" i18n-label
+ path="authority.creator.usrname" flex="1"></eg-grid-column>
+ <eg-grid-column name="create_date" label="Create Date" i18n-label
+ path="authority.create_date" flex="1" datatype="timestamp"></eg-grid-column>
+ <eg-grid-column name="edit_date" label="Edit Date" i18n-label
+ path="authority.edit_date" flex="1" datatype="timestamp"></eg-grid-column>
+ <eg-grid-column name="source" label="Source" i18n-label
+ path="authority.source" flex="1"></eg-grid-column>
+ <eg-grid-column name="owner" label="Owner" i18n-label
+ path="authority.owner" flex="1"></eg-grid-column>
+</eg-grid>
+
--- /dev/null
+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} from '@eg/share/grid/grid';
+import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+
+/* Find, merge, and edit authority records */
+
+@Component({
+ templateUrl: 'browse.component.html',
+ styles: [`#offset-input { width: 4em; }`]
+})
+export class BrowseAuthorityComponent implements OnInit {
+
+ // 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: ComboboxEntry;
+ authorityAxes: ComboboxEntry[];
+ dataSource: GridDataSource;
+ cellTextGenerator: GridCellTextGenerator;
+
+ @ViewChild('grid', {static: false}) grid: GridComponent;
+
+ constructor(
+ private net: NetService,
+ private org: OrgService,
+ private pcrud: PcrudService
+ ) {
+ }
+
+ ngOnInit() {
+
+ this.pcrud.retrieveAll('aba', {}, {atomic: true})
+ .subscribe(axes => {
+ this.authorityAxes = axes
+ .map(axis => ({id: axis.code(), label: axis.name()}))
+ .sort((a1, a2) => a1.label < a2.label ? -1 : 1);
+ });
+
+ this.dataSource = new GridDataSource();
+
+ this.dataSource.getRows = (pager: Pager, sort: any): Observable<any> => {
+ return this.loadAuthorities();
+ }
+
+ this.cellTextGenerator = {
+ heading: row => row.heading
+ }
+ }
+
+ loadAuthorities(): Observable<any> {
+
+ if (!this.searchTerm || !this.authorityAxis.id) {
+ return empty();
+ }
+
+ return this.net.request(
+ 'open-ils.supercat',
+ 'open-ils.supercat.authority.browse.by_axis',
+ this.authorityAxis.id, 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() : ''
+ };
+ }));
+ }
+
+ search(offset?: number) {
+ if (offset) { this.searchOffset += offset; }
+
+ this.grid.reload();
+ }
+}
+
+
-<eg-staff-banner bannerText="Manage Authority Records" i18n-bannerText>
+<eg-staff-banner bannerText="Manage Authority Record #{{authId}}" i18n-bannerText>
</eg-staff-banner>
-<div class="row form-inline mb-3">
- <div class="col-lg-3">
- <div class="input-group">
- <div class="input-group-prepend">
- <span class="input-group-text" id="search-term" i18n>Search Term</span>
+<ngb-tabset #authTabs [activeId]="authTab"
+ (tabChange)="beforeTabChange($event)">
+ <ngb-tab title="Linked Bibs" i18n-title id="bibs">
+ <ng-template ngbTabContent>
+ <div class="mt-3" *ngIf="authMeta">
+ <eg-bib-list #bibList [bibIds]="authMeta.linked_bibs"></eg-bib-list>
</div>
- <input type="text" class="form-control" placeholder="Search Term"
- i18n-placeholder aria-describedby="search-term"
- (keyup.enter)="search()" [(ngModel)]="searchTerm">
- </div>
- </div>
- <div class="col-lg-5">
- <div class="input-group">
- <div class="input-group-prepend">
- <span class="input-group-text" id="auth-axis" i18n>Authority Type</span>
+ </ng-template>
+ </ngb-tab>
+ <ngb-tab title="Edit" i18n-title id="edit">
+ <ng-template ngbTabContent>
+ <div class="mt-3">
+ <eg-marc-editor #marcEditor recordType="authority" [recordId]="authId">
+ </eg-marc-editor>
</div>
- <eg-combobox #axisCbox [(ngModel)]="authorityAxis"
- [entries]="authorityAxes" (onChange)="search()">
- </eg-combobox>
- <button class="btn btn-outline-dark ml-2" (click)="search()" i18n>Submit</button>
- </div>
- </div>
- <div class="col-lg-4 d-flex">
- <div class="flex-1"></div><!-- push right -->
- <div class="form-inline">
- <button class="btn btn-outline-dark ml-2" (click)="search(-1)" i18n>Previous</button>
- <label for='offset-input' class="form-control ml-2" i18n>Page</label>
- <input class="form-control" type="number"
- [(ngModel)]="searchOffset" id="offset-input" (change)="search()"/>
- <button class="btn btn-outline-dark ml-2" (click)="search(1)" i18n>Next</button>
- </div>
- </div>
-</div>
+ </ng-template>
+ </ngb-tab>
+</ngb-tabset>
-<eg-grid #grid [dataSource]="dataSource" [disablePaging]="true">
- <eg-grid-column name="id" label="ID" path="authority.id" i18n-label
- [index]="true" flex="1"></eg-grid-column>
- <eg-grid-column name="link_count" label="Linked Bibs"
- i18n-label flex="1"></eg-grid-column>
- <eg-grid-column name="heading" label="Heading" i18n-label flex="3"></eg-grid-column>
- <eg-grid-column name="control_set" path="authority.control_set.name"
- label="Control Set" i18n-label flex="1"></eg-grid-column>
- <eg-grid-column name="thesaurus" label="Thesaurus" i18n-label flex="1"></eg-grid-column>
- <eg-grid-column name="thesaurus_code" label="Thesaurus Code"
- i18n-label flex="1"></eg-grid-column>
- <eg-grid-column name="creator" label="Creator" i18n-label
- path="authority.creator.usrname" flex="1"></eg-grid-column>
- <eg-grid-column name="create_date" label="Create Date" i18n-label
- path="authority.create_date" flex="1" datatype="timestamp"></eg-grid-column>
- <eg-grid-column name="edit_date" label="Edit Date" i18n-label
- path="authority.edit_date" flex="1" datatype="timestamp"></eg-grid-column>
- <eg-grid-column name="source" label="Source" i18n-label
- path="authority.source" flex="1"></eg-grid-column>
- <eg-grid-column name="owner" label="Owner" i18n-label
- path="authority.owner" flex="1"></eg-grid-column>
-
-
-</eg-grid>
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';
/* Find, merge, and edit authority records */
@Component({
- templateUrl: 'manage.component.html',
- styles: [`#offset-input { width: 4em; }`]
+ templateUrl: 'manage.component.html'
})
export class ManageAuthorityComponent implements OnInit {
- // Grid paging is disabled in this UI to support browsing in
- // both directions. Define our own paging trackers.
- pageSize = 15;
- searchOffset = 0;
+ authId: number;
+ authTab = 'bibs';
+ authMeta: any;
- searchTerm: string;
- authorityAxis: ComboboxEntry;
- authorityAxes: ComboboxEntry[];
- dataSource: GridDataSource;
-
- @ViewChild('grid', {static: false}) grid: GridComponent;
+ bibsDataSource: GridDataSource;
+ @ViewChild('bibsGrid', {static: false}) bibsGrid: GridComponent;
constructor(
+ private router: Router,
+ private route: ActivatedRoute,
private net: NetService,
private org: OrgService,
private pcrud: PcrudService
ngOnInit() {
- this.pcrud.retrieveAll('aba', {}, {atomic: true})
- .subscribe(axes => {
- this.authorityAxes = axes
- .map(axis => ({id: axis.code(), label: axis.name()}))
- .sort((a1, a2) => a1.label < a2.label ? -1 : 1);
- });
-
- this.dataSource = new GridDataSource();
+ this.bibsDataSource = new GridDataSource();
- this.dataSource.getRows = (pager: Pager, sort: any): Observable<any> => {
- return this.loadAuthorities();
+ this.bibsDataSource.getRows = (pager: Pager, sort: any): Observable<any> => {
+ return this.loadLinkedBibs();
}
- }
-
- loadAuthorities(): Observable<any> {
- if (!this.searchTerm || !this.authorityAxis.id) {
- return empty();
- }
+ this.route.paramMap.subscribe((params: ParamMap) => {
+ this.authTab = params.get('tab') || 'bibs';
+ const id = +params.get('id');
- return this.net.request(
- 'open-ils.supercat',
- 'open-ils.supercat.authority.browse.by_axis',
- this.authorityAxis.id, this.searchTerm,
- this.pageSize, this.searchOffset
+ if (id !== this.authId) {
+ this.authId = id;
- ).pipe(switchMap(authIds => {
+ this.net.request(
+ 'open-ils.search',
+ 'open-ils.search.authority.main_entry', this.authId
+ ).subscribe(meta => this.authMeta = meta);
+ }
+ });
+ }
- return this.net.request(
- 'open-ils.search',
- 'open-ils.search.authority.main_entry', authIds
- );
+ // Changing a tab in the UI means changing the route.
+ // Changing the route ultimately results in changing the tab.
+ beforeTabChange(evt: NgbTabChangeEvent) {
- })).pipe(map(authMeta => {
+ // prevent tab changing until after route navigation
+ evt.preventDefault();
- const oOrg = this.org.get(authMeta.authority.owner());
+ this.authTab = evt.nextId;
+ this.routeToTab();
+ }
- 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() : ''
- };
- }));
+ routeToTab() {
+ const url =
+ `/staff/cat/authority/manage/${this.authId}/${this.authTab}`;
+ this.router.navigate([url]);
}
- search(offset?: number) {
- if (offset) { this.searchOffset += offset; }
- this.grid.reload();
+ loadLinkedBibs(): Observable<any> {
+
+ return empty();
}
}
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/:id',
component: AuthorityMarcEditComponent
}, {
- path: 'manage',
+ path: 'browse',
+ component: BrowseAuthorityComponent
+ }, {
+ path: 'manage/:id/:tab',
+ component: ManageAuthorityComponent
+ }, {
+ path: 'manage/:id/:tab',
component: ManageAuthorityComponent
}];
--- /dev/null
+<ng-template #titleTemplate let-row="row">
+ <a routerLink="/staff/catalog/record/{{row.id()}}"
+ i18n-title title="View Record {{row.id()}}">
+ {{row.title()}}
+ </a>
+</ng-template>
+
+<eg-grid #grid [dataSource]="dataSource" idlClass="rmsr" [sortable]="true"
+ [cellTextGenerator]="cellTextGenerator" [persistKey]="gridPersistKey">
+
+ <eg-grid-column name="title" [cellTemplate]="titleTemplate"
+ label="Title" i18n-label></eg-grid-column>
+
+ <eg-grid-column name="author" label="Author" i18n-label></eg-grid-column>
+
+</eg-grid>
--- /dev/null
+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';
+
+
+/* List 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() bucketId: number; // TODO
+
+ @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<any> => {
+
+ if (this.bibIds) {
+ return this.loadIds(pager, sort);
+ }
+
+ return empty();
+ }
+
+ this.cellTextGenerator = {
+ };
+ }
+
+ loadIds(pager: Pager, sort: any): Observable<any> {
+ if (this.bibIds.length === 0) {
+ return empty();
+ }
+
+ return this.pcrud.search('rmsr', {id: this.bibIds}, {
+ order_by: {}, /* todo */
+ limit: pager.limit,
+ offset: pager.offset,
+ flesh: 2,
+ flesh_fields: {
+ rmsr: ['bib_record'],
+ bre: ['creator', 'editor']
+ }
+ });
+ }
+}
+
+
--- /dev/null
+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 {}
+