[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,
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 = <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(() => {
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 = <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', () => {
it('should show empty list message when there are no file', async(() => {

View File

@ -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 {
getAliasAndRelativePathFromDestinationFolderPath(destinationFolderPath: string): DestinationFolderPathModel {
let alias: string; let path: string;
if (destinationFolderPath) {
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 {
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);
}
}

View File

@ -49,3 +49,8 @@ export class FormCloudRepresentation {
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 { 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<Node[]> {
openUploadFileDialog(currentFolderId?: string, selectionMode?: string, isAllFileSources?: boolean): Observable<Node[]> {
const select = new Subject<Node[]>();
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<any> {
return throwError(error || 'Server error');
}
}