[AAE-3204] 'Invalid destination folder path' displayed when clicking on attach file widget of type alfresco & local when destination folder is empty. (#5962)

* [AAE-3204] 'Invalid destination folder path' displayed when clicking on attach file widget of type alfresco & local when destination folder is empty.

* * Removed snackBar
* Removed unwanted Unit test

* * Added unit tests to the recent changes

* Remove unused import

* Exclude a test that will be fixed on different PR

* * Removed breadcrumb restriction on content source type

* * modified rootNodeId based on fileSource type
* Added unit tests too

* Revert exclude  e2e  test

Co-authored-by: adomi <ardit.domi@alfresco.com>
Co-authored-by: Cristina Jalba <cristina.jalba@ness.com>
This commit is contained in:
siva kumar 2020-08-12 19:27:52 +05:30 committed by GitHub
parent 4aa936bb9c
commit 8fbcb4731f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 271 additions and 95 deletions

View File

@ -27,8 +27,7 @@ import {
FormFieldTypes, FormFieldTypes,
FormFieldMetadata, FormFieldMetadata,
FormService, FormService,
DownloadService, DownloadService
NotificationService
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@ -45,7 +44,6 @@ describe('AttachFileCloudWidgetComponent', () => {
let element: HTMLInputElement; let element: HTMLInputElement;
let contentCloudNodeSelectorService: ContentCloudNodeSelectorService; let contentCloudNodeSelectorService: ContentCloudNodeSelectorService;
let processCloudContentService: ProcessCloudContentService; let processCloudContentService: ProcessCloudContentService;
let notificationService: NotificationService;
let formService: FormService; let formService: FormService;
let downloadService: DownloadService; let downloadService: DownloadService;
@ -96,11 +94,43 @@ describe('AttachFileCloudWidgetComponent', () => {
} }
}; };
const allSourceParamsWithWrongPath = { const allSourceWithRootParams = {
fileSource: { fileSource: {
name: 'all file sources', name: 'all file sources',
serviceId: '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 ContentCloudNodeSelectorService
); );
formService = TestBed.inject(FormService); formService = TestBed.inject(FormService);
notificationService = TestBed.inject(NotificationService);
})); }));
afterEach(() => { afterEach(() => {
@ -252,66 +281,6 @@ describe('AttachFileCloudWidgetComponent', () => {
expect(fileIcon).not.toBeNull(); 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 = <FormFieldMetadata> 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 = <FormFieldMetadata> 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(() => { it('should display file list when field has value', async(() => {
widget.field = new FormFieldModel(new FormModel(), { widget.field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.UPLOAD, 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 = <FormFieldMetadata> 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 = <FormFieldMetadata> 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 = <FormFieldMetadata> 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 = <FormFieldMetadata> 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 = <FormFieldMetadata> 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 = <FormFieldMetadata> 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 = <FormFieldMetadata> 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 = <FormFieldMetadata> 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', () => { describe('when is readonly', () => {
it('should show empty list message when there are no file', async(() => { it('should show empty list message when there are no file', async(() => {

View File

@ -23,14 +23,14 @@ import {
LogService, LogService,
ThumbnailService, ThumbnailService,
NotificationService, NotificationService,
ContentLinkModel, FormValues,
TranslationService, ContentLinkModel
FormValues
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { Node, RelatedContentRepresentation } from '@alfresco/js-api'; import { Node, RelatedContentRepresentation } from '@alfresco/js-api';
import { ContentCloudNodeSelectorService } from '../../../services/content-cloud-node-selector.service'; import { ContentCloudNodeSelectorService } from '../../../services/content-cloud-node-selector.service';
import { ProcessCloudContentService } from '../../../services/process-cloud-content.service'; import { ProcessCloudContentService } from '../../../services/process-cloud-content.service';
import { UploadCloudWidgetComponent } from './upload-cloud.widget'; import { UploadCloudWidgetComponent } from './upload-cloud.widget';
import { DestinationFolderPathModel } from '../../../models/form-cloud-representation.model';
@Component({ @Component({
selector: 'adf-cloud-attach-file-cloud-widget', selector: 'adf-cloud-attach-file-cloud-widget',
@ -49,11 +49,14 @@ import { UploadCloudWidgetComponent } from './upload-cloud.widget';
}, },
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent implements OnInit {
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'; typeId = 'AttachFileCloudWidgetComponent';
rootNodeId = '-my-'; rootNodeId = AttachFileCloudWidgetComponent.MY_FILES_FOLDER_ID;
constructor( constructor(
formService: FormService, formService: FormService,
@ -61,8 +64,7 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
thumbnails: ThumbnailService, thumbnails: ThumbnailService,
processCloudContentService: ProcessCloudContentService, processCloudContentService: ProcessCloudContentService,
notificationService: NotificationService, notificationService: NotificationService,
private contentNodeSelectorService: ContentCloudNodeSelectorService, private contentNodeSelectorService: ContentCloudNodeSelectorService
private translationService: TranslationService
) { ) {
super(formService, thumbnails, processCloudContentService, notificationService, logger); super(formService, thumbnails, processCloudContentService, notificationService, logger);
} }
@ -87,21 +89,18 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
const selectedMode = this.field.params.multiple ? 'multiple' : 'single'; const selectedMode = this.field.params.multiple ? 'multiple' : 'single';
if (this.isAlfrescoAndLocal()) { if (this.isAlfrescoAndLocal()) {
const destinationFolderPath = this.field.params.fileSource.destinationFolderPath; const destinationFolderPath = this.getAliasAndRelativePathFromDestinationFolderPath(this.field.params.fileSource.destinationFolderPath);
const alias = this.getAliasFromDestinationFolderPath(destinationFolderPath);
const opts = {
relativePath: this.getRelativePathFromDestinationFolderPath(destinationFolderPath)
};
if (alias && opts && opts.relativePath) { if (destinationFolderPath.path) {
await this.contentNodeSelectorService.fetchNodeIdFromRelativePath(alias, opts).then((nodeId: string) => { const opts = { relativePath: destinationFolderPath.path };
this.rootNodeId = nodeId; await this.contentNodeSelectorService.fetchNodeIdFromRelativePath(destinationFolderPath.alias, opts).then((nodeId: string) => {
this.rootNodeId = nodeId ? nodeId : destinationFolderPath.alias;
}); });
} else { } else {
const errorMessage = this.translationService.instant('ADF_CLOUD_TASK_FORM.ERROR.INVALID_DESTINATION_FOLDER_PATH'); this.rootNodeId = destinationFolderPath.alias;
this.notificationService.showError(errorMessage);
} }
} }
this.contentNodeSelectorService this.contentNodeSelectorService
.openUploadFileDialog(this.rootNodeId, selectedMode, this.isAlfrescoAndLocal()) .openUploadFileDialog(this.rootNodeId, selectedMode, this.isAlfrescoAndLocal())
.subscribe((selections: Node[]) => { .subscribe((selections: Node[]) => {
@ -111,14 +110,19 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
}); });
} }
getAliasFromDestinationFolderPath(destinationFolderPath: string): string { getAliasAndRelativePathFromDestinationFolderPath(destinationFolderPath: string): DestinationFolderPathModel {
let alias: string; let path: string;
if (destinationFolderPath) {
const startOfRelativePathIndex = destinationFolderPath.indexOf('/'); const startOfRelativePathIndex = destinationFolderPath.indexOf('/');
return destinationFolderPath.substring(0, startOfRelativePathIndex); if (startOfRelativePathIndex >= 0) {
alias = destinationFolderPath.substring(0, startOfRelativePathIndex);
path = destinationFolderPath.substring(startOfRelativePathIndex, destinationFolderPath.length);
} else {
alias = destinationFolderPath;
}
} }
getRelativePathFromDestinationFolderPath(destinationFolderPath: string): string { return this.isValidAlias(alias) ? { alias, path } : { alias: AttachFileCloudWidgetComponent.ROOT_FOLDER_ID, path: undefined };
const startOfRelativePathIndex = destinationFolderPath.indexOf('/');
return destinationFolderPath.substring(startOfRelativePathIndex, destinationFolderPath.length);
} }
removeExistingSelection(selections: Node[]) { removeExistingSelection(selections: Node[]) {
@ -155,4 +159,8 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent
this.formService.updateFormValuesRequested.next(values); this.formService.updateFormValuesRequested.next(values);
} }
} }
isValidAlias(alias: string): boolean {
return alias && AttachFileCloudWidgetComponent.VALID_ALIAS.includes(alias);
}
} }

View File

@ -49,3 +49,8 @@ export class FormCloudRepresentation {
this.selectedOutcome = obj.selectedOutcome || null; this.selectedOutcome = obj.selectedOutcome || null;
} }
} }
export interface DestinationFolderPathModel {
alias: string;
path: string;
}

View File

@ -20,7 +20,7 @@ import { AlfrescoApiService } from '@alfresco/adf-core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { ContentNodeSelectorComponent, ContentNodeSelectorComponentData } from '@alfresco/adf-content-services'; import { ContentNodeSelectorComponent, ContentNodeSelectorComponentData } from '@alfresco/adf-content-services';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject, throwError } from 'rxjs';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -32,7 +32,7 @@ export class ContentCloudNodeSelectorService {
private dialog: MatDialog) { private dialog: MatDialog) {
} }
openUploadFileDialog(currentFolderId?: string, selectionMode?: string, showLocalUploadButton?: boolean): Observable<Node[]> { openUploadFileDialog(currentFolderId?: string, selectionMode?: string, isAllFileSources?: boolean): Observable<Node[]> {
const select = new Subject<Node[]>(); const select = new Subject<Node[]>();
select.subscribe({ select.subscribe({
complete: this.close.bind(this) complete: this.close.bind(this)
@ -41,13 +41,13 @@ export class ContentCloudNodeSelectorService {
title: 'Select a file', title: 'Select a file',
actionName: 'Attach', actionName: 'Attach',
currentFolderId, currentFolderId,
restrictRootToCurrentFolderId: true, restrictRootToCurrentFolderId: isAllFileSources,
select, select,
selectionMode, selectionMode,
isSelectionValid: (entry: Node) => entry.isFile, isSelectionValid: (entry: Node) => entry.isFile,
showFilesInResult: true, showFilesInResult: true,
showDropdownSiteList: false, showDropdownSiteList: false,
showLocalUploadButton showLocalUploadButton: isAllFileSources
}; };
this.openContentNodeDialog(data, 'adf-content-node-selector-dialog', '630px'); this.openContentNodeDialog(data, 'adf-content-node-selector-dialog', '630px');
return select; return select;
@ -57,6 +57,8 @@ export class ContentCloudNodeSelectorService {
let nodeId = ''; let nodeId = '';
await this.apiService.getInstance().node.getNode(alias, opts).then(node => { await this.apiService.getInstance().node.getNode(alias, opts).then(node => {
nodeId = node.entry.id; nodeId = node.entry.id;
}).catch((err) => {
this.handleError(err);
}); });
return nodeId; return nodeId;
} }
@ -68,4 +70,8 @@ export class ContentCloudNodeSelectorService {
close() { close() {
this.dialog.closeAll(); this.dialog.closeAll();
} }
private handleError(error: any): Observable<any> {
return throwError(error || 'Server error');
}
} }