import {AuthorityMarcEditComponent} from './marc-edit.component';
import {BrowseAuthorityComponent} from './browse.component';
import {ManageAuthorityComponent} from './manage.component';
+import {BrowseService} from './browse.service';
import {BibListModule} from '@eg/staff/share/bib-list/bib-list.module';
@NgModule({
BibListModule
],
providers: [
+ BrowseService
]
})
<eg-staff-banner bannerText="Manage Authority Records" i18n-bannerText>
</eg-staff-banner>
+<eg-string #rowSelected text="Row Selected for Merge" i18n-text></eg-string>
+
<div class="row form-inline mb-3">
<div class="col-lg-3">
<div class="input-group">
</div>
<input type="text" class="form-control" placeholder="Search Term"
i18n-placeholder aria-describedby="search-term"
- (keyup.enter)="search()" [(ngModel)]="searchTerm">
+ (change)="search()"
+ (keyup.enter)="search()" [(ngModel)]="browse.searchTerm">
</div>
</div>
<div class="col-lg-5">
<span class="input-group-text" id="auth-axis" i18n>Authority Type</span>
</div>
<eg-combobox #axisCbox [(ngModel)]="authorityAxis"
- [entries]="authorityAxes" (onChange)="search()">
+ [entries]="browse.authorityAxes" (onChange)="search(0, $event)">
</eg-combobox>
+ <!--
+ Hiding 'submit' button since it should never be necessary, plus it
+ can lead to firing duplicate searches if you're quick on the draw.
+ If we want it back, uncomment and add a [disabled] attribute to
+ prevent dupe searches.
<button class="btn btn-outline-dark ml-2" (click)="search()" i18n>Submit</button>
+ -->
</div>
</div>
<div class="col-lg-4 d-flex">
<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()"/>
+ [(ngModel)]="browse.searchOffset" id="offset-input" (change)="search()"/>
<button class="btn btn-outline-dark ml-2" (click)="search(1)" i18n>Next</button>
</div>
</div>
</ng-template>
<eg-grid #grid [dataSource]="dataSource" [disablePaging]="true"
+ [rowFlairIsEnabled]="true" [rowFlairCallback]="rowFlairCallback"
[cellTextGenerator]="cellTextGenerator" persistKey="cat.authority.browse">
+
+ <eg-grid-toolbar-action label="Mark for Merge" i18n-label
+ (onClick)="markForMerge($event)"></eg-grid-toolbar-action>
+
+ <eg-grid-toolbar-action label="Un-Mark for Merge" i18n-label
+ (onClick)="unMarkForMerge($event)"></eg-grid-toolbar-action>
+
+ <eg-grid-toolbar-action label="Clear All Merge Marks" i18n-label
+ (onClick)="clearMergeSelection()"></eg-grid-toolbar-action>
+
<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"
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';
+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';
/* Find, merge, and edit authority records */
})
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;
+ rowFlairCallback: (row: any) => GridRowFlairEntry;
+
@ViewChild('grid', {static: false}) grid: GridComponent;
+ @ViewChild('axisCbox', {static: false}) axisCbox: ComboboxComponent;
+ @ViewChild('rowSelected', {static: false}) rowSelected: StringComponent;
constructor(
private net: NetService,
private org: OrgService,
- private pcrud: PcrudService
- ) {
- }
+ private pcrud: PcrudService,
+ private browse: BrowseService
+ ) {}
ngOnInit() {
+ this.browse.fetchAxes();
+ this.setupGrid();
+ }
- 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);
- });
-
+ setupGrid() {
this.dataSource = new GridDataSource();
- this.dataSource.getRows = (pager: Pager, sort: any): Observable<any> => {
- return this.loadAuthorities();
+ this.dataSource.getRows =
+ (pager: Pager, sort: any): Observable<any> => {
+
+ if (this.authorityAxis) {
+ this.browse.authorityAxis = this.authorityAxis.id;
+
+ } else {
+ 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
}
- }
- loadAuthorities(): Observable<any> {
-
- if (!this.searchTerm || !this.authorityAxis.id) {
- return empty();
+ 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;
}
+ }
- 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 => {
+ markForMerge(rows: any[]) {
+ rows.forEach(row =>
+ this.browse.markedForMerge[row.authority.id()] = true);
+ }
- const oOrg = this.org.get(authMeta.authority.owner());
+ unMarkForMerge(rows: any[]) {
+ rows.forEach(row =>
+ delete this.browse.markedForMerge[row.authority.id()]);
+ }
- 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() : ''
- };
- }));
+ clearMergeSelection() {
+ this.browse.markedForMerge = {};
}
search(offset?: number) {
- if (offset) { this.searchOffset += offset; }
-
+ if (offset) {
+ this.browse.searchOffset += offset;
+ }
this.grid.reload();
}
}
--- /dev/null
+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<any> {
+ 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<any> {
+
+ 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() : ''
+ };
+ }));
+ }
+}
+
+
<eg-staff-banner bannerText="Manage Authority Record #{{authId}}" i18n-bannerText>
</eg-staff-banner>
+<div class="row mb-2">
+ <div class="col-lg-3">
+ <a routerLink="/staff/cat/authority/browse">
+ <button class="btn btn-outline-dark">
+ <span class="material-icons material-mat-icon-shrunk-in-button">arrow_back</span>
+ <span class="pl-1" i18n>Return to Browse</span>
+ </button>
+ </a>
+ </div>
+</div>
+
<ngb-tabset #authTabs [activeId]="authTab"
(tabChange)="beforeTabChange($event)">
<ngb-tab title="Linked Bibs" i18n-title id="bibs">
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} from '@eg/share/grid/grid';
import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
/* Find, merge, and edit authority records */
authTab = 'bibs';
authMeta: any;
- bibsDataSource: GridDataSource;
- @ViewChild('bibsGrid', {static: false}) bibsGrid: GridComponent;
-
constructor(
private router: Router,
private route: ActivatedRoute,
}
ngOnInit() {
-
- this.bibsDataSource = new GridDataSource();
-
- this.bibsDataSource.getRows = (pager: Pager, sort: any): Observable<any> => {
- return this.loadLinkedBibs();
- }
-
this.route.paramMap.subscribe((params: ParamMap) => {
this.authTab = params.get('tab') || 'bibs';
const id = +params.get('id');
`/staff/cat/authority/manage/${this.authId}/${this.authTab}`;
this.router.navigate([url]);
}
-
-
- loadLinkedBibs(): Observable<any> {
-
- return empty();
- }
}
</ng-template>
<eg-grid #grid [dataSource]="dataSource" idlClass="rmsr" [sortable]="true"
- [cellTextGenerator]="cellTextGenerator" [persistKey]="gridPersistKey">
+ [cellTextGenerator]="cellTextGenerator" [persistKey]="gridPersistKey"
+ [showDeclaredFieldsOnly]="true">
+
+ <eg-grid-column name="id" label="ID" i18n-label flex="1"></eg-grid-column>
<eg-grid-column name="title" [cellTemplate]="titleTemplate"
- label="Title" i18n-label></eg-grid-column>
+ label="Title" i18n-label flex="3"></eg-grid-column>
<eg-grid-column name="author" label="Author" i18n-label></eg-grid-column>
+ <eg-grid-column name="creator" label="Creator" i18n-label [sortable]="false"
+ path="biblio_record.creator.usrname" flex="1"></eg-grid-column>
+
+ <eg-grid-column name="create_date" label="Create Date" i18n-label
+ [sortable]="false" path="biblio_record.create_date" flex="1"></eg-grid-column>
+
+ <eg-grid-column name="editor" label="Editor" i18n-label [sortable]="false"
+ path="biblio_record.editor.usrname" flex="1"></eg-grid-column>
+
+ <eg-grid-column name="edit_date" label="Edit Date" i18n-label
+ [sortable]="false" path="biblio_record.edit_date" flex="1"></eg-grid-column>
+
</eg-grid>
import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
-/* List of bib records and associated actions */
+/* Grid of bib records and associated actions. */
@Component({
templateUrl: 'bib-list.component.html',
// Display bibs linked to this authority record.
@Input() bibIds: number[];
-
- @Input() bucketId: number; // TODO
-
@Input() gridPersistKey: string;
dataSource: GridDataSource;
}
this.cellTextGenerator = {
+ title: row => row.title
};
}
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: {}, /* todo */
+ order_by: orderBy,
limit: pager.limit,
offset: pager.offset,
flesh: 2,
flesh_fields: {
- rmsr: ['bib_record'],
+ rmsr: ['biblio_record'],
bre: ['creator', 'editor']
}
});
)
);
+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')
+);
+
--- /dev/null
+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;