[ADF-4921] upload widget fixes (#5109)

* upload widget fixes

* fix mocks
This commit is contained in:
Denys Vuika 2019-09-29 13:48:01 +01:00 committed by Eugenio Romano
parent 7ebd287728
commit 178740bbde
7 changed files with 123 additions and 107 deletions

View File

@ -33,7 +33,8 @@
"NOT_LESS_THAN": "Can't be less than {{ minValue }}",
"AT_LEAST_LONG": "Enter at least {{ minLength }} characters",
"NO_LONGER_THAN": "Enter no more than {{ maxLength }} characters"
}
},
"FILE_ALREADY_UPLOADED": "A file with the same name is already uploaded."
},
"FORM_RENDERER": {
"NAMELESS_TASK": "Nameless task"

View File

@ -39,32 +39,32 @@
<div id="adf-attach-widget-readonly-list">
<mat-list *ngIf="hasFile">
<mat-list-item class="adf-attach-files-row" *ngFor="let file of field.value">
<mat-list-item class="adf-attach-files-row" *ngFor="let file of uploadedFiles">
<img mat-list-icon class="adf-attach-widget__icon"
[id]="'file-'+file?.nodeId+'-icon'"
[id]="'file-'+file?.id+'-icon'"
[src]="file.content ? getIcon(file.content.mimeType) : getIcon(file.mimeType)"
[alt]="mimeTypeIcon"
role="button"
tabindex="0"/>
<span matLine id="{{'file-'+file?.nodeId}}"
<span matLine id="{{'file-'+file?.id}}"
role="button" tabindex="0" class="adf-file">{{file.name}}</span>
<button id="{{'file-'+file?.nodeId+'-option-menu'}}" mat-icon-button [matMenuTriggerFor]="fileActionMenu">
<button id="{{'file-'+file?.id+'-option-menu'}}" mat-icon-button [matMenuTriggerFor]="fileActionMenu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #fileActionMenu="matMenu" xPosition="before">
<button id="{{'file-'+file?.nodeId+'-show-file'}}"
[disabled]="file.isExternal"
<button id="{{'file-'+file?.id+'-show-file'}}"
[disabled]="file['isExternal']"
mat-menu-item (click)="onAttachFileClicked(file)">
<mat-icon>image</mat-icon>
<span>{{ 'FORM.FIELD.SHOW_FILE' | translate }}</span>
</button>
<button id="{{'file-'+file?.nodeId+'-download-file'}}"
<button id="{{'file-'+file?.id+'-download-file'}}"
mat-menu-item (click)="downloadContent(file)">
<mat-icon>file_download</mat-icon>
<span>{{ 'FORM.FIELD.DOWNLOAD_FILE' | translate }}</span>
</button>
<button *ngIf="!field.readOnly" id="{{'file-'+file?.nodeId+'-remove-file'}}"
mat-menu-item [id]="'file-'+file?.nodeId+'-remove'"
<button *ngIf="!field.readOnly" id="{{'file-'+file?.id+'-remove-file'}}"
mat-menu-item [id]="'file-'+file?.id+'-remove'"
(click)="onRemoveAttachFile(file);" (keyup.enter)="onRemoveAttachFile(file);">
<mat-icon class="mat-24">highlight_off</mat-icon>
<span>{{ 'FORM.FIELD.REMOVE_FILE' | translate }}</span>

View File

@ -45,6 +45,7 @@ describe('AttachFileCloudWidgetComponent', () => {
let formService: FormService;
const fakePngAnswer = {
id: 1155,
nodeId: 1155,
name: 'a_png_file.png',
created: '2017-07-25T17:17:37.099Z',
@ -86,6 +87,7 @@ describe('AttachFileCloudWidgetComponent', () => {
const fakeLocalPngAnswer = {
id: 1155,
nodeId: 1155,
name: 'a_png_file.png',
created: '2017-07-25T17:17:37.099Z',
createdBy: {

View File

@ -22,9 +22,10 @@ import {
FormService,
LogService,
ThumbnailService,
ContentLinkModel
ContentLinkModel,
NotificationService
} from '@alfresco/adf-core';
import { RelatedContentRepresentation } from '@alfresco/js-api';
import { Node, RelatedContentRepresentation } from '@alfresco/js-api';
import { ContentCloudNodeSelectorService } from '../../services/content-cloud-node-selector.service';
import { ProcessCloudContentService } from '../../services/process-cloud-content.service';
import { UploadCloudWidgetComponent } from '../upload-cloud.widget';
@ -55,16 +56,10 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
public logger: LogService,
public thumbnails: ThumbnailService,
public processCloudContentService: ProcessCloudContentService,
public contentNodeSelectorService: ContentCloudNodeSelectorService
public contentNodeSelectorService: ContentCloudNodeSelectorService,
notificationService: NotificationService
) {
super(formService, thumbnails, processCloudContentService, logger);
}
ngOnInit() {
if (this.field && this.field.value && this.field.value.length > 0) {
this.hasFile = true;
}
this.getMultipleFileParam();
super(formService, thumbnails, processCloudContentService, notificationService, logger);
}
isFileSourceConfigured(): boolean {
@ -111,18 +106,13 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
}
openSelectDialog() {
const filesSaved = [];
const filesSaved: Node[] = [];
this.contentNodeSelectorService
.openUploadFileDialog(this.field.form.contentHost)
.subscribe((selections: any[]) => {
selections.forEach(node => (node.isExternal = true));
const result = {
nodeId: selections[0].id,
name: selections[0].name,
content: selections[0].content,
createdAt: selections[0].createdAt
};
filesSaved.push(result);
.subscribe((selections: Node[]) => {
selections.forEach(node => (node['isExternal'] = true));
filesSaved.push(selections[0]);
this.fixIncompatibilityFromPreviousAndNewForm(filesSaved);
});
}
@ -136,9 +126,9 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
);
}
downloadContent(file: any): void {
downloadContent(file: Node): void {
this.processCloudContentService
.getRawContentNode(file.nodeId, this.field.form.contentHost)
.getRawContentNode(file.id, this.field.form.contentHost)
.subscribe(
(blob: Blob) => {
this.processCloudContentService.downloadNodeContent(

View File

@ -5,18 +5,18 @@
<div class="adf-cloud-upload-widget-container">
<div>
<mat-list *ngIf="hasFile">
<mat-list-item class="adf-upload-files-row" *ngFor="let file of field.value">
<mat-list-item class="adf-upload-files-row" *ngFor="let file of uploadedFiles">
<img mat-list-icon class="adf-upload-widget__icon"
[id]="'file-'+file.nodeId+'-icon'"
[id]="'file-'+file.id+'-icon'"
[src]="getIcon(file.content.mimeType)"
[alt]="mimeTypeIcon"
(click)="fileClicked(file)"
(keyup.enter)="fileClicked(file)"
role="button"
tabindex="0"/>
<span matLine id="{{'file-'+file.nodeId}}" (click)="fileClicked(file)" (keyup.enter)="fileClicked(file)"
<span matLine id="{{'file-'+file.id}}" (click)="fileClicked(file)" (keyup.enter)="fileClicked(file)"
role="button" tabindex="0" class="adf-file">{{file.name}}</span>
<button *ngIf="!field.readOnly" mat-icon-button [id]="'file-'+file.nodeId+'-remove'"
<button *ngIf="!field.readOnly" mat-icon-button [id]="'file-'+file.id+'-remove'"
(click)="removeFile(file);" (keyup.enter)="removeFile(file);">
<mat-icon class="mat-24">highlight_off</mat-icon>
</button>

View File

@ -18,9 +18,10 @@
/* tslint:disable:component-selector */
import { Component, ElementRef, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { Node } from '@alfresco/js-api';
import { Observable, from } from 'rxjs';
import { mergeMap, map, catchError } from 'rxjs/operators';
import { WidgetComponent, baseHost, LogService, FormService, ThumbnailService, ContentLinkModel } from '@alfresco/adf-core';
import { mergeMap } from 'rxjs/operators';
import { WidgetComponent, baseHost, LogService, FormService, ThumbnailService, ContentLinkModel, NotificationService } from '@alfresco/adf-core';
import { ProcessCloudContentService } from '../services/process-cloud-content.service';
@Component({
@ -44,6 +45,7 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
public formService: FormService,
private thumbnailService: ThumbnailService,
public processCloudContentService: ProcessCloudContentService,
private notificationService: NotificationService,
private logService: LogService) {
super(formService);
}
@ -53,6 +55,7 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
this.field.value &&
this.field.value.length > 0) {
this.hasFile = true;
this.fixIncompatibilityFromPreviousAndNewForm([]);
}
this.getMultipleFileParam();
}
@ -64,8 +67,16 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
}
onFileChanged(event: any) {
const files = event.target.files;
const filesSaved = [];
const files: File[] = [];
const filesSaved: Node[] = [];
for (const file of Array.from<File>(event.target.files)) {
if (!this.isUploaded(file)) {
files.push(file);
} else {
this.notificationService.showWarning('FORM.FIELD.FILE_ALREADY_UPLOADED');
}
}
if (files && files.length > 0) {
from(files)
@ -83,34 +94,29 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
}
}
fixIncompatibilityFromPreviousAndNewForm(filesSaved) {
this.field.value = filesSaved;
this.field.form.values[this.field.id] = filesSaved;
this.hasFile = true;
private isUploaded(file: File): boolean {
const current: Node[] = this.field.value || [];
return current.some(entry => entry.name === file.name);
}
getIcon(mimeType) {
protected fixIncompatibilityFromPreviousAndNewForm(filesSaved: Node[]) {
const value: Node[] = [...this.field.value || []];
value.push(...filesSaved || []);
this.field.value = value;
this.field.form.values[this.field.id] = value;
this.hasFile = value.length > 0;
}
getIcon(mimeType: string): string {
return this.thumbnailService.getMimeTypeIcon(mimeType);
}
private uploadRawContent(file): Observable<any> {
return this.processCloudContentService.createTemporaryRawRelatedContent(file, this.field.form.nodeId, this.field.form.contentHost)
.pipe(
map((response: any) => {
this.logService.info(response);
return {
nodeId: response.id,
name: response.name,
content: response.content,
createdAt: response.createdAt
};
}),
catchError((err) => this.handleError(err))
);
}
private handleError(error: any): any {
return this.logService.error(error || 'Server error');
private uploadRawContent(file: File): Observable<Node> {
return this.processCloudContentService.createTemporaryRawRelatedContent(
file, this.field.form.nodeId, this.field.form.contentHost
);
}
getMultipleFileParam() {
@ -121,17 +127,17 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
}
}
private removeElementFromList(file) {
const savedValues = this.field.form.values[this.field.id]
? this.field.form.values[this.field.id] : this.field.value;
const index = savedValues.indexOf(file);
if (index !== -1) {
const filteredValues = savedValues.filter((value: any) => value.nodeId !== file.nodeId);
this.resetFormValues(filteredValues);
}
get uploadedFiles(): Node[] {
const result = this.field.value || this.field.form.values[this.field.id];
return result || [];
}
private resetFormValues(values) {
private removeElementFromList(file: Node) {
const filteredValues = this.uploadedFiles.filter(value => value.id !== file.id);
this.resetFormValues(filteredValues);
}
private resetFormValues(values: Node[]) {
if (values && values.length > 0) {
this.field.value = values;
this.field.form.values[this.field.id] = values;

View File

@ -18,47 +18,64 @@
import { Injectable } from '@angular/core';
import { throwError, Observable, from } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { AlfrescoApiService, LogService, ContentService } from '@alfresco/adf-core';
import {
AlfrescoApiService,
LogService,
ContentService
} from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api';
@Injectable({
providedIn: 'root'
providedIn: 'root'
})
export class ProcessCloudContentService {
constructor(
private apiService: AlfrescoApiService,
private logService: LogService,
public contentService: ContentService
) {}
constructor(
private apiService: AlfrescoApiService,
private logService: LogService,
public contentService: ContentService
) { }
createTemporaryRawRelatedContent(
file: File,
nodeId: string,
contentHost: string
): Observable<Node> {
const changedConfig = this.apiService.lastConfig;
createTemporaryRawRelatedContent(file, nodeId, contentHost): Observable<any> {
const changedConfig = this.apiService.lastConfig;
changedConfig.provider = 'ALL';
changedConfig.hostEcm = contentHost.replace('/alfresco', '');
this.apiService.getInstance().setConfig(changedConfig);
return from(this.apiService.getInstance().upload.uploadFile(
file, '', nodeId, '', { overwrite: true })).pipe(
map((res: any) => {
return (res.entry);
}),
catchError((err) => this.handleError(err))
);
}
changedConfig.provider = 'ALL';
changedConfig.hostEcm = contentHost.replace('/alfresco', '');
getRawContentNode(nodeId: string, contentHost: string): Observable<any> {
const changedConfig = this.apiService.lastConfig;
changedConfig.provider = 'ALL';
changedConfig.hostEcm = contentHost.replace('/alfresco', '');
this.apiService.getInstance().setConfig(changedConfig);
return this.contentService.getNodeContent(nodeId);
}
this.apiService.getInstance().setConfig(changedConfig);
downloadNodeContent(blob: Blob, fileName: string): void {
this.contentService.downloadBlob(blob, fileName);
}
return from(
this.apiService
.getInstance()
.upload.uploadFile(file, '', nodeId, '', { overwrite: true })
).pipe(
map((res: any) => {
return {
...res.entry,
nodeId: res.entry.id
};
}),
catchError(err => this.handleError(err))
);
}
private handleError(error: any) {
this.logService.error(error);
return throwError(error || 'Server error');
}
getRawContentNode(nodeId: string, contentHost: string): Observable<any> {
const changedConfig = this.apiService.lastConfig;
changedConfig.provider = 'ALL';
changedConfig.hostEcm = contentHost.replace('/alfresco', '');
this.apiService.getInstance().setConfig(changedConfig);
return this.contentService.getNodeContent(nodeId);
}
downloadNodeContent(blob: Blob, fileName: string): void {
this.contentService.downloadBlob(blob, fileName);
}
private handleError(error: any) {
this.logService.error(error);
return throwError(error || 'Server error');
}
}