--- /dev/null
+<eg-staff-banner bannerText="MARC Batch Edit" i18n-bannerText></eg-staff-banner>
+
+<div class="row">
+ <div class="col-lg-6">
+ </div>
+ <div class="col-lg-6">
+ <div class="row">
+ <div class="col-lg-3" i18n>Record Source: </div>
+ <div class="col-lg-6">
+ <select class="form-control" [(ngModel)]="source">
+ <option value='bucket' i18n>Bucket</option>
+ <option value='csv' i18n>CSV File</option>
+ <option value='id' i18n>Bib Record ID</option>
+ </select>
+ </div>
+ </div>
+ <div class="row mt-2 p-2 border">
+ <ng-container *ngIf="source == 'bucket'">
+ <div class="col-lg-3" i18n>Bucket named: </div>
+ <div class="col-lg-6">
+ <eg-combobox [entries]="buckets" (onChange)="bucketChanged($event)">
+ </eg-combobox>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="source == 'id'">
+ <div class="col-lg-3" i18n>Record ID: </div>
+ <div class="col-lg-3">
+ <input type="text" class="form-control" [(ngModel)]="recordId"/>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="source == 'csv'">
+ <div class="col-lg-12">
+ <div class="row">
+ <div class="col-lg-3" i18n>Column: </div>
+ <div class="col-lg-2 d-flex">
+ <input type="number" class="form-control" [(ngModel)]="csvColumn"/>
+ <span class="pl-2" i18n> of </span>
+ </div>
+ <div class="col-lg-5">
+ <input type="file" class="form-control"
+ #fileSelector (change)="fileSelected($event)"/>
+ </div>
+ </div>
+ <div class="row pt-2">
+ <div class="col-lg-12" i18n>
+ Columns are numbered starting at 0. For instance, when looking
+ at a CSV file in Excel, the column labeled A is the same as
+ column 0, and the column labeled B is the same as column 1.
+ </div>
+ </div>
+ </div>
+ </ng-container>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-4">
+ <div class="form-check form-check-inline">
+ <input class="form-check-input" type="checkbox"
+ id="xact-checkbox" [(ngModel)]="xactPerRecord"/>
+ <label class="form-check-label" for="xact-checkbox" i18n>
+ Per-Record Transactions?
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-12" i18n>
+ By default, all records are processed within a single database
+ transaction. However, processing large batches of records
+ within a single transaction can negatively impact a running
+ system because it may conflict with other cataloging activities.
+ Use Per-Record transactions to mitigate these conflicts.
+ </div>
+ </div>
+ <div class="row mt-2 p-2 border">
+ <div class="col-lg-12">
+ <button class="btn btn-outline-dark" (click)="process()" i18n>Go!</button>
+ </div>
+ </div>
+ <div class="row mt-2 p-2">
+ </div>
+ </div>
+</div>
--- /dev/null
+import {Component, OnInit, AfterViewInit, ViewChild, Renderer2} from '@angular/core';
+import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {tap} from 'rxjs/operators';
+import {NetService} from '@eg/core/net.service';
+import {AuthService} from '@eg/core/auth.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+
+@Component({
+ templateUrl: 'marcbatch.component.html'
+})
+export class MarcBatchComponent implements OnInit, AfterViewInit {
+
+ session: string;
+ source: 'bucket' | 'csv' | 'id' = 'bucket';
+ buckets: ComboboxEntry[];
+ bucket: number;
+ recordId: number;
+ csvColumn = 0;
+ selectedFile: File;
+ xactPerRecord = false;
+
+ constructor(
+ private router: Router,
+ private route: ActivatedRoute,
+ private renderer: Renderer2,
+ private net: NetService,
+ private pcrud: PcrudService,
+ private auth: AuthService
+ ) {}
+
+ ngOnInit() {
+ this.route.paramMap.subscribe((params: ParamMap) => {
+ this.session = this.route.snapshot.paramMap.get('session');
+ });
+
+ this.load();
+ }
+
+ load() {
+ this.getBuckets();
+ }
+
+ getBuckets(): Promise<any> {
+ if (this.buckets) { return Promise.resolve(); }
+
+ return this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.container.retrieve_by_class',
+ this.auth.token(), this.auth.user().id(),
+ 'biblio', ['staff_client','vandelay_queue']
+
+ ).pipe(tap(buckets => {
+ this.buckets = buckets
+ .sort((b1, b2) => b1.name() < b2.name() ? -1 : 1)
+ .map(b => ({id: b.id(), label: b.name()}))
+
+ })).toPromise();
+ }
+
+ bucketChanged(entry: ComboboxEntry) {
+ this.bucket = entry ? entry.id : null;
+ }
+
+ fileSelected($event) {
+ this.selectedFile = $event.target.files[0];
+ }
+
+ ngAfterViewInit() {}
+}
+
--- /dev/null
+import {NgModule} from '@angular/core';
+import {StaffCommonModule} from '@eg/staff/common.module';
+import {CommonWidgetsModule} from '@eg/share/common-widgets.module';
+import {MarcBatchRoutingModule} from './routing.module';
+import {MarcBatchComponent} from './marcbatch.component';
+
+@NgModule({
+ declarations: [
+ MarcBatchComponent
+ ],
+ imports: [
+ StaffCommonModule,
+ CommonWidgetsModule,
+ MarcBatchRoutingModule
+ ],
+ providers: [
+ ]
+})
+
+export class MarcBatchModule {
+}
--- /dev/null
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {MarcBatchComponent} from './marcbatch.component';
+
+const routes: Routes = [{
+ path: '',
+ component: MarcBatchComponent
+ }, {
+ path: ':session',
+ component: MarcBatchComponent
+}];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+ providers: []
+})
+
+export class MarcBatchRoutingModule {}
+
}, {
path: 'authority',
loadChildren: '@eg/staff/cat/authority/authority.module#AuthorityModule'
+ }, {
+ path: 'marcbatch',
+ loadChildren: '@eg/staff/cat/marcbatch/marcbatch.module#MarcBatchModule'
}
];