From 19a17ca6e67e3d62f4abf8eec344744151430f28 Mon Sep 17 00:00:00 2001 From: Vito Date: Tue, 3 Sep 2019 11:10:40 +0100 Subject: [PATCH] [ADF-4823] added download and show preview for attach cloud widget (#4996) * [ADF-4823] fixed download and start fixing show preview * [ADF-4823] fixed preview files * [ADF-4823] - added unit test * [ADF-4823] - fixed lint problem * [ADF-4823] - rebased and fixed lint problem * added a new method in BrowserActions to check that the action menu is visible, and using that in the tests. * linting fixes --- .../task-details-cloud-demo.component.html | 1 + .../task-details-cloud-demo.component.ts | 8 +- .../widgets/core/content-link.model.ts | 2 + .../attach-file-cloud-widget.component.html | 24 +- ...attach-file-cloud-widget.component.spec.ts | 458 +++++++++++------- .../attach-file-cloud-widget.component.ts | 204 ++++---- .../form/components/form-cloud.component.ts | 2 +- .../form/components/upload-cloud.widget.ts | 9 +- .../services/process-cloud-content.service.ts | 18 +- .../components/task-form-cloud.component.html | 3 +- .../components/task-form-cloud.component.ts | 9 +- .../pages/document-list.page.ts | 5 +- .../form/widgets/attachFileWidgetCloud.ts | 6 +- .../src/lib/core/utils/browser-actions.ts | 10 + 14 files changed, 478 insertions(+), 281 deletions(-) diff --git a/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.html b/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.html index c1a956acec..4249feb8d9 100644 --- a/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.html +++ b/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.html @@ -10,6 +10,7 @@ (taskCompleted)="onTaskCompleted()" (taskClaimed)="onTaskClaimed()" (taskUnclaimed)="onTaskUnclaimed()" + (formContentClicked)="onFormContentClicked($event)" (formSaved)="onFormSaved()"> diff --git a/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.ts b/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.ts index 9a724895e5..63b1d0549a 100644 --- a/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.ts +++ b/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.ts @@ -19,6 +19,7 @@ import { Component, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { NotificationService } from '@alfresco/adf-core'; import { TaskHeaderCloudComponent } from '@alfresco/adf-process-services-cloud'; +import { PreviewService } from 'app/services/preview.service'; @Component({ templateUrl: './task-details-cloud-demo.component.html', @@ -35,7 +36,8 @@ export class TaskDetailsCloudDemoComponent { constructor( private route: ActivatedRoute, private router: Router, - private notificationService: NotificationService + private notificationService: NotificationService, + private previewService: PreviewService ) { this.route.params.subscribe((params) => { this.taskId = params.taskId; @@ -66,8 +68,8 @@ export class TaskDetailsCloudDemoComponent { this.taskHeader.ngOnInit(); } - onFormContentClicked(resourceId) { - this.router.navigate([`/cloud/${this.appName}/task-details/${this.taskId}/files/${resourceId.nodeId}/view`]); + onFormContentClicked(resourceClicked: any) { + this.previewService.showResource(resourceClicked.nodeId); } onFormSaved() { diff --git a/lib/core/form/components/widgets/core/content-link.model.ts b/lib/core/form/components/widgets/core/content-link.model.ts index 1e9bea46f3..e2cdb4936c 100644 --- a/lib/core/form/components/widgets/core/content-link.model.ts +++ b/lib/core/form/components/widgets/core/content-link.model.ts @@ -25,6 +25,7 @@ created: Date; createdBy: any; id: number; + nodeId: string; link: boolean; mimeType: string; name: string; @@ -48,6 +49,7 @@ this.relatedContent = obj && obj.relatedContent; this.simpleType = obj && obj.simpleType; this.thumbnailStatus = obj && obj.thumbnailStatus; + this.nodeId = obj && obj.nodeId; } hasPreviewStatus(): boolean { diff --git a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.html b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.html index 173731ed8d..40c5051fa1 100644 --- a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.html +++ b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.html @@ -48,10 +48,28 @@ tabindex="0"/> {{file.name}} - + + + + + diff --git a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.spec.ts index 42bf7af75d..7c5ecc586a 100644 --- a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.spec.ts @@ -20,7 +20,14 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ContentCloudNodeSelectorService } from '../../services/content-cloud-node-selector.service'; import { ProcessCloudContentService } from '../../services/process-cloud-content.service'; import { AttachFileCloudWidgetComponent } from './attach-file-cloud-widget.component'; -import { setupTestBed, FormFieldModel, FormModel, FormFieldTypes, FormFieldMetadata } from '@alfresco/adf-core'; +import { + setupTestBed, + FormFieldModel, + FormModel, + FormFieldTypes, + FormFieldMetadata, + FormService +} from '@alfresco/adf-core'; import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ContentModule } from '@alfresco/adf-content-services'; @@ -30,193 +37,288 @@ import { Node } from '@alfresco/js-api'; import { FormCloudModule } from '../../form-cloud.module'; describe('AttachFileCloudWidgetComponent', () => { - let widget: AttachFileCloudWidgetComponent; - let fixture: ComponentFixture; - let element: HTMLInputElement; - let contentCloudNodeSelectorService: ContentCloudNodeSelectorService; - let processCloudContentService: ProcessCloudContentService; + let widget: AttachFileCloudWidgetComponent; + let fixture: ComponentFixture; + let element: HTMLInputElement; + let contentCloudNodeSelectorService: ContentCloudNodeSelectorService; + let processCloudContentService: ProcessCloudContentService; + let formService: FormService; - const fakePngAnswer = { - 'nodeId': 1155, - 'name': 'a_png_file.png', - 'created': '2017-07-25T17:17:37.099Z', - 'createdBy': { 'id': 1001, 'firstName': 'Admin', 'lastName': 'admin', 'email': 'admin' }, - 'relatedContent': false, - 'contentAvailable': true, - 'link': false, - 'mimeType': 'image/png', - 'simpleType': 'image', - 'previewStatus': 'queued', - 'thumbnailStatus': 'queued' - }; + const fakePngAnswer = { + nodeId: 1155, + name: 'a_png_file.png', + created: '2017-07-25T17:17:37.099Z', + createdBy: { + id: 1001, + firstName: 'Admin', + lastName: 'admin', + email: 'admin' + }, + relatedContent: false, + contentAvailable: true, + link: false, + mimeType: 'image/png', + simpleType: 'image', + previewStatus: 'queued', + thumbnailStatus: 'queued' + }; - const onlyLocalParams = { - fileSource: { - serviceId: 'local-file' - } - }; + const onlyLocalParams = { + fileSource: { + serviceId: 'local-file' + } + }; - const contentSourceParam = { - fileSource: { - name: 'mock-alf-content', - serviceId: 'alfresco-content' - } - }; + const contentSourceParam = { + fileSource: { + name: 'mock-alf-content', + serviceId: 'alfresco-content' + } + }; - const fakeMinimalNode: Node = { - id: 'fake', - name: 'fake-name', - content: { - mimeType: 'application/pdf' - } - }; + const fakeMinimalNode: Node = { + id: 'fake', + name: 'fake-name', + content: { + mimeType: 'application/pdf' + } + }; - const fakeLocalPngAnswer = { - 'id': 1155, - 'name': 'a_png_file.png', - 'created': '2017-07-25T17:17:37.099Z', - 'createdBy': { 'id': 1001, 'firstName': 'Admin', 'lastName': 'admin', 'email': 'admin' }, - 'relatedContent': false, - 'contentAvailable': true, - 'link': false, - 'mimeType': 'image/png', - 'simpleType': 'image', - 'previewStatus': 'queued', - 'thumbnailStatus': 'queued' - }; + const fakeLocalPngAnswer = { + id: 1155, + name: 'a_png_file.png', + created: '2017-07-25T17:17:37.099Z', + createdBy: { + id: 1001, + firstName: 'Admin', + lastName: 'admin', + email: 'admin' + }, + relatedContent: false, + contentAvailable: true, + link: false, + mimeType: 'image/png', + simpleType: 'image', + previewStatus: 'queued', + thumbnailStatus: 'queued' + }; - setupTestBed({ - imports: [ - ProcessServiceCloudTestingModule, - FormCloudModule, - ContentModule.forRoot() - ], - providers: [], - schemas: [CUSTOM_ELEMENTS_SCHEMA] - }); - - beforeEach(async(() => { - fixture = TestBed.createComponent(AttachFileCloudWidgetComponent); - widget = fixture.componentInstance; - element = fixture.nativeElement; - processCloudContentService = TestBed.get(ProcessCloudContentService); - contentCloudNodeSelectorService = TestBed.get(ContentCloudNodeSelectorService); - })); - - afterEach(() => { - fixture.destroy(); - }); - - it('should be able to create the widget', () => { - expect(widget).not.toBeNull(); - }); - - it('should show up as simple upload when is configured for only local files', async(() => { - widget.field = new FormFieldModel(new FormModel(), { - type: FormFieldTypes.UPLOAD, - value: [] + setupTestBed({ + imports: [ + ProcessServiceCloudTestingModule, + FormCloudModule, + ContentModule.forRoot() + ], + providers: [], + schemas: [CUSTOM_ELEMENTS_SCHEMA] }); - widget.field.id = 'simple-upload-button'; - widget.field.params = onlyLocalParams; - fixture.detectChanges(); - fixture.whenStable().then(() => { - expect(element.querySelector('#simple-upload-button')).not.toBeNull(); - }); - })); - - it('should show up as content upload when is configured with content', async(() => { - widget.field = new FormFieldModel(new FormModel(), { - type: FormFieldTypes.UPLOAD, - value: [] - }); - widget.field.id = 'attach-file-alfresco'; - widget.field.params = contentSourceParam; - fixture.detectChanges(); - fixture.whenStable().then(() => { - expect(element.querySelector('.adf-attach-widget__menu-upload')).not.toBeNull(); - }); - })); - - it('should be able to attach files coming from content selector', async(() => { - spyOn(contentCloudNodeSelectorService, 'openUploadFileDialog').and.returnValue(of([fakeMinimalNode])); - widget.field = new FormFieldModel(new FormModel(), { - type: FormFieldTypes.UPLOAD, - value: [] - }); - widget.field.id = 'attach-file-alfresco'; - widget.field.params = contentSourceParam; - fixture.detectChanges(); - fixture.whenStable().then(() => { - const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); - expect(attachButton).not.toBeNull(); - attachButton.click(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - fixture.debugElement.query(By.css('#attach-mock-alf-content')).nativeElement.click(); - fixture.detectChanges(); - expect(element.querySelector('#file-fake-icon')).not.toBeNull(); - }); - }); - })); - - it('should be able to upload files from local source', async(() => { - widget.field = new FormFieldModel(new FormModel(), { - type: FormFieldTypes.UPLOAD, - value: [] - }); - widget.field.id = 'attach-file-local'; - widget.field.params = onlyLocalParams; - spyOn(processCloudContentService, 'createTemporaryRawRelatedContent').and.returnValue(of(fakeLocalPngAnswer)); - fixture.detectChanges(); - fixture.whenStable().then(() => { - fixture.detectChanges(); - const inputDebugElement = fixture.debugElement.query(By.css('#attach-file-local')); - inputDebugElement.triggerEventHandler('change', { target: { files: [fakeLocalPngAnswer] } }); - fixture.detectChanges(); - expect(element.querySelector('#file-1155-icon')).not.toBeNull(); - }); - })); - - it('should display file list when field has value', async(() => { - widget.field = new FormFieldModel(new FormModel(), { - type: FormFieldTypes.UPLOAD, - value: [fakePngAnswer] - }); - widget.field.id = 'attach-file-attach'; - widget.field.params = onlyLocalParams; - fixture.detectChanges(); - fixture.whenStable().then(() => { - expect(element.querySelector('#file-1155-icon')).not.toBeNull(); - }); - })); - - describe('when a file is uploaded', () => { beforeEach(async(() => { - widget.field = new FormFieldModel(new FormModel(), { - type: FormFieldTypes.UPLOAD, - value: [] - }); - widget.field.id = 'attach-file-attach'; - widget.field.params = onlyLocalParams; - spyOn(processCloudContentService, 'createTemporaryRawRelatedContent').and.returnValue(of(fakeLocalPngAnswer)); - fixture.detectChanges(); - fixture.whenStable().then(() => { - const inputDebugElement = fixture.debugElement.query(By.css('#attach-file-attach')); - inputDebugElement.triggerEventHandler('change', { target: { files: [fakeLocalPngAnswer] } }); - fixture.detectChanges(); - expect(element.querySelector('#file-1155-icon')).not.toBeNull(); - }); + fixture = TestBed.createComponent(AttachFileCloudWidgetComponent); + widget = fixture.componentInstance; + element = fixture.nativeElement; + processCloudContentService = TestBed.get(ProcessCloudContentService); + contentCloudNodeSelectorService = TestBed.get( + ContentCloudNodeSelectorService + ); + formService = TestBed.get(FormService); })); - it('should remove file when remove is clicked', async(() => { - fixture.detectChanges(); - const removeOption: HTMLButtonElement = fixture.debugElement.query(By.css('#file-1155-remove')).nativeElement; - removeOption.click(); - fixture.detectChanges(); - fixture.whenStable().then(() => { - expect(element.querySelector('#file-1155-icon')).toBeNull(); - }); + afterEach(() => { + fixture.destroy(); + }); + + it('should be able to create the widget', () => { + expect(widget).not.toBeNull(); + }); + + it('should show up as simple upload when is configured for only local files', async(() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'simple-upload-button'; + widget.field.params = onlyLocalParams; + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect( + element.querySelector('#simple-upload-button') + ).not.toBeNull(); + }); })); - }); + + it('should show up as content upload when is configured with content', async(() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = contentSourceParam; + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect( + element.querySelector('.adf-attach-widget__menu-upload') + ).not.toBeNull(); + }); + })); + + it('should be able to attach files coming from content selector', async(() => { + spyOn( + contentCloudNodeSelectorService, + 'openUploadFileDialog' + ).and.returnValue(of([fakeMinimalNode])); + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = contentSourceParam; + fixture.detectChanges(); + fixture.whenStable().then(() => { + const attachButton: HTMLButtonElement = element.querySelector( + '#attach-file-alfresco' + ); + expect(attachButton).not.toBeNull(); + attachButton.click(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + fixture.debugElement + .query(By.css('#attach-mock-alf-content')) + .nativeElement.click(); + fixture.detectChanges(); + expect(element.querySelector('#file-fake-icon')).not.toBeNull(); + }); + }); + })); + + it('should be able to upload files from local source', async(() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-local'; + widget.field.params = onlyLocalParams; + spyOn( + processCloudContentService, + 'createTemporaryRawRelatedContent' + ).and.returnValue(of(fakeLocalPngAnswer)); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + const inputDebugElement = fixture.debugElement.query( + By.css('#attach-file-local') + ); + inputDebugElement.triggerEventHandler('change', { + target: { files: [fakeLocalPngAnswer] } + }); + fixture.detectChanges(); + expect(element.querySelector('#file-1155-icon')).not.toBeNull(); + }); + })); + + it('should display file list when field has value', async(() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [fakePngAnswer] + }); + widget.field.id = 'attach-file-attach'; + widget.field.params = onlyLocalParams; + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(element.querySelector('#file-1155-icon')).not.toBeNull(); + }); + })); + + describe('when a file is uploaded', () => { + beforeEach(async(() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-attach'; + widget.field.params = onlyLocalParams; + spyOn( + processCloudContentService, + 'createTemporaryRawRelatedContent' + ).and.returnValue(of(fakeLocalPngAnswer)); + fixture.detectChanges(); + fixture.whenStable().then(() => { + const inputDebugElement = fixture.debugElement.query( + By.css('#attach-file-attach') + ); + inputDebugElement.triggerEventHandler('change', { + target: { files: [fakeLocalPngAnswer] } + }); + fixture.detectChanges(); + expect(element.querySelector('#file-1155-icon')).not.toBeNull(); + }); + })); + + it('should remove file when remove is clicked', (done) => { + fixture.detectChanges(); + const menuButton: HTMLButtonElement = ( + fixture.debugElement.query(By.css('#file-1155-option-menu')) + .nativeElement + ); + menuButton.click(); + fixture.detectChanges(); + const removeOption: HTMLButtonElement = ( + fixture.debugElement.query(By.css('#file-1155-remove')) + .nativeElement + ); + removeOption.click(); + fixture.detectChanges(); + fixture.whenRenderingDone().then(() => { + expect(element.querySelector('#file-1155-icon')).toBeNull(); + done(); + }); + }); + + it('should download file when download is clicked', (done) => { + spyOn(processCloudContentService, 'getRawContentNode').and.returnValue(of(new Blob())); + spyOn(processCloudContentService, 'downloadNodeContent').and.stub(); + fixture.detectChanges(); + const menuButton: HTMLButtonElement = ( + fixture.debugElement.query(By.css('#file-1155-option-menu')) + .nativeElement + ); + menuButton.click(); + fixture.detectChanges(); + const downloadOption: HTMLButtonElement = ( + fixture.debugElement.query(By.css('#file-1155-download-file')) + .nativeElement + ); + downloadOption.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(processCloudContentService.downloadNodeContent).toHaveBeenCalled(); + done(); + }); + }); + + it('should preview file when show is clicked', (done) => { + spyOn(processCloudContentService, 'getRawContentNode').and.returnValue(of(new Blob())); + formService.formContentClicked.subscribe( + (fileClicked: any) => { + expect(fileClicked.nodeId).toBe(1155); + done(); + } + ); + + fixture.detectChanges(); + const menuButton: HTMLButtonElement = ( + fixture.debugElement.query( + By.css('#file-1155-option-menu') + ).nativeElement + ); + menuButton.click(); + fixture.detectChanges(); + const showOption: HTMLButtonElement = ( + fixture.debugElement.query( + By.css('#file-1155-show-file') + ).nativeElement + ); + showOption.click(); + }); + }); }); diff --git a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.ts b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.ts index c2f73cc8eb..0aab9a4250 100644 --- a/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.ts +++ b/lib/process-services-cloud/src/lib/form/components/attach-file-cloud-widget/attach-file-cloud-widget.component.ts @@ -22,7 +22,7 @@ import { FormService, LogService, ThumbnailService, - ProcessContentService + ContentLinkModel } from '@alfresco/adf-core'; import { RelatedContentRepresentation } from '@alfresco/js-api'; import { ContentCloudNodeSelectorService } from '../../services/content-cloud-node-selector.service'; @@ -30,99 +30,137 @@ import { ProcessCloudContentService } from '../../services/process-cloud-content import { UploadCloudWidgetComponent } from '../upload-cloud.widget'; @Component({ - selector: 'adf-cloud-attach-file-cloud-widget', - templateUrl: './attach-file-cloud-widget.component.html', - styleUrls: ['./attach-file-cloud-widget.component.scss'], - host: { - '(click)': 'event($event)', - '(blur)': 'event($event)', - '(change)': 'event($event)', - '(focus)': 'event($event)', - '(focusin)': 'event($event)', - '(focusout)': 'event($event)', - '(input)': 'event($event)', - '(invalid)': 'event($event)', - '(select)': 'event($event)' - }, - encapsulation: ViewEncapsulation.None + selector: 'adf-cloud-attach-file-cloud-widget', + templateUrl: './attach-file-cloud-widget.component.html', + styleUrls: ['./attach-file-cloud-widget.component.scss'], + host: { + '(click)': 'event($event)', + '(blur)': 'event($event)', + '(change)': 'event($event)', + '(focus)': 'event($event)', + '(focusin)': 'event($event)', + '(focusout)': 'event($event)', + '(input)': 'event($event)', + '(invalid)': 'event($event)', + '(select)': 'event($event)' + }, + encapsulation: ViewEncapsulation.None }) -export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent implements OnInit { +export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent + implements OnInit { + static ACS_SERVICE = 'alfresco-content'; - static ACS_SERVICE = 'alfresco-content'; - - constructor( - public formService: FormService, - public logger: LogService, - public processContentService: ProcessContentService, - public thumbnails: ThumbnailService, - public processCloudContentService: ProcessCloudContentService, - public contentNodeSelectorService: ContentCloudNodeSelectorService) { - super(formService, thumbnails, processCloudContentService, logger); - } - - ngOnInit() { - if (this.field && - this.field.value && - this.field.value.length > 0) { - this.hasFile = true; + constructor( + public formService: FormService, + public logger: LogService, + public thumbnails: ThumbnailService, + public processCloudContentService: ProcessCloudContentService, + public contentNodeSelectorService: ContentCloudNodeSelectorService + ) { + super(formService, thumbnails, processCloudContentService, logger); } - this.getMultipleFileParam(); - } - isFileSourceConfigured(): boolean { - return !!this.field.params && !!this.field.params.fileSource; - } + ngOnInit() { + if (this.field && this.field.value && this.field.value.length > 0) { + this.hasFile = true; + } + this.getMultipleFileParam(); + } - isMultipleSourceUpload(): boolean { - return !this.field.readOnly && this.isFileSourceConfigured() && !this.isOnlyLocalSourceSelected(); - } + isFileSourceConfigured(): boolean { + return !!this.field.params && !!this.field.params.fileSource; + } - isOnlyLocalSourceSelected(): boolean { - return this.field.params && - this.field.params.fileSource && - this.field.params.fileSource.serviceId === 'local-file'; - } + isMultipleSourceUpload(): boolean { + return ( + !this.field.readOnly && + this.isFileSourceConfigured() && + !this.isOnlyLocalSourceSelected() + ); + } - isSimpleUploadButton(): boolean { - return this.isUploadButtonVisible() && - !this.isFileSourceConfigured() || - this.isOnlyLocalSourceSelected(); - } + isOnlyLocalSourceSelected(): boolean { + return ( + this.field.params && + this.field.params.fileSource && + this.field.params.fileSource.serviceId === 'local-file' + ); + } - isUploadButtonVisible(): boolean { - return (!this.hasFile || this.multipleOption) && !this.field.readOnly; - } + isSimpleUploadButton(): boolean { + return ( + (this.isUploadButtonVisible() && !this.isFileSourceConfigured()) || + this.isOnlyLocalSourceSelected() + ); + } - onAttachFileChanged(event: any) { - this.onFileChanged(event); - } + isUploadButtonVisible(): boolean { + return (!this.hasFile || this.multipleOption) && !this.field.readOnly; + } - onRemoveAttachFile(file: File | RelatedContentRepresentation) { - this.removeFile(file); - } + onAttachFileChanged(event: any) { + this.onFileChanged(event); + } - uploadFileFromCS() { - this.openSelectDialog(); - } + onRemoveAttachFile(file: File | RelatedContentRepresentation) { + this.removeFile(file); + } - openSelectDialog() { - const filesSaved = []; - 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); - this.fixIncompatibilityFromPreviousAndNewForm(filesSaved); - }); - } + uploadFileFromCS() { + this.openSelectDialog(); + } - isContentSourceSelected(): boolean { - return this.field.params && - this.field.params.fileSource && - this.field.params.fileSource.serviceId === AttachFileCloudWidgetComponent.ACS_SERVICE; - } + openSelectDialog() { + const filesSaved = []; + 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); + this.fixIncompatibilityFromPreviousAndNewForm(filesSaved); + }); + } + + isContentSourceSelected(): boolean { + return ( + this.field.params && + this.field.params.fileSource && + this.field.params.fileSource.serviceId === + AttachFileCloudWidgetComponent.ACS_SERVICE + ); + } + + downloadContent(file: any): void { + this.processCloudContentService + .getRawContentNode(file.nodeId, this.field.form.contentHost) + .subscribe( + (blob: Blob) => { + this.processCloudContentService.downloadNodeContent( + blob, + file.name + ); + }, + () => { + this.logger.error( + 'Impossible retrieve content for download' + ); + } + ); + } + + onAttachFileClicked(file: ContentLinkModel) { + this.processCloudContentService + .getRawContentNode(file.nodeId, this.field.form.contentHost) + .subscribe( + (blob: Blob) => { + file.contentBlob = blob; + this.fileClicked(file); + }); + } } diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts index 8bd3739095..028aebd58c 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.ts @@ -236,7 +236,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges, await this.getFormByTaskId(appName, taskId); const hasUploadWidget = ( this.form).hasUpload; - if (hasUploadWidget && !this.readOnly) { + if (hasUploadWidget) { try { const processStorageCloudModel = await this.formCloudService.getProcessStorageFolderTask(appName, taskId, processInstanceId).toPromise(); this.form.nodeId = processStorageCloudModel.nodeId; diff --git a/lib/process-services-cloud/src/lib/form/components/upload-cloud.widget.ts b/lib/process-services-cloud/src/lib/form/components/upload-cloud.widget.ts index c181a9d660..46dc171b70 100644 --- a/lib/process-services-cloud/src/lib/form/components/upload-cloud.widget.ts +++ b/lib/process-services-cloud/src/lib/form/components/upload-cloud.widget.ts @@ -20,7 +20,7 @@ import { Component, ElementRef, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { Observable, from } from 'rxjs'; import { mergeMap, map, catchError } from 'rxjs/operators'; -import { WidgetComponent, baseHost, LogService, FormService, ThumbnailService } from '@alfresco/adf-core'; +import { WidgetComponent, baseHost, LogService, FormService, ThumbnailService, ContentLinkModel } from '@alfresco/adf-core'; import { ProcessCloudContentService } from '../services/process-cloud-content.service'; @Component({ @@ -122,7 +122,8 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni } private removeElementFromList(file) { - const savedValues = this.field.form.values[this.field.id]; + 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); @@ -142,7 +143,7 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni } } - fileClicked(nodeId: any): void { - this.formService.formContentClicked.next(nodeId); + fileClicked(file: ContentLinkModel): void { + this.formService.formContentClicked.next(file); } } diff --git a/lib/process-services-cloud/src/lib/form/services/process-cloud-content.service.ts b/lib/process-services-cloud/src/lib/form/services/process-cloud-content.service.ts index 377301074e..c54a2f2df9 100644 --- a/lib/process-services-cloud/src/lib/form/services/process-cloud-content.service.ts +++ b/lib/process-services-cloud/src/lib/form/services/process-cloud-content.service.ts @@ -18,7 +18,7 @@ import { Injectable } from '@angular/core'; import { throwError, Observable, from } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; -import { AlfrescoApiService, LogService } from '@alfresco/adf-core'; +import { AlfrescoApiService, LogService, ContentService } from '@alfresco/adf-core'; @Injectable({ providedIn: 'root' @@ -27,11 +27,11 @@ export class ProcessCloudContentService { constructor( private apiService: AlfrescoApiService, - private logService: LogService + private logService: LogService, + public contentService: ContentService ) { } createTemporaryRawRelatedContent(file, nodeId, contentHost): Observable { - const changedConfig = this.apiService.lastConfig; changedConfig.provider = 'ALL'; changedConfig.hostEcm = contentHost.replace('/alfresco', ''); @@ -45,6 +45,18 @@ export class ProcessCloudContentService { ); } + getRawContentNode(nodeId: string, contentHost: string): Observable { + 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'); diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.html index 1858a55b75..3e95ba8b80 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.html +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.html @@ -10,7 +10,8 @@ [showSaveButton]="canCompleteTask()" (formSaved)="onFormSaved($event)" (formCompleted)="onFormCompleted($event)" - (formError)="onError($event)"> + (formError)="onError($event)" + (formContentClicked)="onFormContentClicked($event)"> diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts index 3efd8f75e6..dcc0e972de 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.ts @@ -22,7 +22,7 @@ import { import { FormCloud } from '../../../form/models/form-cloud.model'; import { TaskDetailsCloudModel } from '../../start-task/models/task-details-cloud.model'; import { TaskCloudService } from '../../services/task-cloud.service'; -import { FormRenderingService } from '@alfresco/adf-core'; +import { FormRenderingService, ContentLinkModel } from '@alfresco/adf-core'; import { AttachFileCloudWidgetComponent } from '../../../form/components/attach-file-cloud-widget/attach-file-cloud-widget.component'; import { DropdownCloudWidgetComponent } from '../../../form/components/dropdown-cloud/dropdown-cloud.widget'; import { DateCloudWidgetComponent } from '../../../form/components/date-cloud/date-cloud.widget'; @@ -90,6 +90,9 @@ export class TaskFormCloudComponent implements OnChanges { @Output() error: EventEmitter = new EventEmitter(); + @Output() + formContentClicked: EventEmitter = new EventEmitter(); + taskDetails: TaskDetailsCloudModel; loading: boolean = false; @@ -180,4 +183,8 @@ export class TaskFormCloudComponent implements OnChanges { onError(data: any) { this.error.emit(data); } + + onFormContentClicked(content: ContentLinkModel) { + this.formContentClicked.emit(content); + } } diff --git a/lib/testing/src/lib/content-services/pages/document-list.page.ts b/lib/testing/src/lib/content-services/pages/document-list.page.ts index 7750a04348..1bdd25c94c 100644 --- a/lib/testing/src/lib/content-services/pages/document-list.page.ts +++ b/lib/testing/src/lib/content-services/pages/document-list.page.ts @@ -23,7 +23,6 @@ import { BrowserActions } from '../../core/utils/browser-actions'; export class DocumentListPage { rootElement: ElementFinder; - actionMenu: ElementFinder = element(by.css('div[role="menu"]')); optionButton: Locator = by.css('button[data-automation-id*="action_menu_"]'); tableBody: ElementFinder; dataTable: DataTableComponentPage; @@ -66,12 +65,12 @@ export class DocumentListPage { await BrowserActions.closeMenuAndDialogs(); const row: ElementFinder = this.dataTable.getRow('Display name', content); await BrowserActions.click(row.element(this.optionButton)); - await BrowserVisibility.waitUntilElementIsVisible(this.actionMenu); + await BrowserActions.waitUntilActionMenuIsVisible(); await browser.sleep(500); } async checkActionMenuIsNotDisplayed(): Promise { - await BrowserVisibility.waitUntilElementIsNotVisible(this.actionMenu); + await BrowserActions.waitUntilActionMenuIsNotVisible(); } dataTablePage(): DataTableComponentPage { diff --git a/lib/testing/src/lib/core/pages/form/widgets/attachFileWidgetCloud.ts b/lib/testing/src/lib/core/pages/form/widgets/attachFileWidgetCloud.ts index 523798f5e8..ba44e01670 100644 --- a/lib/testing/src/lib/core/pages/form/widgets/attachFileWidgetCloud.ts +++ b/lib/testing/src/lib/core/pages/form/widgets/attachFileWidgetCloud.ts @@ -76,8 +76,12 @@ export class AttachFileWidgetCloud { async removeFile(fileName: string): Promise { const fileId = await this.getFileId(fileName); - const deleteButton = this.widget.element(by.css(`button[id='${fileId}-remove']`)); + const optionMenu = this.widget.element(by.css(`button[id='${fileId}-option-menu']`)); + await BrowserActions.click(optionMenu); + await BrowserActions.waitUntilActionMenuIsVisible(); + const deleteButton = element(by.css(`button#${fileId}-remove`)); await BrowserActions.click(deleteButton); + await BrowserVisibility.waitUntilElementIsNotVisible(deleteButton); } async viewFile(name): Promise { diff --git a/lib/testing/src/lib/core/utils/browser-actions.ts b/lib/testing/src/lib/core/utils/browser-actions.ts index 2fadac5402..8fc4814836 100644 --- a/lib/testing/src/lib/core/utils/browser-actions.ts +++ b/lib/testing/src/lib/core/utils/browser-actions.ts @@ -26,6 +26,16 @@ export class BrowserActions { await elementFinder.click(); } + static async waitUntilActionMenuIsVisible(): Promise { + const actionMenu = element(by.css('div[role="menu"]')); + await BrowserVisibility.waitUntilElementIsVisible(actionMenu); + } + + static async waitUntilActionMenuIsNotVisible(): Promise { + const actionMenu = element(by.css('div[role="menu"]')); + await BrowserVisibility.waitUntilElementIsNotVisible(actionMenu); + } + static async getUrl(url: string): Promise { return browser.get(url); }