Skip to content

Commit

Permalink
feat(resource): upload pdf document (DSP-1776) (#481)
Browse files Browse the repository at this point in the history
* feat(resource): display supported file types in upload form

* feat(resource): upload document (pdf)

* chore(deps): bump dsp-js to v2.6.0

* fix(test): bug fix in tests

* refactor(resource): set correct switch cases

* fix(resource): fix stupid bug

* refactor(lint): make ts-lint happy
  • Loading branch information
kilchenmann committed Jul 9, 2021
1 parent f472ca4 commit d916b4b
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 49 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -34,7 +34,7 @@
"@angular/platform-browser-dynamic": "^11.2.9",
"@angular/router": "^11.2.9",
"@ckeditor/ckeditor5-angular": "^1.2.3",
"@dasch-swiss/dsp-js": "^2.5.0",
"@dasch-swiss/dsp-js": "^2.6.0",
"@dasch-swiss/dsp-ui": "^1.6.0",
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "5.0.0",
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Expand Up @@ -92,6 +92,7 @@ import { UsersComponent } from './system/users/users.component';
import { UsersListComponent } from './system/users/users-list/users-list.component';
import { VisualizerComponent } from './project/ontology/ontology-visualizer/visualizer/visualizer.component';
import { UploadComponent } from './workspace/resource/representation/upload/upload.component';
import { SplitPipe } from './main/pipes/split.pipe';

// translate: AoT requires an exported function for factories
export function httpLoaderFactory(httpClient: HttpClient) {
Expand Down Expand Up @@ -171,6 +172,7 @@ export function httpLoaderFactory(httpClient: HttpClient) {
UsersListComponent,
VisualizerComponent,
UploadComponent,
SplitPipe,
],
imports: [
AppRoutingModule,
Expand Down
8 changes: 8 additions & 0 deletions src/app/main/pipes/split.pipe.spec.ts
@@ -0,0 +1,8 @@
import { SplitPipe } from './split.pipe';

describe('SplitPipe', () => {
it('create an instance', () => {
const pipe = new SplitPipe();
expect(pipe).toBeTruthy();
});
});
22 changes: 22 additions & 0 deletions src/app/main/pipes/split.pipe.ts
@@ -0,0 +1,22 @@
import { Pipe, PipeTransform } from '@angular/core';

/**
* splits by first argument and returns element from position (second argument)
*
* mystr = application/pdf
* {{ mystr | split: '/':1 }} --> returns 'pdf'
*/
@Pipe({
name: 'split'
})
export class SplitPipe implements PipeTransform {

transform(val: string, separator: string, position: number): string {
return val.split(separator)[position];
}

// transform(value: unknown, ...args: unknown[]): unknown {
// return null;
// }

}
@@ -1,33 +1,27 @@
<div class="form-container">
<form [formGroup]="form">
<div dspDragDrop
*ngIf="isLoading || !file"
(click)="fileInput.click()"
(fileDropped)="addFile($event)"
<div dspDragDrop *ngIf="isLoading || !file" (click)="fileInput.click()" (fileDropped)="addFile($event)"
class="dd-container">
<input hidden
type="file"
(change)="addFile($event)"
#fileInput />
<mat-icon *ngIf="!isLoading"
class="upload-icon">
<input hidden type="file" (change)="addFile($event)" #fileInput />
<mat-icon *ngIf="!isLoading" class="upload-icon">
cloud_upload
</mat-icon>
<dsp-progress-indicator *ngIf="isLoading"></dsp-progress-indicator>
<div class="title">Upload file</div>
<p class="title">Upload file<br>
<span class="mat-body-1">The following file types are supported:<br>
<span *ngFor="let item of allowedFileTypes; let last = last">{{ item | split: '/':1 }}<span
*ngIf="!last">,&nbsp;</span></span>
</span>
</p>
<div class="bottom-line">
Drag and drop or click to upload
</div>
</div>

<ng-container *ngIf="!isLoading && file">
<div class="thumbnail">
<img src="{{ thumbnailUrl }}"
alt="thumbnail" />
<button mat-button
class="delete-file"
title="delete file"
(click)="deleteAttachment()">
<div *ngIf="thumbnailUrl" class="thumbnail">
<img src="{{ thumbnailUrl }}" alt="thumbnail" />
<button mat-button class="delete-file" title="delete file" (click)="deleteAttachment()">
<mat-icon>close</mat-icon>
</button>
</div>
Expand All @@ -48,9 +42,7 @@
<td>{{ convertBytes(file.size) }}</td>
<td>{{ convertDate(file.lastModified) }}</td>
<td>
<button mat-icon-button
class="delete-file"
title="delete file"
<button mat-icon-button class="delete-file" title="delete file"
(click)="deleteAttachment()">
<mat-icon>delete</mat-icon>
</button>
Expand Down
Expand Up @@ -28,7 +28,7 @@
font-size: 48px;
padding: 0;
position: inherit;
top: 35%;
top: 12%;
}
.title {
bottom: 20%;
Expand Down
Expand Up @@ -4,9 +4,10 @@ import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { Constants, CreateStillImageFileValue } from '@dasch-swiss/dsp-js';
import { CreateStillImageFileValue } from '@dasch-swiss/dsp-js';
import { DspActionModule } from '@dasch-swiss/dsp-ui';
import { of } from 'rxjs';
import { SplitPipe } from 'src/app/main/pipes/split.pipe';
import { UploadFileService } from './upload-file.service';
import { UploadComponent } from './upload.component';

Expand Down Expand Up @@ -49,7 +50,8 @@ describe('UploadComponent', () => {
TestBed.configureTestingModule({
declarations: [
UploadComponent,
TestHostComponent
TestHostComponent,
SplitPipe
],
imports: [
DspActionModule,
Expand Down
@@ -1,13 +1,15 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import {
CreateDocumentFileValue,
CreateFileValue,
CreateStillImageFileValue,
UpdateDocumentFileValue,
UpdateFileValue,
UpdateStillImageFileValue
} from '@dasch-swiss/dsp-js';
import { NotificationService } from '@dasch-swiss/dsp-ui';
import { UploadedFile, UploadedFileResponse, UploadFileService } from './upload-file.service';
import { UploadedFileResponse, UploadFileService } from './upload-file.service';

// https://stackoverflow.com/questions/45661010/dynamic-nested-reactive-form-expressionchangedafterithasbeencheckederror
const resolvedPromise = Promise.resolve(null);
Expand All @@ -22,7 +24,8 @@ export class UploadComponent implements OnInit {

@Input() parentForm?: FormGroup;

@Input() representation: string; // only StillImageRepresentation supported so far
@Input() representation: 'stillImage' | 'movingImage' | 'audio' | 'document' | 'text';
// only StillImageRepresentation and DocumentPresentation is supported so far

@Input() formName: string;

Expand All @@ -34,8 +37,10 @@ export class UploadComponent implements OnInit {
isLoading = false;
thumbnailUrl: string;

allowedFileTypes: string[];
// todo: maybe we can use this list to display which file format is allowed to
supportedImageTypes = ['image/jpeg', 'image/jp2', 'image/tiff', 'image/tiff-fx', 'image/png'];
supportedDocumentTypes = ['application/pdf'];

// readonly fromLabels = {
// upload: 'Upload file',
Expand All @@ -49,6 +54,7 @@ export class UploadComponent implements OnInit {

ngOnInit(): void {
this.initializeForm();
this._supportedFileTypes();
}

/**
Expand Down Expand Up @@ -80,14 +86,28 @@ export class UploadComponent implements OnInit {
formData.append(this.file.name, this.file);
this._upload.upload(formData).subscribe(
(res: UploadedFileResponse) => {
const temporaryUrl = res.uploadedFiles[0].temporaryUrl;
const thumbnailUri = '/full/256,/0/default.jpg';
this.thumbnailUrl = `${temporaryUrl}${thumbnailUri}`;

switch (this.representation) {
case 'stillImage':
const temporaryUrl = res.uploadedFiles[0].temporaryUrl;
const thumbnailUri = '/full/256,/0/default.jpg';
this.thumbnailUrl = `${temporaryUrl}${thumbnailUri}`;
break;

case 'document':
// the preview thumbnail is deactivated for the moment;
// --> TODO: it will be activated as soon as we implement a pdf viewer
// this.thumbnailUrl = res.uploadedFiles[0].temporaryUrl;
this.thumbnailUrl = undefined;
break;

default:
this.thumbnailUrl = undefined;
break;
}

this.fileControl.setValue(res.uploadedFiles[0]);
const fileValue = this.getNewValue();
// console.log('here we should emit the values', res)
// console.log(fileValue);

if (fileValue) {
this.fileInfo.emit(fileValue);
Expand Down Expand Up @@ -184,9 +204,22 @@ export class UploadComponent implements OnInit {

const filename = this.fileControl.value.internalFilename;

// --> TODO: handle different file types
let fileValue: CreateStillImageFileValue | CreateDocumentFileValue;

switch (this.representation) {
case 'stillImage':
fileValue = new CreateStillImageFileValue();
break;

case 'document':
fileValue = new CreateDocumentFileValue();
break;

default:
// --> TODO for UPLOAD: expand with other representation file types
break;
}

const fileValue = new CreateStillImageFileValue();
fileValue.filename = filename;

return fileValue;
Expand All @@ -206,9 +239,23 @@ export class UploadComponent implements OnInit {

const filename = this.fileControl.value.internalFilename;

// --> TODO: handle different file types
let fileValue: UpdateStillImageFileValue | UpdateDocumentFileValue;

const fileValue = new UpdateStillImageFileValue();

switch (this.representation) {
case 'stillImage':
fileValue = new UpdateStillImageFileValue();
break;

case 'document':
fileValue = new UpdateDocumentFileValue();
break;
default:
// --> TODO for UPLOAD: expand with other representation file types
break;
}

// const fileValue = new UpdateStillImageFileValue();
fileValue.filename = filename;
fileValue.id = id;

Expand All @@ -228,16 +275,19 @@ export class UploadComponent implements OnInit {
* returns supported file types list for certain resource type
*/
private _supportedFileTypes(): string[] {
let allowedFileTypes: string[];
this.allowedFileTypes = [];
switch (this.representation) {
case 'stillImage':
allowedFileTypes = this.supportedImageTypes;
this.allowedFileTypes = this.supportedImageTypes;
break;
case 'document':
this.allowedFileTypes = this.supportedDocumentTypes;
break;
default:
allowedFileTypes = [];
this.allowedFileTypes = [];
break;
}
return allowedFileTypes;
return this.allowedFileTypes;
}

/**
Expand Down
Expand Up @@ -165,7 +165,14 @@ export class ResourceInstanceFormComponent implements OnInit, OnDestroy {
});

if (this.fileValue) {
this.propertiesObj[Constants.HasStillImageFileValue] = [this.fileValue];
switch (this.hasFileValue) {
case 'stillImage':
this.propertiesObj[Constants.HasStillImageFileValue] = [this.fileValue];
break;
case 'document':
this.propertiesObj[Constants.HasDocumentFileValue] = [this.fileValue];
break;
}
}

createResource.properties = this.propertiesObj;
Expand Down Expand Up @@ -370,11 +377,19 @@ export class ResourceInstanceFormComponent implements OnInit, OnDestroy {

// filter out all props that cannot be edited or are link props but also the hasFileValue props
this.properties = onto.getPropertyDefinitionsByType(ResourcePropertyDefinition).filter(
prop => prop.isEditable && !prop.isLinkProperty && prop.id !== Constants.HasStillImageFileValue);
prop =>
!prop.isLinkProperty &&
prop.isEditable &&
prop.id !== Constants.HasStillImageFileValue &&
prop.id !== Constants.HasDocumentFileValue // --> TODO for UPLOAD: expand with other representation file values
);

if (onto.properties[Constants.HasStillImageFileValue]) {
this.hasFileValue = 'stillImage';
}
if (onto.properties[Constants.HasDocumentFileValue]) {
this.hasFileValue = 'document';
}

// notifies the user that the selected resource does not have any properties defined yet.
if (!this.selectPropertiesComponent && this.properties.length === 0) {
Expand Down

0 comments on commit d916b4b

Please sign in to comment.