</li>
<li class="list-group-item">
<div class="d-flex">
- <eg-record-bucket-dialog #bucketDialog [queueId]="queueId">
- </eg-record-bucket-dialog>
+ <eg-bucket-dialog #bucketDialog bucketClass="biblio" [fromBibQueue]="queueId">
+ </eg-bucket-dialog>
<div class="flex-1">
<a [routerLink]="" (click)="bucketDialog.open({size:'lg'})" i18n>
Copy Queue To Bucket
-<eg-record-bucket-dialog #addBasketToBucketDialog>
-</eg-record-bucket-dialog>
+<eg-bucket-dialog #addBasketToBucketDialog>
+</eg-bucket-dialog>
<div class="row">
<div class="col-lg-4 pr-1">
import {NetService} from '@eg/core/net.service';
import {AuthService} from '@eg/core/auth.service';
import {PrintService} from '@eg/share/print/print.service';
-import {RecordBucketDialogComponent
- } from '@eg/staff/share/buckets/record-bucket-dialog.component';
+import {BucketDialogComponent
+ } from '@eg/staff/share/buckets/bucket-dialog.component';
@Component({
selector: 'eg-catalog-basket-actions',
basketAction: string;
@ViewChild('addBasketToBucketDialog')
- addToBucketDialog: RecordBucketDialogComponent;
+ addToBucketDialog: BucketDialogComponent;
constructor(
private router: Router,
case 'bucket':
this.basket.getRecordIds().then(ids => {
- this.addToBucketDialog.recordId = ids;
- this.addToBucketDialog.open({size: 'lg'});
+ this.addToBucketDialog.bucketClass = 'biblio';
+ this.addToBucketDialog.itemIds = ids;
+ this.addToBucketDialog.open({size: 'lg'}).then(
+ ok => {},
+ dismissed => {}
+ );
});
break;
<eg-string key="catalog.record.toast.cleared"
text="Record Marks Cleared"></eg-string>
-<eg-record-bucket-dialog #recordBucketDialog [recordId]="recId">
-</eg-record-bucket-dialog>
+<eg-bucket-dialog #recordBucketDialog bucketClass="biblio" [itemIds]="[recId]">
+</eg-bucket-dialog>
<div class="row ml-0 mr-0">
<eg-copy-alerts-dialog #copyAlertsDialog></eg-copy-alerts-dialog>
<eg-replace-barcode-dialog #replaceBarcode></eg-replace-barcode-dialog>
<eg-delete-volcopy-dialog #deleteVolcopy></eg-delete-volcopy-dialog>
+<eg-bucket-dialog #bucketDialog></eg-bucket-dialog>
<!-- holdings grid -->
<div class='eg-copies w-100 mt-3'>
(onClick)="openItemNotes($event, 'create')">
</eg-grid-toolbar-action>
+ <eg-grid-toolbar-action
+ i18n-group group="Add" i18n-label label="Add Items To Bucket"
+ (onClick)="openBucketDialog($event)">
+ Z</eg-grid-toolbar-action>
+
<!-- row actions: Edit -->
<eg-grid-toolbar-action
} from '@eg/staff/share/holdings/replace-barcode-dialog.component';
import {DeleteVolcopyDialogComponent
} from '@eg/staff/share/holdings/delete-volcopy-dialog.component';
+import {BucketDialogComponent
+ } from '@eg/staff/share/buckets/bucket-dialog.component';
// The holdings grid models a single HoldingsTree, composed of HoldingsTreeNodes
// flattened on-demand into a list of HoldingEntry objects.
private replaceBarcode: ReplaceBarcodeDialogComponent;
@ViewChild('deleteVolcopy')
private deleteVolcopy: DeleteVolcopyDialogComponent;
+ @ViewChild('bucketDialog')
+ private bucketDialog: BucketDialogComponent;
holdingsTree: HoldingsTree;
const params = {target: copyIds, holdFor: 'staff'};
this.router.navigate(['/staff/catalog/hold/C'], {queryParams: params});
}
+
+ openBucketDialog(rows: HoldingsEntry[]) {
+ const copyIds = this.selectedCopyIds(rows);
+ if (copyIds.length > 0) {
+ this.bucketDialog.bucketClass = 'copy';
+ this.bucketDialog.itemIds = copyIds;
+ this.bucketDialog.open({size: 'lg'}).then(
+ // No need to reload the grid after adding items to buckets.
+ () => {},
+ dismissed => {}
+ );
+ }
+ }
}
routerLink's
egDateFilter's
-->
-<eg-record-bucket-dialog #addToListDialog>
-</eg-record-bucket-dialog>
<div class="col-lg-12 card tight-card mb-2 bg-light">
<div class="card-body">
<span i18n>Place Hold</span>
</button>
</span>
- <!--
- <span class="pl-1">
- <button
- (click)="addToListDialog.recordId=summary.record.id(); addToListDialog.open({size: 'lg'})"
- class="btn btn-sm btn-info label-with-material-icon small-text-1">
- <span class="material-icons">playlist_add_check</span>
- <span i18n>Add to List</span>
- </button>
- </span>
- -->
</div>
</div>
</div>
import {TitleComponent} from '@eg/share/title/title.component';
import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
import {DateSelectComponent} from '@eg/share/date-select/date-select.component';
-import {RecordBucketDialogComponent} from '@eg/staff/share/buckets/record-bucket-dialog.component';
+import {BucketDialogComponent} from '@eg/staff/share/buckets/bucket-dialog.component';
import {BibSummaryComponent} from '@eg/staff/share/bib-summary/bib-summary.component';
import {TranslateComponent} from '@eg/staff/share/translate/translate.component';
import {AdminPageComponent} from '@eg/staff/share/admin-page/admin-page.component';
OpChangeComponent,
FmRecordEditorComponent,
DateSelectComponent,
- RecordBucketDialogComponent,
+ BucketDialogComponent,
BibSummaryComponent,
TranslateComponent,
AdminPageComponent
OpChangeComponent,
FmRecordEditorComponent,
DateSelectComponent,
- RecordBucketDialogComponent,
+ BucketDialogComponent,
BibSummaryComponent,
TranslateComponent,
AdminPageComponent
--- /dev/null
+<ng-template #dialogContent>
+ <div class="modal-header bg-info">
+ <h4 class="modal-title">
+ <ng-container *ngIf="itemIds.length > 0">
+ <span *ngIf="itemIds.length == 1" i18n>
+ Add Item #{{itemIds[0]}} to Bucket</span>
+ <span *ngIf="itemIds.length > 1" i18n>
+ Add {{itemIds.length}} Items to Bucket</span>
+ </ng-container>
+ <span *ngIf="fromBibQueue" i18n>Add Records from queue #{{fromBibQueue}} to Bucket</span>
+ </h4>
+ <button type="button" class="close"
+ i18n-aria-label aria-label="Close"
+ (click)="dismiss('cross_click')">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="row">
+ <div class="col-lg-3 font-weight-bold" i18n>Name of existing bucket</div>
+ <div class="col-lg-5">
+ <eg-combobox [entries]="formatBucketEntries()"
+ (onChange)="bucketChanged($event)"
+ placeholder="Existing Bucket..." i18n-placeholder>
+ </eg-combobox>
+ </div>
+ <div class="col-lg-4">
+ <button class="btn btn-info" (click)="addToSelected()" i18n
+ [disabled]="!selectedBucket">
+ Add To Selected Bucket
+ </button>
+ </div>
+ </div>
+ <div class="row mt-3">
+ <div class="col-lg-3 font-weight-bold" i18n>Name of new bucket</div>
+ <div class="col-lg-5">
+ <input type="text" class="form-control"
+ placeholder="New Bucket Name..."
+ i18n-placeholder
+ [(ngModel)]="newBucketName"/>
+ </div>
+ <div class="col-lg-4">
+ <button class="btn btn-info" (click)="addToNew()" i18n
+ [disabled]="!newBucketName">
+ Add To New Bucket
+ </button>
+ </div>
+ </div>
+ <div class="row mt-3">
+ <div class="col-lg-3 font-weight-bold" i18n>New bucket description</div>
+ <div class="col-lg-5">
+ <textarea size="3" type="text" class="form-control"
+ placeholder="Optional New Bucket Description..."
+ i18n-placeholder
+ [(ngModel)]="newBucketDesc">
+ </textarea>
+ </div>
+ </div>
+ </div>
+</ng-template>
--- /dev/null
+import {Component, OnInit, Input, Renderer2} from '@angular/core';
+import {NetService} from '@eg/core/net.service';
+import {IdlService} from '@eg/core/idl.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 {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+
+/**
+ * Dialog for adding bib records to new and existing record buckets.
+ */
+
+@Component({
+ selector: 'eg-bucket-dialog',
+ templateUrl: 'bucket-dialog.component.html'
+})
+
+export class BucketDialogComponent extends DialogComponent implements OnInit {
+
+ selectedBucket: number;
+ newBucketName: string;
+ newBucketDesc: string;
+ buckets: any[];
+
+ @Input() bucketClass: 'biblio' | 'user' | 'callnumber' | 'copy';
+ @Input() bucketType: string; // e.g. staff_client
+
+ // ID's of items to add to the bucket
+ @Input() itemIds: number[];
+
+ // If set, itemIds will be derived from the records in a bib queue
+ @Input() fromBibQueue: number;
+
+ // bucket item classes are these plus a following 'i'.
+ bucketFmClass: 'ccb' | 'ccnb' | 'cbreb' | 'cub';
+ targetField: string;
+
+ constructor(
+ private modal: NgbModal, // required for passing to parent
+ private renderer: Renderer2,
+ private toast: ToastService,
+ private idl: IdlService,
+ private net: NetService,
+ private evt: EventService,
+ private auth: AuthService) {
+ super(modal); // required for subclassing
+ this.buckets = [];
+ this.itemIds = [];
+ this.fromBibQueue = null;
+ }
+
+ ngOnInit() {
+ this.onOpen$.subscribe(ok => {
+ this.reset(); // Reset data on dialog open
+ this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.container.retrieve_by_class.authoritative',
+ this.auth.token(), this.auth.user().id(),
+ this.bucketClass, this.bucketType
+ ).subscribe(buckets => this.buckets = buckets);
+ });
+ }
+
+ reset() {
+ this.selectedBucket = null;
+ this.newBucketName = '';
+ this.newBucketDesc = '';
+
+ if (!this.bucketClass) {
+ this.bucketClass = 'biblio';
+ }
+
+ switch (this.bucketClass) {
+ case 'biblio':
+ if (this.fromBibQueue) {
+ this.bucketType = 'vandelay_queue';
+ }
+ this.bucketFmClass = 'cbreb';
+ this.targetField = 'target_biblio_record_entry';
+ break;
+ case 'copy':
+ this.bucketFmClass = 'ccb';
+ this.targetField = 'target_copy';
+ break;
+ case 'callnumber':
+ this.bucketFmClass = 'ccnb';
+ this.targetField = 'target_call_number';
+ break;
+ case 'user':
+ this.bucketFmClass = 'cub';
+ this.targetField = 'target_user';
+ }
+
+ if (!this.bucketType) {
+ this.bucketType = 'staff_client';
+ }
+ }
+
+ addToSelected() {
+ this.addToBucket(this.selectedBucket);
+ }
+
+ bucketChanged(entry: ComboboxEntry) {
+ if (entry) {
+ this.selectedBucket = entry.id;
+ } else {
+ this.selectedBucket = null;
+ }
+ }
+
+ formatBucketEntries(): ComboboxEntry[] {
+ return this.buckets.map(b => ({id: b.id(), label: b.name()}));
+ }
+
+ // Create a new bucket then add the record
+ addToNew() {
+ const bucket = this.idl.create(this.bucketFmClass);
+
+ bucket.owner(this.auth.user().id());
+ bucket.name(this.newBucketName);
+ bucket.description(this.newBucketDesc);
+ bucket.btype(this.bucketType);
+
+ this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.container.create',
+ this.auth.token(), this.bucketClass, bucket
+ ).subscribe(bktId => {
+ const evt = this.evt.parse(bktId);
+ if (evt) {
+ this.toast.danger(evt.desc);
+ } else {
+ // make it find-able to the queue-add method which
+ // requires the bucket name.
+ bucket.id(bktId);
+ this.buckets.push(bucket);
+ this.addToBucket(bktId);
+ }
+ });
+ }
+
+ addToBucket(id: number) {
+ if (this.itemIds.length > 0) {
+ this.addRecordToBucket(id);
+ } else if (this.fromBibQueue) {
+ this.addBibQueueToBucket(id);
+ }
+ }
+
+ // Add the record(s) to the bucket with provided ID.
+ addRecordToBucket(bucketId: number) {
+ const items = [];
+ this.itemIds.forEach(itemId => {
+ const item = this.idl.create(this.bucketFmClass + 'i');
+ item.bucket(bucketId);
+ item[this.targetField](itemId);
+ items.push(item);
+ });
+
+ this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.container.item.create',
+ this.auth.token(), this.bucketClass, items
+ ).subscribe(resp => {
+ const evt = this.evt.parse(resp);
+ if (evt) {
+ this.toast.danger(evt.toString());
+ } else {
+ this.close();
+ }
+ });
+ }
+
+ addBibQueueToBucket(bucketId: number) {
+ const bucket = this.buckets.filter(b => b.id() === bucketId)[0];
+ if (!bucket) { return; }
+
+ this.net.request(
+ 'open-ils.vandelay',
+ 'open-ils.vandelay.bib_queue.to_bucket',
+ this.auth.token(), this.fromBibQueue, bucket.name()
+ ).toPromise().then(resp => {
+ const evt = this.evt.parse(resp);
+ if (evt) {
+ this.toast.danger(evt.toString());
+ } else {
+ this.close();
+ }
+ });
+ }
+}
+
+
+
+++ /dev/null
-<ng-template #dialogContent>
- <div class="modal-header bg-info">
- <h4 class="modal-title">
- <ng-container *ngIf="recIds.length > 0">
- <span *ngIf="recIds.length == 1" i18n>
- Add Record #{{recIds[0]}} to Bucket</span>
- <span *ngIf="recIds.length > 1" i18n>
- Add {{recIds.length}} Record(s) to Bucket</span>
- </ng-container>
- <span *ngIf="qId" i18n>Add Records from queue #{{qId}} to Bucket</span>
- </h4>
- <button type="button" class="close"
- i18n-aria-label aria-label="Close"
- (click)="dismiss('cross_click')">
- <span aria-hidden="true">×</span>
- </button>
- </div>
- <div class="modal-body">
- <div class="row">
- <div class="col-lg-3 font-weight-bold" i18n>Name of existing bucket</div>
- <div class="col-lg-5">
- <select
- class="form-control"
- placeholder="Existing Bucket..."
- i18n-placeholder
- [(ngModel)]="selectedBucket">
- <option *ngFor="let bkt of buckets"
- value="{{bkt.id()}}">{{bkt.name()}}</option>
- </select>
- </div>
- <div class="col-lg-4">
- <button class="btn btn-info" (click)="addToSelected()" i18n
- [disabled]="!selectedBucket">
- Add To Selected Bucket
- </button>
- </div>
- </div>
- <div class="row mt-3">
- <div class="col-lg-3 font-weight-bold" i18n>Name of new bucket</div>
- <div class="col-lg-5">
- <input type="text" class="form-control"
- placeholder="New Bucket Name..."
- i18n-placeholder
- [(ngModel)]="newBucketName"/>
- </div>
- <div class="col-lg-4">
- <button class="btn btn-info" (click)="addToNew()" i18n
- [disabled]="!newBucketName">
- Add To New Bucket
- </button>
- </div>
- </div>
- <div class="row mt-3">
- <div class="col-lg-3 font-weight-bold" i18n>New bucket description</div>
- <div class="col-lg-5">
- <textarea size="3" type="text" class="form-control"
- placeholder="Optional New Bucket Description..."
- i18n-placeholder
- [(ngModel)]="newBucketDesc">
- </textarea>
- </div>
- </div>
- </div>
-</ng-template>
+++ /dev/null
-import {Component, OnInit, Input, Renderer2} from '@angular/core';
-import {NetService} from '@eg/core/net.service';
-import {IdlService} from '@eg/core/idl.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';
-
-/**
- * Dialog for adding bib records to new and existing record buckets.
- */
-
-@Component({
- selector: 'eg-record-bucket-dialog',
- templateUrl: 'record-bucket-dialog.component.html'
-})
-
-export class RecordBucketDialogComponent
- extends DialogComponent implements OnInit {
-
- selectedBucket: number;
- newBucketName: string;
- newBucketDesc: string;
- buckets: any[];
-
- @Input() bucketType: string;
-
- // Add one or more bib records to bucket by ID.
- recIds: number[];
- @Input() set recordId(id: number | number[]) {
- this.recIds = [].concat(id);
- }
-
- // Add items from a (vandelay) bib queue to a bucket
- qId: number;
- @Input() set queueId(id: number) {
- this.qId = id;
- }
-
- constructor(
- private modal: NgbModal, // required for passing to parent
- private renderer: Renderer2,
- private toast: ToastService,
- private idl: IdlService,
- private net: NetService,
- private evt: EventService,
- private auth: AuthService) {
- super(modal); // required for subclassing
- this.recIds = [];
- }
-
- ngOnInit() {
-
- if (this.qId) {
- this.bucketType = 'vandelay_queue';
- } else {
- this.bucketType = 'staff_client';
- }
-
- this.onOpen$.subscribe(ok => {
- // Reset data on dialog open
-
- this.selectedBucket = null;
- this.newBucketName = '';
- this.newBucketDesc = '';
-
- this.net.request(
- 'open-ils.actor',
- 'open-ils.actor.container.retrieve_by_class.authoritative',
- this.auth.token(), this.auth.user().id(),
- 'biblio', this.bucketType
- ).subscribe(buckets => this.buckets = buckets);
- });
- }
-
- addToSelected() {
- this.addToBucket(this.selectedBucket);
- }
-
- // Create a new bucket then add the record
- addToNew() {
- const bucket = this.idl.create('cbreb');
-
- bucket.owner(this.auth.user().id());
- bucket.name(this.newBucketName);
- bucket.description(this.newBucketDesc);
- bucket.btype(this.bucketType);
-
- this.net.request(
- 'open-ils.actor',
- 'open-ils.actor.container.create',
- this.auth.token(), 'biblio', bucket
- ).subscribe(bktId => {
- const evt = this.evt.parse(bktId);
- if (evt) {
- this.toast.danger(evt.desc);
- } else {
- // make it find-able to the queue-add method which
- // requires the bucket name.
- bucket.id(bktId);
- this.buckets.push(bucket);
- this.addToBucket(bktId);
- }
- });
- }
-
- addToBucket(id: number) {
- if (this.recIds.length > 0) {
- this.addRecordToBucket(id);
- } else if (this.qId) {
- this.addQueueToBucket(id);
- }
- }
-
- // Add the record(s) to the bucket with provided ID.
- addRecordToBucket(bucketId: number) {
- const items = [];
- this.recIds.forEach(recId => {
- const item = this.idl.create('cbrebi');
- item.bucket(bucketId);
- item.target_biblio_record_entry(recId);
- items.push(item);
- });
-
- this.net.request(
- 'open-ils.actor',
- 'open-ils.actor.container.item.create',
- this.auth.token(), 'biblio', items
- ).subscribe(resp => {
- const evt = this.evt.parse(resp);
- if (evt) {
- this.toast.danger(evt.toString());
- } else {
- this.close();
- }
- });
- }
-
- addQueueToBucket(bucketId: number) {
- const bucket = this.buckets.filter(b => b.id() === bucketId)[0];
- if (!bucket) { return; }
-
- this.net.request(
- 'open-ils.vandelay',
- 'open-ils.vandelay.bib_queue.to_bucket',
- this.auth.token(), this.qId, bucket.name()
- ).toPromise().then(resp => {
- const evt = this.evt.parse(resp);
- if (evt) {
- this.toast.danger(evt.toString());
- } else {
- this.close();
- }
- });
- }
-}
-
-
-