lp1787968 jacket_upload: UI
authorJason Etheridge <jason@EquinoxOLI.org>
Fri, 3 Sep 2021 15:25:14 +0000 (11:25 -0400)
committerMichele Morgan <mmorgan@noblenet.org>
Thu, 24 Mar 2022 15:53:01 +0000 (11:53 -0400)
Signed-off-by: Jason Etheridge <jason@EquinoxOLI.org>
Signed-off-by: Michele Morgan <mmorgan@noblenet.org>

Open-ILS/src/eg2/src/app/staff/catalog/catalog.module.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/actions.component.html
Open-ILS/src/eg2/src/app/staff/catalog/record/upload-jacket-image-dialog.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/catalog/record/upload-jacket-image-dialog.component.ts [new file with mode: 0644]

index 2108000..3222d87 100644 (file)
@@ -22,6 +22,7 @@ import {HoldComponent} from './hold/hold.component';
 import {PartsComponent} from './record/parts.component';
 import {NotesComponent} from './record/notes.component';
 import {AddToCarouselDialogComponent} from './record/add-to-carousel-dialog.component';
+import {UploadJacketImageDialogComponent} from './record/upload-jacket-image-dialog.component';
 import {PartMergeDialogComponent} from './record/part-merge-dialog.component';
 import {BrowseComponent} from './browse.component';
 import {BrowseResultsComponent} from './browse/results.component';
@@ -33,6 +34,7 @@ import {SearchTemplatesComponent} from './search-templates.component';
 import {MarcEditModule} from '@eg/staff/share/marc-edit/marc-edit.module';
 import {PreferencesComponent} from './prefs.component';
 import {BrowsePagerComponent} from './result/browse-pager.component';
+import {HttpClientModule} from '@angular/common/http';
 
 @NgModule({
   declarations: [
@@ -51,6 +53,7 @@ import {BrowsePagerComponent} from './result/browse-pager.component';
     PartsComponent,
     NotesComponent,
     AddToCarouselDialogComponent,
+    UploadJacketImageDialogComponent,
     PartMergeDialogComponent,
     BrowseComponent,
     BrowseResultsComponent,
@@ -70,7 +73,8 @@ import {BrowsePagerComponent} from './result/browse-pager.component';
     HoldingsModule,
     BookingModule,
     PatronModule,
-    MarcEditModule
+    MarcEditModule,
+    HttpClientModule
   ],
   providers: [
     StaffCatalogService
index 8634f82..0b13009 100644 (file)
@@ -16,6 +16,9 @@
 <eg-add-to-carousel-dialog #recordCarouselDialog [recordIds]="[recId]">
 </eg-add-to-carousel-dialog>
 
+<upload-jacket-image-dialog #jacketImageDialog [recordId]="recId">
+</upload-jacket-image-dialog>
+
 <div class="row ml-0 mr-0">
 
   <a target="_blank" href="/eg/opac/record/{{recId}}">
@@ -91,6 +94,9 @@
       <button class="dropdown-item" (click)="recordCarouselDialog.open({size: 'lg'})">
         <span i18n>Add To Carousel</span>
       </button>
+      <button class="dropdown-item" (click)="jacketImageDialog.open({size: 'lg'})">
+        <span i18n>Upload Cover Image</span>
+      </button>
       <a class="dropdown-item"
         href="/eg/staff/acq/legacy/lineitem/related/{{recId}}?target=bib">
         <span i18n>View/Place Orders</span>
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/upload-jacket-image-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/record/upload-jacket-image-dialog.component.html
new file mode 100644 (file)
index 0000000..1c7612d
--- /dev/null
@@ -0,0 +1,43 @@
+<ng-template #dialogContent>
+  <div class="modal-header bg-info">
+    <h4 class="modal-title">
+      <span i18n>Upload Cover Image</span>
+    </h4>
+    <button type="button" class="close"
+    i18n-aria-label aria-label="Close" (click)="clearErrors(); close(false)">
+    <span aria-hidden="true">&times;</span>
+  </button>
+</div>
+<div class="modal-body">
+    <!--<form method="POST" enctype="multipart/form-data" action="/jacket-upload">
+        <input type="file" name="jacket_upload">
+        <input type="text" name="ses">
+        <input type="text" name="bib_record">
+        <input type="submit">
+    </form>-->
+    <input type="file" class="file-input" (change)="onFileSelected($event)" #fileUpload>
+    <div class="progress" *ngIf="uploading">
+      <div class="progress-bar progress-bar-striped active w-100"
+        role="progressbar" aria-valuenow="100"
+        aria-valuemin="0" aria-valuemax="100">
+        <span i18n>Uploading..</span>
+      </div>
+    </div>
+    <div style="margin-top: 20px" *ngIf="errorUploading">
+        <span *ngIf="errorAuthentication" class="alert alert-danger" i18n>Not authenticated. Expired login?</span>
+        <span *ngIf="errorAuthorization" class="alert alert-danger" i18n>Not authorized. Check your permissions.</span>
+        <span *ngIf="errorNotFound" class="alert alert-danger" i18n>Not found. Bib record deleted?</span>
+        <span *ngIf="errorCompressionConfig" class="alert alert-danger" i18n>Invalid global compression value. Talk to your system administrator.</span>
+        <span *ngIf="errorLocationConfig" class="alert alert-danger" i18n>Do not know where to upload files. Talk to your system administrator.</span>
+        <span *ngIf="errorWritingFile" class="alert alert-danger" i18n>Can not save uploaded file. Talk to your system administrator.</span>
+        <span *ngIf="errorSize" class="alert alert-danger" i18n>File size larger than configured limit. Check your library setting or try a smaller file.</span>
+        <span *ngIf="errorParsing" class="alert alert-danger" i18n>Error parsing the image. Is it a common image filetype?</span>
+        <span *ngIf="errorGeneric" class="alert alert-danger" i18n>Error uploading or processing file.</span>
+    </div>
+
+</div>
+<div class="modal-footer">
+  <button type="button" class="btn btn-success" [disabled]="uploading || noFile"
+  (click)="uploadJacketImage()" i18n>Upload Cover Image</button>
+</div>
+</ng-template>
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/upload-jacket-image-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/record/upload-jacket-image-dialog.component.ts
new file mode 100644 (file)
index 0000000..d02911e
--- /dev/null
@@ -0,0 +1,138 @@
+import {Component, Input, OnInit, ViewChild} from '@angular/core';
+import {FormControl} from '@angular/forms';
+import {takeLast, finalize} from 'rxjs/operators';
+import {DialogComponent} from '@eg/share/dialog/dialog.component';
+import {AuthService} from '@eg/core/auth.service';
+import {NetService} from '@eg/core/net.service';
+import {EventService} from '@eg/core/event.service';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
+import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+import {StringComponent} from '@eg/share/string/string.component';
+import {HttpClient, HttpResponse, HttpErrorResponse, HttpEventType} from '@angular/common/http';
+
+@Component({
+  selector: 'upload-jacket-image-dialog',
+  templateUrl: './upload-jacket-image-dialog.component.html'
+})
+
+
+export class UploadJacketImageDialogComponent extends DialogComponent implements OnInit {
+
+    // ID of bib record for jacket image
+    @Input() recordId: number;
+
+    uploading: boolean;
+    noFile: boolean;
+    errorUploading: boolean;
+    errorAuthentication: boolean;
+    errorAuthorization: boolean;
+    errorCompressionConfig: boolean;
+    errorNotFound: boolean;
+    errorLocationConfig: boolean;
+    errorWritingFile: boolean;
+    errorSize: boolean;
+    errorParsing: boolean;
+    errorGeneric: boolean;
+
+    private fileEvent: any;
+
+    constructor(
+        private modal: NgbModal,
+        private auth: AuthService,
+        private evt: EventService,
+        private net: NetService,
+        private toast: ToastService,
+        private http: HttpClient
+    ) {
+        super(modal);
+    }
+
+    clearErrors() {
+        this.errorAuthentication = false;
+        this.errorAuthorization = false;
+        this.errorCompressionConfig = false;
+        this.errorNotFound = false;
+        this.errorLocationConfig = false;
+        this.errorWritingFile = false;
+        this.errorSize = false;
+        this.errorParsing = false;
+        this.errorGeneric = false;
+        this.errorUploading = false;
+    }
+
+    ngOnInit() {
+        this.uploading = false;
+        this.noFile = true;
+        this.clearErrors();
+    }
+
+    onFileSelected(event) {
+        console.debug('onFileSelected',event);
+        this.fileEvent = event;
+        const file:File = this.fileEvent.target.files[0];
+        if (file) {
+            this.noFile = false;
+        } else {
+            this.noFile = true;
+        }
+    }
+
+    uploadJacketImage() {
+        const file:File = this.fileEvent.target.files[0];
+        if (file) {
+            this.uploading = true;
+            this.clearErrors();
+            const formData = new FormData();
+            formData.append("jacket_upload", file);
+            formData.append("ses", this.auth.token());
+            formData.append("bib_record", this.recordId.toString());
+
+            const upload$ = this.http.post("/jacket-upload", formData, {
+                reportProgress: true,
+                observe: 'events'
+            });
+
+            upload$.subscribe(
+              x => {
+                console.debug('Jacket upload: ' , x);
+                if (x instanceof HttpResponse) {
+                    console.debug('yay',x.body);
+                    if (x.body != '1') {
+                        this.uploading = false;
+                        this.errorUploading = true;
+                    }
+                    switch(x.body) {
+                        case "session not found": this.errorAuthentication = true; break;
+                        case "permission denied": this.errorAuthorization = true; break;
+                        case "invalid compression level": this.errorCompressionConfig = true; break;
+                        case "bib not found": this.errorNotFound = true; break;
+                        case "jacket location not configured": this.errorLocationConfig = true; break;
+                        case "unable to open file for writing": this.errorWritingFile = true; break;
+                        case "file too large": this.errorSize = true; break;
+                        case "parse error": this.errorParsing = true; break;
+                        case "upload error": this.errorGeneric = true; break;
+                        default: this.errorGeneric = true; break;
+                    }
+                }
+              },
+              err => {
+                this.uploading = false;
+                this.errorUploading = true;
+                this.errorGeneric = true;
+                console.error('jacket upload error: ' , err);
+              },
+              () => this.refreshPage()
+            );
+        }
+    }
+
+    refreshPage() {
+        if (this.errorUploading) {
+            console.debug('no refresh page due to error');
+        } else {
+            console.debug('refresh page');
+            location.href = location.href;
+        }
+    }
+}