diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts index 9fa79da64b..69515d3a56 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts @@ -27,8 +27,7 @@ import { FormFieldTypes, FormFieldMetadata, FormService, - DownloadService, - NotificationService + DownloadService } from '@alfresco/adf-core'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @@ -45,7 +44,6 @@ describe('AttachFileCloudWidgetComponent', () => { let element: HTMLInputElement; let contentCloudNodeSelectorService: ContentCloudNodeSelectorService; let processCloudContentService: ProcessCloudContentService; - let notificationService: NotificationService; let formService: FormService; let downloadService: DownloadService; @@ -96,11 +94,43 @@ describe('AttachFileCloudWidgetComponent', () => { } }; - const allSourceParamsWithWrongPath = { + const allSourceWithRootParams = { fileSource: { name: 'all file sources', serviceId: 'all-file-sources', - destinationFolderPath: 'mock-folder' + destinationFolderPath: '-root-' + } + }; + + const allSourceWithMyFilesParams = { + fileSource: { + name: 'all file sources', + serviceId: 'all-file-sources', + destinationFolderPath: '-my-' + } + }; + + const allSourceWithShareParams = { + fileSource: { + name: 'all file sources', + serviceId: 'all-file-sources', + destinationFolderPath: '-shared-' + } + }; + + const allSourceWithWrongAliasParams = { + fileSource: { + name: 'all file sources', + serviceId: 'all-file-sources', + destinationFolderPath: '-wrongAlias-' + } + }; + + const allSourceWithNoAliasParams = { + fileSource: { + name: 'all file sources', + serviceId: 'all-file-sources', + destinationFolderPath: '/noalias/createdFolder' } }; @@ -160,7 +190,6 @@ describe('AttachFileCloudWidgetComponent', () => { ContentCloudNodeSelectorService ); formService = TestBed.inject(FormService); - notificationService = TestBed.inject(NotificationService); })); afterEach(() => { @@ -252,66 +281,6 @@ describe('AttachFileCloudWidgetComponent', () => { expect(fileIcon).not.toBeNull(); }); - it('should be able to fetch nodeId if destinationFolderPtah defined ', async() => { - const fetchNodeIdFromRelativePathSpy = spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath').and.returnValue(mockNodeId); - 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 = allSourceParams; - fixture.detectChanges(); - await fixture.whenStable(); - const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); - - expect(attachButton).not.toBeNull(); - - attachButton.click(); - await fixture.whenStable(); - fixture.detectChanges(); - - const alias = '-root-'; - const opt = { relativePath: '/myfiles' }; - expect(fetchNodeIdFromRelativePathSpy).toHaveBeenCalledWith(alias, opt); - expect(widget.field.params.fileSource.destinationFolderPath).toBe('-root-/myfiles'); - expect(widget.rootNodeId).toEqual('mock-node-id'); - }); - - it('should be able to show error notification if destinationFolderPtah wrong/undefined', async() => { - const fetchNodeIdFromRelativePathSpy = spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath').and.returnValue(mockNodeId); - spyOn( - contentCloudNodeSelectorService, - 'openUploadFileDialog' - ).and.returnValue(of([fakeMinimalNode])); - widget.field = new FormFieldModel(new FormModel(), { - type: FormFieldTypes.UPLOAD, - value: [] - }); - const showErrorSpy = spyOn(notificationService, 'showError').and.callThrough(); - widget.field = new FormFieldModel(new FormModel(), { - type: FormFieldTypes.UPLOAD, - value: [] - }); - widget.field.id = 'attach-file-alfresco'; - widget.field.params = allSourceParamsWithWrongPath; - fixture.detectChanges(); - await fixture.whenStable(); - const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); - - expect(attachButton).not.toBeNull(); - - attachButton.click(); - await fixture.whenStable(); - fixture.detectChanges(); - - expect(fetchNodeIdFromRelativePathSpy).not.toHaveBeenCalled(); - expect(showErrorSpy).toHaveBeenCalled(); - }); - it('should display file list when field has value', async(() => { widget.field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.UPLOAD, @@ -339,6 +308,194 @@ describe('AttachFileCloudWidgetComponent', () => { }); }); + describe('destinationFolderPath', () => { + + let fetchNodeIdFromRelativePathSpy: jasmine.Spy; + let openUploadFileDialogSpy: jasmine.Spy; + + beforeEach(async(() => { + fetchNodeIdFromRelativePathSpy = spyOn(contentCloudNodeSelectorService, 'fetchNodeIdFromRelativePath').and.returnValue(mockNodeId); + openUploadFileDialogSpy = spyOn(contentCloudNodeSelectorService, 'openUploadFileDialog').and.returnValue(of([fakeMinimalNode])); + })); + + it('should be able to fetch nodeId if destinationFolderPtah defined ', async() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = allSourceParams; + fixture.detectChanges(); + await fixture.whenStable(); + const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); + + expect(attachButton).not.toBeNull(); + + attachButton.click(); + await fixture.whenStable(); + fixture.detectChanges(); + + const alias = '-root-'; + const opt = { relativePath: '/myfiles' }; + expect(fetchNodeIdFromRelativePathSpy).toHaveBeenCalledWith(alias, opt); + expect(widget.field.params.fileSource.destinationFolderPath).toBe('-root-/myfiles'); + expect(widget.rootNodeId).toEqual('mock-node-id'); + }); + + it('Should be able to set given alias as rootNodeId if destinationFolderPath contains only alias i.e -root-', async() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = allSourceWithRootParams; + fixture.detectChanges(); + await fixture.whenStable(); + const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); + + expect(attachButton).not.toBeNull(); + + attachButton.click(); + await fixture.whenStable(); + fixture.detectChanges(); + + expect(widget.rootNodeId).toEqual('-root-'); + expect(openUploadFileDialogSpy).toHaveBeenCalledWith('-root-', 'single', true); + }); + + it('Should be able to set given alias as rootNodeId if destinationFolderPath contains only alias i.e -my-', async() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = allSourceWithMyFilesParams; + fixture.detectChanges(); + await fixture.whenStable(); + const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); + + expect(attachButton).not.toBeNull(); + + attachButton.click(); + await fixture.whenStable(); + fixture.detectChanges(); + + expect(widget.rootNodeId).toEqual('-my-'); + expect(openUploadFileDialogSpy).toHaveBeenCalledWith('-my-', 'single', true); + }); + + it('Should be able to set given alias as rootNodeId if destinationFolderPath contains only alias i.e -shared-', async() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = allSourceWithShareParams; + fixture.detectChanges(); + await fixture.whenStable(); + const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); + + expect(attachButton).not.toBeNull(); + + attachButton.click(); + await fixture.whenStable(); + fixture.detectChanges(); + + expect(widget.rootNodeId).toEqual('-shared-'); + expect(openUploadFileDialogSpy).toHaveBeenCalledWith('-shared-', 'single', true); + }); + + it('Should be able to set default alias as rootNodeId if destinationFolderPath contains wrong alias', async() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = allSourceWithWrongAliasParams; + widget.field.params.multiple = true; + fixture.detectChanges(); + await fixture.whenStable(); + const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); + + expect(attachButton).not.toBeNull(); + + attachButton.click(); + await fixture.whenStable(); + fixture.detectChanges(); + + expect(widget.rootNodeId).toEqual('-root-'); + expect(openUploadFileDialogSpy).toHaveBeenCalledWith('-root-', 'multiple', true); + }); + + it('Should be able to set default alias as rootNodeId if destinationFolderPath does not have alias', async() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = allSourceWithNoAliasParams; + widget.field.params.multiple = true; + fixture.detectChanges(); + await fixture.whenStable(); + const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); + + expect(attachButton).not.toBeNull(); + + attachButton.click(); + await fixture.whenStable(); + fixture.detectChanges(); + + expect(widget.rootNodeId).toEqual('-root-'); + expect(openUploadFileDialogSpy).toHaveBeenCalledWith('-root-', 'multiple', true); + }); + + describe('FilesSource', () => { + + it('should be able to set myFiles folderId as rootNodeId if fileSource set only to content', async() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = contentSourceParam; + fixture.detectChanges(); + await fixture.whenStable(); + const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); + + expect(attachButton).not.toBeNull(); + + attachButton.click(); + await fixture.whenStable(); + fixture.detectChanges(); + + expect(widget.rootNodeId).toEqual('-my-'); + expect(openUploadFileDialogSpy).toHaveBeenCalledWith('-my-', 'single', false); + }); + + it('should be able to set root folderId as rootNodeId if fileSource set to content and local', async() => { + widget.field = new FormFieldModel(new FormModel(), { + type: FormFieldTypes.UPLOAD, + value: [] + }); + widget.field.id = 'attach-file-alfresco'; + widget.field.params = allSourceWithWrongAliasParams; + widget.field.params.multiple = false; + fixture.detectChanges(); + await fixture.whenStable(); + const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); + + expect(attachButton).not.toBeNull(); + + attachButton.click(); + await fixture.whenStable(); + fixture.detectChanges(); + + expect(widget.rootNodeId).toEqual('-root-'); + expect(openUploadFileDialogSpy).toHaveBeenCalledWith('-root-', 'single', true); + }); + }); + }); + describe('when is readonly', () => { it('should show empty list message when there are no file', async(() => { diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts index 77662a2033..504a862919 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.ts @@ -23,14 +23,14 @@ import { LogService, ThumbnailService, NotificationService, - ContentLinkModel, - TranslationService, - FormValues + FormValues, + ContentLinkModel } from '@alfresco/adf-core'; 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'; +import { DestinationFolderPathModel } from '../../../models/form-cloud-representation.model'; @Component({ selector: 'adf-cloud-attach-file-cloud-widget', @@ -49,11 +49,14 @@ import { UploadCloudWidgetComponent } from './upload-cloud.widget'; }, encapsulation: ViewEncapsulation.None }) -export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent - implements OnInit { +export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent implements OnInit { + + static MY_FILES_FOLDER_ID = '-my-'; + static ROOT_FOLDER_ID = '-root-'; + static VALID_ALIAS = [AttachFileCloudWidgetComponent.ROOT_FOLDER_ID, AttachFileCloudWidgetComponent.MY_FILES_FOLDER_ID, '-shared-']; typeId = 'AttachFileCloudWidgetComponent'; - rootNodeId = '-my-'; + rootNodeId = AttachFileCloudWidgetComponent.MY_FILES_FOLDER_ID; constructor( formService: FormService, @@ -61,8 +64,7 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent thumbnails: ThumbnailService, processCloudContentService: ProcessCloudContentService, notificationService: NotificationService, - private contentNodeSelectorService: ContentCloudNodeSelectorService, - private translationService: TranslationService + private contentNodeSelectorService: ContentCloudNodeSelectorService ) { super(formService, thumbnails, processCloudContentService, notificationService, logger); } @@ -87,21 +89,18 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent const selectedMode = this.field.params.multiple ? 'multiple' : 'single'; if (this.isAlfrescoAndLocal()) { - const destinationFolderPath = this.field.params.fileSource.destinationFolderPath; - const alias = this.getAliasFromDestinationFolderPath(destinationFolderPath); - const opts = { - relativePath: this.getRelativePathFromDestinationFolderPath(destinationFolderPath) - }; + const destinationFolderPath = this.getAliasAndRelativePathFromDestinationFolderPath(this.field.params.fileSource.destinationFolderPath); - if (alias && opts && opts.relativePath) { - await this.contentNodeSelectorService.fetchNodeIdFromRelativePath(alias, opts).then((nodeId: string) => { - this.rootNodeId = nodeId; + if (destinationFolderPath.path) { + const opts = { relativePath: destinationFolderPath.path }; + await this.contentNodeSelectorService.fetchNodeIdFromRelativePath(destinationFolderPath.alias, opts).then((nodeId: string) => { + this.rootNodeId = nodeId ? nodeId : destinationFolderPath.alias; }); } else { - const errorMessage = this.translationService.instant('ADF_CLOUD_TASK_FORM.ERROR.INVALID_DESTINATION_FOLDER_PATH'); - this.notificationService.showError(errorMessage); + this.rootNodeId = destinationFolderPath.alias; } } + this.contentNodeSelectorService .openUploadFileDialog(this.rootNodeId, selectedMode, this.isAlfrescoAndLocal()) .subscribe((selections: Node[]) => { @@ -111,14 +110,19 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent }); } - getAliasFromDestinationFolderPath(destinationFolderPath: string): string { - const startOfRelativePathIndex = destinationFolderPath.indexOf('/'); - return destinationFolderPath.substring(0, startOfRelativePathIndex); - } + getAliasAndRelativePathFromDestinationFolderPath(destinationFolderPath: string): DestinationFolderPathModel { + let alias: string; let path: string; + if (destinationFolderPath) { + const startOfRelativePathIndex = destinationFolderPath.indexOf('/'); + if (startOfRelativePathIndex >= 0) { + alias = destinationFolderPath.substring(0, startOfRelativePathIndex); + path = destinationFolderPath.substring(startOfRelativePathIndex, destinationFolderPath.length); + } else { + alias = destinationFolderPath; + } + } - getRelativePathFromDestinationFolderPath(destinationFolderPath: string): string { - const startOfRelativePathIndex = destinationFolderPath.indexOf('/'); - return destinationFolderPath.substring(startOfRelativePathIndex, destinationFolderPath.length); + return this.isValidAlias(alias) ? { alias, path } : { alias: AttachFileCloudWidgetComponent.ROOT_FOLDER_ID, path: undefined }; } removeExistingSelection(selections: Node[]) { @@ -155,4 +159,8 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent this.formService.updateFormValuesRequested.next(values); } } + + isValidAlias(alias: string): boolean { + return alias && AttachFileCloudWidgetComponent.VALID_ALIAS.includes(alias); + } } diff --git a/lib/process-services-cloud/src/lib/form/models/form-cloud-representation.model.ts b/lib/process-services-cloud/src/lib/form/models/form-cloud-representation.model.ts index ef17b12f0c..365050622e 100644 --- a/lib/process-services-cloud/src/lib/form/models/form-cloud-representation.model.ts +++ b/lib/process-services-cloud/src/lib/form/models/form-cloud-representation.model.ts @@ -49,3 +49,8 @@ export class FormCloudRepresentation { this.selectedOutcome = obj.selectedOutcome || null; } } + +export interface DestinationFolderPathModel { + alias: string; + path: string; +} diff --git a/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts b/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts index b49226f61c..45713d6c72 100644 --- a/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts +++ b/lib/process-services-cloud/src/lib/form/services/content-cloud-node-selector.service.ts @@ -20,7 +20,7 @@ import { AlfrescoApiService } from '@alfresco/adf-core'; import { MatDialog } from '@angular/material/dialog'; import { ContentNodeSelectorComponent, ContentNodeSelectorComponentData } from '@alfresco/adf-content-services'; import { Node } from '@alfresco/js-api'; -import { Observable, Subject } from 'rxjs'; +import { Observable, Subject, throwError } from 'rxjs'; @Injectable({ providedIn: 'root' @@ -32,7 +32,7 @@ export class ContentCloudNodeSelectorService { private dialog: MatDialog) { } - openUploadFileDialog(currentFolderId?: string, selectionMode?: string, showLocalUploadButton?: boolean): Observable { + openUploadFileDialog(currentFolderId?: string, selectionMode?: string, isAllFileSources?: boolean): Observable { const select = new Subject(); select.subscribe({ complete: this.close.bind(this) @@ -41,13 +41,13 @@ export class ContentCloudNodeSelectorService { title: 'Select a file', actionName: 'Attach', currentFolderId, - restrictRootToCurrentFolderId: true, + restrictRootToCurrentFolderId: isAllFileSources, select, selectionMode, isSelectionValid: (entry: Node) => entry.isFile, showFilesInResult: true, showDropdownSiteList: false, - showLocalUploadButton + showLocalUploadButton: isAllFileSources }; this.openContentNodeDialog(data, 'adf-content-node-selector-dialog', '630px'); return select; @@ -57,6 +57,8 @@ export class ContentCloudNodeSelectorService { let nodeId = ''; await this.apiService.getInstance().node.getNode(alias, opts).then(node => { nodeId = node.entry.id; + }).catch((err) => { + this.handleError(err); }); return nodeId; } @@ -68,4 +70,8 @@ export class ContentCloudNodeSelectorService { close() { this.dialog.closeAll(); } + + private handleError(error: any): Observable { + return throwError(error || 'Server error'); + } }