[AAE-6242] upload a new version of a file attached in a form (#7651)

* [AAE-6242] Create upload new version dialog to handle the upload of the new file version

* [AAE-6242] Create version manager service to open version manager dialog

* [AAE-6242] Export service and dialog

* [AAE-6242] add adf-upload button to the show the upload new file button

* [AAE-6242] open upload new version dialog

* [AAE-6242] Removed console log

* [AAE-8798] display update option name to newVersion

* [AAE-8799] Emit version manager data when new file version is uploaded

* [AAE-8799] When a new file version is uploaded open new version dialog and update current file version with the new file version

* [AAE-8799] Rename UploadNewVersionDialogComponent to VersionManagerDialogComponent and UploadNewVersionDialogData to VersionManagerDialogData

* [AAE-8799] Use default root folder id

* [AAE-8799] Add #uploadSingleFile ViewChild in order get the input reference

* [AAE-8799] Trigger adf-upload-button by clicking on the button in order to open the file chooser and upload a new file version

* [AAE-8799] Version manager dialog emits file upload error

* [AAE-8799] Format version manager dialog code

* [AAE-8799] Reject upload and permission errors

* [AAE-8799] Catch upload new version errors

* [AAE-8799] Update allowable operation type

* [AAE-8799] Rename VersionManagerDialogComponent into NewVersionUploaderDialogComponent and VersionManagerService into NewVersionUploaderService, create specific folder for new version uploader component and service

* Restore previous UploadButtonComponent version

* [AAE-8799] Use [adf-upload] directive to upload new file version

* [AAE-8799] Add mock file for new version uploader unit tests

* [AAE-8799] Override mat dialog configuration

* [AAE-8799] Add unit test related to event emitted from Dialog

* [AAE-8799] Create model to handle New Version Uploader data

* [AAE-8799] Return data on dialog close

* [AAE-8799] Add showVersionsOnly property to dialog to show only file version list

* [AAE-8799] Add dialogAction to emit dialog actions

* [AAE-8799] Return observable instead of promise

* [AAE-8799] Update new file version type

* [AAE-8799] Subscribe dialog because return an Observable

* [AAE-8799] Add license header

* [AAE-8799] Add i18n new version uploader translations

* [AAE-8799] If data.title is not provided, add a default title

* [AAE-8799] Change panelClass for manage versions visualizations, add dialog styles

* [AAE-8799] Add upload new version dialog unit test

* [AAE-8799] Add upload new version dialog unit test related to manage versions section

* [AAE-8799] Add onUploadNewFileVersion unit tests

* [AAE-8799] Test new dialog panelClass

* [AAE-8799] Create a method to set dialog title, if title isn't provided from parent component, a default title is set

* [AAE-8799] Add doc to new-version-uploader-dilog component and service

* [AAE-8799] Add new-version-uploader.dialog.service documentation
This commit is contained in:
Amedeo Lepore
2022-05-27 09:54:09 +02:00
committed by GitHub
parent 95fd3e822a
commit 4457aed5b4
25 changed files with 1278 additions and 16 deletions

View File

@@ -26,6 +26,7 @@
(rowClick)="onRowClicked($event)"
(attachFileClick)="onAttachFileClicked($event)"
(downloadFile)="downloadContent($event)"
(uploadNewFileVersion)="onUploadNewFileVersion($event)"
(contentModelFileHandler)="contentModelFormFileHandler($event)"
(removeAttachFile)="onRemoveAttachFile($event)"
></adf-cloud-file-properties-table>

View File

@@ -29,7 +29,8 @@ import {
DownloadService,
AppConfigService,
UploadWidgetContentLinkModel,
LocalizedDatePipe
LocalizedDatePipe,
NotificationService
} from '@alfresco/adf-core';
import {
allSourceParams,
@@ -60,11 +61,12 @@ import {
} from '../../../mocks/attach-file-cloud-widget.mock';
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ContentModule, ContentNodeSelectorPanelService } from '@alfresco/adf-content-services';
import { ContentModule, ContentNodeSelectorPanelService, NewVersionUploaderDataAction, NewVersionUploaderService } from '@alfresco/adf-content-services';
import { By } from '@angular/platform-browser';
import { of } from 'rxjs';
import { of, throwError } from 'rxjs';
import { FormCloudModule } from '../../../form-cloud.module';
import { TranslateModule } from '@ngx-translate/core';
import { mockNode } from 'content-services/src/lib/mock';
describe('AttachFileCloudWidgetComponent', () => {
let widget: AttachFileCloudWidgetComponent;
@@ -82,6 +84,8 @@ describe('AttachFileCloudWidgetComponent', () => {
let contentClickedSpy: jasmine.Spy;
let openUploadFileDialogSpy: jasmine.Spy;
let localizedDataPipe: LocalizedDatePipe;
let newVersionUploaderService: NewVersionUploaderService;
let notificationService: NotificationService;
const createUploadWidgetField = (form: FormModel, fieldId: string, value?: any, params?: any, multiple?: boolean, name?: string, readOnly?: boolean) => {
widget.field = new FormFieldModel(form, {
@@ -204,7 +208,7 @@ describe('AttachFileCloudWidgetComponent', () => {
describe('when is required', () => {
it('should be able to display label with asterisk', async () => {
widget.field = new FormFieldModel( new FormModel({ taskId: '<id>' }), {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
type: FormFieldTypes.UPLOAD,
required: true
});
@@ -298,7 +302,7 @@ describe('AttachFileCloudWidgetComponent', () => {
it('should be able to use mapped string variable value if the destinationFolderPath set to string type variable', async () => {
const getNodeIdFromPathSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeIdBasedOnStringVariableValue);
const form = new FormModel({ formVariables, processVariables});
const form = new FormModel({ formVariables, processVariables });
createUploadWidgetField(form, 'attach-file-alfresco', [], mockAllFileSourceWithStringVariablePathType);
fixture.detectChanges();
await fixture.whenStable();
@@ -383,9 +387,9 @@ describe('AttachFileCloudWidgetComponent', () => {
appConfigService.config = Object.assign(appConfigService.config, {
'alfresco-deployed-apps': [
{
name: 'fakeapp'
name: 'fakeapp'
}
]
]
});
expect(widget.replaceAppNameAliasWithValue('/myfiles/-appname-/folder')).toBe('/myfiles/fakeapp/folder');
@@ -504,7 +508,7 @@ describe('AttachFileCloudWidgetComponent', () => {
describe('when a file is uploaded', () => {
beforeEach(async () => {
apiServiceSpy = spyOn(widget['nodesApi'], 'getNode').and.returnValue(new Promise(resolve => resolve({entry: fakeNodeWithProperties})));
apiServiceSpy = spyOn(widget['nodesApi'], 'getNode').and.returnValue(new Promise(resolve => resolve({ entry: fakeNodeWithProperties })));
spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(new Promise(resolve => resolve('fake-properties')));
openUploadFileDialogSpy.and.returnValue(of([fakeNodeWithProperties]));
widget.field = new FormFieldModel(new FormModel(), {
@@ -846,4 +850,48 @@ describe('AttachFileCloudWidgetComponent', () => {
expect(getProcessVariableValueSpy).not.toHaveBeenCalled();
});
});
describe('onUploadNewFileVersion', () => {
let spyOnOpenUploadNewVersionDialog: jasmine.Spy;
let spyOnReplaceOldFileVersionWithNew: jasmine.Spy;
let spyOnShowError: jasmine.Spy;
beforeEach(() => {
notificationService = TestBed.inject(NotificationService);
newVersionUploaderService = TestBed.inject(NewVersionUploaderService);
spyOnOpenUploadNewVersionDialog = spyOn(newVersionUploaderService, 'openUploadNewVersionDialog')
.and.returnValue(of({ action: NewVersionUploaderDataAction.refresh }));
spyOnReplaceOldFileVersionWithNew = spyOn(widget, 'replaceOldFileVersionWithNew');
spyOnShowError = spyOn(notificationService, 'showError');
});
it('Should open new version uploader dialog', async () => {
await fixture.whenStable();
widget.onUploadNewFileVersion(mockNode);
expect(spyOnOpenUploadNewVersionDialog).toHaveBeenCalledWith(mockNode);
});
it('Should not replace old file version with the new one if dialog returned action is not upload', async () => {
await fixture.whenStable();
widget.onUploadNewFileVersion(mockNode);
expect(spyOnReplaceOldFileVersionWithNew).not.toHaveBeenCalled();
});
it('Should replace old file version with the new one if dialog returned action is upload', async () => {
spyOnOpenUploadNewVersionDialog.and.returnValue(of({ action: NewVersionUploaderDataAction.upload }));
await fixture.whenStable();
widget.onUploadNewFileVersion(mockNode);
expect(spyOnReplaceOldFileVersionWithNew).toHaveBeenCalledTimes(1);
});
it('Should show notification error if new version uploader dialog return error', async () => {
const mockError = {value: 'Upload error'};
spyOnOpenUploadNewVersionDialog.and.returnValue(throwError(mockError));
await fixture.whenStable();
widget.onUploadNewFileVersion(mockNode);
expect(spyOnReplaceOldFileVersionWithNew).not.toHaveBeenCalled();
expect(spyOnShowError).toHaveBeenCalledWith(mockError.value);
});
});
});

View File

@@ -35,7 +35,7 @@ import { ContentCloudNodeSelectorService } from '../../../services/content-cloud
import { ProcessCloudContentService } from '../../../services/process-cloud-content.service';
import { UploadCloudWidgetComponent } from './upload-cloud.widget';
import { DestinationFolderPathModel, DestinationFolderPathType } from '../../../models/form-cloud-representation.model';
import { ContentNodeSelectorPanelService } from '@alfresco/adf-content-services';
import { ContentNodeSelectorPanelService, NewVersionUploaderData, NewVersionUploaderDataAction, NewVersionUploaderDialogData, NewVersionUploaderService, VersionManagerUploadData } from '@alfresco/adf-content-services';
export const RETRIEVE_METADATA_OPTION = 'retrieveMetadata';
export const ALIAS_ROOT_FOLDER = '-root-';
@@ -81,7 +81,8 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent i
private contentNodeSelectorService: ContentCloudNodeSelectorService,
private appConfigService: AppConfigService,
private apiService: AlfrescoApiService,
private contentNodeSelectorPanelService: ContentNodeSelectorPanelService
private contentNodeSelectorPanelService: ContentNodeSelectorPanelService,
private newVersionUploaderService: NewVersionUploaderService
) {
super(formService, thumbnails, processCloudContentService, notificationService, logger);
}
@@ -211,6 +212,16 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent i
this.processCloudContentService.downloadFile(file.id);
}
onUploadNewFileVersion(node: NewVersionUploaderDialogData): void {
this.newVersionUploaderService.openUploadNewVersionDialog(node).subscribe((newVersionUploaderData: NewVersionUploaderData) => {
if (newVersionUploaderData.action === NewVersionUploaderDataAction.upload) {
this.replaceOldFileVersionWithNew(newVersionUploaderData as VersionManagerUploadData);
}
},
error => this.notificationService.showError(error.value)
);
}
onAttachFileClicked(nodeSelector: any) {
nodeSelector.nodeId = nodeSelector.id;
this.fileClicked(new ContentLinkModel(nodeSelector));

View File

@@ -14,7 +14,7 @@
[alt]="mimeTypeIcon" role="button" tabindex="0" />
</td>
</ng-container>
<ng-container matColumnDef="fileName">
<th mat-header-cell *matHeaderCellDef>{{ 'FORM.FIELD.FILE_NAME' | translate }}</th>
<td mat-cell *matCellDef="let element">
@@ -22,7 +22,7 @@
(click)="onRowClicked(element)">{{element.name}}</span>
</td>
</ng-container>
<ng-container *ngFor="let columnName of field?.params?.displayableCMProperties" [matColumnDef]="columnName.name">
<th mat-header-cell *matHeaderCellDef>{{ columnName.title ? columnName.title : columnName.name | titlecase
}}</th>
@@ -31,7 +31,7 @@
(click)="onRowClicked(row)">{{ getColumnValue(row, columnName) }}</span>
</td>
</ng-container>
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let element">
@@ -62,11 +62,19 @@
<mat-icon class="mat-24">highlight_off</mat-icon>
<span>{{ 'FORM.FIELD.REMOVE_FILE' | translate }}</span>
</button>
<div *ngIf="displayMenuOption('newVersion')">
<button [adf-upload]="true" [mode]="['click']"
(upload-files)="onUploadNewFileVersion($event, element);"
id="{{'file-'+ element?.id +'-upload-new-version'}}" mat-menu-item>
<mat-icon class="mat-24">file_upload</mat-icon>
<span>{{ 'ADF_VERSION_LIST.ACTIONS.UPLOAD.TITLE' | translate }}</span>
</button>
</div>
</mat-menu>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>

View File

@@ -20,6 +20,7 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { LocalizedDatePipe, ThumbnailService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api';
import { NewVersionUploaderDialogData } from '@alfresco/adf-content-services';
export const RETRIEVE_METADATA_OPTION = 'retrieveMetadata';
@@ -56,6 +57,9 @@ export class FilePropertiesTableCloudComponent {
@Output()
downloadFile: EventEmitter<Node> = new EventEmitter<Node>();
@Output()
uploadNewFileVersion: EventEmitter<NewVersionUploaderDialogData> = new EventEmitter<NewVersionUploaderDialogData>();
@Output()
contentModelFileHandler: EventEmitter<any> = new EventEmitter<Node>();
@@ -76,6 +80,14 @@ export class FilePropertiesTableCloudComponent {
this.downloadFile.emit(file);
}
onUploadNewFileVersion(customEvent: any, node: Node){
const newVersionUploaderDialogData: NewVersionUploaderDialogData = {
file: customEvent.detail.files[0].file,
node
};
this.uploadNewFileVersion.emit(newVersionUploaderDialogData);
}
contentModelFormFileHandler(file?: any) {
this.contentModelFileHandler.emit(file);
}

View File

@@ -24,6 +24,7 @@ import { mergeMap } from 'rxjs/operators';
import { WidgetComponent, LogService, FormService, ThumbnailService, NotificationService } from '@alfresco/adf-core';
import { ProcessCloudContentService } from '../../../services/process-cloud-content.service';
import { FileSourceTypes, DestinationFolderPathType } from '../../../models/form-cloud-representation.model';
import { VersionManagerUploadData } from '@alfresco/adf-content-services';
@Component({
selector: 'upload-cloud-widget',
@@ -78,6 +79,13 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
}
}
replaceOldFileVersionWithNew(versionManagerData: VersionManagerUploadData) {
const currentUploadedFileIndex = this.uploadedFiles.findIndex(file => file.name === versionManagerData.currentVersion.name);
this.uploadedFiles[currentUploadedFileIndex] = { ...versionManagerData.newVersion.value.entry};
this.field.value = [...this.uploadedFiles];
this.field.form.values[this.field.id] = [...this.uploadedFiles];
}
onFileChanged(event: any) {
const files: File[] = [];
const filesSaved: Node[] = [];

View File

@@ -24,7 +24,7 @@ import { MaterialModule } from '../material.module';
import { FormCloudComponent } from './components/form-cloud.component';
import { FormDefinitionSelectorCloudComponent } from './components/form-definition-selector-cloud.component';
import { FormCustomOutcomesComponent } from './components/form-cloud-custom-outcomes.component';
import { ContentMetadataModule, ContentNodeSelectorModule } from '@alfresco/adf-content-services';
import { ContentMetadataModule, ContentNodeSelectorModule, UploadModule } from '@alfresco/adf-content-services';
import { DateCloudWidgetComponent } from './components/widgets/date/date-cloud.widget';
import { DropdownCloudWidgetComponent } from './components/widgets/dropdown/dropdown-cloud.widget';
@@ -51,7 +51,8 @@ import { FilePropertiesTableCloudComponent } from './components/widgets/attach-f
ContentNodeSelectorModule,
PeopleCloudModule,
GroupCloudModule,
ContentMetadataModule
ContentMetadataModule,
UploadModule
],
declarations: [
FormCloudComponent,