[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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1278 additions and 16 deletions

View File

@ -0,0 +1,89 @@
---
Title: New Version Uploader service
Added: v1.0.0
Status: Active
Last reviewed: 2022-05-26
---
# [New Version Uploader service](../../../lib/content-services/src/lib/new-version-uploader/new-version-uploader.service.ts "Defined in new-version-uploader.service.ts")
Display a dialog that allows to upload new file version or to manage the current node versions.
## Class members
### Methods
- **openUploadNewVersionDialog**(data: [NewVersionUploaderDialogData](../../../lib/content-services/src/lib/new-version-uploader/models/new-version-uploader.model.ts), config: `MatDialogConfig`): `Observable`<br/>
Opens a dialog to upload new file version or to manage current node versions
- _data:_ [NewVersionUploaderDialogData](../../../lib/content-services/src/lib/new-version-uploader/models/new-version-uploader.model.ts) - The data to pass to the dialog
- _config:_ `MatDialogConfig` - A configuration object that allows to override default dialog configuration
- **Returns** `Observable` - [`Observable`](http://reactivex.io/documentation/observable.html) which you can subscribe in order to get information about the dialog actions or error notification in case of error condition.
## Details
You can open dialog in two different ways:
- [Upload new file version](#upload-new-version)
- [Manage node versions](#manage-versions)
### Upload New Version
The dialog shows
- a side by side comparison between the current target node (type, name, icon) and the new file that should update it's version
- the new version's minor/major changes
- the optional comment
- a button to upload a new file version
![Upload new version image](../../docassets/images/adf-new-version-uploader_upload.png)
Usage example:
```ts
import { NewVersionUploaderService } from '@alfresco/adf-content-services'
constructor(private newVersionUploaderService: NewVersionUploaderService){}
yourFunctionToOpenDialog(){
const newVersionUploaderDialogData: NewVersionUploaderDialogData = {
file,
node
};
this.newVersionUploaderService.openUploadNewVersionDialog(newVersionUploaderDialogData).subscribe(
(data: NewVersionUploaderData) => {
// place your action here on operation success!
},
(error) => {
// place your action here on operation error!
})
}
```
---
### Manage Versions
Setting `showVersionsOnly` to `true` the dialog displays the version history of a node, with the ability to restore, delete and view version of the current node
![Manage versions image](../../docassets/images/adf-new-version-uploader_manage-versions.png)
Usage example:
```ts
import { NewVersionUploaderService } from '@alfresco/adf-content-services'
constructor(private newVersionUploaderService: NewVersionUploaderService){}
yourFunctionToOpenDialog(){
const newVersionUploaderDialogData: NewVersionUploaderDialogData = {
file,
node,
showVersionsOnly: true
};
this.newVersionUploaderService.openUploadNewVersionDialog(newVersionUploaderDialogData).subscribe(
(data: NewVersionUploaderData) => {
// place your action here on operation success!
})
}
```
## See Also
- [Version list component](../components/docs/content-services/components/version-list.component.md)
- [Version Comparison Component](../components/docs/content-services/components/version-comparison.component.md)
- [Version Upload Component](../components/docs/content-services/components/version-upload.component.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -22,6 +22,17 @@
"NO_LABEL": "No"
}
},
"ADF-NEW-VERSION-UPLOADER": {
"DIALOG_LIST": {
"TITLE": "Manage Versions",
"CLOSE": "Close"
},
"DIALOG_UPLOAD": {
"TITLE": "Upload New Version",
"CANCEL": "Cancel",
"UPLOAD": "Upload"
}
},
"ADF_VERSION_COMPARISON": {
"CURRENT_VERSION": "Current",
"NEW_VERSION": "New",

View File

@ -0,0 +1,182 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export const mockNode: any = ({
isFile: true,
createdByUser: { id: 'admin', displayName: 'Administrator' },
modifiedAt: '2017-05-24T15:08:55.640Z',
nodeType: 'cm:content',
content: {
mimeType: 'application/rtf',
mimeTypeName: 'Rich Text Format',
sizeInBytes: 14530,
encoding: 'UTF-8'
},
parentId: 'd124de26-6ba0-4f40-8d98-4907da2d337a',
createdAt: '2017-05-24T15:08:55.640Z',
path: {
name: '/Company Home/Guest Home',
isComplete: true,
elements: [{
id: '94acfc73-7014-4475-9bd9-93a2162f0f8c',
name: 'Company Home'
}, { id: 'd124de26-6ba0-4f40-8d98-4907da2d337a', name: 'Guest Home' }]
},
isFolder: false,
modifiedByUser: { id: 'admin', displayName: 'Administrator' },
name: 'b_txt_file.rtf',
id: '70e1cc6a-6918-468a-b84a-1048093b06fd',
properties: { 'cm:versionLabel': '1.0', 'cm:versionType': 'MAJOR' },
allowableOperations: ['delete', 'update']
});
export const mockFile = new File(['fakefake'], 'file-fake.png', { type: 'image/png' });
export const mockNewVersionUploaderData: any = {
action: 'upload',
newVersion: {
value: {
entry: {
isFile: true,
createdByUser: {
id: 'hruser',
displayName: 'hruser'
},
modifiedAt: '2022-05-24T10:19:43.544Z',
nodeType: 'cm:content',
content: {
mimeType:
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
mimeTypeName: 'Microsoft Word 2007',
sizeInBytes: 11887,
encoding: 'UTF-8'
},
parentId: '422538ca-ea4b-4086-83f9-b36e4521ec7f',
aspectNames: [
'rn:renditioned',
'cm:versionable',
'cm:titled',
'cm:auditable',
'cm:author',
'cm:thumbnailModification'
],
createdAt: '2022-05-24T07:26:44.429Z',
isFolder: false,
modifiedByUser: {
id: 'hruser',
displayName: 'hruser'
},
name: 'Test3.docx',
id: '42ddb84d-fc96-4b45-aa3c-f24ca997d602',
properties: {
'cm:versionType': 'MINOR',
'cm:versionLabel': '1.1',
'cm:author': 'Amedeo Lepore',
'cm:lastThumbnailModification': ['doclib:1653377205499']
},
allowableOperations: ['delete', 'update', 'updatePermissions']
}
}
},
currentVersion: {
isFile: true,
createdByUser: {
id: 'hruser',
displayName: 'hruser'
},
modifiedAt: '2022-05-24T07:26:45.337Z',
nodeType: 'cm:content',
content: {
mimeType:
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
mimeTypeName: 'Microsoft Word 2007',
sizeInBytes: 11949,
encoding: 'UTF-8'
},
parentId: '422538ca-ea4b-4086-83f9-b36e4521ec7f',
aspectNames: [
'rn:renditioned',
'cm:versionable',
'cm:titled',
'cm:auditable',
'cm:author',
'cm:thumbnailModification'
],
createdAt: '2022-05-24T07:26:44.429Z',
path: {
name: '/Company Home/User Homes/hruser',
isComplete: true,
elements: [
{
id: '4e2284fd-9457-4914-a612-ea844e87f53f',
name: 'Company Home',
nodeType: 'cm:folder',
aspectNames: ['cm:titled', 'cm:auditable', 'app:uifacets']
},
{
id: '75a5d2d2-6edb-40b6-822e-499f5e8beffb',
name: 'User Homes',
nodeType: 'cm:folder',
aspectNames: ['cm:titled', 'cm:auditable', 'app:uifacets']
},
{
id: '422538ca-ea4b-4086-83f9-b36e4521ec7f',
name: 'hruser',
nodeType: 'cm:folder',
aspectNames: ['cm:ownable', 'cm:auditable']
}
]
},
isFolder: false,
permissions: {
inherited: [
{
authorityId: 'ROLE_OWNER',
name: 'All',
accessStatus: 'ALLOWED'
},
{
authorityId: 'hruser',
name: 'All',
accessStatus: 'ALLOWED'
}
],
settable: [
'Contributor',
'Collaborator',
'Coordinator',
'Editor',
'Consumer'
],
isInheritanceEnabled: true
},
modifiedByUser: {
id: 'hruser',
displayName: 'hruser'
},
name: 'Test2.docx',
id: '42ddb84d-fc96-4b45-aa3c-f24ca997d602',
properties: {
'cm:versionType': 'MAJOR',
'cm:versionLabel': '1.0',
'cm:author': 'Amedeo Lepore',
'cm:lastThumbnailModification': ['doclib:1653377205499']
},
allowableOperations: ['delete', 'update', 'updatePermissions'],
isExternal: true
}
};

View File

@ -22,3 +22,4 @@ export * from './search.service.mock';
export * from './search-filter-mock';
export * from './sites-dropdown.component.mock';
export * from './search-query.mock';
export * from './new-version-uploader.service.mock';

View File

@ -0,0 +1,18 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './public-api';

View File

@ -0,0 +1,17 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './new-version-uploader.model';

View File

@ -0,0 +1,55 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { MinimalNodeEntryEntity, Version, NodeChildAssociation, Node } from '@alfresco/js-api';
import { NodeEntityEvent } from '../../document-list';
export interface NewVersionUploaderDialogData {
title?: string;
node: MinimalNodeEntryEntity;
file?: File;
currentVersion?: Version;
showVersionsOnly?: boolean;
}
export type NewVersionUploaderData = VersionManagerUploadData | ViewVersion | RefreshData;
// eslint-disable-next-line no-shadow
export enum NewVersionUploaderDataAction {
refresh = 'refresh',
upload = 'upload',
view = 'view'
}
interface BaseData {
action: NewVersionUploaderDataAction;
}
export interface VersionManagerUploadData extends BaseData {
action: NewVersionUploaderDataAction.upload;
newVersion: NodeEntityEvent;
currentVersion: NodeChildAssociation;
}
export interface ViewVersion extends BaseData {
action: NewVersionUploaderDataAction.view;
versionId: string;
}
export interface RefreshData extends BaseData {
action: NewVersionUploaderDataAction.refresh;
node: Node;
}

View File

@ -0,0 +1,33 @@
<header mat-dialog-title>{{ title | translate }}</header>
<section mat-dialog-content *ngIf="!data.showVersionsOnly">
<adf-version-comparison id="adf-version-comparison" [newFileVersion]="data.file" [node]="data.node"></adf-version-comparison>
<adf-version-upload
id="adf-version-upload-button"
[node]="data.node"
[newFileVersion]="data.file"
[currentVersion]="data.currentVersion"
(success)="handleUpload($event)"
(cancel)="handleCancel()"
(error)="onUploadError($event)"
>
</adf-version-upload>
</section>
<ng-container *ngIf="data.showVersionsOnly">
<section mat-dialog-content>
<div class="adf-version-list-container">
<div class="adf-version-list-table">
<adf-version-list
[node]="data.node"
[showComments]="'adf-version-manager.allowComments' | adfAppConfig: true"
[allowDownload]="'adf-version-manager.allowDownload' | adfAppConfig: true"
(deleted)="refresh($event)"
(restored)="refresh($event)"
(viewVersion)="onViewingVersion($event)"
></adf-version-list>
</div>
</div>
</section>
<footer mat-dialog-actions>
<button mat-button color="primary" [mat-dialog-close]="true">{{ 'ADF-NEW-VERSION-UPLOADER.DIALOG_LIST.CLOSE' | translate }}</button>
</footer>
</ng-container>

View File

@ -0,0 +1,79 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.adf-new-version-uploader-dialog {
&-list {
height: 400px;
}
&-upload {
height: 500px;
}
.mat-dialog {
&-title {
flex: 0 0 auto;
font-size: 20px;
font-weight: 600;
font-style: normal;
font-stretch: normal;
line-height: 1.6;
margin: 0;
letter-spacing: -0.5px;
color: var(--theme-text-bold-color);
}
&-content {
flex: 1 1 auto;
position: relative;
overflow-y: auto;
max-height: 100vh;
overflow: hidden;
padding: 2px 26px;
}
&-actions {
/* stylelint-disable-next-line shorthand-property-no-redundant-values */
padding: 8px 8px 24px 8px;
display: flex;
justify-content: flex-end;
color: var(--theme-text-color);
button {
text-transform: uppercase;
font-weight: normal;
}
}
}
.mat-list-item-content {
padding: 0;
margin: 0 16px;
}
.adf-version-list-container {
.adf-version-list {
height: 250px;
overflow: hidden;
padding: 0;
}
.mat-list.adf-version-list {
overflow: auto;
}
}
}

View File

@ -0,0 +1,209 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { TranslateModule } from '@ngx-translate/core';
import { setupTestBed } from 'core';
import { mockFile, mockNode } from '../mock';
import { ContentTestingModule } from '../testing/content.testing.module';
import { UploadVersionButtonComponent } from '../upload';
import { VersionComparisonComponent, VersionListComponent, VersionUploadComponent } from '../version-manager';
import { NewVersionUploaderDataAction } from './models';
import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog';
describe('NewVersionUploaderDialog', () => {
let component: NewVersionUploaderDialogComponent;
let fixture: ComponentFixture<NewVersionUploaderDialogComponent>;
let nativeElement;
const cssSelectors = {
adfVersionUploadButton: '#adf-version-upload-button',
adfVersionComparison: '#adf-version-comparison',
adfVersionList: '.adf-version-list',
matDialogTitle: '.mat-dialog-title'
};
const mockDialogRef = {
close: jasmine.createSpy('close'),
open: jasmine.createSpy('open')
};
const showVersionsOnly = true;
setupTestBed({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
declarations: [
NewVersionUploaderDialogComponent,
VersionListComponent,
VersionUploadComponent,
UploadVersionButtonComponent,
VersionComparisonComponent
],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: { node: mockNode, showVersionsOnly, file: mockFile } },
{
provide: MatDialogRef, useValue: mockDialogRef
}
]
});
beforeEach(() => {
fixture = TestBed.createComponent(NewVersionUploaderDialogComponent);
component = fixture.componentInstance;
nativeElement = fixture.debugElement.nativeElement;
});
afterEach(() => {
fixture.destroy();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('Upload New Version', () => {
const expectedUploadNewVersionTitle = 'ADF-NEW-VERSION-UPLOADER.DIALOG_UPLOAD.TITLE';
it('should display adf version upload button if showVersionsOnly is passed as false from parent component', () => {
component.data.showVersionsOnly = false;
fixture.detectChanges();
const adfVersionComponent = nativeElement.querySelector(cssSelectors.adfVersionUploadButton);
expect(adfVersionComponent).not.toEqual(null);
});
it('should display adf version comparison if showVersionsOnly is passed as false from parent component', () => {
component.data.showVersionsOnly = false;
fixture.detectChanges();
const adfVersionComparisonComponent = nativeElement.querySelector(cssSelectors.adfVersionComparison);
expect(adfVersionComparisonComponent).not.toEqual(null);
});
it('should not display adf version list if showVersionsOnly is passed as false from parent component', () => {
component.data.showVersionsOnly = false;
fixture.detectChanges();
const adfVersionComparisonComponent = nativeElement.querySelector(cssSelectors.adfVersionList);
expect(adfVersionComparisonComponent).toEqual(null);
});
it('should show default title if title is not provided from parent component', () => {
component.data.showVersionsOnly = false;
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
expect(matDialogTitle.innerHTML).toEqual(expectedUploadNewVersionTitle);
});
it('should show default title if title is provided as empty from parent component', () => {
component.data.showVersionsOnly = false;
component.data.title = '';
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
expect(matDialogTitle.innerHTML).toEqual(expectedUploadNewVersionTitle);
});
it('should not show Upload New Version default title if title is provided from parent component', () => {
component.data.showVersionsOnly = false;
component.data.title = 'TEST_TITLE';
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
expect(matDialogTitle.innerHTML).toEqual('TEST_TITLE');
});
it('should emit dialog action when upload a new file', () => {
const spyOnDialogAction = spyOn(component.dialogAction, 'emit');
component.data.showVersionsOnly = false;
fixture.detectChanges();
component.handleUpload(mockNode);
const expectedEmittedValue = {
action: NewVersionUploaderDataAction.upload,
currentVersion: component.data.node,
newVersion: mockNode
};
expect(spyOnDialogAction).toHaveBeenCalledWith(expectedEmittedValue);
});
it('should close dialog after file is uploaded', () => {
component.data.showVersionsOnly = false;
fixture.detectChanges();
component.handleUpload(mockFile);
expect(mockDialogRef.close).toHaveBeenCalled();
});
it('should close dialog after click on dialog cancel', () => {
component.data.showVersionsOnly = false;
fixture.detectChanges();
component.handleCancel();
expect(mockDialogRef.close).toHaveBeenCalled();
});
});
describe('Manage Versions', () => {
const expectedManageVersionsTitle = 'ADF-NEW-VERSION-UPLOADER.DIALOG_LIST.TITLE';
it('should display adf version list if showVersionsOnly is passed as true from parent component', () => {
component.data.showVersionsOnly = true;
fixture.detectChanges();
const adfVersionListComponent = document.querySelector(cssSelectors.adfVersionList);
expect(adfVersionListComponent).not.toEqual(null);
});
it('should not display adf version upload button if showVersionsOnly is passed as true from parent component', () => {
component.data.showVersionsOnly = true;
fixture.detectChanges();
const adfVersionComponent = nativeElement.querySelector(cssSelectors.adfVersionUploadButton);
expect(adfVersionComponent).toEqual(null);
});
it('should not display adf version comparison if showVersionsOnly is passed as true from parent component', () => {
component.data.showVersionsOnly = true;
fixture.detectChanges();
const adfVersionComponent = nativeElement.querySelector(cssSelectors.adfVersionComparison);
expect(adfVersionComponent).toEqual(null);
});
it('should show Manage Versions default title if title is not provided from parent component', () => {
component.data.showVersionsOnly = true;
component.data.title = undefined;
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
expect(matDialogTitle.innerHTML).toEqual(expectedManageVersionsTitle);
});
it('should show Manage Versions default title if title is provided as empty from parent component', () => {
component.data.showVersionsOnly = true;
component.data.title = '';
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
expect(matDialogTitle.innerHTML).toEqual(expectedManageVersionsTitle);
});
it('should not show Manage Versions default title if title is provided from parent component', () => {
component.data.showVersionsOnly = true;
component.data.title = 'TEST_TITLE';
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
expect(matDialogTitle.innerHTML).toEqual('TEST_TITLE');
});
});
});

View File

@ -0,0 +1,83 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Node } from '@alfresco/js-api';
import { Component, EventEmitter, Inject, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { NewVersionUploaderDialogData, NewVersionUploaderData, NewVersionUploaderDataAction } from './models';
@Component({
selector: 'adf-new-version-uploader-dialog',
templateUrl: './new-version-uploader.dialog.html',
styleUrls: ['./new-version-uploader.dialog.scss'],
encapsulation: ViewEncapsulation.None
})
export class NewVersionUploaderDialogComponent implements OnInit {
/**
* Dialog title to show into the header.
* If data.title is not provided, a default title is set
* */
title: string;
/** Emitted when an action is done. */
@Output()
dialogAction = new EventEmitter<NewVersionUploaderData>();
/** Emitted when an error occurs. */
@Output()
uploadError = new EventEmitter<any>();
constructor(
@Inject(MAT_DIALOG_DATA) public data: NewVersionUploaderDialogData,
private dialogRef: MatDialogRef<NewVersionUploaderDialogComponent>
) { }
ngOnInit(): void {
this.setDialogTitle();
}
private setDialogTitle() {
if (!this.data.title) {
this.title = this.data.showVersionsOnly ? 'ADF-NEW-VERSION-UPLOADER.DIALOG_LIST.TITLE' : 'ADF-NEW-VERSION-UPLOADER.DIALOG_UPLOAD.TITLE';
} else {
this.title = this.data.title;
}
}
handleUpload(newFileVersion) {
this.dialogAction.emit({ action: NewVersionUploaderDataAction.upload, newVersion: newFileVersion, currentVersion: this.data.node });
this.dialogRef.close();
}
handleCancel() {
this.dialogRef.close();
}
onUploadError(error) {
this.uploadError.emit(error);
}
onViewingVersion(versionId: string) {
this.dialogAction.emit({ action: NewVersionUploaderDataAction.view, versionId });
}
refresh(node: Node) {
this.dialogAction.emit({ action: NewVersionUploaderDataAction.refresh, node });
}
}

View File

@ -0,0 +1,46 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';
import { MaterialModule } from '../material.module';
import { UploadModule } from '../upload/upload.module';
import { CoreModule } from '@alfresco/adf-core';
import { VersionManagerModule } from '../version-manager';
import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog';
@NgModule({
imports: [
CommonModule,
MaterialModule,
CoreModule,
UploadModule,
FormsModule,
VersionManagerModule
],
declarations: [
NewVersionUploaderDialogComponent
],
exports: [
NewVersionUploaderDialogComponent,
FormsModule
]
})
export class NewVersionUploaderModule { }

View File

@ -0,0 +1,242 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ContentService } from '@alfresco/adf-core';
import { Component, EventEmitter, Output } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { TranslateModule } from '@ngx-translate/core';
import { BehaviorSubject, of, Subject } from 'rxjs';
import { mockFile, mockNewVersionUploaderData, mockNode } from '../mock';
import { ContentTestingModule } from '../testing/content.testing.module';
import { NewVersionUploaderData, NewVersionUploaderDataAction, NewVersionUploaderDialogData, RefreshData, VersionManagerUploadData, ViewVersion } from './models';
import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog';
import { NewVersionUploaderService } from './new-version-uploader.service';
@Component({
template: ''
})
class TestDialogComponent {
@Output()
dialogAction = new EventEmitter<NewVersionUploaderData>();
@Output()
uploadError = new EventEmitter<any>();
afterClosed = () => of({ action: 'refresh', node: mockNode });
}
describe('NewVersionUploaderService', () => {
let fixture: ComponentFixture<TestDialogComponent>;
let service: NewVersionUploaderService;
let contentService: ContentService;
let dialog: MatDialog;
let spyOnDialogOpen: jasmine.Spy;
let dialogRefSpyObj;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
declarations: [TestDialogComponent]
});
});
beforeEach(() => {
service = TestBed.inject(NewVersionUploaderService);
contentService = TestBed.inject(ContentService);
dialog = TestBed.inject(MatDialog);
fixture = TestBed.createComponent(TestDialogComponent);
dialogRefSpyObj = jasmine.createSpyObj({ afterClosed: null });
dialogRefSpyObj.componentInstance = fixture.componentInstance;
dialogRefSpyObj.afterClosed = fixture.componentInstance.afterClosed;
spyOnDialogOpen = spyOn(dialog, 'open').and.returnValue(dialogRefSpyObj);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
describe('openUploadNewVersionDialog', () => {
it('Should not open dialog if update operation is not allowed', () => {
spyOn(contentService, 'hasAllowableOperations').and.returnValue(false);
expect(spyOnDialogOpen).not.toHaveBeenCalled();
});
it('Should return error if update operation is not allowed', async () => {
spyOn(contentService, 'hasAllowableOperations').and.returnValue(false);
const mockNewVersionUploaderDialogData: NewVersionUploaderDialogData = {
node: mockNode,
file: mockFile
};
try {
await service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData).toPromise();
fail('An error should have been thrown');
} catch (error) {
expect(error).toEqual({ value: 'OPERATION.ERROR.PERMISSION' });
}
});
describe('Mat Dialog configuration', () => {
let mockNewVersionUploaderDialogData: NewVersionUploaderDialogData;
beforeEach(() => {
spyOn(contentService, 'hasAllowableOperations').and.returnValue(true);
spyOn(service.versionsApi, 'listVersionHistory').and.returnValue(Promise.resolve({
list: { entries: [{ entry: '2' }] }
}));
mockNewVersionUploaderDialogData = {
node: mockNode,
file: mockFile
};
});
it('Should open dialog with default configuration', fakeAsync(() => {
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData).toPromise();
tick();
expect(spyOnDialogOpen).toHaveBeenCalledWith(NewVersionUploaderDialogComponent, {
data: { file: mockFile, node: mockNode, currentVersion: '2', showComments: true, allowDownload: true, showVersionsOnly: undefined },
panelClass: ['adf-new-version-uploader-dialog', 'adf-new-version-uploader-dialog-upload'],
width: '630px'
});
}));
it('Should override default dialog panelClass', fakeAsync(() => {
const mockDialogConfiguration: MatDialogConfig = {
panelClass: 'adf-custom-class',
width: '500px'
};
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData, mockDialogConfiguration).toPromise();
tick();
expect(spyOnDialogOpen).toHaveBeenCalledWith(NewVersionUploaderDialogComponent, {
data: { file: mockFile, node: mockNode, currentVersion: '2', showComments: true, allowDownload: true, showVersionsOnly: undefined },
panelClass: 'adf-custom-class',
width: '500px'
});
}));
it('Should set dialog height', fakeAsync(() => {
const mockDialogConfiguration: MatDialogConfig = {
height: '600px'
};
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData, mockDialogConfiguration).toPromise();
tick();
expect(spyOnDialogOpen).toHaveBeenCalledWith(NewVersionUploaderDialogComponent, {
data: { file: mockFile, node: mockNode, currentVersion: '2', showComments: true, allowDownload: true, showVersionsOnly: undefined },
panelClass: ['adf-new-version-uploader-dialog', 'adf-new-version-uploader-dialog-upload'],
width: '630px',
height: '600px'
});
}));
it('Should not override dialog configuration, if dialog configuration is empty', fakeAsync(() => {
const mockDialogConfiguration: MatDialogConfig = {};
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData, mockDialogConfiguration).toPromise();
tick();
expect(spyOnDialogOpen).toHaveBeenCalledWith(NewVersionUploaderDialogComponent, {
data: { file: mockFile, node: mockNode, currentVersion: '2', showComments: true, allowDownload: true, showVersionsOnly: undefined },
panelClass: ['adf-new-version-uploader-dialog', 'adf-new-version-uploader-dialog-upload'],
width: '630px'
});
}));
it('Should dialog add list css class if showVersionsOnly is true', fakeAsync(() => {
const mockNewVersionUploaderDialogDataWithVersionsOnly = {
node: mockNode,
file: mockFile,
showVersionsOnly: true
};
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogDataWithVersionsOnly).toPromise();
tick();
expect(spyOnDialogOpen).toHaveBeenCalledWith(NewVersionUploaderDialogComponent, {
data: { file: mockFile, node: mockNode, currentVersion: '2', showComments: true, allowDownload: true, showVersionsOnly: true },
panelClass: ['adf-new-version-uploader-dialog', 'adf-new-version-uploader-dialog-list'],
width: '630px'
});
}));
});
describe('Subscribe events from Dialog', () => {
let mockNewVersionUploaderDialogData: NewVersionUploaderDialogData;
beforeEach(() => {
spyOn(contentService, 'hasAllowableOperations').and.returnValue(true);
spyOn(service.versionsApi, 'listVersionHistory').and.returnValue(Promise.resolve({
list: { entries: [{ entry: '2' }] }
}));
mockNewVersionUploaderDialogData = {
node: mockNode,
file: mockFile
};
});
it('Should return Refresh action', (done) => {
dialogRefSpyObj.componentInstance = {
dialogAction: new BehaviorSubject<RefreshData>({ action: NewVersionUploaderDataAction.refresh, node: mockNode }),
uploadError: new Subject()
};
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData).subscribe((res) => {
expect(res).toEqual({ action: NewVersionUploaderDataAction.refresh, node: mockNode });
done();
});
});
it('Should return Upload action', (done) => {
dialogRefSpyObj.componentInstance = {
dialogAction: new BehaviorSubject<VersionManagerUploadData>(mockNewVersionUploaderData),
uploadError: new Subject()
};
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData).subscribe((res) => {
expect(res).toEqual(mockNewVersionUploaderData);
done();
});
});
it('Should return View Version action', (done) => {
dialogRefSpyObj.componentInstance = {
dialogAction: new BehaviorSubject<ViewVersion>({ action: NewVersionUploaderDataAction.view, versionId: '2' }),
uploadError: new Subject()
};
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData).subscribe((res) => {
expect(res).toEqual({ action: NewVersionUploaderDataAction.view, versionId: '2' });
done();
});
});
it('Should return upload error', (done) => {
dialogRefSpyObj.componentInstance = {
dialogAction: new Subject(),
uploadError: new BehaviorSubject<any>({ value: 'Upload error' })
};
spyOnDialogOpen.and.returnValue(dialogRefSpyObj);
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData).subscribe(() => {
fail('An error should have been thrown');
},
error => {
expect(error).toEqual({ value: 'Upload error' });
done();
});
});
});
});
});

View File

@ -0,0 +1,86 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { AlfrescoApiService, ContentService } from '@alfresco/adf-core';
import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog';
import { VersionPaging, VersionsApi } from '@alfresco/js-api';
import { NewVersionUploaderData, NewVersionUploaderDialogData } from './models';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class NewVersionUploaderService {
_versionsApi: VersionsApi;
get versionsApi(): VersionsApi {
this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance());
return this._versionsApi;
}
constructor(
private contentService: ContentService,
private apiService: AlfrescoApiService,
private dialog: MatDialog
) { }
/**
* Open a dialog NewVersionUploaderDialogComponent to display:
* - a side by side comparison between the current target node (type, name, icon) and the new file that should update it's version
* - the new version's minor/major changes and the optional comment of a node and the ability to upload a new file version
* - if data.showVersionsOnly is set to true, displays the version history of a node, with the ability to restore, delete and view version of the current node
* @param data data to pass to MatDialog
* @param config allow to override default MatDialogConfig
* @returns an Observable represents the triggered dialog action or an error in case of an error condition
*/
openUploadNewVersionDialog(data: NewVersionUploaderDialogData, config?: MatDialogConfig) {
const { file, node, showVersionsOnly } = data;
const showComments = true;
const allowDownload = true;
return new Observable((observer) => {
if (this.contentService.hasAllowableOperations(node, 'update')) {
this.versionsApi.listVersionHistory(node.id).then((versionPaging: VersionPaging) => {
const dialogRef = this.dialog.open(NewVersionUploaderDialogComponent, {
data: { file, node, currentVersion: versionPaging.list.entries[0].entry, showComments, allowDownload, showVersionsOnly },
panelClass: this.composePanelClass(showVersionsOnly),
width: '630px',
...(config && Object.keys(config).length > 0 && config)
});
dialogRef.componentInstance.dialogAction.asObservable()
.subscribe((newVersionUploaderData: NewVersionUploaderData) => {
observer.next(newVersionUploaderData);
});
dialogRef.componentInstance.uploadError.asObservable().subscribe(error => {
observer.error(error);
});
});
} else {
observer.error({ value: 'OPERATION.ERROR.PERMISSION' });
}
});
}
private composePanelClass(showVersionsOnly: boolean): string | string[] {
const dialogCssClass = 'adf-new-version-uploader-dialog';
return [dialogCssClass, `${dialogCssClass}-${showVersionsOnly ? 'list' : 'upload'}`];
}
}

View File

@ -0,0 +1,21 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './new-version-uploader.dialog';
export * from './new-version-uploader.module';
export * from './new-version-uploader.service';
export * from './models';

View File

@ -35,5 +35,6 @@ export * from './lib/tree-view/index';
export * from './lib/group/index';
export * from './lib/aspect-list/index';
export * from './lib/content-type/index';
export * from './lib/new-version-uploader';
export * from './lib/content.module';

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

@ -62,6 +62,14 @@
<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>

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,