[ACS-5839] migrate to latest JS-API types ()

* [ci:force] migrate Minimal Node to Node

* [ci:force] remove js-api wrappers and use real types

* [ci:force] remove js-api wrappers and use real types

* [ci:force] fix linting errors

* [ci:force] fix linting errors

* [ci:force] security fixes

* [ci:force] sonarcloud bug fixes

* [ci:force] dead code elimination, sonar suggested fixes
This commit is contained in:
Denys Vuika 2023-08-29 20:56:40 +01:00 committed by GitHub
parent a5b05b3e5f
commit 3b4ce3b857
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 1337 additions and 1984 deletions
demo-shell/src/app/components
docs
lib
content-services/src/lib
core/src/lib/mock
process-services-cloud/src/lib/form
process-services/src/lib
tsconfig.json

@ -31,7 +31,7 @@ import {
import { Location } from '@angular/common';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { MinimalNodeEntity, NodePaging, Pagination, MinimalNodeEntryEntity, SiteEntry, SearchEntry } from '@alfresco/js-api';
import { NodeEntry, NodePaging, Pagination, Node, SiteEntry, SearchEntry } from '@alfresco/js-api';
import {
NotificationService,
DataRow,
@ -71,12 +71,9 @@ const DEFAULT_FOLDER_TO_SHOW = '-my-';
templateUrl: './files.component.html',
styleUrls: ['./files.component.scss'],
encapsulation: ViewEncapsulation.None,
providers: [
{provide: FormRenderingService, useClass: ProcessFormRenderingService}
]
providers: [{ provide: FormRenderingService, useClass: ProcessFormRenderingService }]
})
export class FilesComponent implements OnInit, OnChanges, OnDestroy {
protected onDestroy$ = new Subject<boolean>();
errorMessage: string = null;
@ -88,9 +85,9 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
includeFields = ['isFavorite', 'isLocked', 'aspectNames', 'definition'];
selectionModes = [
{value: 'none', viewValue: 'None'},
{value: 'single', viewValue: 'Single'},
{value: 'multiple', viewValue: 'Multiple'}
{ value: 'none', viewValue: 'None' },
{ value: 'single', viewValue: 'Single' },
{ value: 'multiple', viewValue: 'Multiple' }
];
// The identifier of a node. You can also use one of these well-known aliases: -my- | -shared- | -root-
@ -199,13 +196,13 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
@Output()
deleteElementSuccess: EventEmitter<any> = new EventEmitter();
@ViewChild('documentList', {static: true})
@ViewChild('documentList', { static: true })
documentList: DocumentListComponent;
@ViewChild('standardPagination')
standardPagination: PaginationComponent;
@ViewChild(InfinitePaginationComponent, {static: true})
@ViewChild(InfinitePaginationComponent, { static: true })
infinitePaginationComponent: InfinitePaginationComponent;
permissionsStyle: PermissionStyleModel[] = [];
@ -217,19 +214,20 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
displayEmptyMetadata = false;
hyperlinkNavigation = false;
constructor(private notificationService: NotificationService,
private uploadService: UploadService,
private contentService: ContentService,
private dialog: MatDialog,
private location: Location,
private router: Router,
private preference: UserPreferencesService,
private preview: PreviewService,
@Optional() private route: ActivatedRoute,
private contentMetadataService: ContentMetadataService,
private dialogAspectListService: DialogAspectListService,
private nodeService: NodesApiService) {
}
constructor(
private notificationService: NotificationService,
private uploadService: UploadService,
private contentService: ContentService,
private dialog: MatDialog,
private location: Location,
private router: Router,
private preference: UserPreferencesService,
private preview: PreviewService,
@Optional() private route: ActivatedRoute,
private contentMetadataService: ContentMetadataService,
private dialogAspectListService: DialogAspectListService,
private nodeService: NodesApiService
) {}
showFile(event) {
const entry = event.value.entry;
@ -273,27 +271,17 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
this.onFileUploadEvent(value[0]);
});
this.uploadService.fileUploadDeleted
.pipe(takeUntil(this.onDestroy$))
.subscribe(value => this.onFileUploadEvent(value));
this.uploadService.fileUploadDeleted.pipe(takeUntil(this.onDestroy$)).subscribe((value) => this.onFileUploadEvent(value));
this.contentService.folderCreated
.pipe(takeUntil(this.onDestroy$))
.subscribe(value => this.onFolderCreated(value));
this.contentService.folderCreated.pipe(takeUntil(this.onDestroy$)).subscribe((value) => this.onFolderCreated(value));
this.contentService.folderCreate
.pipe(takeUntil(this.onDestroy$))
.subscribe(value => this.onFolderAction(value));
this.contentService.folderCreate.pipe(takeUntil(this.onDestroy$)).subscribe((value) => this.onFolderAction(value));
this.contentService.folderEdit
.pipe(takeUntil(this.onDestroy$))
.subscribe(value => this.onFolderAction(value));
this.contentService.folderEdit.pipe(takeUntil(this.onDestroy$)).subscribe((value) => this.onFolderAction(value));
this.contentMetadataService.error
.pipe(takeUntil(this.onDestroy$))
.subscribe((err: { message: string }) => {
this.notificationService.showError(err.message);
});
this.contentMetadataService.error.pipe(takeUntil(this.onDestroy$)).subscribe((err: { message: string }) => {
this.notificationService.showError(err.message);
});
}
onFileUploadEvent(event: FileUploadEvent) {
@ -326,9 +314,9 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
} as Pagination;
}
getCurrentDocumentListNode(): MinimalNodeEntity[] {
getCurrentDocumentListNode(): NodeEntry[] {
if (this.documentList.folderNode) {
return [{entry: this.documentList.folderNode}];
return [{ entry: this.documentList.folderNode }];
} else {
return [];
}
@ -416,7 +404,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
if (this.contentService.hasAllowableOperations(contentEntry, 'update')) {
this.dialog.open(VersionManagerDialogAdapterComponent, {
data: {contentEntry, showComments, allowDownload},
data: { contentEntry, showComments, allowDownload },
panelClass: 'adf-version-manager-dialog',
width: '630px'
});
@ -427,7 +415,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
onAspectUpdate(event: any) {
this.dialogAspectListService.openAspectListDialog(event.value.entry.id).subscribe((aspectList) => {
this.nodeService.updateNode(event.value.entry.id, {aspectNames: [...aspectList]}).subscribe(() => {
this.nodeService.updateNode(event.value.entry.id, { aspectNames: [...aspectList] }).subscribe(() => {
this.openSnackMessageInfo('Node Aspects Updated');
});
});
@ -476,7 +464,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
return null;
}
canEditFolder(selection: Array<MinimalNodeEntity>): boolean {
canEditFolder(selection: Array<NodeEntry>): boolean {
if (selection && selection.length === 1) {
const entry = selection[0].entry;
@ -487,7 +475,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
return false;
}
canCreateContent(parentNode: MinimalNodeEntryEntity): boolean {
canCreateContent(parentNode: Node): boolean {
if (parentNode) {
return this.contentService.hasAllowableOperations(parentNode, 'create');
}
@ -521,10 +509,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
toggleGalleryView(): void {
this.displayMode = this.displayMode === DisplayMode.List ? DisplayMode.Gallery : DisplayMode.List;
const url = this
.router
.createUrlTree(['/files', this.currentFolderId, 'display', this.displayMode])
.toString();
const url = this.router.createUrlTree(['/files', this.currentFolderId, 'display', this.displayMode]).toString();
this.location.go(url);
}
@ -611,7 +596,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
objectFromMap[filter.key] = paramValue;
});
this.router.navigate([], {relativeTo: this.route, queryParams: objectFromMap});
this.router.navigate([], { relativeTo: this.route, queryParams: objectFromMap });
}
clearFilterNavigation() {

@ -17,20 +17,17 @@
import { Component, Inject, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
import { Node } from '@alfresco/js-api';
@Component({
templateUrl: './metadata-dialog-adapter.component.html',
encapsulation: ViewEncapsulation.None
})
export class MetadataDialogAdapterComponent {
public contentEntry: MinimalNodeEntryEntity;
contentEntry: Node;
displayEmptyMetadata = false;
constructor(@Inject(MAT_DIALOG_DATA) data: any,
private containingDialog?: MatDialogRef<MetadataDialogAdapterComponent>) {
constructor(@Inject(MAT_DIALOG_DATA) data: any, private containingDialog?: MatDialogRef<MetadataDialogAdapterComponent>) {
this.contentEntry = data.contentEntry;
this.displayEmptyMetadata = data.displayEmptyMetadata;
}

@ -17,7 +17,7 @@
import { Component, Inject, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
import { Node } from '@alfresco/js-api';
import { PreviewService } from '../../services/preview.service';
import { NotificationService } from '@alfresco/adf-core';
import { FileUploadErrorEvent } from '@alfresco/adf-content-services';
@ -27,19 +27,19 @@ import { FileUploadErrorEvent } from '@alfresco/adf-content-services';
encapsulation: ViewEncapsulation.None
})
export class VersionManagerDialogAdapterComponent {
public contentEntry: MinimalNodeEntryEntity;
public newFileVersion: File;
contentEntry: Node;
newFileVersion: File;
showComments = true;
allowDownload = true;
readOnly = false;
showVersionComparison = false;
constructor(private previewService: PreviewService,
private notificationService: NotificationService,
@Inject(MAT_DIALOG_DATA) data: any,
private containingDialog?: MatDialogRef<VersionManagerDialogAdapterComponent>) {
constructor(
private previewService: PreviewService,
private notificationService: NotificationService,
@Inject(MAT_DIALOG_DATA) data: any,
private containingDialog?: MatDialogRef<VersionManagerDialogAdapterComponent>
) {
this.contentEntry = data.contentEntry;
this.newFileVersion = data.hasOwnProperty('newFileVersion') ? data.newFileVersion : this.newFileVersion;
this.showComments = data.hasOwnProperty('showComments') ? data.showComments : this.showComments;
@ -47,8 +47,7 @@ export class VersionManagerDialogAdapterComponent {
}
uploadError(event: FileUploadErrorEvent) {
const errorMessage = event.error;
this.notificationService.showError(errorMessage);
this.notificationService.showError(event.error);
}
close() {

@ -17,7 +17,7 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { MinimalNodeEntity } from '@alfresco/js-api';
import { NodeEntry } from '@alfresco/js-api';
import { PreviewService } from '../../services/preview.service';
@Component({
@ -26,9 +26,7 @@ import { PreviewService } from '../../services/preview.service';
styleUrls: ['./search-bar.component.scss']
})
export class SearchBarComponent {
constructor(public router: Router, private preview: PreviewService) {
}
constructor(public router: Router, private preview: PreviewService) {}
/**
* Called when the user submits the search, e.g. hits enter or clicks submit
@ -37,17 +35,19 @@ export class SearchBarComponent {
*/
onSearchSubmit(event: KeyboardEvent) {
const value = (event.target as HTMLInputElement).value;
this.router.navigate(['/search', {
q: value
}]);
this.router.navigate([
'/search',
{
q: value
}
]);
}
onItemClicked(event: MinimalNodeEntity) {
onItemClicked(event: NodeEntry) {
if (event.entry.isFile) {
this.preview.showResource(event.entry.id);
} else if (event.entry.isFolder) {
this.router.navigate(['/files', event.entry.id]);
}
}
}

@ -121,7 +121,7 @@ will trigger the same action.) You can also add your own handler by implementing
`execute` event.
Note that you can use _both_ a built-in handler and your own `execute`
function in the same action. The `execute` function is passed a [`NodeMinimalEntry`](../../../lib/content-services/src/lib/document-list/models/document-library.model.ts) as its
function in the same action. The `execute` function is passed a **NodeEntry** as its
parameter. For
example, with `handler="delete"` you could use `execute` to show a message with the name,
type, and other details of the item just deleted:

@ -15,11 +15,11 @@ Extends from [`BaseCardViewUpdate`](../../../lib/core/src/lib/card-view/interfac
```ts
export interface BaseCardViewContentUpdate {
itemUpdated$: Subject<UpdateNotification>;
updatedAspect$: Subject<MinimalNode>;
updatedAspect$: Subject<Node>;
update(property: CardViewBaseItemModel, newValue: any);
updateElement(notification: CardViewBaseItemModel);
updateNodeAspect(node: MinimalNode);
updateNodeAspect(node: Node);
}
```

@ -73,7 +73,7 @@ constructor(private contentDialogService: ContentNodeDialogService){}
yourFunctionOnCopyOrMove(){
this.contentDialogService
.openCopyMoveDialog(actionName, targetNode, neededPermissionForAction)
.subscribe((selections: MinimalNode[]) => {
.subscribe((selections: Node[]) => {
// place your action here on operation success!
});
}

@ -106,73 +106,6 @@ and the
[REST API Explorer](https://api-explorer.alfresco.com/api-explorer/#/nodes)
for more information.
### Getting node information
The `getNode` method gives access to the [`MinimalNode`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeMinimalEntry.md) object that represents the
details of a node:
```ts
interface MinimalNode extends Node {
   id: string;
   parentId: string;
   name: string;
   nodeType: string;
   isFolder: boolean;
   isFile: boolean;
   modifiedAt: Date;
   modifiedByUser: UserInfo;
   createdAt: Date;
   createdByUser: UserInfo;
   content: ContentInfo;
   path: PathInfoEntity;
   properties: NodeProperties;
}
```
This provides useful information about the node, such as its name, creation and
modification dates, etc. Also, the `id` and `parentId` properties contain the node
ID strings for the current node and its enclosing folder.
Sometimes, a [`MinimalNode`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeMinimalEntry.md) is provided directly, for example, the `folderNode` property
of a [Document List component](../../content-services/components/document-list.component.md) or the data context of a
[Document List row](../../content-services/components/document-list.component.md#underlying-node-object). In these cases,
you might pass the `id` or `parentId` as a [route parameter](https://angular.io/guide/router)
to a page describing the node in full detail. The component receiving the node ID can
use the [Nodes Api service](nodes-api.service.md) to "decode" the ID string into a [`MinimalNode`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeMinimalEntry.md):
```ts
import { ActivatedRoute, Router } from '@angular/router';
import { Component, OnInit } from '@angular/core';
import { NodesApiService } from '@alfresco/adf-core';
import { MinimalNode } from '@alfresco/js-api';
...
export class RepositoryDetailsPageComponent implements OnInit {
 nodeId: string;
 nodeName: string;
 isFile: boolean;
...
 constructor(private router: Router,
             private activatedRoute: ActivatedRoute,
             private nodeService: NodesApiService) {
 }
 ngOnInit() {
   this.nodeId = this.activatedRoute.snapshot.params['node-id'];
   this.nodeService.getNode(this.nodeId).subscribe((entry: MinimalNode) => {
     const node: MinimalNode = entry;
     this.nodeName = node.name;
     this.isFile = node.isFile;
...
   });
 }
```
You can supply a number of extra options using the `options` parameter. See the
[getNode](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodesApi.md#getNode)
page in the Alfresco JS API docs for more information.
### Getting folder node contents
The `getNodeChildren` method returns the contents of a folder

@ -133,9 +133,9 @@ to _alfresco-1002_ as follows:
You then need to pass the node as the input `values` object with the other properties:
```ts
let node: MinimalNode = null;
let node: Node = null;
this.nodesApiService.getNode(NODE_ID).subscribe((minimalNode) => this.node = minimalNode);
this.nodesApiService.getNode(NODE_ID).subscribe((res) => this.node = res);
const formValues: FormValues = {
'file' : node

@ -24,70 +24,74 @@ import { ContentTestingModule } from '../testing/content.testing.module';
import { AspectListDialogComponentData } from './aspect-list-dialog-data.interface';
import { AspectListService } from './services/aspect-list.service';
import { delay } from 'rxjs/operators';
import { AspectEntry, MinimalNode } from '@alfresco/js-api';
import { AspectEntry, Node } from '@alfresco/js-api';
import { NodesApiService } from '../common/services/nodes-api.service';
const aspectListMock: AspectEntry[] = [{
entry: {
parentId: 'frs:aspectZero',
id: 'frs:AspectOne',
description: 'First Aspect with random description',
title: 'FirstAspect',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:encrypted'
},
{
id: 'channelUsername',
title: 'The authenticated channel username',
dataType: 'd:encrypted'
}
]
const aspectListMock: AspectEntry[] = [
{
entry: {
parentId: 'frs:aspectZero',
id: 'frs:AspectOne',
description: 'First Aspect with random description',
title: 'FirstAspect',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:encrypted'
},
{
id: 'channelUsername',
title: 'The authenticated channel username',
dataType: 'd:encrypted'
}
]
}
},
{
entry: {
parentId: 'frs:AspectZer',
id: 'frs:SecondAspect',
description: 'Second Aspect description',
title: 'SecondAspect',
properties: [
{
id: 'assetId',
title: 'Published Asset Id',
dataType: 'd:text'
},
{
id: 'assetUrl',
title: 'Published Asset URL',
dataType: 'd:text'
}
]
}
}
},
{
entry: {
parentId: 'frs:AspectZer',
id: 'frs:SecondAspect',
description: 'Second Aspect description',
title: 'SecondAspect',
properties: [
{
id: 'assetId',
title: 'Published Asset Id',
dataType: 'd:text'
},
{
id: 'assetUrl',
title: 'Published Asset URL',
dataType: 'd:text'
}
]
}
}];
];
const customAspectListMock: AspectEntry[] = [{
entry: {
parentId: 'cst:customAspect',
id: 'cst:customAspect',
description: 'Custom Aspect with random description',
title: 'CustomAspect',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:propA'
},
{
id: 'channelUsername',
title: 'The authenticated channel username',
dataType: 'd:propB'
}
]
const customAspectListMock: AspectEntry[] = [
{
entry: {
parentId: 'cst:customAspect',
id: 'cst:customAspect',
description: 'Custom Aspect with random description',
title: 'CustomAspect',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:propA'
},
{
id: 'channelUsername',
title: 'The authenticated channel username',
dataType: 'd:propB'
}
]
}
}
}];
];
describe('AspectListDialogComponent', () => {
let fixture: ComponentFixture<AspectListDialogComponent>;
@ -97,10 +101,9 @@ describe('AspectListDialogComponent', () => {
const event = new KeyboardEvent('keydown', {
bubbles: true,
keyCode: 27
} as KeyboardEventInit );
} as KeyboardEventInit);
describe('Without passing node id', () => {
beforeEach(async () => {
data = {
title: 'Title',
@ -110,11 +113,7 @@ describe('AspectListDialogComponent', () => {
};
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule,
MatDialogModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule, MatDialogModule],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: data },
{
@ -156,7 +155,9 @@ describe('AspectListDialogComponent', () => {
expect(dialogTitle).not.toBeNull();
expect(dialogTitle.innerText).toBe(data.title);
const dialogDescription = fixture.nativeElement.querySelector('[data-automation-id="aspect-list-dialog-title"] .adf-aspect-list-dialog-description');
const dialogDescription = fixture.nativeElement.querySelector(
'[data-automation-id="aspect-list-dialog-title"] .adf-aspect-list-dialog-description'
);
expect(dialogDescription).not.toBeNull();
expect(dialogDescription.innerText).toBe(data.description);
@ -228,7 +229,11 @@ describe('AspectListDialogComponent', () => {
});
it('should complete the select stream Cancel button is clicked', (done) => {
data.select.subscribe(() => { }, () => { }, () => done());
data.select.subscribe(
() => {},
() => {},
() => done()
);
const cancelButton: HTMLButtonElement = fixture.nativeElement.querySelector('#aspect-list-dialog-actions-cancel');
expect(cancelButton).toBeDefined();
cancelButton.click();
@ -237,7 +242,6 @@ describe('AspectListDialogComponent', () => {
});
describe('Passing the node id', () => {
beforeEach(async () => {
data = {
title: 'Title',
@ -248,11 +252,7 @@ describe('AspectListDialogComponent', () => {
};
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule,
MatDialogModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule, MatDialogModule],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: data },
{
@ -274,7 +274,9 @@ describe('AspectListDialogComponent', () => {
spyOn(aspectListService, 'getAspects').and.returnValue(of([...aspectListMock, ...customAspectListMock]));
spyOn(aspectListService, 'getVisibleAspects').and.returnValue(['frs:AspectOne']);
spyOn(aspectListService, 'getCustomAspects').and.returnValue(of(customAspectListMock));
spyOn(nodeService, 'getNode').and.returnValue(of(new MinimalNode({ id: 'fake-node-id', aspectNames: ['frs:AspectOne', 'cst:customAspect'] })).pipe(delay(0)));
spyOn(nodeService, 'getNode').and.returnValue(
of(new Node({ id: 'fake-node-id', aspectNames: ['frs:AspectOne', 'cst:customAspect'] })).pipe(delay(0))
);
fixture = TestBed.createComponent(AspectListDialogComponent);
fixture.componentInstance.data.select = new Subject<string[]>();
fixture.detectChanges();
@ -326,5 +328,4 @@ describe('AspectListDialogComponent', () => {
expect(applyButton.disabled).toBe(false);
});
});
});

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { MinimalNode } from '@alfresco/js-api';
import { Node } from '@alfresco/js-api';
import { TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { NodesApiService } from '../../common/services/nodes-api.service';
@ -27,7 +27,6 @@ import { CardViewContentUpdateService } from '../../common/services/card-view-co
import { TagService } from '@alfresco/adf-content-services';
describe('NodeAspectService', () => {
let dialogAspectListService: DialogAspectListService;
let nodeAspectService: NodeAspectService;
let nodeApiService: NodesApiService;
@ -35,10 +34,7 @@ describe('NodeAspectService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
]
imports: [TranslateModule.forRoot(), ContentTestingModule]
});
dialogAspectListService = TestBed.inject(DialogAspectListService);
nodeAspectService = TestBed.inject(NodeAspectService);
@ -81,7 +77,7 @@ describe('NodeAspectService', () => {
expect(nodeUpdated.id).toBe('fake-node-id');
expect(nodeUpdated.aspectNames).toEqual(['a', 'b', 'c']);
});
const fakeNode = new MinimalNode({ id: 'fake-node-id', aspectNames: ['a', 'b', 'c'] });
const fakeNode = new Node({ id: 'fake-node-id', aspectNames: ['a', 'b', 'c'] });
spyOn(dialogAspectListService, 'openAspectListDialog').and.returnValue(of(['a', 'b', 'c']));
spyOn(nodeApiService, 'updateNode').and.returnValue(of(fakeNode));
nodeAspectService.updateNodeAspects('fake-node-id');
@ -92,7 +88,7 @@ describe('NodeAspectService', () => {
expect(nodeUpdated.id).toBe('fake-node-id');
expect(nodeUpdated.aspectNames).toEqual(['a', 'b', 'c']);
});
const fakeNode = new MinimalNode({ id: 'fake-node-id', aspectNames: ['a', 'b', 'c'] });
const fakeNode = new Node({ id: 'fake-node-id', aspectNames: ['a', 'b', 'c'] });
spyOn(dialogAspectListService, 'openAspectListDialog').and.returnValue(of(['a', 'b', 'c']));
spyOn(nodeApiService, 'updateNode').and.returnValue(of(fakeNode));
nodeAspectService.updateNodeAspects('fake-node-id');
@ -101,7 +97,7 @@ describe('NodeAspectService', () => {
it('should call emit on refresh from TagService', () => {
const tagService = TestBed.inject(TagService);
spyOn(dialogAspectListService, 'openAspectListDialog').and.returnValue(of([]));
const node = new MinimalNode({ id: 'fake-node-id', aspectNames: ['a', 'b', 'c'] });
const node = new Node({ id: 'fake-node-id', aspectNames: ['a', 'b', 'c'] });
spyOn(nodeApiService, 'updateNode').and.returnValue(of(node));
spyOn(tagService.refresh, 'emit');
nodeAspectService.updateNodeAspects('some node id', 'some-selector');

@ -15,19 +15,9 @@
* limitations under the License.
*/
import {
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
ViewChild,
ViewEncapsulation,
OnDestroy
} from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild, ViewEncapsulation, OnDestroy } from '@angular/core';
import { MatSelect } from '@angular/material/select';
import { Node, PathElementEntity } from '@alfresco/js-api';
import { Node, PathElement } from '@alfresco/js-api';
import { DocumentListComponent } from '../document-list/components/document-list.component';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@ -40,7 +30,6 @@ import { takeUntil } from 'rxjs/operators';
host: { class: 'adf-breadcrumb' }
})
export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
/** Active node, builds UI based on folderNode.path.elements collection. */
@Input()
folderNode: Node = null;
@ -79,10 +68,10 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
@Input()
maxItems: number;
previousNodes: PathElementEntity[];
lastNodes: PathElementEntity[];
previousNodes: PathElement[];
lastNodes: PathElement[];
route: PathElementEntity[] = [];
route: PathElement[] = [];
private onDestroy$ = new Subject<boolean>();
@ -96,18 +85,16 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
/** Emitted when the user clicks on a breadcrumb. */
@Output()
navigate = new EventEmitter<PathElementEntity>();
navigate = new EventEmitter<PathElement>();
ngOnInit() {
this.transform = this.transform ? this.transform : null;
if (this.target) {
this.target.$folderNode
.pipe(takeUntil(this.onDestroy$))
.subscribe((folderNode: Node) => {
this.folderNode = folderNode;
this.recalculateNodes();
});
this.target.$folderNode.pipe(takeUntil(this.onDestroy$)).subscribe((folderNode: Node) => {
this.folderNode = folderNode;
this.recalculateNodes();
});
}
}
@ -141,7 +128,7 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
return !!this.previousNodes;
}
parseRoute(node: Node): PathElementEntity[] {
parseRoute(node: Node): PathElement[] {
if (node && node.path) {
const route = (node.path.elements || []).slice();
@ -149,7 +136,7 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
id: node.id,
name: node.name,
node
} as PathElementEntity);
} as PathElement);
const rootPos = this.getElementPosition(route, this.rootId);
if (rootPos > 0) {
@ -170,7 +157,7 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
return [];
}
private getElementPosition(route: PathElementEntity[], nodeId: string): number {
private getElementPosition(route: PathElement[], nodeId: string): number {
let position: number = -1;
if (route && route.length > 0 && nodeId) {
@ -184,7 +171,7 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
return !this.readOnly && !lastItem;
}
onRoutePathClick(route: PathElementEntity, event?: Event): void {
onRoutePathClick(route: PathElement, event?: Event): void {
if (event && event.type === 'click') {
event.preventDefault();
}
@ -192,7 +179,7 @@ export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
this.onRouteClick(route);
}
onRouteClick(route: PathElementEntity) {
onRouteClick(route: PathElement) {
if (route && !this.readOnly) {
this.navigate.emit(route);

@ -17,7 +17,7 @@
import { Component, OnChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import { MatSelect } from '@angular/material/select';
import { PathElementEntity, Node } from '@alfresco/js-api';
import { PathElement, Node } from '@alfresco/js-api';
import { BreadcrumbComponent } from './breadcrumb.component';
@Component({
@ -28,12 +28,11 @@ import { BreadcrumbComponent } from './breadcrumb.component';
host: { class: 'adf-dropdown-breadcrumb' }
})
export class DropdownBreadcrumbComponent extends BreadcrumbComponent implements OnChanges {
@ViewChild('dropdown')
dropdown: MatSelect;
currentNode: PathElementEntity;
previousNodes: PathElementEntity[];
currentNode: PathElement;
previousNodes: PathElement[];
/**
* Calculate the current and previous nodes from the route array

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { AssocChildBody, AssociationBody } from '@alfresco/js-api';
import { ChildAssociationBody, AssociationBody } from '@alfresco/js-api';
export interface FileUploadProgress {
loaded: number;
@ -63,7 +63,7 @@ export class FileUploadOptions {
* You can optionally specify an array of **secondaryChildren** to create one or more secondary child associations,
* such that the newly created node acts as a parent node.
*/
secondaryChildren?: AssocChildBody[];
secondaryChildren?: ChildAssociationBody[];
/**
* You can optionally specify an array of **targets** to create one or more peer associations such that the newly created node acts as a source node.
*/
@ -112,9 +112,13 @@ export class FileModel {
percent: 0
};
this.options = Object.assign({}, {
newVersion: false
}, options);
this.options = Object.assign(
{},
{
newVersion: false
},
options
);
}
get extension(): string {

@ -15,24 +15,23 @@
* limitations under the License.
*/
import { MinimalNode } from '@alfresco/js-api';
import { Node } from '@alfresco/js-api';
import { fakeAsync, TestBed } from '@angular/core/testing';
import { CardViewContentUpdateService } from './card-view-content-update.service';
describe('CardViewContentUpdateService', () => {
let cardViewContentUpdateService: CardViewContentUpdateService;
let cardViewContentUpdateService: CardViewContentUpdateService;
beforeEach(() => {
cardViewContentUpdateService = TestBed.inject(CardViewContentUpdateService);
});
beforeEach(() => {
cardViewContentUpdateService = TestBed.inject(CardViewContentUpdateService);
it('should send updated node when aspect changed', fakeAsync(() => {
const fakeNode = { id: 'Bigfoot' } as Node;
cardViewContentUpdateService.updatedAspect$.subscribe((node) => {
expect(node.id).toBe('Bigfoot');
});
it('should send updated node when aspect changed', fakeAsync(() => {
const fakeNode: MinimalNode = { id: 'Bigfoot'} as MinimalNode;
cardViewContentUpdateService.updatedAspect$.subscribe((node: MinimalNode) => {
expect(node.id).toBe('Bigfoot');
});
cardViewContentUpdateService.updateNodeAspect(fakeNode);
}));
cardViewContentUpdateService.updateNodeAspect(fakeNode);
}));
});

@ -16,43 +16,41 @@
*/
import { UpdateNotification, CardViewBaseItemModel, CardViewUpdateService } from '@alfresco/adf-core';
import { MinimalNode } from '@alfresco/js-api';
import { Node } from '@alfresco/js-api';
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { BaseCardViewContentUpdate } from '../../interfaces/base-card-view-content-update.interface';
@Injectable({
providedIn: 'root'
providedIn: 'root'
})
export class CardViewContentUpdateService implements BaseCardViewContentUpdate {
itemUpdated$ = new Subject<UpdateNotification>();
updatedAspect$ = new Subject<Node>();
itemUpdated$ = new Subject<UpdateNotification>();
constructor(private cardViewUpdateService: CardViewUpdateService) {
this.linkVariables();
}
updatedAspect$ = new Subject<MinimalNode>();
update(property: CardViewBaseItemModel, newValue: any) {
this.cardViewUpdateService.update(property, newValue);
}
constructor(private cardViewUpdateService: CardViewUpdateService) {
this.linkVariables();
}
updateElement(notification: CardViewBaseItemModel) {
this.cardViewUpdateService.updateElement(notification);
}
update(property: CardViewBaseItemModel, newValue: any) {
this.cardViewUpdateService.update(property, newValue);
}
updateNodeAspect(node: Node) {
this.updatedAspect$.next(node);
}
updateElement(notification: CardViewBaseItemModel) {
this.cardViewUpdateService.updateElement(notification);
}
private linkVariables() {
this.linkItemUpdated();
}
updateNodeAspect(node: MinimalNode) {
this.updatedAspect$.next(node);
}
private linkVariables() {
this.linkItemUpdated();
}
private linkItemUpdated() {
this.cardViewUpdateService.itemUpdated$.subscribe(res => {
this.itemUpdated$.next(res);
});
}
private linkItemUpdated() {
this.cardViewUpdateService.itemUpdated$.subscribe((res) => {
this.itemUpdated$.next(res);
});
}
}

@ -16,7 +16,7 @@
*/
import { Injectable } from '@angular/core';
import { ContentApi, MinimalNode, Node, NodeEntry } from '@alfresco/js-api';
import { ContentApi, Node, NodeEntry } from '@alfresco/js-api';
import { Subject } from 'rxjs';
import { AlfrescoApiService, AuthenticationService } from '@alfresco/adf-core';
import { PermissionsEnum } from '../models/permissions.enum';
@ -33,10 +33,9 @@ export interface FolderCreatedEvent {
providedIn: 'root'
})
export class ContentService {
folderCreated: Subject<FolderCreatedEvent> = new Subject<FolderCreatedEvent>();
folderCreate: Subject<MinimalNode> = new Subject<MinimalNode>();
folderEdit: Subject<MinimalNode> = new Subject<MinimalNode>();
folderCreated = new Subject<FolderCreatedEvent>();
folderCreate = new Subject<Node>();
folderEdit = new Subject<Node>();
private _contentApi: ContentApi;
get contentApi(): ContentApi {
@ -44,10 +43,7 @@ export class ContentService {
return this._contentApi;
}
constructor(public authService: AuthenticationService,
public apiService: AlfrescoApiService) {
}
constructor(public authService: AuthenticationService, public apiService: AlfrescoApiService) {}
/**
* Gets a content URL for the given node.
@ -89,17 +85,16 @@ export class ContentService {
let hasPermissions = false;
userId = userId ?? this.authService.getEcmUsername();
const permissions = [...(node.permissions?.locallySet || []), ...(node.permissions?.inherited || [])]
.filter((currentPermission) => currentPermission.authorityId === userId);
const permissions = [...(node.permissions?.locallySet || []), ...(node.permissions?.inherited || [])].filter(
(currentPermission) => currentPermission.authorityId === userId
);
if (permissions.length) {
if (permission && permission.startsWith('!')) {
hasPermissions = !permissions.find((currentPermission) => currentPermission.name === permission.replace('!', ''));
} else {
hasPermissions = !!permissions.find((currentPermission) => currentPermission.name === permission);
}
} else {
if (permission === PermissionsEnum.CONSUMER) {
hasPermissions = true;
} else if (permission === PermissionsEnum.NOT_CONSUMER) {
@ -124,11 +119,12 @@ export class ContentService {
if (node && node.allowableOperations) {
if (allowableOperation && allowableOperation.startsWith('!')) {
hasAllowableOperations = !node.allowableOperations.find((currentOperation) => currentOperation === allowableOperation.replace('!', ''));
hasAllowableOperations = !node.allowableOperations.find(
(currentOperation) => currentOperation === allowableOperation.replace('!', '')
);
} else {
hasAllowableOperations = !!node.allowableOperations.find((currentOperation) => currentOperation === allowableOperation);
}
} else {
if (allowableOperation && allowableOperation.startsWith('!')) {
hasAllowableOperations = true;
@ -149,5 +145,4 @@ export class ContentService {
return hasAllowableOperations;
}
}

@ -16,7 +16,7 @@
*/
import { Injectable } from '@angular/core';
import { MinimalNode, NodeEntry, NodePaging, NodesApi, TrashcanApi, Node } from '@alfresco/js-api';
import { NodeEntry, NodePaging, NodesApi, TrashcanApi, Node } from '@alfresco/js-api';
import { Subject, from, Observable, throwError } from 'rxjs';
import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core';
import { catchError, map } from 'rxjs/operators';
@ -26,7 +26,6 @@ import { NodeMetadata } from '../models/node-metadata.model';
providedIn: 'root'
})
export class NodesApiService {
/**
* Publish/subscribe to events related to node updates.
*/
@ -44,11 +43,9 @@ export class NodesApiService {
return this._nodesApi;
}
constructor(private apiService: AlfrescoApiService,
private preferences: UserPreferencesService) {
}
constructor(private apiService: AlfrescoApiService, private preferences: UserPreferencesService) {}
private getEntryFromEntity(entity: NodeEntry) {
private getEntryFromEntity(entity: NodeEntry): Node {
return entity.entry;
}
@ -59,7 +56,7 @@ export class NodesApiService {
* @param options Optional parameters supported by JS-API
* @returns Node information
*/
getNode(nodeId: string, options: any = {}): Observable<MinimalNode> {
getNode(nodeId: string, options: any = {}): Observable<Node> {
const defaults = {
include: ['path', 'properties', 'allowableOperations', 'permissions']
};
@ -86,9 +83,7 @@ export class NodesApiService {
};
const queryOptions = Object.assign(defaults, options);
return from(this.nodesApi.listNodeChildren(nodeId, queryOptions)).pipe(
catchError((err) => throwError(err))
);
return from(this.nodesApi.listNodeChildren(nodeId, queryOptions)).pipe(catchError((err) => throwError(err)));
}
/**
@ -99,7 +94,7 @@ export class NodesApiService {
* @param options Optional parameters supported by JS-API
* @returns Details of the new node
*/
createNode(parentNodeId: string, nodeBody: any, options: any = {}): Observable<MinimalNode> {
createNode(parentNodeId: string, nodeBody: any, options: any = {}): Observable<Node> {
return from(this.nodesApi.createNode(parentNodeId, nodeBody, options)).pipe(
map(this.getEntryFromEntity),
catchError((err) => throwError(err))
@ -114,7 +109,7 @@ export class NodesApiService {
* @param options Optional parameters supported by JS-API
* @returns Details of the new folder
*/
createFolder(parentNodeId: string, nodeBody: any, options: any = {}): Observable<MinimalNode> {
createFolder(parentNodeId: string, nodeBody: any, options: any = {}): Observable<Node> {
const body = Object.assign({ nodeType: 'cm:folder' }, nodeBody);
return this.createNode(parentNodeId, body, options);
}
@ -127,7 +122,7 @@ export class NodesApiService {
* @param options Optional parameters supported by JS-API
* @returns Updated node information
*/
updateNode(nodeId: string, nodeBody: any, options: any = {}): Observable<MinimalNode> {
updateNode(nodeId: string, nodeBody: any, options: any = {}): Observable<Node> {
const defaults = {
include: ['path', 'properties', 'allowableOperations', 'permissions', 'definition']
};
@ -147,9 +142,7 @@ export class NodesApiService {
* @returns Empty result that notifies when the deletion is complete
*/
deleteNode(nodeId: string, options: any = {}): Observable<any> {
return from(this.nodesApi.deleteNode(nodeId, options)).pipe(
catchError((err) => throwError(err))
);
return from(this.nodesApi.deleteNode(nodeId, options)).pipe(catchError((err) => throwError(err)));
}
/**
@ -158,7 +151,7 @@ export class NodesApiService {
* @param nodeId ID of the node to restore
* @returns Details of the restored node
*/
restoreNode(nodeId: string): Observable<MinimalNode> {
restoreNode(nodeId: string): Observable<Node> {
return from(this.trashcanApi.restoreDeletedNode(nodeId)).pipe(
map(this.getEntryFromEntity),
catchError((err) => throwError(err))
@ -172,8 +165,7 @@ export class NodesApiService {
* @returns Node metadata
*/
public getNodeMetadata(nodeId: string): Observable<NodeMetadata> {
return from(this.nodesApi.getNode(nodeId))
.pipe(map(this.cleanMetadataFromSemicolon));
return from(this.nodesApi.getNode(nodeId)).pipe(map(this.cleanMetadataFromSemicolon));
}
/**
@ -194,7 +186,7 @@ export class NodesApiService {
}
}
return this.createNodeInsideRoot(name || this.generateUuid(), nodeType, properties, path);
return this.createNodeInsideRoot(name || window.crypto.randomUUID(), nodeType, properties, path);
}
/**
@ -204,10 +196,7 @@ export class NodesApiService {
* @returns Content data
*/
getNodeContent(nodeId: string): Observable<any> {
return from(this.nodesApi.getNodeContent(nodeId))
.pipe(
catchError((err) => throwError(err))
);
return from(this.nodesApi.getNodeContent(nodeId)).pipe(catchError((err) => throwError(err)));
}
/**
@ -229,14 +218,6 @@ export class NodesApiService {
return from(this.nodesApi.createNode('-root-', body, {}));
}
private generateUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
private cleanMetadataFromSemicolon(nodeEntry: NodeEntry): NodeMetadata {
const metadata = {};
@ -244,9 +225,9 @@ export class NodesApiService {
for (const key in nodeEntry.entry.properties) {
if (key) {
if (key.indexOf(':') !== -1) {
metadata [key.split(':')[1]] = nodeEntry.entry.properties[key];
metadata[key.split(':')[1]] = nodeEntry.entry.properties[key];
} else {
metadata [key] = nodeEntry.entry.properties[key];
metadata[key] = nodeEntry.entry.properties[key];
}
}
}
@ -254,5 +235,4 @@ export class NodesApiService {
return new NodeMetadata(metadata, nodeEntry.entry.nodeType);
}
}

@ -19,7 +19,7 @@ import { Injectable } from '@angular/core';
import { from, Observable, throwError } from 'rxjs';
import { AlfrescoApiService, LogService } from '@alfresco/adf-core';
import {
MinimalNode,
Node,
SiteBodyCreate,
SiteEntry,
SiteGroupEntry,
@ -38,16 +38,13 @@ import { catchError } from 'rxjs/operators';
providedIn: 'root'
})
export class SitesService {
private _sitesApi: SitesApi;
get sitesApi(): SitesApi {
this._sitesApi = this._sitesApi ?? new SitesApi(this.apiService.getInstance());
return this._sitesApi;
}
constructor(private apiService: AlfrescoApiService,
private logService: LogService) {
}
constructor(private apiService: AlfrescoApiService, private logService: LogService) {}
/**
* Create a site
@ -56,10 +53,7 @@ export class SitesService {
* @returns site SiteEntry
*/
createSite(siteBody: SiteBodyCreate): Observable<SiteEntry> {
return from(this.sitesApi.createSite(siteBody))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.createSite(siteBody)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -74,10 +68,7 @@ export class SitesService {
include: ['properties']
};
const queryOptions = Object.assign({}, defaultOptions, opts);
return from(this.sitesApi.listSites(queryOptions))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.listSites(queryOptions)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -88,10 +79,7 @@ export class SitesService {
* @returns Information about the site
*/
getSite(siteId: string, opts?: any): Observable<SiteEntry | any> {
return from(this.sitesApi.getSite(siteId, opts))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.getSite(siteId, opts)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -104,10 +92,7 @@ export class SitesService {
deleteSite(siteId: string, permanentFlag: boolean = true): Observable<any> {
const options: any = {};
options.permanent = permanentFlag;
return from(this.sitesApi.deleteSite(siteId, options))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.deleteSite(siteId, options)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -148,13 +133,10 @@ export class SitesService {
* @param node Node to look for parent site
* @returns Site guid
*/
getSiteNameFromNodePath(node: MinimalNode): string {
getSiteNameFromNodePath(node: Node): string {
let siteName = '';
if (node.path && node.path.elements) {
const foundNode = node.path
.elements.find((pathNode: MinimalNode) =>
pathNode.nodeType === 'st:site' &&
pathNode.name !== 'Sites');
const foundNode = node.path.elements.find((pathNode) => pathNode.nodeType === 'st:site' && pathNode.name !== 'Sites');
siteName = foundNode ? foundNode.name : '';
}
return siteName.toLocaleLowerCase();
@ -167,10 +149,7 @@ export class SitesService {
* @returns Site membership requests
*/
getSiteMembershipRequests(opts?: any): Observable<SiteMembershipRequestWithPersonPaging> {
return from(this.sitesApi.getSiteMembershipRequests(opts))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.getSiteMembershipRequests(opts)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -182,10 +161,7 @@ export class SitesService {
* @return Observable<SiteMemberEntry>
*/
createSiteMembership(siteId: string, siteMembershipBodyCreate: SiteMembershipBodyCreate, opts?: any): Observable<SiteMemberEntry> {
return from(this.sitesApi.createSiteMembership(siteId, siteMembershipBodyCreate, opts))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.createSiteMembership(siteId, siteMembershipBodyCreate, opts)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -197,11 +173,15 @@ export class SitesService {
* @param opts Optional parameters
* @return Observable<SiteMemberEntry>
*/
updateSiteMembership(siteId: string, personId: string, siteMembershipBodyUpdate: SiteMembershipBodyUpdate, opts?: any): Observable<SiteMemberEntry> {
return from(this.sitesApi.updateSiteMembership(siteId, personId, siteMembershipBodyUpdate, opts))
.pipe(
catchError((err: any) => this.handleError(err))
);
updateSiteMembership(
siteId: string,
personId: string,
siteMembershipBodyUpdate: SiteMembershipBodyUpdate,
opts?: any
): Observable<SiteMemberEntry> {
return from(this.sitesApi.updateSiteMembership(siteId, personId, siteMembershipBodyUpdate, opts)).pipe(
catchError((err: any) => this.handleError(err))
);
}
/**
@ -212,10 +192,7 @@ export class SitesService {
* @return Null response notifying when the operation is complete
*/
deleteSiteMembership(siteId: string, personId: string): Observable<void> {
return from(this.sitesApi.deleteSiteMembership(siteId, personId))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.deleteSiteMembership(siteId, personId)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -227,10 +204,7 @@ export class SitesService {
* @returns Null response notifying when the operation is complete
*/
approveSiteMembershipRequest(siteId: string, inviteeId: string, opts?: any): Observable<SiteMembershipRequestWithPersonPaging> {
return from(this.sitesApi.approveSiteMembershipRequest(siteId, inviteeId, opts))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.approveSiteMembershipRequest(siteId, inviteeId, opts)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -242,10 +216,7 @@ export class SitesService {
* @returns Null response notifying when the operation is complete
*/
rejectSiteMembershipRequest(siteId: string, inviteeId: string, opts?: any): Observable<SiteMembershipRequestWithPersonPaging> {
return from(this.sitesApi.rejectSiteMembershipRequest(siteId, inviteeId, opts))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.rejectSiteMembershipRequest(siteId, inviteeId, opts)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -256,10 +227,7 @@ export class SitesService {
* @returns Observable<SiteGroupPaging>
*/
listSiteGroups(siteId: string, opts?: any): Observable<SiteGroupPaging> {
return from(this.sitesApi.listSiteGroups(siteId, opts))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.listSiteGroups(siteId, opts)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -270,10 +238,7 @@ export class SitesService {
* @returns Observable<SiteGroupEntry>
*/
createSiteGroupMembership(siteId: string, siteMembershipBodyCreate: SiteMembershipBodyCreate): Observable<SiteGroupEntry> {
return from(this.sitesApi.createSiteGroupMembership(siteId, siteMembershipBodyCreate))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.createSiteGroupMembership(siteId, siteMembershipBodyCreate)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -284,10 +249,7 @@ export class SitesService {
* @return Observable<SiteGroupEntry>
*/
getSiteGroupMembership(siteId: string, groupId: string): Observable<SiteGroupEntry> {
return from(this.sitesApi.getSiteGroupMembership(siteId, groupId))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.getSiteGroupMembership(siteId, groupId)).pipe(catchError((err: any) => this.handleError(err)));
}
/**
@ -299,10 +261,9 @@ export class SitesService {
* @return Observable<SiteGroupEntry>
*/
updateSiteGroupMembership(siteId: string, groupId: string, siteMembershipBodyUpdate: SiteMembershipBodyUpdate): Observable<SiteGroupEntry> {
return from(this.sitesApi.updateSiteGroupMembership(siteId, groupId, siteMembershipBodyUpdate))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.updateSiteGroupMembership(siteId, groupId, siteMembershipBodyUpdate)).pipe(
catchError((err: any) => this.handleError(err))
);
}
/**
@ -313,10 +274,7 @@ export class SitesService {
* @return Observable<void>
*/
deleteSiteGroupMembership(siteId: string, groupId: string): Observable<void> {
return from(this.sitesApi.deleteSiteGroupMembership(siteId, groupId))
.pipe(
catchError((err: any) => this.handleError(err))
);
return from(this.sitesApi.deleteSiteGroupMembership(siteId, groupId)).pipe(catchError((err: any) => this.handleError(err)));
}
private handleError(error: any): Observable<never> {

@ -18,27 +18,10 @@
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { DebugElement, SimpleChange } from '@angular/core';
import { By } from '@angular/platform-browser';
import {
Category,
CategoryPaging,
ClassesApi,
MinimalNode,
Node,
Tag,
TagBody,
TagEntry,
TagPaging,
TagPagingList
} from '@alfresco/js-api';
import { Category, CategoryPaging, ClassesApi, Node, Tag, TagBody, TagEntry, TagPaging, TagPagingList } from '@alfresco/js-api';
import { ContentMetadataComponent } from './content-metadata.component';
import { ContentMetadataService } from '../../services/content-metadata.service';
import {
AppConfigService,
CardViewBaseItemModel,
CardViewComponent,
LogService,
UpdateNotification
} from '@alfresco/adf-core';
import { AppConfigService, CardViewBaseItemModel, CardViewComponent, LogService, UpdateNotification } from '@alfresco/adf-core';
import { NodesApiService } from '../../../common/services/nodes-api.service';
import { EMPTY, of, throwError } from 'rxjs';
import { ContentTestingModule } from '../../../testing/content.testing.module';
@ -86,7 +69,7 @@ describe('ContentMetadataComponent', () => {
const category1 = new Category({ id: 'test', name: 'testCat' });
const category2 = new Category({ id: 'test2', name: 'testCat2' });
const categoryPagingResponse: CategoryPaging = { list: { pagination: {}, entries: [ { entry: category1 }, { entry: category2 }]}};
const categoryPagingResponse: CategoryPaging = { list: { pagination: {}, entries: [{ entry: category1 }, { entry: category2 }] } };
const findTagElements = (): DebugElement[] => fixture.debugElement.queryAll(By.css('.adf-metadata-properties-tag'));
@ -123,8 +106,8 @@ describe('ContentMetadataComponent', () => {
async function updateAspectProperty(newValue: string): Promise<void> {
component.editable = true;
const property = {key: 'properties.property-key', value: 'original-value'} as CardViewBaseItemModel;
const expectedNode = {...node, name: 'some-modified-value'};
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
const expectedNode = { ...node, name: 'some-modified-value' };
spyOn(nodesApiService, 'updateNode').and.returnValue(of(expectedNode));
updateService.update(property, newValue);
@ -139,10 +122,7 @@ describe('ContentMetadataComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule],
providers: [
{
provide: LogService,
@ -247,7 +227,7 @@ describe('ContentMetadataComponent', () => {
}));
it('nodeAspectUpdate', fakeAsync(() => {
const fakeNode = { id: 'fake-minimal-node', aspectNames: ['ft:a', 'ft:b', 'ft:c'], name: 'fake-node'} as MinimalNode;
const fakeNode = { id: 'fake-minimal-node', aspectNames: ['ft:a', 'ft:b', 'ft:c'], name: 'fake-node' } as Node;
spyOn(contentMetadataService, 'getGroupedProperties').and.stub();
spyOn(contentMetadataService, 'getBasicProperties').and.stub();
updateService.updateNodeAspect(fakeNode);
@ -265,13 +245,13 @@ describe('ContentMetadataComponent', () => {
}));
it('should save changedProperties which delete property and update node on save click', fakeAsync(async () => {
const expectedNode = {...node, name: 'some-modified-value'};
const expectedNode = { ...node, name: 'some-modified-value' };
await updateAspectProperty('');
expect(component.node).toEqual({...expectedNode, properties: {}});
expect(component.node).toEqual({ ...expectedNode, properties: {} });
expect(nodesApiService.updateNode).toHaveBeenCalled();
}));
it('should call removeTag and assignTagsToNode on TagService on save click', fakeAsync( () => {
it('should call removeTag and assignTagsToNode on TagService on save click', fakeAsync(() => {
component.editable = true;
component.displayTags = true;
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
@ -300,7 +280,7 @@ describe('ContentMetadataComponent', () => {
expect(tagService.assignTagsToNode).toHaveBeenCalledWith(node.id, [tag1, tag2]);
}));
it('should call getTagsByNodeId on TagService on save click', fakeAsync( () => {
it('should call getTagsByNodeId on TagService on save click', fakeAsync(() => {
component.editable = true;
component.displayTags = true;
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
@ -361,7 +341,7 @@ describe('ContentMetadataComponent', () => {
tick(100);
expect(component.node).toEqual(expectedNode);
expect(contentMetadataService.openConfirmDialog).toHaveBeenCalledWith({nodeType: 'ft:poppoli'});
expect(contentMetadataService.openConfirmDialog).toHaveBeenCalledWith({ nodeType: 'ft:poppoli' });
expect(nodesApiService.updateNode).toHaveBeenCalled();
discardPeriodicTasks();
}));
@ -445,7 +425,7 @@ describe('ContentMetadataComponent', () => {
});
describe('Properties loading', () => {
let expectedNode: MinimalNode;
let expectedNode: Node;
beforeEach(() => {
expectedNode = { ...node, name: 'some-modified-value' };
@ -537,7 +517,9 @@ describe('ContentMetadataComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const firstGroupedPropertiesComponent = fixture.debugElement.query(By.css('.adf-metadata-grouped-properties-container adf-card-view')).componentInstance;
const firstGroupedPropertiesComponent = fixture.debugElement.query(
By.css('.adf-metadata-grouped-properties-container adf-card-view')
).componentInstance;
expect(firstGroupedPropertiesComponent.properties).toBe(expectedProperties);
});
@ -553,7 +535,9 @@ describe('ContentMetadataComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const basicPropertiesComponent = fixture.debugElement.query(By.css('.adf-metadata-grouped-properties-container adf-card-view')).componentInstance;
const basicPropertiesComponent = fixture.debugElement.query(
By.css('.adf-metadata-grouped-properties-container adf-card-view')
).componentInstance;
expect(basicPropertiesComponent.displayEmpty).toBe(false);
});
@ -575,14 +559,17 @@ describe('ContentMetadataComponent', () => {
component.expanded = true;
const cardViewGroup = {
title: 'Group 1', properties: [{
data: null,
default: null,
displayValue: 'DefaultName',
icon: '',
key: 'properties.cm:default',
label: 'To'
}]
title: 'Group 1',
properties: [
{
data: null,
default: null,
displayValue: 'DefaultName',
icon: '',
key: 'properties.cm:default',
label: 'To'
}
]
};
spyOn(contentMetadataService, 'getGroupedProperties').and.returnValue(of([{ properties: [cardViewGroup] } as any]));
@ -618,11 +605,10 @@ describe('ContentMetadataComponent', () => {
});
});
describe('Display properties with aspect oriented config', () => {
let appConfig: AppConfigService;
let classesApi: ClassesApi;
let expectedNode: MinimalNode;
let expectedNode: Node;
const versionableResponse: PropertyGroup = {
name: 'cm:versionable',
@ -697,21 +683,11 @@ describe('ContentMetadataComponent', () => {
beforeEach(() => {
appConfig = TestBed.inject(AppConfigService);
const propertyDescriptorsService = TestBed.inject(
PropertyDescriptorsService
);
const propertyDescriptorsService = TestBed.inject(PropertyDescriptorsService);
classesApi = propertyDescriptorsService['classesApi'];
expectedNode = {
...node,
aspectNames: [
'rn:renditioned',
'cm:versionable',
'cm:titled',
'cm:auditable',
'cm:author',
'cm:thumbnailModification',
'exif:exif'
],
aspectNames: ['rn:renditioned', 'cm:versionable', 'cm:titled', 'cm:auditable', 'cm:author', 'cm:thumbnailModification', 'exif:exif'],
name: 'some-modified-value',
properties: {
'exif:pixelXDimension': 1024,
@ -849,11 +825,15 @@ describe('ContentMetadataComponent', () => {
exifProp.nativeElement.click();
const pixelXDimentionElement = fixture.debugElement.query(By.css('[data-automation-id="card-textitem-label-properties.exif:pixelXDimension"]'));
const pixelXDimentionElement = fixture.debugElement.query(
By.css('[data-automation-id="card-textitem-label-properties.exif:pixelXDimension"]')
);
expect(pixelXDimentionElement).toBeTruthy();
expect(pixelXDimentionElement.nativeElement.textContent.trim()).toEqual('Image Width');
const pixelYDimentionElement = fixture.debugElement.query(By.css('[data-automation-id="card-textitem-label-properties.exif:pixelYDimension"]'));
const pixelYDimentionElement = fixture.debugElement.query(
By.css('[data-automation-id="card-textitem-label-properties.exif:pixelYDimension"]')
);
expect(pixelYDimentionElement).toBeTruthy();
expect(pixelYDimentionElement.nativeElement.textContent.trim()).toEqual('Image Height');
});
@ -880,7 +860,7 @@ describe('ContentMetadataComponent', () => {
});
describe('Expand the panel', () => {
let expectedNode: MinimalNode;
let expectedNode: Node;
beforeEach(() => {
expectedNode = { ...node, name: 'some-modified-value' };
@ -948,7 +928,7 @@ describe('ContentMetadataComponent', () => {
describe('events', () => {
it('should not propagate the event on left arrows press', () => {
fixture.detectChanges();
const event = { keyCode: 37, stopPropagation: () => { } };
const event = { keyCode: 37, stopPropagation: () => {} };
spyOn(event, 'stopPropagation').and.stub();
const element = fixture.debugElement.query(By.css('adf-card-view'));
element.triggerEventHandler('keydown', event);
@ -957,7 +937,7 @@ describe('ContentMetadataComponent', () => {
it('should not propagate the event on right arrows press', () => {
fixture.detectChanges();
const event = { keyCode: 39, stopPropagation: () => { } };
const event = { keyCode: 39, stopPropagation: () => {} };
spyOn(event, 'stopPropagation').and.stub();
const element = fixture.debugElement.query(By.css('adf-card-view'));
element.triggerEventHandler('keydown', event);
@ -966,7 +946,7 @@ describe('ContentMetadataComponent', () => {
it('should propagate the event on other keys press', () => {
fixture.detectChanges();
const event = { keyCode: 40, stopPropagation: () => { } };
const event = { keyCode: 40, stopPropagation: () => {} };
spyOn(event, 'stopPropagation').and.stub();
const element = fixture.debugElement.query(By.css('adf-card-view'));
element.triggerEventHandler('keydown', event);
@ -1141,7 +1121,7 @@ describe('ContentMetadataComponent', () => {
expect(tagsCreator.disabledTagsRemoving).toBeTrue();
});
it('should have assigned false to disabledTagsRemoving if forkJoin fails', fakeAsync( () => {
it('should have assigned false to disabledTagsRemoving if forkJoin fails', fakeAsync(() => {
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
const expectedNode = { ...node, name: 'some-modified-value' };
spyOn(nodesApiService, 'updateNode').and.returnValue(of(expectedNode));
@ -1234,7 +1214,7 @@ describe('ContentMetadataComponent', () => {
});
it('should render categories when ngOnChanges', () => {
component.ngOnChanges({ node: new SimpleChange(undefined, node, false)});
component.ngOnChanges({ node: new SimpleChange(undefined, node, false) });
fixture.detectChanges();
const categories = getCategories();
@ -1256,7 +1236,6 @@ describe('ContentMetadataComponent', () => {
});
it('should not reload categories in ngOnChanges if node is not changed', () => {
component.ngOnChanges({});
fixture.detectChanges();
@ -1330,12 +1309,12 @@ describe('ContentMetadataComponent', () => {
it('should clear categories and emit event when classifiable changes', (done) => {
component.node.aspectNames = [];
component.ngOnChanges({ node: new SimpleChange(undefined, node, false)});
component.ngOnChanges({ node: new SimpleChange(undefined, node, false) });
component.classifiableChanged.subscribe(() => {
expect(component.categories).toEqual([]);
done();
});
component.ngOnChanges({ node: new SimpleChange(undefined, node, false)});
component.ngOnChanges({ node: new SimpleChange(undefined, node, false) });
});
it('should enable discard and save buttons after emitting categories change event', () => {
@ -1357,7 +1336,7 @@ describe('ContentMetadataComponent', () => {
expect(categoriesManagementComponent.disableRemoval).toBeTrue();
});
it('should not disable removal if forkJoin fails', fakeAsync( () => {
it('should not disable removal if forkJoin fails', fakeAsync(() => {
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
const expectedNode = { ...node, name: 'some-modified-value' };
spyOn(nodesApiService, 'updateNode').and.returnValue(of(expectedNode));
@ -1393,15 +1372,15 @@ describe('ContentMetadataComponent', () => {
component.ngOnInit();
fixture.detectChanges();
expect(categoriesManagementComponent.categories).toEqual([ category1, category2 ]);
expect(categoriesManagementComponent.categories).toEqual([category1, category2]);
expect(categoryService.getCategoryLinksForNode).toHaveBeenCalledWith(node.id);
});
it('should set correct tags after ngOnChanges', () => {
component.ngOnChanges({ node: new SimpleChange(undefined, node, false)});
component.ngOnChanges({ node: new SimpleChange(undefined, node, false) });
fixture.detectChanges();
expect(categoriesManagementComponent.categories).toEqual([ category1, category2 ]);
expect(categoriesManagementComponent.categories).toEqual([category1, category2]);
expect(categoryService.getCategoryLinksForNode).toHaveBeenCalledWith(node.id);
});
});

@ -18,16 +18,7 @@
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import {
MinimalNode,
Node,
NodeEntry,
NodePaging,
RequestScope,
ResultSetPaging,
SiteEntry,
SitePaging
} from '@alfresco/js-api';
import { Node, NodeEntry, NodePaging, RequestScope, ResultSetPaging, SiteEntry, SitePaging } from '@alfresco/js-api';
import { of } from 'rxjs';
import { ContentNodeSelectorPanelComponent } from './content-node-selector-panel.component';
import { ContentTestingModule } from '../testing/content.testing.module';
@ -83,17 +74,13 @@ describe('ContentNodeSelectorPanelComponent', () => {
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), ContentTestingModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
});
describe('General component features', () => {
beforeEach(async () => {
fixture = TestBed.createComponent(ContentNodeSelectorPanelComponent);
component = fixture.componentInstance;
@ -105,10 +92,14 @@ describe('ContentNodeSelectorPanelComponent', () => {
searchQueryBuilderService = component.queryBuilderService;
component.queryBuilderService.resetToDefaults();
spyOn(nodeService, 'getNode').and.returnValue(of(new MinimalNode({
id: 'fake-node',
path: { elements: [{ nodeType: 'st:site', name: 'fake-site' }] }
})));
spyOn(nodeService, 'getNode').and.returnValue(
of(
new Node({
id: 'fake-node',
path: { elements: [{ nodeType: 'st:site', name: 'fake-site' }] }
})
)
);
searchSpy = spyOn(searchQueryBuilderService, 'execute');
const fakeSite = new SiteEntry({
entry: {
@ -127,7 +118,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
});
describe('Search functionality', () => {
let getCorrespondingNodeIdsSpy;
let getCorrespondingNodeIdsSpy: jasmine.Spy;
let customResourcesService: CustomResourcesService;
const entry: Node = { id: 'fakeid' } as Node;
@ -137,24 +128,27 @@ describe('ContentNodeSelectorPanelComponent', () => {
component.isSelectionValid = (node: Node) => node.isFile;
spyOn(documentListService, 'getFolderNode').and.returnValue(of(expectedDefaultFolderNode));
spyOn(documentListService, 'getFolder').and.returnValue(of(new NodePaging({
list: {
pagination: {},
entries: [],
source: {}
}
})));
spyOn(documentListService, 'getFolder').and.returnValue(
of(
new NodePaging({
list: {
pagination: {},
entries: [],
source: {}
}
})
)
);
spyOn(sitesService, 'getSites').and.returnValue(of(new SitePaging({ list: { entries: [] } })));
customResourcesService = TestBed.inject(CustomResourcesService);
getCorrespondingNodeIdsSpy = spyOn(customResourcesService, 'getCorrespondingNodeIds').and
.callFake((id) => {
if (id === '-sites-') {
return of(['123456testId', '09876543testId']);
}
return of([id]);
});
getCorrespondingNodeIdsSpy = spyOn(customResourcesService, 'getCorrespondingNodeIds').and.callFake((id) => {
if (id === '-sites-') {
return of(['123456testId', '09876543testId']);
}
return of([id]);
});
component.currentFolderId = 'cat-girl-nuku-nuku';
component.documentList.ngOnInit();
@ -259,14 +253,14 @@ describe('ContentNodeSelectorPanelComponent', () => {
tick(debounceSearch);
expect(searchSpy.calls.count()).toBe(1, 'Search count should be one after only one search');
expect(searchSpy.calls.count()).toBe(1);
component.siteChanged({ entry: { guid: 'namek' } } as SiteEntry);
const expectedQueryBody = mockQueryBody;
expectedQueryBody.filterQueries = [{ query: `ANCESTOR:'workspace://SpacesStore/namek'` }];
expect(searchSpy.calls.count()).toBe(2, 'Search count should be two after the site change');
expect(searchSpy.calls.count()).toBe(2);
expect(searchSpy).toHaveBeenCalledWith(expectedQueryBody);
}));
@ -285,7 +279,9 @@ describe('ContentNodeSelectorPanelComponent', () => {
const expectedQueryBodyWithSiteChange = mockQueryBody;
expectedQueryBodyWithSiteChange.filterQueries = [
{ query: `ANCESTOR:'workspace://SpacesStore/-sites-' OR ANCESTOR:'workspace://SpacesStore/123456testId' OR ANCESTOR:'workspace://SpacesStore/09876543testId'` }
{
query: `ANCESTOR:'workspace://SpacesStore/-sites-' OR ANCESTOR:'workspace://SpacesStore/123456testId' OR ANCESTOR:'workspace://SpacesStore/09876543testId'`
}
];
expect(searchSpy).toHaveBeenCalled();
@ -302,7 +298,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
tick(debounceSearch);
component.siteChanged({ entry: { guid: '-sites-' } } as SiteEntry);
expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(1, 'getCorrespondingNodeIdsSpy calls count should be one after the site changes to known alias \'-sites\-');
expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(1);
expect(getCorrespondingNodeIdsSpy.calls.mostRecent().args[0]).toEqual('-sites-');
}));
@ -329,7 +325,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
tick(debounceSearch);
expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(0, 'getCorrespondingNodeIdsSpy calls count should be 0 when no site is selected');
expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(0);
}));
it('should NOT get the corresponding node ids on search when NO known alias is selected from dropdown', fakeAsync(() => {
@ -350,7 +346,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
typeToSearchBox('vegeta');
tick(debounceSearch);
expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(0, 'getCorrespondingNodeIdsSpy should not be called');
expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(0);
component.siteChanged({ entry: { guid: 'namek' } } as SiteEntry);
@ -364,8 +360,8 @@ describe('ContentNodeSelectorPanelComponent', () => {
const searchIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-icon"]'));
const clearIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
expect(searchIcon).not.toBeNull('Search icon should be in the DOM');
expect(clearIcon).toBeNull('Clear icon should NOT be in the DOM');
expect(searchIcon).not.toBeNull();
expect(clearIcon).toBeNull();
}));
it('should show the X (clear) icon without the search icon when the search contains at least one character', fakeAsync(() => {
@ -378,8 +374,8 @@ describe('ContentNodeSelectorPanelComponent', () => {
const searchIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-icon"]'));
const clearIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
expect(searchIcon).toBeNull('Search icon should NOT be in the DOM');
expect(clearIcon).not.toBeNull('Clear icon should be in the DOM');
expect(searchIcon).toBeNull();
expect(clearIcon).not.toBeNull();
}));
it('should clear the search field, nodes and chosenNode when clicking on the X (clear) icon', async () => {
@ -420,7 +416,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
spyOn(customResourcesService, 'hasCorrespondingNodeIds').and.returnValue(true);
const showingSearchSpy = spyOn(component.showingSearch, 'emit');
component.queryBuilderService.execute({ query: { query: 'search' } });
await component.queryBuilderService.execute({ query: { query: 'search' } });
triggerSearchResults(fakeResultSetPaging);
fixture.detectChanges();
@ -464,7 +460,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
searchQueryBuilderService.update();
getCorrespondingNodeIdsSpy.and.throwError('Failed');
const showingSearchSpy = spyOn(component.showingSearch, 'emit');
component.queryBuilderService.execute({ query: { query: 'search' } });
await component.queryBuilderService.execute({ query: { query: 'search' } });
triggerSearchResults(fakeResultSetPaging);
fixture.detectChanges();
@ -481,9 +477,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
component.siteChanged({ entry: { guid: 'my-site-id' } } as SiteEntry);
const expectedQueryBodyWithSiteChange = mockQueryBody;
expectedQueryBodyWithSiteChange.filterQueries = [
{ query: `ANCESTOR:'workspace://SpacesStore/my-site-id'` }
];
expectedQueryBodyWithSiteChange.filterQueries = [{ query: `ANCESTOR:'workspace://SpacesStore/my-site-id'` }];
expect(searchSpy).toHaveBeenCalledWith(expectedQueryBodyWithSiteChange);
});
@ -516,9 +510,9 @@ describe('ContentNodeSelectorPanelComponent', () => {
tick(debounceSearch);
fixture.detectChanges();
expect(searchSpy.calls.count()).toBe(1, 'no other search has been performed');
expect(searchSpy.calls.count()).toBe(1);
expect(component.clearSearch).toHaveBeenCalled();
expect(component.folderIdToShow).toBe('cat-girl-nuku-nuku', 'back to the folder in which the search was performed');
expect(component.folderIdToShow).toBe('cat-girl-nuku-nuku');
flush();
}));
@ -558,38 +552,40 @@ describe('ContentNodeSelectorPanelComponent', () => {
expect(component.folderIdToShow).toBe('namek');
}));
it('should show the current folder\'s content instead of search results if search was not performed', async () => {
it('should show the current folder content instead of search results if search was not performed', async () => {
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
expect(documentList).not.toBeNull('Document list should be shown');
expect(documentList).not.toBeNull();
expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku');
});
it('should pass through the rowFilter to the documentList', async () => {
const filter = (shareDataRow: ShareDataRow) =>
shareDataRow.node.entry.name === 'impossible-name';
const filter = (shareDataRow: ShareDataRow) => shareDataRow.node.entry.name === 'impossible-name';
component.rowFilter = filter;
fixture.detectChanges();
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
expect(documentList).not.toBeNull('Document list should be shown');
expect(documentList.componentInstance.rowFilter({
node: {
entry: new Node({
name: 'impossible-name',
id: 'name'
})
}
}))
.toBe(filter({
expect(documentList).not.toBeNull();
expect(
documentList.componentInstance.rowFilter({
node: {
entry: new Node({
name: 'impossible-name',
id: 'name'
})
}
} as ShareDataRow));
})
).toBe(
filter({
node: {
entry: new Node({
name: 'impossible-name',
id: 'name'
})
}
} as ShareDataRow)
);
});
it('should pass through the excludeSiteContent to the rowFilter of the documentList', async () => {
@ -598,12 +594,11 @@ describe('ContentNodeSelectorPanelComponent', () => {
fixture.detectChanges();
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
expect(documentList).not.toBeNull('Document list should be shown');
expect(documentList.componentInstance.rowFilter).toBeTruthy('Document list should have had a rowFilter');
expect(documentList).not.toBeNull();
expect(documentList.componentInstance.rowFilter).toBeTruthy();
const testSiteContent = new Node({ id: 'blog-id', properties: { 'st:componentId': 'blog' } });
expect(documentList.componentInstance.rowFilter({ node: { entry: testSiteContent } }, null, null))
.toBe(false);
expect(documentList.componentInstance.rowFilter({ node: { entry: testSiteContent } }, null, null)).toBe(false);
});
it('should pass through the imageResolver to the documentList', async () => {
@ -613,7 +608,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
fixture.detectChanges();
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
expect(documentList).not.toBeNull('Document list should be shown');
expect(documentList).not.toBeNull();
expect(documentList.componentInstance.imageResolver).toBe(resolver);
});
@ -625,7 +620,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
fixture.detectChanges();
const documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]'));
expect(documentList).not.toBeNull('Document list should be shown');
expect(documentList).not.toBeNull();
expect(component.hasValidQuery).toEqual(true);
expect(documentList.componentInstance.currentFolderId).toBeNull();
done();
@ -670,12 +665,12 @@ describe('ContentNodeSelectorPanelComponent', () => {
fixture.whenStable().then(() => {
const clearButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]'));
expect(clearButton).not.toBeNull('Clear button should be in DOM');
expect(clearButton).not.toBeNull();
clearButton.triggerEventHandler('click', {});
fixture.detectChanges();
const documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]'));
expect(documentList).not.toBeNull('Document list should be shown');
expect(documentList).not.toBeNull();
expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku');
done();
});
@ -714,7 +709,6 @@ describe('ContentNodeSelectorPanelComponent', () => {
});
describe('Pagination "Load more" button', () => {
it('should NOT be shown by default', () => {
fixture.detectChanges();
const pagination = fixture.debugElement.query(By.css('[data-automation-id="adf-infinite-pagination-button"]'));
@ -745,7 +739,9 @@ describe('ContentNodeSelectorPanelComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const spinnerSelector = By.css('[data-automation-id="content-node-selector-search-pagination"] [data-automation-id="adf-infinite-pagination-spinner"]');
const spinnerSelector = By.css(
'[data-automation-id="content-node-selector-search-pagination"] [data-automation-id="adf-infinite-pagination-spinner"]'
);
const paginationLoading = fixture.debugElement.query(spinnerSelector);
expect(paginationLoading).not.toBeNull();
@ -782,6 +778,5 @@ describe('ContentNodeSelectorPanelComponent', () => {
});
});
});
});
});

@ -18,22 +18,8 @@
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import {
MinimalNode,
Node,
NodeEntry,
NodePaging,
ResultSetPaging,
SiteEntry,
SitePaging,
UserInfo
} from '@alfresco/js-api';
import {
AppConfigService,
DataRow,
ThumbnailService,
DataColumn
} from '@alfresco/adf-core';
import { Node, NodeEntry, NodePaging, ResultSetPaging, SiteEntry, SitePaging, UserInfo } from '@alfresco/js-api';
import { AppConfigService, DataRow, ThumbnailService, DataColumn } from '@alfresco/adf-core';
import { ContentService } from '../common/services/content.service';
import { UploadService } from '../common/services/upload.service';
import { NodesApiService } from '../common/services/nodes-api.service';
@ -90,17 +76,13 @@ describe('ContentNodeSelectorPanelComponent', () => {
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), ContentTestingModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
});
describe('General component features', () => {
beforeEach(() => {
fixture = TestBed.createComponent(ContentNodeSelectorPanelComponent);
component = fixture.componentInstance;
@ -116,10 +98,14 @@ describe('ContentNodeSelectorPanelComponent', () => {
searchQueryBuilderService = component.queryBuilderService;
component.queryBuilderService.resetToDefaults();
spyOn(nodeService, 'getNode').and.returnValue(of(new MinimalNode({
id: 'fake-node',
path: { elements: [{ nodeType: 'st:site', name: 'fake-site' }] }
})));
spyOn(nodeService, 'getNode').and.returnValue(
of(
new Node({
id: 'fake-node',
path: { elements: [{ nodeType: 'st:site', name: 'fake-site' }] }
})
)
);
const fakeSite = new SiteEntry({
entry: {
id: 'fake-site',
@ -136,7 +122,6 @@ describe('ContentNodeSelectorPanelComponent', () => {
});
describe('Site selection', () => {
beforeEach(() => {
spyOn(sitesService, 'getSites').and.returnValue(of(new SitePaging({ list: { entries: [] } })));
component.currentFolderId = 'fake-starting-folder';
@ -167,7 +152,6 @@ describe('ContentNodeSelectorPanelComponent', () => {
});
describe('Parameters', () => {
let documentListService: DocumentListService;
beforeEach(() => {
@ -175,14 +159,15 @@ describe('ContentNodeSelectorPanelComponent', () => {
spyOn(documentListService, 'getFolderNode').and.returnValue(of(new NodeEntry()));
spyOn(documentListService, 'getFolder').and.returnValue(throwError('No results for test'));
spyOn(sitesService, 'getSites').and.returnValue(of(new SitePaging({
list: {
entries: [
{ entry: { guid: 'namek', id: 'namek' } },
{ entry: { guid: 'blog', id: 'blog' } }
]
}
})));
spyOn(sitesService, 'getSites').and.returnValue(
of(
new SitePaging({
list: {
entries: [{ entry: { guid: 'namek', id: 'namek' } }, { entry: { guid: 'blog', id: 'blog' } }]
}
})
)
);
component.currentFolderId = 'cat-girl-nuku-nuku';
fixture.detectChanges();
@ -207,8 +192,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
fixture.detectChanges();
const testSiteContent = new Node({ id: 'blog-id', properties: { 'st:componentId': 'blog' } });
expect(component.rowFilter({ node: { entry: testSiteContent } } as any, null, null))
.toBe(false, 'did not filter out blog');
expect(component.rowFilter({ node: { entry: testSiteContent } } as any, null, null)).toBe(false, 'did not filter out blog');
});
it('should still be able to filter out the exclude site content after rowFilter changes', () => {
@ -227,13 +211,17 @@ describe('ContentNodeSelectorPanelComponent', () => {
properties: { 'st:componentId': 'blog' },
isFile: true
});
expect(component.rowFilter({ node: { entry: testSiteContent } } as any, null, null))
.toBe(false, 'did not filter out blog with filterFunction1');
expect(component.rowFilter({ node: { entry: testSiteContent } } as any, null, null)).toBe(
false,
'did not filter out blog with filterFunction1'
);
component.rowFilter = filterFunction2;
fixture.detectChanges();
expect(component.rowFilter({ node: { entry: testSiteContent } } as any, null, null))
.toBe(false, 'did not filter out blog with filterFunction2');
expect(component.rowFilter({ node: { entry: testSiteContent } } as any, null, null)).toBe(
false,
'did not filter out blog with filterFunction2'
);
});
it('should NOT filter out any site content by default', () => {
@ -245,33 +233,28 @@ describe('ContentNodeSelectorPanelComponent', () => {
it('should render search input by default', () => {
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('.adf-content-node-selector-content-input'))
.not.toBe(null);
expect(fixture.debugElement.nativeElement.querySelector('.adf-content-node-selector-content-input')).not.toBe(null);
});
it('should not render search input if `showSearch` is false', () => {
component.showSearch = false;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('.adf-content-node-selector-content-input'))
.toBe(null);
expect(fixture.debugElement.nativeElement.querySelector('.adf-content-node-selector-content-input')).toBe(null);
});
it('should render sites list dropdown by default', () => {
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('adf-sites-dropdown'))
.not.toBe(null);
expect(fixture.debugElement.nativeElement.querySelector('adf-sites-dropdown')).not.toBe(null);
});
it('should not render sites list dropdown if `showDropdownSiteList` is false', () => {
component.showDropdownSiteList = false;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('adf-sites-dropdown'))
.toBe(null);
expect(fixture.debugElement.nativeElement.querySelector('adf-sites-dropdown')).toBe(null);
});
});
describe('Breadcrumbs', () => {
let documentListService: DocumentListService;
beforeEach(() => {
@ -292,7 +275,6 @@ describe('ContentNodeSelectorPanelComponent', () => {
const breadcrumb = fixture.debugElement.query(By.directive(DropdownBreadcrumbComponent));
expect(breadcrumb).not.toBeNull();
expect(breadcrumb.componentInstance.folderNode).toEqual(undefined);
});
it('should not show the breadcrumb if search was performed as last action', async () => {
@ -314,7 +296,6 @@ describe('ContentNodeSelectorPanelComponent', () => {
fixture.detectChanges();
const breadcrumb = fixture.debugElement.query(By.directive(DropdownBreadcrumbComponent));
expect(breadcrumb).not.toBeNull();
});
it('should show the breadcrumb in search results for a valid node selection', async () => {
@ -377,7 +358,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
name: 'trans-node-name',
path: { elements: [{ id: 'testId', name: 'testName' }] }
};
component.breadcrumbTransform = (() => transformedFolderNode);
component.breadcrumbTransform = () => transformedFolderNode;
fixture.detectChanges();
await fixture.whenStable();
@ -391,7 +372,6 @@ describe('ContentNodeSelectorPanelComponent', () => {
});
describe('Chosen node', () => {
const entry: Node = { id: 'fakeid' } as Node;
const nodePage: NodePaging = { list: { pagination: {} } };
let hasAllowableOperations;
@ -464,7 +444,6 @@ describe('ContentNodeSelectorPanelComponent', () => {
});
describe('in the case when isSelectionValid is a custom function for checking permissions,', () => {
beforeEach(() => {
component.isSelectionValid = returnHasPermission;
});
@ -528,7 +507,6 @@ describe('ContentNodeSelectorPanelComponent', () => {
});
describe('in the case when isSelectionValid is null', () => {
beforeEach(() => {
component.isSelectionValid = null;
});
@ -579,7 +557,6 @@ describe('ContentNodeSelectorPanelComponent', () => {
});
describe('in the case when isSelectionValid is not defined', () => {
beforeEach(() => {
component.isSelectionValid = undefined;
});
@ -632,10 +609,13 @@ describe('ContentNodeSelectorPanelComponent', () => {
const isUploadingSpy = spyOn(uploadService, 'isUploading').and.returnValue(true);
const documentListReloadSpy = spyOn(component.documentList, 'reloadWithoutResettingSelection');
const fakeFileModels = [new FileModel({
name: 'fake-name',
size: 100
} as File), new FileModel({ name: 'fake-name-2', size: 200 } as File)];
const fakeFileModels = [
new FileModel({
name: 'fake-name',
size: 100
} as File),
new FileModel({ name: 'fake-name-2', size: 200 } as File)
];
const fileUploadCompleteEvent = new FileUploadCompleteEvent(fakeFileModels[0], 1, fakeFileModels[0], 0);
uploadService.fileUploadComplete.next(fileUploadCompleteEvent);
@ -698,11 +678,9 @@ describe('ContentNodeSelectorPanelComponent', () => {
expect(component.getPreselectNodesBasedOnSelectionMode()).toEqual([]);
});
});
});
describe('Search panel', () => {
beforeEach(() => {
contentNodeSelectorPanelService.customModels = undefined;
});

@ -17,7 +17,7 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { DownloadEntry, MinimalNode } from '@alfresco/js-api';
import { DownloadEntry } from '@alfresco/js-api';
import { LogService } from '@alfresco/adf-core';
import { NodesApiService } from '../../common/services/nodes-api.service';
import { DownloadZipService } from './services/download-zip.service';
@ -31,19 +31,19 @@ import { ContentService } from '../../common/services/content.service';
encapsulation: ViewEncapsulation.None
})
export class DownloadZipDialogComponent implements OnInit {
// flag for async threads
cancelled = false;
downloadId: string;
constructor(private dialogRef: MatDialogRef<DownloadZipDialogComponent>,
@Inject(MAT_DIALOG_DATA)
public data: any,
private logService: LogService,
private downloadZipService: DownloadZipService,
private nodeService: NodesApiService,
private contentService: ContentService) {
}
constructor(
private dialogRef: MatDialogRef<DownloadZipDialogComponent>,
@Inject(MAT_DIALOG_DATA)
public data: any,
private logService: LogService,
private downloadZipService: DownloadZipService,
private nodeService: NodesApiService,
private contentService: ContentService
) {}
ngOnInit() {
if (this.data && this.data.nodeIds && this.data.nodeIds.length > 0) {
@ -63,12 +63,11 @@ export class DownloadZipDialogComponent implements OnInit {
downloadZip(nodeIds: string[]) {
if (nodeIds && nodeIds.length > 0) {
this.downloadZipService.createDownload({ nodeIds }).subscribe((data: DownloadEntry) => {
if (data && data.entry && data.entry.id) {
const url = this.contentService.getContentUrl(data.entry.id, true);
this.nodeService.getNode(data.entry.id).subscribe((downloadNode: MinimalNode) => {
this.nodeService.getNode(data.entry.id).subscribe((downloadNode) => {
this.logService.log(downloadNode);
const fileName = downloadNode.name;
this.downloadId = data.entry.id;

@ -16,7 +16,7 @@
*/
import { Directive, HostListener, Input, OnChanges, Output, EventEmitter } from '@angular/core';
import { SiteBody, FavoriteBody, FavoriteEntry, FavoritesApi } from '@alfresco/js-api';
import { FavoriteBodyCreate, FavoritesApi } from '@alfresco/js-api';
import { AlfrescoApiService } from '@alfresco/adf-core';
import { LibraryEntity } from '../interfaces/library-entity.interface';
@ -34,7 +34,7 @@ export class LibraryFavoriteDirective implements OnChanges {
private targetLibrary = null;
_favoritesApi: FavoritesApi;
private _favoritesApi: FavoritesApi;
get favoritesApi(): FavoritesApi {
this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.alfrescoApiService.getInstance());
return this._favoritesApi;
@ -57,8 +57,7 @@ export class LibraryFavoriteDirective implements OnChanges {
}
}
constructor(private alfrescoApiService: AlfrescoApiService) {
}
constructor(private alfrescoApiService: AlfrescoApiService) {}
ngOnChanges(changes) {
if (!changes.library.currentValue) {
@ -87,10 +86,10 @@ export class LibraryFavoriteDirective implements OnChanges {
}
}
private addFavorite(favoriteBody: FavoriteBody) {
private addFavorite(favoriteBody: FavoriteBodyCreate) {
this.favoritesApi
.createFavorite('-me-', favoriteBody)
.then((libraryEntry: FavoriteEntry) => {
.then((libraryEntry) => {
this.targetLibrary.isFavorite = true;
this.toggle.emit(libraryEntry);
})
@ -100,7 +99,7 @@ export class LibraryFavoriteDirective implements OnChanges {
private removeFavorite(favoriteId: string) {
this.favoritesApi
.deleteFavorite('-me-', favoriteId)
.then((libraryBody: SiteBody) => {
.then((libraryBody) => {
this.targetLibrary.isFavorite = false;
this.toggle.emit(libraryBody);
})

@ -17,8 +17,8 @@
/* eslint-disable @angular-eslint/no-input-rename */
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output } from '@angular/core';
import { FavoriteBody, NodeEntry, SharedLinkEntry, Node, SharedLink, FavoritesApi } from '@alfresco/js-api';
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { FavoriteBodyCreate, NodeEntry, SharedLinkEntry, Node, SharedLink, FavoritesApi } from '@alfresco/js-api';
import { Observable, from, forkJoin, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { AlfrescoApiService } from '@alfresco/adf-core';
@ -30,7 +30,7 @@ import { AlfrescoApiService } from '@alfresco/adf-core';
export class NodeFavoriteDirective implements OnChanges {
favorites: any[] = [];
_favoritesApi: FavoritesApi;
private _favoritesApi: FavoritesApi;
get favoritesApi(): FavoritesApi {
this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.alfrescoApiService.getInstance());
return this._favoritesApi;
@ -41,20 +41,19 @@ export class NodeFavoriteDirective implements OnChanges {
selection: NodeEntry[] = [];
/** Emitted when the favorite setting is complete. */
@Output() toggle: EventEmitter<any> = new EventEmitter();
@Output() toggle = new EventEmitter<any>();
/** Emitted when the favorite setting fails. */
@Output() error: EventEmitter<any> = new EventEmitter();
@Output() error = new EventEmitter<any>();
@HostListener('click')
onClick() {
this.toggleFavorite();
}
constructor(private alfrescoApiService: AlfrescoApiService) {
}
constructor(private alfrescoApiService: AlfrescoApiService) {}
ngOnChanges(changes) {
ngOnChanges(changes: SimpleChanges) {
if (!changes.selection.currentValue.length) {
this.favorites = [];
@ -81,7 +80,7 @@ export class NodeFavoriteDirective implements OnChanges {
forkJoin(batch).subscribe(
() => {
this.favorites.map((selected) => selected.entry.isFavorite = false);
this.favorites.forEach((selected) => (selected.entry.isFavorite = false));
this.toggle.emit();
},
(error) => this.error.emit(error)
@ -90,23 +89,21 @@ export class NodeFavoriteDirective implements OnChanges {
if (!every) {
const notFavorite = this.favorites.filter((node) => !node.entry.isFavorite);
const body: FavoriteBody[] = notFavorite.map((node) => this.createFavoriteBody(node));
const body = notFavorite.map((node) => this.createFavoriteBody(node));
from(this.favoritesApi.createFavorite('-me-', body as any))
.subscribe(
() => {
notFavorite.map((selected) => selected.entry.isFavorite = true);
this.toggle.emit();
},
(error) => this.error.emit(error)
);
from(this.favoritesApi.createFavorite('-me-', body as any)).subscribe(
() => {
notFavorite.forEach((selected) => (selected.entry.isFavorite = true));
this.toggle.emit();
},
(error) => this.error.emit(error)
);
}
}
markFavoritesNodes(selection: NodeEntry[]) {
if (selection.length <= this.favorites.length) {
const newFavorites = this.reduce(this.favorites, selection);
this.favorites = newFavorites;
this.favorites = this.reduce(this.favorites, selection);
}
const result = this.diff(selection, this.favorites);
@ -125,8 +122,8 @@ export class NodeFavoriteDirective implements OnChanges {
return this.favorites.every((selected) => selected.entry.isFavorite);
}
private getProcessBatch(selection): any[] {
return selection.map((selected: NodeEntry) => this.getFavorite(selected));
private getProcessBatch(selection: NodeEntry[]): Observable<any>[] {
return selection.map((selected) => this.getFavorite(selected));
}
private getFavorite(selected: NodeEntry | SharedLinkEntry): Observable<any> {
@ -153,22 +150,24 @@ export class NodeFavoriteDirective implements OnChanges {
isFavorite: true
}
})),
catchError(() => of({
entry: {
id,
isFolder,
isFile,
name,
isFavorite: false
}
}))
catchError(() =>
of({
entry: {
id,
isFolder,
isFile,
name,
isFavorite: false
}
})
)
);
}
private createFavoriteBody(node): FavoriteBody {
private createFavoriteBody(node: NodeEntry): FavoriteBodyCreate {
const type = this.getNodeType(node);
// shared files have nodeId
const id = node.entry.nodeId || node.entry.id;
const id = node.entry['nodeId'] || node.entry.id;
return {
target: {
@ -179,7 +178,7 @@ export class NodeFavoriteDirective implements OnChanges {
};
}
private getNodeType(node): string {
private getNodeType(node: NodeEntry): string {
// shared could only be files
if (!node.entry.isFile && !node.entry.isFolder) {
return 'file';
@ -188,15 +187,15 @@ export class NodeFavoriteDirective implements OnChanges {
return node.entry.isFile ? 'file' : 'folder';
}
private diff(list, patch): any[] {
private diff(list: NodeEntry[], patch: any[]): NodeEntry[] {
const ids = patch.map((item) => item.entry.id);
return list.filter((item) => ids.includes(item.entry.id) ? null : item);
return list.filter((item) => (ids.includes(item.entry.id) ? null : item));
}
private reduce(patch, comparator): any[] {
private reduce(patch: any[], comparator: NodeEntry[]): any[] {
const ids = comparator.map((item) => item.entry.id);
return patch.filter((item) => ids.includes(item.entry.id) ? item : null);
return patch.filter((item) => (ids.includes(item.entry.id) ? item : null));
}
}

@ -26,10 +26,10 @@ import {
DataTableModule,
ObjectDataTableAdapter,
ShowHeaderMode,
ThumbnailService, AppConfigService
ThumbnailService,
AppConfigService
} from '@alfresco/adf-core';
import { ContentService } from '../../common/services/content.service';
import { Subject, of, throwError } from 'rxjs';
import {
FileNode,
@ -45,15 +45,13 @@ import {
mockNode3
} from '../../mock';
import { ContentActionModel } from '../models/content-action.model';
import { NodeMinimal, NodeMinimalEntry, NodePaging } from '../models/document-library.model';
import { ImageResolver } from './../data/image-resolver.model';
import { RowFilter } from './../data/row-filter.model';
import { DocumentListService } from './../services/document-list.service';
import { CustomResourcesService } from './../services/custom-resources.service';
import { DocumentListComponent } from './document-list.component';
import { ContentTestingModule } from '../../testing/content.testing.module';
import { FavoritePaging, NodeEntry } from '@alfresco/js-api';
import { FavoritePaging, NodeEntry, NodePaging, Node } from '@alfresco/js-api';
import { By } from '@angular/platform-browser';
import { DocumentListModule } from '../document-list.module';
import { TranslateModule } from '@ngx-translate/core';
@ -69,7 +67,6 @@ const mockDialog = {
};
describe('DocumentList', () => {
let documentList: DocumentListComponent;
let documentListService: DocumentListService;
let apiService: AlfrescoApiService;
@ -87,14 +84,9 @@ describe('DocumentList', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
{ provide: MatDialog, useValue: mockDialog }
]
providers: [{ provide: MatDialog, useValue: mockDialog }]
});
eventMock = {
preventDefault: () => {}
@ -120,7 +112,9 @@ describe('DocumentList', () => {
documentList.currentFolderId = 'no-node';
spyGetSites = spyOn(customResourcesService.sitesApi, 'listSites').and.returnValue(Promise.resolve(fakeGetSitesAnswer));
spyFavorite = spyOn(customResourcesService.favoritesApi, 'listFavorites').and.returnValue(Promise.resolve(new FavoritePaging({ list: { entries: [] } })));
spyFavorite = spyOn(customResourcesService.favoritesApi, 'listFavorites').and.returnValue(
Promise.resolve(new FavoritePaging({ list: { entries: [] } }))
);
});
afterEach(() => {
@ -128,7 +122,6 @@ describe('DocumentList', () => {
});
describe('presets', () => {
const validatePreset = (keys: string[]) => {
const columns = documentList.data.getColumns();
expect(columns.length).toBe(keys.length);
@ -144,14 +137,7 @@ describe('DocumentList', () => {
fixture.detectChanges();
await fixture.whenStable();
validatePreset([
'$thumbnail',
'name',
'path',
'content.sizeInBytes',
'archivedAt',
'archivedByUser.displayName'
]);
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'archivedAt', 'archivedByUser.displayName']);
});
it('should load -sites- preset', async () => {
@ -160,11 +146,7 @@ describe('DocumentList', () => {
fixture.detectChanges();
await fixture.whenStable();
validatePreset([
'$thumbnail',
'title',
'visibility'
]);
validatePreset(['$thumbnail', 'title', 'visibility']);
});
it('shuld load -mysites- preset', async () => {
@ -173,11 +155,7 @@ describe('DocumentList', () => {
fixture.detectChanges();
await fixture.whenStable();
validatePreset([
'$thumbnail',
'title',
'visibility'
]);
validatePreset(['$thumbnail', 'title', 'visibility']);
});
it('should load -favorites- preset', async () => {
@ -186,14 +164,7 @@ describe('DocumentList', () => {
fixture.detectChanges();
await fixture.whenStable();
validatePreset([
'$thumbnail',
'name',
'path',
'content.sizeInBytes',
'modifiedAt',
'modifiedByUser.displayName'
]);
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'modifiedAt', 'modifiedByUser.displayName']);
});
it('should load -recent- preset', async () => {
@ -202,13 +173,7 @@ describe('DocumentList', () => {
fixture.detectChanges();
await fixture.whenStable();
validatePreset([
'$thumbnail',
'name',
'path',
'content.sizeInBytes',
'modifiedAt'
]);
validatePreset(['$thumbnail', 'name', 'path', 'content.sizeInBytes', 'modifiedAt']);
});
it('should load -sharedlinks- preset', async () => {
@ -234,13 +199,7 @@ describe('DocumentList', () => {
fixture.detectChanges();
await fixture.whenStable();
validatePreset([
'$thumbnail',
'name',
'content.sizeInBytes',
'modifiedAt',
'modifiedByUser.displayName'
]);
validatePreset(['$thumbnail', 'name', 'content.sizeInBytes', 'modifiedAt', 'modifiedByUser.displayName']);
});
});
@ -330,8 +289,7 @@ describe('DocumentList', () => {
it('should call action handler with node', () => {
const node = new FileNode();
const action = new ContentActionModel();
action.handler = () => {
};
action.handler = () => {};
spyOn(action, 'handler').and.stub();
@ -342,8 +300,7 @@ describe('DocumentList', () => {
it('should call action handler with node and permission', () => {
const node = new FileNode();
const action = new ContentActionModel();
action.handler = () => {
};
action.handler = () => {};
action.permission = 'fake-permission';
spyOn(action, 'handler').and.stub();
@ -355,8 +312,7 @@ describe('DocumentList', () => {
it('should call action execute with node if it is defined', () => {
const node = new FileNode();
const action = new ContentActionModel();
action.execute = () => {
};
action.execute = () => {};
spyOn(action, 'execute').and.stub();
documentList.executeContentAction(node, action);
@ -369,8 +325,7 @@ describe('DocumentList', () => {
const node = new FileNode();
const action = new ContentActionModel();
action.handler = () => deleteObservable;
action.execute = () => {
};
action.execute = () => {};
spyOn(action, 'execute').and.stub();
documentList.executeContentAction(node, action);
@ -482,10 +437,7 @@ describe('DocumentList', () => {
const documentMenu = new ContentActionModel();
documentMenu.target = 'document';
documentList.actions = [
folderMenu,
documentMenu
];
documentList.actions = [folderMenu, documentMenu];
let actions = documentList.getNodeActions(new FolderNode());
expect(actions.length).toBe(1);
@ -505,9 +457,7 @@ describe('DocumentList', () => {
title: 'FileAction'
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = { entry: { isFile: true, name: 'xyz', allowableOperations: ['create', 'update'] } };
@ -594,9 +544,7 @@ describe('DocumentList', () => {
title: 'FileAction'
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = { entry: { isFile: true, name: 'xyz', allowableOperations: ['create', 'update'] } };
@ -614,9 +562,7 @@ describe('DocumentList', () => {
title: 'FolderAction'
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = { entry: { isFolder: true, name: 'xyz', allowableOperations: ['create', 'update'] } };
@ -634,9 +580,7 @@ describe('DocumentList', () => {
title: 'FileAction'
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = { entry: { isFile: true, name: 'xyz', allowableOperations: ['create', 'update', 'delete'] } };
@ -653,9 +597,7 @@ describe('DocumentList', () => {
title: 'FileAction'
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = {
entry: {
@ -682,9 +624,7 @@ describe('DocumentList', () => {
spyOn(apiService.getInstance(), 'getEcmUsername').and.returnValue('lockOwner');
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = {
entry: {
@ -715,9 +655,7 @@ describe('DocumentList', () => {
spyOn(apiService.getInstance(), 'getEcmUsername').and.returnValue('jerryTheKillerCow');
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = {
entry: {
@ -747,9 +685,7 @@ describe('DocumentList', () => {
title: 'FolderAction'
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = {
entry: {
@ -773,9 +709,7 @@ describe('DocumentList', () => {
disableWithNoPermission: false
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = { entry: { isFile: true, name: 'xyz', allowableOperations: null } };
@ -793,9 +727,7 @@ describe('DocumentList', () => {
disableWithNoPermission: false
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = { entry: { isFolder: true, name: 'xyz', allowableOperations: null } };
@ -813,9 +745,7 @@ describe('DocumentList', () => {
disableWithNoPermission: true
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = { entry: { isFile: true, name: 'xyz', allowableOperations: null } };
@ -834,9 +764,7 @@ describe('DocumentList', () => {
disableWithNoPermission: true
});
documentList.actions = [
documentMenu
];
documentList.actions = [documentMenu];
const nodeFile = { entry: { isFolder: true, name: 'xyz', allowableOperations: null } };
@ -852,7 +780,7 @@ describe('DocumentList', () => {
documentButton.target = 'document';
documentList.actions = [documentButton];
let node = new NodeMinimalEntry();
let node = new NodeEntry();
expect(documentList.getNodeActions(node)).toEqual([]);
node = new FileNode();
@ -1022,7 +950,7 @@ describe('DocumentList', () => {
expect(documentList.navigateTo(null)).toBeFalsy();
});
it('should perform navigation through corret linked folder', () => {
it('should perform navigation through correct linked folder', () => {
const linkFolder = new FolderNode();
linkFolder.entry.id = 'link-folder';
linkFolder.entry.nodeType = 'app:folderlink';
@ -1040,7 +968,7 @@ describe('DocumentList', () => {
let called = false;
documentList.navigationMode = DocumentListComponent.SINGLE_CLICK_NAVIGATION;
documentList.preview.subscribe(() => called = true);
documentList.preview.subscribe(() => (called = true));
documentList.onNodeClick(file);
expect(called).toBeFalsy();
@ -1065,7 +993,7 @@ describe('DocumentList', () => {
});
it('should display folder content from loadFolder on reload if folderNode defined', () => {
documentList.folderNode = new NodeMinimal();
documentList.folderNode = new Node();
spyOn(documentList, 'loadFolder').and.callThrough();
documentList.reload();
@ -1203,7 +1131,7 @@ describe('DocumentList', () => {
});
it('should emit [nodeClick] event on row click', () => {
const node = new NodeMinimalEntry();
const node = new NodeEntry();
spyOn(documentList, 'onNodeClick').and.callThrough();
documentList.onNodeClick(node);
@ -1211,7 +1139,7 @@ describe('DocumentList', () => {
});
it('should emit node-click DOM event', () => {
const node = new NodeMinimalEntry();
const node = new NodeEntry();
document.addEventListener('node-click', (res) => {
expect(res).toBeDefined();
@ -1221,7 +1149,7 @@ describe('DocumentList', () => {
});
it('should emit [nodeDblClick] event on row double-click', () => {
const node = new NodeMinimalEntry();
const node = new NodeEntry();
spyOn(documentList, 'onNodeDblClick').and.callThrough();
documentList.onNodeDblClick(node);
@ -1229,7 +1157,7 @@ describe('DocumentList', () => {
});
it('should emit node-dblclick DOM event', () => {
const node = new NodeMinimalEntry();
const node = new NodeEntry();
document.addEventListener('node-dblclick', (res) => {
expect(res).toBeDefined();
@ -1316,7 +1244,7 @@ describe('DocumentList', () => {
const error = { message: '{ "error": { "statusCode": 403 } }' };
documentList.currentFolderId = '1d26e465-dea3-42f3-b415-faa8364b9692';
documentList.folderNode = new NodeMinimal();
documentList.folderNode = new Node();
documentList.folderNode.id = '1d26e465-dea3-42f3-b415-faa8364b9692';
spyFolderNode.and.returnValue(of({ entry: fakeNodeWithNoPermission }));
@ -1330,7 +1258,9 @@ describe('DocumentList', () => {
});
it('should allow to perform navigation for virtual sources', () => {
spyFolderNode = spyOn(documentListService, 'loadFolderByNodeId').and.callFake(() => of(new DocumentLoaderNode(null, { list: { pagination: {} } })));
spyFolderNode = spyOn(documentListService, 'loadFolderByNodeId').and.callFake(() =>
of(new DocumentLoaderNode(null, { list: { pagination: {} } }))
);
const sources = ['-trashcan-', '-sharedlinks-', '-sites-', '-mysites-', '-favorites-', '-recent-'];
const node = new FolderNode('folder');
@ -1502,13 +1432,17 @@ describe('DocumentList', () => {
documentList.ngOnChanges({ currentFolderId: new SimpleChange(undefined, 'fake-id', true) });
expect(documentListService.getFolder).toHaveBeenCalledWith(null, {
where: undefined,
maxItems: 25,
skipCount: 0,
orderBy: ['isFolder desc', 'name asc'],
rootFolderId: 'fake-id'
}, ['test-include']);
expect(documentListService.getFolder).toHaveBeenCalledWith(
null,
{
where: undefined,
maxItems: 25,
skipCount: 0,
orderBy: ['isFolder desc', 'name asc'],
rootFolderId: 'fake-id'
},
['test-include']
);
});
it('should add where in the server request when present', () => {
@ -1518,13 +1452,17 @@ describe('DocumentList', () => {
documentList.ngOnChanges({ currentFolderId: new SimpleChange(undefined, 'fake-id', true) });
expect(documentListService.getFolder).toHaveBeenCalledWith(null, {
where: '(isFolder=true)',
maxItems: 25,
skipCount: 0,
orderBy: ['isFolder desc', 'name asc'],
rootFolderId: 'fake-id'
}, ['test-include']);
expect(documentListService.getFolder).toHaveBeenCalledWith(
null,
{
where: '(isFolder=true)',
maxItems: 25,
skipCount: 0,
orderBy: ['isFolder desc', 'name asc'],
rootFolderId: 'fake-id'
},
['test-include']
);
});
it('should add orderBy in the server request', () => {
@ -1535,13 +1473,17 @@ describe('DocumentList', () => {
documentList.ngOnChanges({ currentFolderId: new SimpleChange(undefined, 'fake-id', true) });
expect(documentListService.getFolder).toHaveBeenCalledWith(null, {
maxItems: 25,
skipCount: 0,
where: null,
orderBy: ['isFolder desc', 'size desc'],
rootFolderId: 'fake-id'
}, ['test-include']);
expect(documentListService.getFolder).toHaveBeenCalledWith(
null,
{
maxItems: 25,
skipCount: 0,
where: null,
orderBy: ['isFolder desc', 'size desc'],
rootFolderId: 'fake-id'
},
['test-include']
);
});
it('should reset the pagination when enter in a new folder', () => {
@ -1553,23 +1495,31 @@ describe('DocumentList', () => {
skipCount: 10
});
expect(documentListService.getFolder).toHaveBeenCalledWith(null, Object({
maxItems: 10,
skipCount: 10,
orderBy: ['isFolder desc', 'name asc'],
rootFolderId: 'no-node',
where: undefined
}), undefined);
expect(documentListService.getFolder).toHaveBeenCalledWith(
null,
Object({
maxItems: 10,
skipCount: 10,
orderBy: ['isFolder desc', 'name asc'],
rootFolderId: 'no-node',
where: undefined
}),
undefined
);
documentList.onNodeClick(folder);
expect(documentListService.getFolder).toHaveBeenCalledWith(null, Object({
maxItems: 25,
skipCount: 0,
orderBy: ['isFolder desc', 'name asc'],
rootFolderId: 'folder-id',
where: undefined
}), undefined);
expect(documentListService.getFolder).toHaveBeenCalledWith(
null,
Object({
maxItems: 25,
skipCount: 0,
orderBy: ['isFolder desc', 'name asc'],
rootFolderId: 'folder-id',
where: undefined
}),
undefined
);
});
it('should display fileAutoDownload dialog if node size exceeds appConfig.viewer.fileAutoDownloadSizeThresholdInMB', async () => {
@ -1581,13 +1531,15 @@ describe('DocumentList', () => {
}
};
documentList.navigationMode = DocumentListComponent.SINGLE_CLICK_NAVIGATION;
const node = { entry: {
const node = {
entry: {
...mockNode1,
content: {
...mockNode1.content,
sizeInBytes: 104857600
}
} };
}
};
documentList.onNodeClick(node);
fixture.detectChanges();
@ -1597,7 +1549,6 @@ describe('DocumentList', () => {
});
describe('Preselect nodes', () => {
beforeEach(() => {
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_created.svg`);
});
@ -1634,7 +1585,10 @@ describe('DocumentList', () => {
it('should call the datatable select row method for each preselected node', async () => {
const datatableSelectRowSpy = spyOn(documentList.dataTable, 'selectRow');
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
const fakeDatatableRows = [
new ShareDataRow(mockPreselectedNodes[0], contentService, null),
new ShareDataRow(mockPreselectedNodes[1], contentService, null)
];
spyOn(documentList, 'preselectRowsOfPreselectedNodes');
documentList.preselectedRows = fakeDatatableRows;
@ -1665,7 +1619,10 @@ describe('DocumentList', () => {
it('should return only the first preselected row when selection mode is single', () => {
documentList.selectionMode = 'single';
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
const fakeDatatableRows = [
new ShareDataRow(mockPreselectedNodes[0], contentService, null),
new ShareDataRow(mockPreselectedNodes[1], contentService, null)
];
documentList.preselectedRows = fakeDatatableRows;
const preselectedRows = documentList.getPreselectedRowsBasedOnSelectionMode();
@ -1675,7 +1632,10 @@ describe('DocumentList', () => {
it('should return all the preselected rows when selection mode is multiple', () => {
documentList.selectionMode = 'multiple';
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
const fakeDatatableRows = [
new ShareDataRow(mockPreselectedNodes[0], contentService, null),
new ShareDataRow(mockPreselectedNodes[1], contentService, null)
];
documentList.preselectedRows = fakeDatatableRows;
const preselectedRows = documentList.getPreselectedRowsBasedOnSelectionMode();
@ -1692,7 +1652,10 @@ describe('DocumentList', () => {
it('should the combined selection be only the first preselected row when selection mode is single', () => {
const getSelectionFromAdapterSpy = spyOn(documentList.data, 'getSelectedRows');
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
const fakeDatatableRows = [
new ShareDataRow(mockPreselectedNodes[0], contentService, null),
new ShareDataRow(mockPreselectedNodes[1], contentService, null)
];
documentList.preselectedRows = fakeDatatableRows;
documentList.selectionMode = 'single';
const selection = documentList.getSelectionBasedOnSelectionMode();
@ -1703,7 +1666,10 @@ describe('DocumentList', () => {
});
it('should get the selection from the adapter when selection mode is multiple', () => {
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
const fakeDatatableRows = [
new ShareDataRow(mockPreselectedNodes[0], contentService, null),
new ShareDataRow(mockPreselectedNodes[1], contentService, null)
];
fakeDatatableRows[0].isSelected = true;
fakeDatatableRows[1].isSelected = false;
documentList.data.setRows(fakeDatatableRows);
@ -1747,7 +1713,10 @@ describe('DocumentList', () => {
const getRowByNodeIdSpy = spyOn(documentList.data, 'getRowByNodeId').and.callThrough();
const onNodeUnselectSpy = spyOn(documentList, 'onNodeUnselect');
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
const fakeDatatableRows = [
new ShareDataRow(mockPreselectedNodes[0], contentService, null),
new ShareDataRow(mockPreselectedNodes[1], contentService, null)
];
fakeDatatableRows[0].isSelected = true;
documentList.data.setRows(fakeDatatableRows);
let selection = documentList.data.getSelectedRows();
@ -1766,7 +1735,10 @@ describe('DocumentList', () => {
it('should preselect the rows of the preselected nodes', () => {
const getRowByNodeIdSpy = spyOn(documentList.data, 'getRowByNodeId').and.callThrough();
const fakeDatatableRows = [new ShareDataRow(mockPreselectedNodes[0], contentService, null), new ShareDataRow(mockPreselectedNodes[1], contentService, null)];
const fakeDatatableRows = [
new ShareDataRow(mockPreselectedNodes[0], contentService, null),
new ShareDataRow(mockPreselectedNodes[1], contentService, null)
];
documentList.data.setRows(fakeDatatableRows);
documentList.selectionMode = 'multiple';
@ -1814,7 +1786,7 @@ describe('DocumentList', () => {
@Component({
template: `
<adf-document-list #customDocumentList>
<adf-document-list #customDocumentList>
<adf-custom-loading-content-template>
<span id="custom-loading-template">This is a custom loading template</span>
</adf-custom-loading-content-template>
@ -1840,12 +1812,7 @@ describe('DocumentListComponent rendering', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [CustomTemplateComponent],
imports: [
TranslateModule.forRoot(),
ContentTestingModule,
DataTableModule,
DocumentListModule
]
imports: [TranslateModule.forRoot(), ContentTestingModule, DataTableModule, DocumentListModule]
});
fixture = TestBed.createComponent(CustomTemplateComponent);
component = fixture.componentInstance;
@ -1905,5 +1872,4 @@ describe('DocumentListComponent rendering', () => {
const cell3 = fixture.nativeElement.querySelector('div[title="Id"][data-automation-id="Name 3"]');
expect(cell3.innerText).toBe('3');
});
});

@ -22,16 +22,14 @@ import { SearchHeaderQueryBuilderService } from '../../../search/services/search
import { FilterSearch } from './../../../search/models/filter-search.interface';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { NodePaging, MinimalNode } from '@alfresco/js-api';
import { ADF_DOCUMENT_PARENT_COMPONENT } from '../document-list.token';
@Component({
selector: 'adf-filter-header',
templateUrl: './filter-header.component.html',
providers: [{ provide: SEARCH_QUERY_SERVICE_TOKEN, useClass: SearchHeaderQueryBuilderService}]
providers: [{ provide: SEARCH_QUERY_SERVICE_TOKEN, useClass: SearchHeaderQueryBuilderService }]
})
export class FilterHeaderComponent implements OnInit, OnChanges, OnDestroy {
/** (optional) Initial filter value to sort . */
@Input()
value: any = {};
@ -47,18 +45,18 @@ export class FilterHeaderComponent implements OnInit, OnChanges, OnDestroy {
isFilterServiceActive: boolean;
private onDestroy$ = new Subject<boolean>();
constructor(@Inject(ADF_DOCUMENT_PARENT_COMPONENT) private documentList: any,
@Inject(SEARCH_QUERY_SERVICE_TOKEN) private searchFilterQueryBuilder: SearchHeaderQueryBuilderService) {
constructor(
@Inject(ADF_DOCUMENT_PARENT_COMPONENT) private documentList: any,
@Inject(SEARCH_QUERY_SERVICE_TOKEN) private searchFilterQueryBuilder: SearchHeaderQueryBuilderService
) {
this.isFilterServiceActive = this.searchFilterQueryBuilder.isFilterServiceActive();
}
ngOnInit() {
this.searchFilterQueryBuilder.executed
.pipe(takeUntil(this.onDestroy$))
.subscribe((newNodePaging: NodePaging) => {
this.documentList.node = newNodePaging;
this.documentList.reload();
});
this.searchFilterQueryBuilder.executed.pipe(takeUntil(this.onDestroy$)).subscribe((newNodePaging) => {
this.documentList.node = newNodePaging;
this.documentList.reload();
});
this.initDataPagination();
this.initDataSorting();
@ -84,24 +82,20 @@ export class FilterHeaderComponent implements OnInit, OnChanges, OnDestroy {
}
initDataPagination() {
this.documentList.pagination
.pipe(takeUntil(this.onDestroy$))
.subscribe((newPagination: PaginationModel) => {
this.searchFilterQueryBuilder.setupCurrentPagination(newPagination.maxItems, newPagination.skipCount);
});
this.documentList.pagination.pipe(takeUntil(this.onDestroy$)).subscribe((newPagination: PaginationModel) => {
this.searchFilterQueryBuilder.setupCurrentPagination(newPagination.maxItems, newPagination.skipCount);
});
}
initDataSorting() {
this.documentList.sortingSubject
.pipe(takeUntil(this.onDestroy$))
.subscribe((sorting: DataSorting[]) => {
this.searchFilterQueryBuilder.setSorting(sorting);
});
this.documentList.sortingSubject.pipe(takeUntil(this.onDestroy$)).subscribe((sorting: DataSorting[]) => {
this.searchFilterQueryBuilder.setSorting(sorting);
});
}
private configureSearchParent(currentFolderId: string) {
if (this.searchFilterQueryBuilder.isCustomSourceNode(currentFolderId)) {
this.searchFilterQueryBuilder.getNodeIdForCustomSource(currentFolderId).subscribe((node: MinimalNode) => {
this.searchFilterQueryBuilder.getNodeIdForCustomSource(currentFolderId).subscribe((node) => {
this.initSearchHeader(node.id);
});
} else {
@ -116,7 +110,6 @@ export class FilterHeaderComponent implements OnInit, OnChanges, OnDestroy {
this.searchFilterQueryBuilder.setActiveFilter(columnKey, this.value[columnKey]);
});
}
}
ngOnDestroy() {

@ -16,7 +16,7 @@
*/
import { DataRow, ObjectUtils, ThumbnailService } from '@alfresco/adf-core';
import { MinimalNode, NodeEntry } from '@alfresco/js-api';
import { Node, NodeEntry } from '@alfresco/js-api';
import { PermissionStyleModel } from './../models/permissions-style.model';
import { ContentService } from './../../common/services/content.service';
@ -38,16 +38,19 @@ export class ShareDataRow implements DataRow {
this.cache = {};
}
constructor(private obj: NodeEntry,
private contentService: ContentService,
private permissionsStyle: PermissionStyleModel[],
private thumbnailService?: ThumbnailService,
private allowDropFiles?: boolean) {
constructor(
private obj: NodeEntry,
private contentService: ContentService,
private permissionsStyle: PermissionStyleModel[],
private thumbnailService?: ThumbnailService,
private allowDropFiles?: boolean
) {
if (!obj) {
throw new Error(ERR_OBJECT_NOT_FOUND);
}
this.isDropTarget = allowDropFiles !== undefined ? this.allowDropFiles && this.checkNodeTypeAndPermissions(obj) : this.checkNodeTypeAndPermissions(obj);
this.isDropTarget =
allowDropFiles !== undefined ? this.allowDropFiles && this.checkNodeTypeAndPermissions(obj) : this.checkNodeTypeAndPermissions(obj);
if (permissionsStyle) {
this.cssClass = this.getPermissionClass(obj);
}
@ -62,25 +65,25 @@ export class ShareDataRow implements DataRow {
let permissionsClasses = '';
this.permissionsStyle.forEach((currentPermissionsStyle: PermissionStyleModel) => {
if (this.applyPermissionStyleToFolder(nodeEntity.entry, currentPermissionsStyle) || this.applyPermissionStyleToFile(nodeEntity.entry, currentPermissionsStyle)) {
if (
this.applyPermissionStyleToFolder(nodeEntity.entry, currentPermissionsStyle) ||
this.applyPermissionStyleToFile(nodeEntity.entry, currentPermissionsStyle)
) {
if (this.contentService.hasAllowableOperations(nodeEntity.entry, currentPermissionsStyle.permission)) {
permissionsClasses += ` ${currentPermissionsStyle.css}`;
}
}
});
return permissionsClasses;
}
private applyPermissionStyleToFile(node: MinimalNode, currentPermissionsStyle: PermissionStyleModel): boolean {
return (currentPermissionsStyle.isFile && node.isFile);
private applyPermissionStyleToFile(node: Node, currentPermissionsStyle: PermissionStyleModel): boolean {
return currentPermissionsStyle.isFile && node.isFile;
}
private applyPermissionStyleToFolder(node: MinimalNode, currentPermissionsStyle: PermissionStyleModel): boolean {
return (currentPermissionsStyle.isFolder && node.isFolder);
private applyPermissionStyleToFolder(node: Node, currentPermissionsStyle: PermissionStyleModel): boolean {
return currentPermissionsStyle.isFolder && node.isFolder;
}
isFolderAndHasPermissionToUpload(nodeEntry: NodeEntry): boolean {

@ -1,85 +0,0 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* 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.
*/
// note: contains only limited subset of available fields
import { NodeEntry, Node } from '@alfresco/js-api';
export class NodePaging {
list: NodePagingList;
}
export class NodePagingList {
pagination: Pagination;
entries: NodeMinimalEntry[];
}
export class NodeMinimalEntry implements NodeEntry {
entry: NodeMinimal;
}
export class Pagination {
count: number;
hasMoreItems: boolean;
totalItems: number;
skipCount: number;
maxItems: number;
}
export class NodeMinimal implements Node {
id: string;
parentId: string;
name: string;
nodeType: string;
isFolder: boolean;
isFile: boolean;
modifiedAt: Date;
modifiedByUser: UserInfo;
createdAt: Date;
createdByUser: UserInfo;
content: ContentInfo;
path: PathInfoEntity;
properties: NodeProperties = {};
aspectNames: string[];
}
export class UserInfo {
displayName: string;
id: string;
}
export class ContentInfo {
mimeType: string;
mimeTypeName: string;
sizeInBytes: number;
encoding: string;
}
export class PathInfoEntity {
elements: PathElementEntity[];
isComplete: boolean;
name: string;
}
export class PathElementEntity {
id: string;
name: string;
}
export interface NodeProperties {
[key: string]: any;
}

@ -43,7 +43,6 @@ export * from './services/lock.service';
// models
export * from './models/content-action.model';
export * from './models/document-library.model';
export * from './models/permissions.model';
export * from './models/permissions-style.model';
export * from './models/node-action.enum';

@ -19,7 +19,7 @@ import { AlfrescoApiService, LogService, PaginationModel } from '@alfresco/adf-c
import { NodesApiService } from '../../common/services/nodes-api.service';
import { Injectable } from '@angular/core';
import { MinimalNode, NodeEntry, NodePaging, NodesApi } from '@alfresco/js-api';
import { Node, NodeEntry, NodePaging, NodesApi } from '@alfresco/js-api';
import { DocumentLoaderNode } from '../models/document-folder.model';
import { Observable, from, throwError, forkJoin } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
@ -32,18 +32,18 @@ const ROOT_ID = '-root-';
providedIn: 'root'
})
export class DocumentListService implements DocumentListLoader {
private _nodesApi: NodesApi;
get nodes(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance());
return this._nodesApi;
}
constructor(private nodesApiService: NodesApiService,
private apiService: AlfrescoApiService,
private logService: LogService,
private customResourcesService: CustomResourcesService) {
}
constructor(
private nodesApiService: NodesApiService,
private apiService: AlfrescoApiService,
private logService: LogService,
private customResourcesService: CustomResourcesService
) {}
/**
* Deletes a node.
@ -63,9 +63,7 @@ export class DocumentListService implements DocumentListLoader {
* @returns NodeEntry for the copied node
*/
copyNode(nodeId: string, targetParentId: string): Observable<NodeEntry> {
return from(this.nodes.copyNode(nodeId, { targetParentId })).pipe(
catchError((err) => this.handleError(err))
);
return from(this.nodes.copyNode(nodeId, { targetParentId })).pipe(catchError((err) => this.handleError(err)));
}
/**
@ -76,9 +74,7 @@ export class DocumentListService implements DocumentListLoader {
* @returns NodeEntry for the moved node
*/
moveNode(nodeId: string, targetParentId: string): Observable<NodeEntry> {
return from(this.nodes.moveNode(nodeId, { targetParentId })).pipe(
catchError((err) => this.handleError(err))
);
return from(this.nodes.moveNode(nodeId, { targetParentId })).pipe(catchError((err) => this.handleError(err)));
}
/**
@ -95,8 +91,9 @@ export class DocumentListService implements DocumentListLoader {
rootNodeId = opts.rootFolderId;
}
const includeFieldsRequest = ['path', 'properties', 'allowableOperations', 'permissions', 'aspectNames', ...includeFields]
.filter((element, index, array) => index === array.indexOf(element));
const includeFieldsRequest = ['path', 'properties', 'allowableOperations', 'permissions', 'aspectNames', ...includeFields].filter(
(element, index, array) => index === array.indexOf(element)
);
const params: any = {
includeSource: true,
@ -122,9 +119,7 @@ export class DocumentListService implements DocumentListLoader {
}
}
return from(this.nodes.listNodeChildren(rootNodeId, params)).pipe(
catchError((err) => this.handleError(err))
);
return from(this.nodes.listNodeChildren(rootNodeId, params)).pipe(catchError((err) => this.handleError(err)));
}
/**
@ -134,9 +129,10 @@ export class DocumentListService implements DocumentListLoader {
* @param includeFields Extra information to include (available options are "aspectNames", "isLink" and "association")
* @returns Details of the folder
*/
getNode(nodeId: string, includeFields: string[] = []): Observable<MinimalNode> {
const includeFieldsRequest = ['path', 'properties', 'allowableOperations', 'permissions', 'definition', ...includeFields]
.filter((element, index, array) => index === array.indexOf(element));
getNode(nodeId: string, includeFields: string[] = []): Observable<Node> {
const includeFieldsRequest = ['path', 'properties', 'allowableOperations', 'permissions', 'definition', ...includeFields].filter(
(element, index, array) => index === array.indexOf(element)
);
const opts: any = {
includeSource: true,
@ -154,17 +150,16 @@ export class DocumentListService implements DocumentListLoader {
* @returns Details of the folder
*/
getFolderNode(nodeId: string, includeFields: string[] = []): Observable<NodeEntry> {
const includeFieldsRequest = ['path', 'properties', 'allowableOperations', 'permissions', 'aspectNames', ...includeFields]
.filter((element, index, array) => index === array.indexOf(element));
const includeFieldsRequest = ['path', 'properties', 'allowableOperations', 'permissions', 'aspectNames', ...includeFields].filter(
(element, index, array) => index === array.indexOf(element)
);
const opts: any = {
includeSource: true,
include: includeFieldsRequest
};
return from(this.nodes.getNode(nodeId, opts)).pipe(
catchError((err) => this.handleError(err))
);
return from(this.nodes.getNode(nodeId, opts)).pipe(catchError((err) => this.handleError(err)));
}
isCustomSourceService(nodeId): boolean {
@ -181,28 +176,43 @@ export class DocumentListService implements DocumentListLoader {
* @param orderBy order by node property
* @returns Details of the folder
*/
loadFolderByNodeId(nodeId: string, pagination: PaginationModel, includeFields: string[], where?: string, orderBy?: string[]): Observable<DocumentLoaderNode> {
loadFolderByNodeId(
nodeId: string,
pagination: PaginationModel,
includeFields: string[],
where?: string,
orderBy?: string[]
): Observable<DocumentLoaderNode> {
if (this.customResourcesService.isCustomSource(nodeId)) {
return this.customResourcesService.loadFolderByNodeId(nodeId, pagination, includeFields, where).pipe(
map((result: any) => new DocumentLoaderNode(null, result))
);
return this.customResourcesService
.loadFolderByNodeId(nodeId, pagination, includeFields, where)
.pipe(map((result: any) => new DocumentLoaderNode(null, result)));
} else {
return this.retrieveDocumentNode(nodeId, pagination, includeFields, where, orderBy);
}
}
private retrieveDocumentNode(nodeId: string, pagination: PaginationModel, includeFields: string[], where?: string, orderBy?: string[]): Observable<DocumentLoaderNode> {
private retrieveDocumentNode(
nodeId: string,
pagination: PaginationModel,
includeFields: string[],
where?: string,
orderBy?: string[]
): Observable<DocumentLoaderNode> {
return forkJoin([
this.getFolderNode(nodeId, includeFields),
this.getFolder(null, {
maxItems: pagination.maxItems,
skipCount: pagination.skipCount,
orderBy,
rootFolderId: nodeId,
where
}, includeFields)]).pipe(
map((results) => new DocumentLoaderNode(results[0], results[1]))
);
this.getFolder(
null,
{
maxItems: pagination.maxItems,
skipCount: pagination.skipCount,
orderBy,
rootFolderId: nodeId,
where
},
includeFields
)
]).pipe(map((results) => new DocumentLoaderNode(results[0], results[1])));
}
private handleError(error: any) {

@ -16,14 +16,14 @@
*/
import { CardViewBaseItemModel, UpdateNotification } from '@alfresco/adf-core';
import { MinimalNode } from '@alfresco/js-api';
import { Node } from '@alfresco/js-api';
import { Subject } from 'rxjs';
export interface BaseCardViewContentUpdate {
itemUpdated$: Subject<UpdateNotification>;
updatedAspect$: Subject<MinimalNode>;
updatedAspect$: Subject<Node>;
update(property: CardViewBaseItemModel, newValue: any);
updateElement(notification: CardViewBaseItemModel);
updateNodeAspect(node: MinimalNode);
updateNodeAspect(node: Node);
}

@ -15,85 +15,75 @@
* limitations under the License.
*/
import {
ContentInfo,
NodeMinimal,
NodeMinimalEntry,
NodePaging,
NodePagingList,
PathInfoEntity
} from '../document-list';
import { ContentInfo, Node, NodeEntry, PathInfo } from '@alfresco/js-api';
export class PageNode extends NodePaging {
constructor(entries?: NodeMinimalEntry[]) {
super();
this.list = new NodePagingList();
this.list.entries = entries || [];
}
}
export class FileNode extends NodeMinimalEntry {
export class FileNode extends NodeEntry {
constructor(name?: string, mimeType?: string, id?: string) {
super();
this.entry = new NodeMinimal();
this.entry = new Node();
this.entry.id = id || 'file-id';
this.entry.isFile = true;
this.entry.isFolder = false;
this.entry.name = name;
this.entry.path = new PathInfoEntity();
this.entry.path = new PathInfo();
this.entry.content = new ContentInfo();
this.entry.content.mimeType = mimeType || 'text/plain';
this.entry.properties = {};
}
}
export class FolderNode extends NodeMinimalEntry {
export class FolderNode extends NodeEntry {
constructor(name?: string) {
super();
this.entry = new NodeMinimal();
this.entry = new Node();
this.entry.id = 'folder-id';
this.entry.isFile = false;
this.entry.isFolder = true;
this.entry.name = name;
this.entry.path = new PathInfoEntity();
this.entry.path = new PathInfo();
this.entry.aspectNames = ['cm:folder'];
this.entry.properties = {};
}
}
export class SmartFolderNode extends NodeMinimalEntry {
export class SmartFolderNode extends NodeEntry {
constructor(name?: string) {
super();
this.entry = new NodeMinimal();
this.entry = new Node();
this.entry.id = 'smart-folder-id';
this.entry.isFile = false;
this.entry.isFolder = true;
this.entry.name = name;
this.entry.path = new PathInfoEntity();
this.entry.path = new PathInfo();
this.entry.aspectNames = ['smf:systemConfigSmartFolder'];
this.entry.properties = {};
}
}
export class RuleFolderNode extends NodeMinimalEntry {
export class RuleFolderNode extends NodeEntry {
constructor(name?: string) {
super();
this.entry = new NodeMinimal();
this.entry = new Node();
this.entry.id = 'rule-folder-id';
this.entry.isFile = false;
this.entry.isFolder = true;
this.entry.name = name;
this.entry.path = new PathInfoEntity();
this.entry.path = new PathInfo();
this.entry.aspectNames = ['rule:rules'];
this.entry.properties = {};
}
}
export class LinkFolderNode extends NodeMinimalEntry {
export class LinkFolderNode extends NodeEntry {
constructor(name?: string) {
super();
this.entry = new NodeMinimal();
this.entry = new Node();
this.entry.id = 'link-folder-id';
this.entry.isFile = false;
this.entry.isFolder = true;
this.entry.nodeType = 'app:folderlink';
this.entry.name = name;
this.entry.path = new PathInfoEntity();
this.entry.path = new PathInfo();
this.entry.properties = {};
}
}

@ -15,12 +15,12 @@
* limitations under the License.
*/
import { MinimalNodeEntryEntity, Version, NodeChildAssociation, Node } from '@alfresco/js-api';
import { Version, NodeChildAssociation, Node } from '@alfresco/js-api';
import { NodeEntityEvent } from '../../document-list';
export interface NewVersionUploaderDialogData {
title?: string;
node: MinimalNodeEntryEntity;
node: Node;
file?: File;
currentVersion?: Version;
showVersionsOnly?: boolean;

@ -34,11 +34,10 @@ import {
fakeSiteRoles
} from '../../../mock/permission-list.component.mock';
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { MinimalNode } from '@alfresco/js-api';
import { Node } from '@alfresco/js-api';
import { NodesApiService } from '../../../common/services/nodes-api.service';
describe('PermissionListComponent', () => {
let fixture: ComponentFixture<PermissionListComponent>;
let component: PermissionListComponent;
let element: HTMLElement;
@ -51,10 +50,7 @@ describe('PermissionListComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
]
imports: [TranslateModule.forRoot(), ContentTestingModule]
});
fixture = TestBed.createComponent(PermissionListComponent);
component = fixture.componentInstance;
@ -114,7 +110,7 @@ describe('PermissionListComponent', () => {
});
describe('Inherited Permission', () => {
it('should show inherited details', async () => {
it('should show inherited details', async () => {
getNodeSpy.and.returnValue(of(fakeNodeInheritedOnly));
component.ngOnInit();
@ -122,23 +118,23 @@ describe('PermissionListComponent', () => {
await fixture.whenStable();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined();
expect(element.querySelector('.adf-inherit-container h3').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON');
expect(element.querySelector('span[title="total"]').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON'
);
expect(element.querySelector('span[title="total"]').textContent.trim()).toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
});
it('should toggle the inherited button', async () => {
it('should toggle the inherited button', async () => {
getNodeSpy.and.returnValue(of(fakeNodeInheritedOnly));
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined();
expect(element.querySelector('.adf-inherit-container h3').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON');
expect(element.querySelector('span[title="total"]').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON'
);
expect(element.querySelector('span[title="total"]').textContent.trim()).toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
spyOn(nodeService, 'updateNode').and.returnValue(of(fakeLocalPermission));
@ -148,13 +144,13 @@ describe('PermissionListComponent', () => {
fixture.detectChanges();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBe(null);
expect(element.querySelector('.adf-inherit-container h3').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.OFF');
expect(element.querySelector('span[title="total"]').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.OFF'
);
expect(element.querySelector('span[title="total"]').textContent.trim()).toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
});
it('should not toggle inherited button for read only users', async () => {
it('should not toggle inherited button for read only users', async () => {
getNodeSpy.and.returnValue(of(fakeReadOnlyNodeInherited));
component.ngOnInit();
@ -162,10 +158,10 @@ describe('PermissionListComponent', () => {
await fixture.whenStable();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined();
expect(element.querySelector('.adf-inherit-container h3').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON');
expect(element.querySelector('span[title="total"]').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON'
);
expect(element.querySelector('span[title="total"]').textContent.trim()).toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
spyOn(nodeService, 'updateNode').and.returnValue(of(fakeLocalPermission));
@ -176,22 +172,20 @@ describe('PermissionListComponent', () => {
await fixture.whenStable();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined();
expect(element.querySelector('.adf-inherit-container h3').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON');
expect(element.querySelector('span[title="total"]').textContent.trim())
.toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
expect(document.querySelector('.adf-snackbar-message-content').textContent)
.toContain('PERMISSION_MANAGER.ERROR.NOT-ALLOWED');
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON'
);
expect(element.querySelector('span[title="total"]').textContent.trim()).toBe('PERMISSION_MANAGER.LABELS.INHERITED-SUBTITLE');
expect(document.querySelector('.adf-snackbar-message-content').textContent).toContain('PERMISSION_MANAGER.ERROR.NOT-ALLOWED');
});
});
describe('locally set permission', () => {
describe('locally set permission', () => {
beforeEach(() => {
getNodeSpy.and.returnValue(of(fakeLocalPermission));
});
it('should show locally set permissions', async () => {
it('should show locally set permissions', async () => {
searchQuerySpy.and.returnValue(of(fakeSiteNodeResponse));
component.ngOnInit();
@ -212,7 +206,7 @@ describe('PermissionListComponent', () => {
expect(element.querySelector('adf-user-name-column').textContent).toContain('GROUP_EVERYONE');
expect(element.querySelector('#adf-select-role-permission').textContent).toContain('Contributor');
const selectBox = fixture.debugElement.query(By.css(('[id="adf-select-role-permission"] .mat-select-trigger')));
const selectBox = fixture.debugElement.query(By.css('[id="adf-select-role-permission"] .mat-select-trigger'));
selectBox.triggerEventHandler('click', null);
fixture.detectChanges();
@ -234,14 +228,16 @@ describe('PermissionListComponent', () => {
expect(element.querySelector('adf-user-name-column').textContent).toContain('GROUP_site_testsite_SiteManager');
expect(element.querySelector('#adf-select-role-permission').textContent).toContain('ADF.ROLES.SITEMANAGER');
const deleteButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-delete-permission-button-GROUP_site_testsite_SiteManager"]');
const deleteButton = element.querySelector<HTMLButtonElement>(
'[data-automation-id="adf-delete-permission-button-GROUP_site_testsite_SiteManager"]'
);
expect(deleteButton.disabled).toBe(true);
const otherDeleteButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-delete-permission-button-superadminuser"]');
expect(otherDeleteButton.disabled).toBe(false);
});
it('should update the role when another value is chosen', async () => {
spyOn(nodeService, 'updateNode').and.returnValue(of(new MinimalNode({id: 'fake-uwpdated-node'})));
it('should update the role when another value is chosen', async () => {
spyOn(nodeService, 'updateNode').and.returnValue(of(new Node({ id: 'fake-uwpdated-node' })));
searchQuerySpy.and.returnValue(of(fakeEmptyResponse));
component.ngOnInit();
@ -251,7 +247,7 @@ describe('PermissionListComponent', () => {
expect(element.querySelector('adf-user-name-column').textContent).toContain('GROUP_EVERYONE');
expect(element.querySelector('#adf-select-role-permission').textContent).toContain('Contributor');
const selectBox = fixture.debugElement.query(By.css(('[id="adf-select-role-permission"] .mat-select-trigger')));
const selectBox = fixture.debugElement.query(By.css('[id="adf-select-role-permission"] .mat-select-trigger'));
selectBox.triggerEventHandler('click', null);
fixture.detectChanges();
const options = fixture.debugElement.queryAll(By.css('mat-option'));
@ -259,11 +255,13 @@ describe('PermissionListComponent', () => {
expect(options.length).toBe(5);
options[3].triggerEventHandler('click', {});
fixture.detectChanges();
expect(nodeService.updateNode).toHaveBeenCalledWith('f472543f-7218-403d-917b-7a5861257244', { permissions: { locallySet: [ { accessStatus: 'ALLOWED', name: 'Editor', authorityId: 'GROUP_EVERYONE' } ] } });
expect(nodeService.updateNode).toHaveBeenCalledWith('f472543f-7218-403d-917b-7a5861257244', {
permissions: { locallySet: [{ accessStatus: 'ALLOWED', name: 'Editor', authorityId: 'GROUP_EVERYONE' }] }
});
});
it('should delete the person', async () => {
spyOn(nodeService, 'updateNode').and.returnValue(of(new MinimalNode({id: 'fake-uwpdated-node'})));
it('should delete the person', async () => {
spyOn(nodeService, 'updateNode').and.returnValue(of(new Node({ id: 'fake-uwpdated-node' })));
searchQuerySpy.and.returnValue(of(fakeEmptyResponse));
component.ngOnInit();
@ -277,8 +275,7 @@ describe('PermissionListComponent', () => {
deleteButton.click();
fixture.detectChanges();
expect(nodeService.updateNode).toHaveBeenCalledWith('f472543f-7218-403d-917b-7a5861257244', { permissions: { locallySet: [ ] } });
expect(nodeService.updateNode).toHaveBeenCalledWith('f472543f-7218-403d-917b-7a5861257244', { permissions: { locallySet: [] } });
});
});
});

@ -20,7 +20,7 @@ import { AlfrescoApiService, AppConfigService, DataSorting } from '@alfresco/adf
import { SearchConfiguration } from '../models/search-configuration.interface';
import { BaseQueryBuilderService } from './base-query-builder.service';
import { SearchCategory } from '../models/search-category.interface';
import { MinimalNode, QueryBody } from '@alfresco/js-api';
import { Node } from '@alfresco/js-api';
import { filter } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { SearchSortingDefinition } from '../models/search-sorting-definition.interface';
@ -31,18 +31,14 @@ import { NodesApiService } from '../../common/services/nodes-api.service';
providedIn: 'root'
})
export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService {
private customSources = ['-trashcan-', '-sharedlinks-', '-sites-', '-mysites-', '-favorites-', '-recent-', '-my-'];
activeFilters: FilterSearch[] = [];
constructor(appConfig: AppConfigService,
alfrescoApiService: AlfrescoApiService,
private nodeApiService: NodesApiService) {
constructor(appConfig: AppConfigService, alfrescoApiService: AlfrescoApiService, private nodeApiService: NodesApiService) {
super(appConfig, alfrescoApiService);
this.updated.pipe(
filter((query: QueryBody) => !!query)).subscribe(() => {
this.updated.pipe(filter((query) => !!query)).subscribe(() => {
this.execute();
});
}
@ -56,9 +52,7 @@ export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService {
}
setupCurrentPagination(maxItems: number, skipCount: number) {
if (!this.paging ||
(this.paging &&
this.paging.maxItems !== maxItems || this.paging.skipCount !== skipCount)) {
if (!this.paging || (this.paging && this.paging.maxItems !== maxItems) || this.paging.skipCount !== skipCount) {
this.paging = { maxItems, skipCount };
this.execute();
}
@ -118,7 +112,7 @@ export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService {
private getSortingFieldFromColumnName(columnName: string) {
if (this.sortingOptions.length > 0) {
const sortOption: SearchSortingDefinition = this.sortingOptions.find((option: SearchSortingDefinition) => option.key === columnName);
const sortOption = this.sortingOptions.find((option) => option.key === columnName);
return sortOption ? sortOption.field : '';
}
return '';
@ -127,25 +121,23 @@ export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService {
getCategoryForColumn(columnKey: string): SearchCategory {
let foundCategory = null;
if (this.categories !== null) {
foundCategory = this.categories.find(
category => category.columnKey === columnKey
);
foundCategory = this.categories.find((category) => category.columnKey === columnKey);
}
return foundCategory;
}
setCurrentRootFolderId(currentFolderId: string) {
const alreadyAddedFilter = this.filterQueries.find(filterQueries =>
filterQueries.query.includes(currentFolderId)
);
const alreadyAddedFilter = this.filterQueries.find((filterQueries) => filterQueries.query.includes(currentFolderId));
if (alreadyAddedFilter !== undefined) {
this.filterQueries = [];
}
this.filterQueries = [{
query: `PARENT:"workspace://SpacesStore/${currentFolderId}"`
}];
this.filterQueries = [
{
query: `PARENT:"workspace://SpacesStore/${currentFolderId}"`
}
];
this.execute();
}
@ -154,8 +146,7 @@ export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService {
return this.customSources.includes(currentNodeId);
}
getNodeIdForCustomSource(customSourceId: string): Observable<MinimalNode> {
getNodeIdForCustomSource(customSourceId: string): Observable<Node> {
return this.nodeApiService.getNode(customSourceId);
}
}

@ -16,19 +16,13 @@
*/
export class AlfrescoApiMock {
login() {
return new Promise((resolve) => {
resolve('TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1');
});
return Promise.resolve('TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1');
}
logout() {
return new Promise((resolve) => {
resolve('logout');
});
return Promise.resolve('logout');
}
changeConfig() {
}
changeConfig() {}
}

@ -34,7 +34,7 @@ import {
import {
allSourceParams,
contentSourceParam,
fakeMinimalNode,
fakeNode,
mockNodeId,
fakeLocalPngResponse,
onlyLocalParams,
@ -61,13 +61,18 @@ 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, NewVersionUploaderDataAction, NewVersionUploaderService } from '@alfresco/adf-content-services';
import {
ContentModule,
ContentNodeSelectorPanelService,
NewVersionUploaderDataAction,
NewVersionUploaderService
} from '@alfresco/adf-content-services';
import { By } from '@angular/platform-browser';
import { of, throwError } from 'rxjs';
import { FormCloudModule } from '../../../form-cloud.module';
import { TranslateModule } from '@ngx-translate/core';
const mockNodeToBeVersioned: any = ({
const mockNodeToBeVersioned: any = {
isFile: true,
createdByUser: { id: 'admin', displayName: 'Administrator' },
modifiedAt: '2017-05-24T15:08:55.640Z',
@ -83,10 +88,13 @@ const mockNodeToBeVersioned: any = ({
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' }]
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' },
@ -94,7 +102,7 @@ const mockNodeToBeVersioned: any = ({
id: '70e1cc6a-6918-468a-b84a-1048093b06fd',
properties: { 'cm:versionLabel': '1.0', 'cm:versionType': 'MAJOR' },
allowableOperations: ['delete', 'update']
});
};
describe('AttachFileCloudWidgetComponent', () => {
let widget: AttachFileCloudWidgetComponent;
@ -115,7 +123,15 @@ describe('AttachFileCloudWidgetComponent', () => {
let newVersionUploaderService: NewVersionUploaderService;
let notificationService: NotificationService;
const createUploadWidgetField = (form: FormModel, fieldId: string, value?: any, params?: any, multiple?: boolean, name?: string, readOnly?: boolean) => {
const createUploadWidgetField = (
form: FormModel,
fieldId: string,
value?: any,
params?: any,
multiple?: boolean,
name?: string,
readOnly?: boolean
) => {
widget.field = new FormFieldModel(form, {
type: FormFieldTypes.UPLOAD,
value,
@ -134,12 +150,7 @@ describe('AttachFileCloudWidgetComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessServiceCloudTestingModule,
FormCloudModule,
ContentModule.forRoot()
],
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule, FormCloudModule, ContentModule.forRoot()],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
downloadService = TestBed.inject(DownloadService);
@ -147,15 +158,11 @@ describe('AttachFileCloudWidgetComponent', () => {
widget = fixture.componentInstance;
element = fixture.nativeElement;
processCloudContentService = TestBed.inject(ProcessCloudContentService);
contentCloudNodeSelectorService = TestBed.inject(
ContentCloudNodeSelectorService
);
appConfigService = TestBed.inject(
AppConfigService
);
contentCloudNodeSelectorService = TestBed.inject(ContentCloudNodeSelectorService);
appConfigService = TestBed.inject(AppConfigService);
formService = TestBed.inject(FormService);
contentNodeSelectorPanelService = TestBed.inject(ContentNodeSelectorPanelService);
openUploadFileDialogSpy = spyOn(contentCloudNodeSelectorService, 'openUploadFileDialog').and.returnValue(of([fakeMinimalNode]));
openUploadFileDialogSpy = spyOn(contentCloudNodeSelectorService, 'openUploadFileDialog').and.returnValue(of([fakeNode]));
localizedDataPipe = new LocalizedDatePipe();
});
@ -234,7 +241,6 @@ describe('AttachFileCloudWidgetComponent', () => {
});
describe('when is required', () => {
it('should be able to display label with asterisk', async () => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
type: FormFieldTypes.UPLOAD,
@ -252,7 +258,6 @@ describe('AttachFileCloudWidgetComponent', () => {
});
describe('Upload widget with displayable ContentModel properties', () => {
it('should display CM Properties if the file contains value', async () => {
createUploadWidgetField(new FormModel(), 'attach-file-alfresco', [fakeLocalPngHavingCMProperties], displayableCMParams);
fixture.detectChanges();
@ -291,7 +296,6 @@ describe('AttachFileCloudWidgetComponent', () => {
});
describe('destinationFolderPath', () => {
it('should be able to fetch nodeId if destinationFolderPath is defined', async () => {
const getNodeIdFromPathSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeId);
@ -328,7 +332,9 @@ 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 getNodeIdFromPathSpy = spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(
mockNodeIdBasedOnStringVariableValue
);
const form = new FormModel({ formVariables, processVariables });
createUploadWidgetField(form, 'attach-file-alfresco', [], mockAllFileSourceWithStringVariablePathType);
@ -469,7 +475,6 @@ describe('AttachFileCloudWidgetComponent', () => {
});
describe('when is readonly', () => {
it('should show empty list message when there are no file', async () => {
createUploadWidgetField(new FormModel(), 'empty-test', [], onlyLocalParams, null, null, true);
@ -517,8 +522,8 @@ describe('AttachFileCloudWidgetComponent', () => {
describe('when a file is uploaded', () => {
beforeEach(async () => {
apiServiceSpy = spyOn(widget['nodesApi'], 'getNode').and.returnValue(new Promise(resolve => resolve({ entry: fakeNodeWithProperties })));
spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(new Promise(resolve => resolve('fake-properties')));
apiServiceSpy = spyOn(widget['nodesApi'], 'getNode').and.returnValue(Promise.resolve({ entry: fakeNodeWithProperties }));
spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(Promise.resolve('fake-properties'));
openUploadFileDialogSpy.and.returnValue(of([fakeNodeWithProperties]));
widget.field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.UPLOAD,
@ -575,11 +580,9 @@ describe('AttachFileCloudWidgetComponent', () => {
it('should preview file when show is clicked', async () => {
spyOn(processCloudContentService, 'getRawContentNode').and.returnValue(of(new Blob()));
await formService.formContentClicked.subscribe(
(fileClicked: any) => {
expect(fileClicked.nodeId).toBe('fake-properties');
}
);
await formService.formContentClicked.subscribe((fileClicked: any) => {
expect(fileClicked.nodeId).toBe('fake-properties');
});
fixture.detectChanges();
const menuButton = fixture.debugElement.query(By.css('#file-fake-properties-option-menu')).nativeElement as HTMLButtonElement;
@ -598,7 +601,8 @@ describe('AttachFileCloudWidgetComponent', () => {
menuButton.click();
fixture.detectChanges();
const retrieveMetadataOption = fixture.debugElement.query(By.css('#file-fake-properties-retrieve-file-metadata')).nativeElement as HTMLButtonElement;
const retrieveMetadataOption = fixture.debugElement.query(By.css('#file-fake-properties-retrieve-file-metadata'))
.nativeElement as HTMLButtonElement;
retrieveMetadataOption.click();
expect(apiServiceSpy).toHaveBeenCalledWith(fakeNodeWithProperties.id);
@ -609,9 +613,7 @@ describe('AttachFileCloudWidgetComponent', () => {
it('should display the default menu options if no options are provided', async () => {
widget.field.params = onlyLocalParams;
const inputDebugElement = fixture.debugElement.query(
By.css('#attach-file-alfresco')
);
const inputDebugElement = fixture.debugElement.query(By.css('#attach-file-alfresco'));
inputDebugElement.triggerEventHandler('change', {
target: { files: [fakeLocalPngAnswer] }
});
@ -637,7 +639,7 @@ describe('AttachFileCloudWidgetComponent', () => {
describe('contentModelFormFileHandler', () => {
beforeEach(async () => {
apiServiceSpy = spyOn(widget['nodesApi'], 'getNode').and.returnValue(new Promise(resolve => resolve({ entry: fakeNodeWithProperties })));
apiServiceSpy = spyOn(widget['nodesApi'], 'getNode').and.returnValue(Promise.resolve({ entry: fakeNodeWithProperties }));
contentModelFormFileHandlerSpy = spyOn(widget, 'contentModelFormFileHandler').and.callThrough();
updateFormSpy = spyOn(formService.updateFormValuesRequested, 'next');
contentClickedSpy = spyOn(formService.formContentClicked, 'next');
@ -673,7 +675,7 @@ describe('AttachFileCloudWidgetComponent', () => {
});
it('should not be called onInit when widget has more than one file', async () => {
widget.field.value = [fakeNodeWithProperties, fakeMinimalNode];
widget.field.value = [fakeNodeWithProperties, fakeNode];
fixture.detectChanges();
await fixture.whenStable();
@ -681,19 +683,19 @@ describe('AttachFileCloudWidgetComponent', () => {
});
it('should not be called on remove node if node removed is not the selected one', async () => {
widget.field.value = [fakeNodeWithProperties, fakeMinimalNode];
widget.field.value = [fakeNodeWithProperties, fakeNode];
widget.selectedNode = fakeNodeWithProperties;
fixture.detectChanges();
widget.onRemoveAttachFile(fakeMinimalNode);
widget.onRemoveAttachFile(fakeNode);
await fixture.whenStable();
expect(contentModelFormFileHandlerSpy).not.toHaveBeenCalled();
});
it('should have been called on remove node if node removed is the selected one', async () => {
widget.field.value = [fakeNodeWithProperties, fakeMinimalNode];
widget.field.value = [fakeNodeWithProperties, fakeNode];
widget.selectedNode = fakeNodeWithProperties;
fixture.detectChanges();
@ -718,7 +720,7 @@ describe('AttachFileCloudWidgetComponent', () => {
it('should not be called on attach file when has a file previously', async () => {
spyOn(contentCloudNodeSelectorService, 'getNodeIdFromPath').and.returnValue(mockNodeId);
widget.field.value = [fakeMinimalNode];
widget.field.value = [fakeNode];
clickOnAttachFileWidget('attach-file-alfresco');
fixture.detectChanges();
@ -728,7 +730,7 @@ describe('AttachFileCloudWidgetComponent', () => {
});
it('should be called when selecting a row if no previous row was selected', async () => {
widget.field.value = [fakeNodeWithProperties, fakeMinimalNode];
widget.field.value = [fakeNodeWithProperties, fakeNode];
widget.selectedNode = null;
widget.onRowClicked(fakeNodeWithProperties);
@ -743,8 +745,8 @@ describe('AttachFileCloudWidgetComponent', () => {
});
it('should be called when selecting a row and previous row was selected', async () => {
widget.field.value = [fakeNodeWithProperties, fakeMinimalNode];
widget.selectedNode = fakeMinimalNode;
widget.field.value = [fakeNodeWithProperties, fakeNode];
widget.selectedNode = fakeNode;
widget.onRowClicked(fakeNodeWithProperties);
@ -758,7 +760,7 @@ describe('AttachFileCloudWidgetComponent', () => {
});
it('should be called when deselecting a row', async () => {
widget.field.value = [fakeNodeWithProperties, fakeMinimalNode];
widget.field.value = [fakeNodeWithProperties, fakeNode];
widget.selectedNode = fakeNodeWithProperties;
widget.onRowClicked(fakeNodeWithProperties);
@ -850,8 +852,9 @@ describe('AttachFileCloudWidgetComponent', () => {
beforeEach(() => {
notificationService = TestBed.inject(NotificationService);
newVersionUploaderService = TestBed.inject(NewVersionUploaderService);
spyOnOpenUploadNewVersionDialog = spyOn(newVersionUploaderService, 'openUploadNewVersionDialog')
.and.returnValue(of({ action: NewVersionUploaderDataAction.refresh }));
spyOnOpenUploadNewVersionDialog = spyOn(newVersionUploaderService, 'openUploadNewVersionDialog').and.returnValue(
of({ action: NewVersionUploaderDataAction.refresh })
);
spyOnReplaceOldFileVersionWithNew = spyOn(widget, 'replaceOldFileVersionWithNew');
spyOnShowError = spyOn(notificationService, 'showError');
});
@ -876,18 +879,16 @@ describe('AttachFileCloudWidgetComponent', () => {
});
it('Should show notification error if new version uploader dialog return error', async () => {
const mockError = {value: 'Upload error'};
const mockError = { value: 'Upload error' };
spyOnOpenUploadNewVersionDialog.and.returnValue(throwError(mockError));
await fixture.whenStable();
widget.onUploadNewFileVersion(mockNodeToBeVersioned);
expect(spyOnReplaceOldFileVersionWithNew).not.toHaveBeenCalled();
expect(spyOnShowError).toHaveBeenCalledWith(mockError.value);
});
});
describe('when tooltip is set', () => {
beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
type: FormFieldTypes.UPLOAD,
@ -905,7 +906,7 @@ describe('AttachFileCloudWidgetComponent', () => {
const tooltipElement = fixture.debugElement.query(By.css('.mat-tooltip')).nativeElement;
expect(tooltipElement).toBeTruthy();
expect(tooltipElement.textContent.trim()).toBe('my custom tooltip');
});
});
it('should hide tooltip', async () => {
const attachButton = fixture.nativeElement.querySelector('button');

@ -201,29 +201,6 @@ export const allSourceWithStringTypeEmptyValue = {
}
};
export const allSourceWithFolderTypeEmptyValue = {
fileSource: {
name: 'all file sources',
serviceId: FileSourceTypes.ALL_FILE_SOURCES_SERVICE_ID,
destinationFolderPath: {
value: null,
name: 'folderVariableName',
type: DestinationFolderPathType.FOLDER_TYPE
}
}
};
export const allSourceWithRootParams = {
fileSource: {
name: 'all file sources',
serviceId: FileSourceTypes.ALL_FILE_SOURCES_SERVICE_ID,
destinationFolderPath: {
value: '-root-',
type: DestinationFolderPathType.STATIC_TYPE
}
}
};
export const allSourceWithWrongAliasParams = {
fileSource: {
name: 'all file sources',
@ -248,22 +225,7 @@ export const allSourceWithNoAliasParams = {
}
};
export const allSourceWithoutDestinationFolderPath = {
fileSource: {
name: 'all file sources',
serviceId: FileSourceTypes.ALL_FILE_SOURCES_SERVICE_ID
}
};
export const allSourceWithoutValueProperty = {
fileSource: {
name: 'all file sources',
serviceId: FileSourceTypes.ALL_FILE_SOURCES_SERVICE_ID,
destinationFolderPath: '-mockAlias-'
}
};
export const fakeMinimalNode = {
export const fakeNode = {
id: 'fake',
name: 'fake-name',
content: {
@ -298,10 +260,6 @@ export const mockNodeIdBasedOnStringVariableValue = new Promise<string>((resolve
resolve('mock-string-value-node-id');
});
export const mockNodeIdBasedOnFolderVariableValue = new Promise((resolve) => {
resolve('mock-folder-value-node-id');
});
export const fakeLocalPngAnswer = {
id: 1155,
nodeId: 1155,
@ -447,7 +405,7 @@ export const processVariables = [
createTime: 1566989626283,
lastUpdatedTime: 1566989626283,
executionId: null,
value: [{ id: 'mock-folder-id'}],
value: [{ id: 'mock-folder-id' }],
markedAsDeleted: false,
processInstanceId: '1be4785f-c982-11e9-bdd8-96d6903e4e44',
taskId: '1beab9f6-c982-11e9-bdd8-96d6903e4e44',

@ -18,12 +18,7 @@
import { AlfrescoApiService, LogService, ExternalContent, ExternalContentLink } from '@alfresco/adf-core';
import { SitesService } from '@alfresco/adf-content-services';
import { Injectable } from '@angular/core';
import {
IntegrationAlfrescoOnPremiseApi,
MinimalNode,
RelatedContentRepresentation,
ActivitiContentApi
} from '@alfresco/js-api';
import { IntegrationAlfrescoOnPremiseApi, Node, RelatedContentRepresentation, ActivitiContentApi } from '@alfresco/js-api';
import { Observable, from, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
@ -31,13 +26,13 @@ import { map, catchError } from 'rxjs/operators';
providedIn: 'root'
})
export class ActivitiContentService {
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
static GENERIC_ERROR_MESSAGE: string = 'Server error';
private _integrationAlfrescoOnPremiseApi: IntegrationAlfrescoOnPremiseApi;
get integrationAlfrescoOnPremiseApi(): IntegrationAlfrescoOnPremiseApi {
this._integrationAlfrescoOnPremiseApi = this._integrationAlfrescoOnPremiseApi ?? new IntegrationAlfrescoOnPremiseApi(this.apiService.getInstance());
this._integrationAlfrescoOnPremiseApi =
this._integrationAlfrescoOnPremiseApi ?? new IntegrationAlfrescoOnPremiseApi(this.apiService.getInstance());
return this._integrationAlfrescoOnPremiseApi;
}
@ -47,10 +42,7 @@ export class ActivitiContentService {
return this._contentApi;
}
constructor(private apiService: AlfrescoApiService,
private logService: LogService,
private sitesService: SitesService) {
}
constructor(private apiService: AlfrescoApiService, private logService: LogService, private sitesService: SitesService) {}
/**
* Returns a list of child nodes below the specified folder
@ -60,11 +52,10 @@ export class ActivitiContentService {
*/
getAlfrescoNodes(accountId: string, folderId: string): Observable<[ExternalContent]> {
const accountShortId = accountId.replace('alfresco-', '');
return from(this.integrationAlfrescoOnPremiseApi.getContentInFolder(accountShortId, folderId))
.pipe(
map(this.toJsonArray),
catchError((err) => this.handleError(err))
);
return from(this.integrationAlfrescoOnPremiseApi.getContentInFolder(accountShortId, folderId)).pipe(
map(this.toJsonArray),
catchError((err) => this.handleError(err))
);
}
/**
@ -78,11 +69,10 @@ export class ActivitiContentService {
tenantId,
includeAccounts: includeAccount ? includeAccount : true
};
return from(this.integrationAlfrescoOnPremiseApi.getRepositories(opts))
.pipe(
map(this.toJsonArray),
catchError((err) => this.handleError(err))
);
return from(this.integrationAlfrescoOnPremiseApi.getRepositories(opts)).pipe(
map(this.toJsonArray),
catchError((err) => this.handleError(err))
);
}
/**
@ -93,20 +83,21 @@ export class ActivitiContentService {
* @param siteId
*/
linkAlfrescoNode(accountId: string, node: ExternalContent, siteId: string): Observable<ExternalContentLink> {
return from(this.contentApi.createTemporaryRelatedContent({
link: true,
name: node.title,
simpleType: node.simpleType,
source: accountId,
sourceId: node.id + '@' + siteId
}))
.pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
return from(
this.contentApi.createTemporaryRelatedContent({
link: true,
name: node.title,
simpleType: node.simpleType,
source: accountId,
sourceId: node.id + '@' + siteId
})
).pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
}
applyAlfrescoNode(node: MinimalNode, siteId: string, accountId: string) {
applyAlfrescoNode(node: Node, siteId: string, accountId: string) {
const currentSideId = siteId ? siteId : this.sitesService.getSiteNameFromNodePath(node);
const params: RelatedContentRepresentation = {
source: accountId,
@ -115,11 +106,10 @@ export class ActivitiContentService {
name: node.name,
link: node.isLink
};
return from(this.contentApi.createTemporaryRelatedContent(params))
.pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
return from(this.contentApi.createTemporaryRelatedContent(params)).pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
}
toJson(res: any) {
@ -139,8 +129,11 @@ export class ActivitiContentService {
handleError(error: any): Observable<any> {
let errMsg = ActivitiContentService.UNKNOWN_ERROR_MESSAGE;
if (error) {
errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : ActivitiContentService.GENERIC_ERROR_MESSAGE;
errMsg = error.message
? error.message
: error.status
? `${error.status} - ${error.statusText}`
: ActivitiContentService.GENERIC_ERROR_MESSAGE;
}
this.logService.error(errMsg);
return throwError(errMsg);

@ -18,14 +18,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { AttachFileWidgetComponent } from './attach-file-widget.component';
import {
FormFieldModel,
FormModel,
FormFieldTypes,
FormService,
FormFieldMetadata,
DownloadService
} from '@alfresco/adf-core';
import { FormFieldModel, FormModel, FormFieldTypes, FormService, FormFieldMetadata, DownloadService } from '@alfresco/adf-core';
import { ContentNodeDialogService, ContentModule } from '@alfresco/adf-content-services';
import { of } from 'rxjs';
import { Node } from '@alfresco/js-api';
@ -101,7 +94,7 @@ const externalDefinedSourceParams = {
}
} as FormFieldMetadata;
const fakeMinimalNode: Node = {
const fakeNode = {
id: 'fake',
name: 'fake-name',
content: {
@ -140,7 +133,6 @@ const fakePngAnswer: any = {
};
describe('AttachFileWidgetComponent', () => {
let widget: AttachFileWidgetComponent;
let fixture: ComponentFixture<AttachFileWidgetComponent>;
let element: HTMLInputElement;
@ -153,11 +145,7 @@ describe('AttachFileWidgetComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessTestingModule,
ContentModule.forRoot()
]
imports: [TranslateModule.forRoot(), ProcessTestingModule, ContentModule.forRoot()]
});
fixture = TestBed.createComponent(AttachFileWidgetComponent);
widget = fixture.componentInstance;
@ -218,7 +206,7 @@ describe('AttachFileWidgetComponent', () => {
expect(fakeRepoOption2[0]).not.toBeNull();
});
it ('should show only remote repos when just link to files is true', async () => {
it('should show only remote repos when just link to files is true', async () => {
widget.field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.UPLOAD,
value: []
@ -252,7 +240,7 @@ describe('AttachFileWidgetComponent', () => {
it('should isLink property of the selected node become true when the widget has link enabled', async () => {
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of(fakeRepositoryListAnswer));
const applyAlfrescoNodeSpy = spyOn(activitiContentService, 'applyAlfrescoNode');
spyOn(contentNodeDialogService, 'openFileBrowseDialogByDefaultLocation').and.returnValue(of([fakeMinimalNode]));
spyOn(contentNodeDialogService, 'openFileBrowseDialogByDefaultLocation').and.returnValue(of([fakeNode]));
widget.field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.UPLOAD,
value: []
@ -271,13 +259,13 @@ describe('AttachFileWidgetComponent', () => {
await fixture.whenStable();
fixture.debugElement.query(By.css('#attach-SHAREME')).nativeElement.click();
expect(applyAlfrescoNodeSpy).toHaveBeenCalledWith({ ...fakeMinimalNode, isLink: true }, undefined, 'alfresco-1000-SHAREME');
expect(applyAlfrescoNodeSpy).toHaveBeenCalledWith({ ...fakeNode, isLink: true }, undefined, 'alfresco-1000-SHAREME');
});
it('should isLink property of the selected node become false when the widget has link disabled', async () => {
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of(fakeRepositoryListAnswer));
const applyAlfrescoNodeSpy = spyOn(activitiContentService, 'applyAlfrescoNode');
spyOn(contentNodeDialogService, 'openFileBrowseDialogByDefaultLocation').and.returnValue(of([fakeMinimalNode]));
spyOn(contentNodeDialogService, 'openFileBrowseDialogByDefaultLocation').and.returnValue(of([fakeNode]));
widget.field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.UPLOAD,
value: []
@ -296,13 +284,13 @@ describe('AttachFileWidgetComponent', () => {
await fixture.whenStable();
fixture.debugElement.query(By.css('#attach-SHAREME')).nativeElement.click();
expect(applyAlfrescoNodeSpy).toHaveBeenCalledWith({ ...fakeMinimalNode, isLink: false }, undefined, 'alfresco-1000-SHAREME');
expect(applyAlfrescoNodeSpy).toHaveBeenCalledWith({ ...fakeNode, isLink: false }, undefined, 'alfresco-1000-SHAREME');
});
it('should be able to upload files coming from content node selector', async () => {
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of(fakeRepositoryListAnswer));
spyOn(activitiContentService, 'applyAlfrescoNode').and.returnValue(of(fakePngAnswer));
spyOn(contentNodeDialogService, 'openFileBrowseDialogByDefaultLocation').and.returnValue(of([fakeMinimalNode]));
spyOn(contentNodeDialogService, 'openFileBrowseDialogByDefaultLocation').and.returnValue(of([fakeNode]));
widget.field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.UPLOAD,
value: []
@ -337,7 +325,7 @@ describe('AttachFileWidgetComponent', () => {
};
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of(fakeRepositoryListAnswer));
spyOn(activitiContentService, 'applyAlfrescoNode').and.returnValues(of(fakePngAnswer), of(fakePngUpload));
spyOn(contentNodeDialogService, 'openFileBrowseDialogByDefaultLocation').and.returnValue(of([fakeMinimalNode]));
spyOn(contentNodeDialogService, 'openFileBrowseDialogByDefaultLocation').and.returnValue(of([fakeNode]));
widget.field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.UPLOAD,
value: []
@ -374,7 +362,7 @@ describe('AttachFileWidgetComponent', () => {
widget.field.params = definedSourceParams;
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of(fakeRepositoryListAnswer));
spyOn(activitiContentService, 'applyAlfrescoNode').and.returnValue(of(fakePngAnswer));
spyOn(contentNodeDialogService, 'openFileBrowseDialogByFolderId').and.returnValue(of([fakeMinimalNode]));
spyOn(contentNodeDialogService, 'openFileBrowseDialogByFolderId').and.returnValue(of([fakeNode]));
fixture.detectChanges();
await fixture.whenStable();
@ -430,7 +418,6 @@ describe('AttachFileWidgetComponent', () => {
});
describe('when a file is uploaded', () => {
beforeEach(async () => {
widget.field = new FormFieldModel(new FormModel(), {
type: FormFieldTypes.UPLOAD,
@ -557,7 +544,6 @@ describe('AttachFileWidgetComponent', () => {
await fixture.whenStable();
const downloadOption = fixture.debugElement.query(By.css('#file-1155-download-file')).nativeElement as HTMLButtonElement;
expect(downloadOption.disabled).toBeFalsy();
});
it('should not display the show button file when there is no contentAvailable', async () => {
@ -572,7 +558,7 @@ describe('AttachFileWidgetComponent', () => {
const showOption = fixture.debugElement.query(By.css('#file-1155-show-file')).nativeElement as HTMLButtonElement;
expect(showOption.disabled).toBeTruthy();
});
});
});
it('should be able to upload files when a defined folder from external content service', async () => {
widget.field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.UPLOAD, value: [] });
@ -580,7 +566,7 @@ describe('AttachFileWidgetComponent', () => {
widget.field.params = externalDefinedSourceParams;
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of(fakeRepositoryListAnswer));
spyOn(activitiContentService, 'applyAlfrescoNode').and.returnValue(of(fakePngAnswer));
spyOn(attachFileWidgetDialogService, 'openLogin').and.returnValue(of([fakeMinimalNode]));
spyOn(attachFileWidgetDialogService, 'openLogin').and.returnValue(of([fakeNode]));
fixture.detectChanges();
await fixture.whenStable();
@ -605,7 +591,7 @@ describe('AttachFileWidgetComponent', () => {
widget.field.params = externalDefinedSourceParams;
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of(fakeRepositoryListAnswer));
spyOn(activitiContentService, 'applyAlfrescoNode').and.returnValue(of(fakePngAnswer));
const openLoginSpy = spyOn(attachFileWidgetDialogService, 'openLogin').and.returnValue(of([fakeMinimalNode]));
const openLoginSpy = spyOn(attachFileWidgetDialogService, 'openLogin').and.returnValue(of([fakeNode]));
fixture.detectChanges();
await fixture.whenStable();

@ -25,13 +25,13 @@ import { Node } from '@alfresco/js-api';
import { ProcessTestingModule } from '../../../testing/process.testing.module';
import { TranslateModule } from '@ngx-translate/core';
const fakeMinimalNode: Node = {
const fakeNode = {
id: 'fake',
name: 'fake-name'
} as Node;
const definedSourceParams = {
folderSource : {
folderSource: {
serviceId: 'goofy-sources',
name: 'pippo-baudo',
selectedFolder: {
@ -42,7 +42,6 @@ const definedSourceParams = {
};
describe('AttachFolderWidgetComponent', () => {
let widget: AttachFolderWidgetComponent;
let fixture: ComponentFixture<AttachFolderWidgetComponent>;
let element: HTMLInputElement;
@ -51,10 +50,7 @@ describe('AttachFolderWidgetComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessTestingModule
]
imports: [TranslateModule.forRoot(), ProcessTestingModule]
});
fixture = TestBed.createComponent(AttachFolderWidgetComponent);
widget = fixture.componentInstance;
@ -80,7 +76,7 @@ describe('AttachFolderWidgetComponent', () => {
});
it('should show the folder selected by content node', async () => {
spyOn(contentNodeDialogService, 'openFolderBrowseDialogBySite').and.returnValue(of([fakeMinimalNode]));
spyOn(contentNodeDialogService, 'openFolderBrowseDialogBySite').and.returnValue(of([fakeNode]));
expect(widget).not.toBeNull();
widget.field = new FormFieldModel(new FormModel(), {
type: 'select-folder',
@ -99,7 +95,7 @@ describe('AttachFolderWidgetComponent', () => {
});
it('should show the folder selected by content node opening on a configured folder', async () => {
spyOn(contentNodeDialogService, 'openFolderBrowseDialogByFolderId').and.returnValue(of([fakeMinimalNode]));
spyOn(contentNodeDialogService, 'openFolderBrowseDialogByFolderId').and.returnValue(of([fakeNode]));
expect(widget).not.toBeNull();
widget.field = new FormFieldModel(new FormModel(), {
type: 'select-folder',
@ -120,7 +116,7 @@ describe('AttachFolderWidgetComponent', () => {
});
it('should retrieve the node information on init', async () => {
spyOn(nodeService, 'getNode').and.returnValue(of(fakeMinimalNode));
spyOn(nodeService, 'getNode').and.returnValue(of(fakeNode));
expect(widget).not.toBeNull();
widget.field = new FormFieldModel(new FormModel(), {
type: 'select-folder',
@ -136,7 +132,7 @@ describe('AttachFolderWidgetComponent', () => {
});
it('should remove the folder via the remove button', async () => {
spyOn(nodeService, 'getNode').and.returnValue(of(fakeMinimalNode));
spyOn(nodeService, 'getNode').and.returnValue(of(fakeNode));
expect(widget).not.toBeNull();
widget.field = new FormFieldModel(new FormModel(), {
type: 'select-folder',

@ -18,28 +18,6 @@
/* spell-checker: disable */
import { ProcessInstance } from '../../process-list/models/process-instance.model';
export class ProcessList {
data: ProcessInstance[];
size: number;
start: number;
total: number;
constructor(data?: ProcessInstance[]) {
this.data = data || [];
}
}
export class SingleProcessList extends ProcessList {
constructor(name?: string) {
const instance = new ProcessInstance({
id: '123',
name
});
super([instance]);
}
}
export const exampleProcess = new ProcessInstance({
id: '123',
name: 'Process 123',
@ -90,86 +68,3 @@ export const exampleProcessNoName = new ProcessInstance({
},
processDefinitionName: 'My Process'
});
export const fakeProcessInstances = {
size: 2,
total: 2,
start: 0,
data: [
{
id: '340124',
name: 'James Franklin EMEA Onboarding',
businessKey: null,
processDefinitionId: 'HROnboarding:60:338704',
tenantId: 'tenant_1',
started: new Date('2017-10-09T12:19:44.560+0000'),
ended: null,
startedBy: {
id: 4004,
firstName: 'Integration',
lastName: 'Test',
email: 'srintegrationtest@test.com'
},
processDefinitionName: 'HROnboarding',
processDefinitionDescription: 'HR Onboarding Workflow',
processDefinitionKey: 'fakeProcessDefinitionKey1',
processDefinitionCategory: 'http://www.activiti.org/processdef',
processDefinitionVersion: 60,
processDefinitionDeploymentId: '338695',
graphicalNotationDefined: true,
startFormDefined: false,
suspended: false,
variables: []
},
{
id: '340063',
name: 'Mary Franklin AMERICAS Onboarding',
businessKey: null,
processDefinitionId: 'HROnboarding:60:338704',
tenantId: 'tenant_1',
started: '2017-10-09T12:18:07.484+0000',
ended: null,
startedBy: {
id: 4004,
firstName: 'Integration',
lastName: 'Test',
email: 'srintegrationtest@test.com'
},
processDefinitionName: 'HROnboarding',
processDefinitionDescription: 'HR Onboarding Workflow',
processDefinitionKey: 'HROnboarding',
processDefinitionCategory: 'http://www.activiti.org/processdef',
processDefinitionVersion: 60,
processDefinitionDeploymentId: '338695',
graphicalNotationDefined: true,
startFormDefined: false,
suspended: false,
variables: []
},
{
id: '337604',
name: 'John Jacobs AMERICAS Onboarding',
businessKey: null,
processDefinitionId: 'HROnboarding:49:303243',
tenantId: 'tenant_1',
started: '2017-09-25T10:02:23.522+0000',
ended: null,
startedBy: {
id: 4004,
firstName: 'Integration',
lastName: 'Test',
email: 'srintegrationtest@test.com'
},
processDefinitionName: 'HROnboarding',
processDefinitionDescription: 'HR Onboarding Workflow',
processDefinitionKey: 'fakeProcessDefinitionKey2',
processDefinitionCategory: 'http://www.activiti.org/processdef',
processDefinitionVersion: 49,
processDefinitionDeploymentId: '303234',
graphicalNotationDefined: true,
startFormDefined: false,
suspended: false,
variables: []
}
]
};

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { AppDefinitionRepresentationModel, TaskDetailsModel } from '../../task-list';
import { TaskDetailsModel } from '../../task-list';
import { ProcessDefinitionRepresentation } from '../../process-list/models/process-definition.model';
export const mockError = {
@ -23,38 +23,21 @@ export const mockError = {
messageKey: 'GENERAL.ERROR.FORBIDDEN'
};
export const fakeApp1 = new AppDefinitionRepresentationModel({
deploymentId: 26,
name: 'HR processes',
icon: 'glyphicon-cloud',
description: null,
theme: 'theme-6',
modelId: 4,
id: 1
});
export const fakeApp2 = new AppDefinitionRepresentationModel({
deploymentId: 2501,
name: 'Sales onboarding',
icon: 'glyphicon-asterisk',
description: null,
theme: 'theme-1',
modelId: 1002,
id: 1000
});
export const fakeTasksList = {
data: [new TaskDetailsModel({
id: 1,
name: 'Task 1',
processInstanceId: 1000,
created: '2016-11-10T03:37:30.010+0000'
}), new TaskDetailsModel({
id: 2,
name: 'Task 2',
processInstanceId: 1000,
created: '2016-11-10T03:37:30.010+0000'
})]
data: [
new TaskDetailsModel({
id: 1,
name: 'Task 1',
processInstanceId: 1000,
created: '2016-11-10T03:37:30.010+0000'
}),
new TaskDetailsModel({
id: 2,
name: 'Task 2',
processInstanceId: 1000,
created: '2016-11-10T03:37:30.010+0000'
})
]
};
export const fakeProcessDef = new ProcessDefinitionRepresentation({

@ -21,9 +21,7 @@ export * from './process/start-process.component.mock';
export * from './process/process.model.mock';
export * from './process/process-comments.mock';
export * from './task/start-task.mock';
export * from './task/task-details.mock';
export * from './task/task-details.component.mock';
export * from './task/task-list.mock';
export * from './task/tasklist-service.mock';
export * from './process/process-filters.mock';

@ -1,25 +0,0 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* 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 startTaskMock = {
name: 'fakeName',
description: 'fakeDescription',
assignee: null,
dueDate: '2017-11-03T15:25:42.749+0000',
formKey: null,
category: 'fakeAppId'
};

@ -1,20 +0,0 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* 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 mockTaskDetailsComponent = {
noTaskDetailsTemplateComponent: null
};

@ -18,46 +18,6 @@
import { UserRepresentation } from '@alfresco/js-api';
import { TaskDetailsModel } from '../../task-list/models/task-details.model';
export const standaloneTaskWithForm = new TaskDetailsModel({
id: '100',
name: 'Standalone Task With Form',
description: null,
category: null,
assignee: {
id: 1001,
firstName: 'Wilbur',
lastName: 'Adams',
email: 'wilbur@app.activiti.com'
},
created: '2016-11-03T15:25:42.749+0000',
dueDate: null,
endDate: null,
duration: null,
priority: 50,
parentTaskId: null,
parentTaskName: null,
processInstanceId: null,
processInstanceName: null,
processDefinitionId: null,
processDefinitionName: null,
processDefinitionDescription: null,
processDefinitionKey: null,
processDefinitionCategory: null,
processDefinitionVersion: null,
processDefinitionDeploymentId: null,
formKey: '222',
processInstanceStartUserId: null,
initiatorCanCompleteTask: false,
adhocTaskCanBeReassigned: false,
taskDefinitionKey: 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE',
executionId: '86',
involvedGroups: [],
involvedPeople: [],
memberOfCandidateUsers: false,
managerOfCandidateGroup: false,
memberOfCandidateGroup: false
});
export const standaloneTaskWithoutForm = new TaskDetailsModel({
id: '200',
name: 'Standalone Task Without Form',
@ -546,7 +506,7 @@ export const taskDetailsWithOutFormMock = new TaskDetailsModel({
name: 'Request translation',
description: 'fake description',
category: null,
assignee: {id: 1001, firstName: 'Admin', lastName: 'Paul', email: 'fake-email@gmail.com' },
assignee: { id: 1001, firstName: 'Admin', lastName: 'Paul', email: 'fake-email@gmail.com' },
created: '2016-11-03T15:25:42.749+0000',
dueDate: '2016-11-03T15:25:42.749+0000',
endDate: null,
@ -576,260 +536,260 @@ export const taskDetailsWithOutFormMock = new TaskDetailsModel({
});
export const taskFormMock = {
id: 4,
name: 'Translation request',
processDefinitionId: 'TranslationProcess:2:8',
processDefinitionName: 'Translation Process',
processDefinitionKey: 'TranslationProcess',
taskId: '91',
taskDefinitionKey: 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE',
tabs: [],
fields: [
{
fieldType: 'ContainerRepresentation',
id: '1582747048995',
name: 'Label',
type: 'container',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
dateDisplayFormat: null,
layout: null,
sizeX: 2,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null,
numberOfColumns: 2,
fields: {
1: [
{
fieldType: 'FormFieldRepresentation',
id: 'text1',
name: 'Text1',
type: 'text',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
params: { existingColspan: 1, maxColspan: 2 },
dateDisplayFormat: null,
layout: { row: -1, column: -1, colspan: 1 },
sizeX: 1,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null
}
],
2: [
{
fieldType: 'FormFieldRepresentation',
id: 'text2',
name: 'Text2',
type: 'text',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
params: { existingColspan: 1, maxColspan: 1 },
dateDisplayFormat: null,
layout: { row: -1, column: -1, colspan: 1 },
sizeX: 1,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null
}
]
}
},
{
fieldType: 'ContainerRepresentation',
id: '1582747052793',
name: 'Label',
type: 'container',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
dateDisplayFormat: null,
layout: null,
sizeX: 2,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null,
numberOfColumns: 2,
fields: {
1: [
{
fieldType: 'FormFieldRepresentation',
id: 'text3',
name: 'Text3',
type: 'text',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
params: { existingColspan: 1, maxColspan: 2 },
dateDisplayFormat: null,
layout: { row: -1, column: -1, colspan: 1 },
sizeX: 1,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: {
leftFormFieldId: 'text1',
leftRestResponseId: null,
operator: '==',
rightValue: '',
rightType: null,
rightFormFieldId: 'text2',
rightRestResponseId: '',
nextConditionOperator: '',
nextCondition: null
}
}
],
2: [
{
fieldType: 'FormFieldRepresentation',
id: 'numberField',
name: 'numberField',
type: 'integer',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
params: {
existingColspan: 1,
maxColspan: 1
},
dateDisplayFormat: null,
layout: {
row: -1,
column: -1,
colspan: 1
},
sizeX: 1,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null
}
]
}
}
],
outcomes: [],
javascriptEvents: [],
className: '',
style: '',
customFieldTemplates: {},
metadata: {},
variables: [],
customFieldsValueInfo: {},
gridsterForm: false,
globalDateFormat: 'D-M-YYYY'
};
id: 4,
name: 'Translation request',
processDefinitionId: 'TranslationProcess:2:8',
processDefinitionName: 'Translation Process',
processDefinitionKey: 'TranslationProcess',
taskId: '91',
taskDefinitionKey: 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE',
tabs: [],
fields: [
{
fieldType: 'ContainerRepresentation',
id: '1582747048995',
name: 'Label',
type: 'container',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
dateDisplayFormat: null,
layout: null,
sizeX: 2,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null,
numberOfColumns: 2,
fields: {
1: [
{
fieldType: 'FormFieldRepresentation',
id: 'text1',
name: 'Text1',
type: 'text',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
params: { existingColspan: 1, maxColspan: 2 },
dateDisplayFormat: null,
layout: { row: -1, column: -1, colspan: 1 },
sizeX: 1,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null
}
],
2: [
{
fieldType: 'FormFieldRepresentation',
id: 'text2',
name: 'Text2',
type: 'text',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
params: { existingColspan: 1, maxColspan: 1 },
dateDisplayFormat: null,
layout: { row: -1, column: -1, colspan: 1 },
sizeX: 1,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null
}
]
}
},
{
fieldType: 'ContainerRepresentation',
id: '1582747052793',
name: 'Label',
type: 'container',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
dateDisplayFormat: null,
layout: null,
sizeX: 2,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null,
numberOfColumns: 2,
fields: {
1: [
{
fieldType: 'FormFieldRepresentation',
id: 'text3',
name: 'Text3',
type: 'text',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
params: { existingColspan: 1, maxColspan: 2 },
dateDisplayFormat: null,
layout: { row: -1, column: -1, colspan: 1 },
sizeX: 1,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: {
leftFormFieldId: 'text1',
leftRestResponseId: null,
operator: '==',
rightValue: '',
rightType: null,
rightFormFieldId: 'text2',
rightRestResponseId: '',
nextConditionOperator: '',
nextCondition: null
}
}
],
2: [
{
fieldType: 'FormFieldRepresentation',
id: 'numberField',
name: 'numberField',
type: 'integer',
value: null,
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
minValue: null,
maxValue: null,
regexPattern: null,
optionType: null,
hasEmptyValue: null,
options: null,
restUrl: null,
restResponsePath: null,
restIdProperty: null,
restLabelProperty: null,
tab: null,
className: null,
params: {
existingColspan: 1,
maxColspan: 1
},
dateDisplayFormat: null,
layout: {
row: -1,
column: -1,
colspan: 1
},
sizeX: 1,
sizeY: 1,
row: -1,
col: -1,
visibilityCondition: null
}
]
}
}
],
outcomes: [],
javascriptEvents: [],
className: '',
style: '',
customFieldTemplates: {},
metadata: {},
variables: [],
customFieldsValueInfo: {},
gridsterForm: false,
globalDateFormat: 'D-M-YYYY'
};
export const tasksMock = [new TaskDetailsModel(taskDetailsMock)];

@ -18,176 +18,159 @@
import { TaskListModel } from '../../task-list/models/task-list.model';
import { fakeAppFilter } from './task-filters.mock';
export const fakeApps = {
size: 2, total: 2, start: 0,
data: [
{
id: 1, defaultAppId: null, name: 'Sales-Fakes-App', description: 'desc-fake1', modelId: 22,
theme: 'theme-1-fake', icon: 'glyphicon-asterisk', deploymentId: '111', tenantId: null
},
{
id: 2, defaultAppId: null, name: 'health-care-Fake', description: 'desc-fake2', modelId: 33,
theme: 'theme-2-fake', icon: 'glyphicon-asterisk', deploymentId: '444', tenantId: null
}
]
};
export const fakeUser1 = { id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName' };
export const fakeUser2 = { id: 1001, email: 'some-one@somegroup.com', firstName: 'some', lastName: 'one' };
export const fakeTaskList = new TaskListModel({
size: 1, total: 1, start: 0,
size: 1,
total: 1,
start: 0,
data: [
{
id: '1', name: 'FakeNameTask', description: null, category: null,
id: '1',
name: 'FakeNameTask',
description: null,
category: null,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
}
]
});
export const fakeTaskListDifferentProcessDefinitionKey = {
size: 2, total: 1, start: 0,
data: [
{
id: '1', name: 'FakeNameTask', description: null, category: null,
assignee: fakeUser1,
processDefinitionKey: '1',
created: '2016-07-15T11:19:17.440+0000'
},
{
id: '2', name: 'FakeNameTask2', description: null, category: null,
assignee: fakeUser1,
processDefinitionKey: '2',
created: '2016-07-15T11:19:17.440+0000'
}
]
};
export const secondFakeTaskList = {
size: 1, total: 1, start: 0,
size: 1,
total: 1,
start: 0,
data: [
{
id: '200', name: 'FakeNameTask', description: null, category: null,
id: '200',
name: 'FakeNameTask',
description: null,
category: null,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
}
]
};
export const mockErrorTaskList = {
error: 'wrong request'
};
export const fakeTaskDetails = { id: '999', name: 'fake-task-name', formKey: '99', assignee: fakeUser1 };
export const fakeTasksComment = {
size: 2, total: 2, start: 0,
data: [
{
id: 1, message: 'fake-message-1', created: '', createdBy: fakeUser1
},
{
id: 2, message: 'fake-message-2', created: '', createdBy: fakeUser1
}
]
};
export const fakeTasksChecklist = {
size: 1, total: 1, start: 0,
size: 1,
total: 1,
start: 0,
data: [
{
id: 1, name: 'FakeCheckTask1', description: null, category: null,
id: 1,
name: 'FakeCheckTask1',
description: null,
category: null,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
},
{
id: 2, name: 'FakeCheckTask2', description: null, category: null,
id: 2,
name: 'FakeCheckTask2',
description: null,
category: null,
assignee: fakeUser1,
created: '2016-07-15T11:19:17.440+0000'
}
]
};
export const fakeAppPromise = new Promise((resolve) => {
resolve(fakeAppFilter);
});
export const fakeAppPromise = Promise.resolve(fakeAppFilter);
export const fakeFormList = {
size: 2,
total: 2,
start: 0,
data: [{
id: 1,
name: 'form with all widgets',
description: '',
createdBy: 2,
createdByFullName: 'Admin Admin',
lastUpdatedBy: 2,
lastUpdatedByFullName: 'Admin Admin',
lastUpdated: 1491400951205,
latestVersion: true,
version: 4,
comment: null,
stencilSet: null,
referenceId: null,
modelType: 2,
favorite: null,
permission: 'write',
tenantId: null
}, {
id: 2,
name: 'uppy',
description: '',
createdBy: 2,
createdByFullName: 'Admin Admin',
lastUpdatedBy: 2,
lastUpdatedByFullName: 'Admin Admin',
lastUpdated: 1490951054477,
latestVersion: true,
version: 2,
comment: null,
stencilSet: null,
referenceId: null,
modelType: 2,
favorite: null,
permission: 'write',
tenantId: null
}]
data: [
{
id: 1,
name: 'form with all widgets',
description: '',
createdBy: 2,
createdByFullName: 'Admin Admin',
lastUpdatedBy: 2,
lastUpdatedByFullName: 'Admin Admin',
lastUpdated: 1491400951205,
latestVersion: true,
version: 4,
comment: null,
stencilSet: null,
referenceId: null,
modelType: 2,
favorite: null,
permission: 'write',
tenantId: null
},
{
id: 2,
name: 'uppy',
description: '',
createdBy: 2,
createdByFullName: 'Admin Admin',
lastUpdatedBy: 2,
lastUpdatedByFullName: 'Admin Admin',
lastUpdated: 1490951054477,
latestVersion: true,
version: 2,
comment: null,
stencilSet: null,
referenceId: null,
modelType: 2,
favorite: null,
permission: 'write',
tenantId: null
}
]
};
export const fakeTaskOpen1 = {
id: '1', name: 'FakeOpenTask1', description: null, category: null,
assignee: fakeUser1,
created: '2017-07-15T11:19:17.440+0000',
dueDate: null,
endDate: null
};
id: '1',
name: 'FakeOpenTask1',
description: null,
category: null,
assignee: fakeUser1,
created: '2017-07-15T11:19:17.440+0000',
dueDate: null,
endDate: null
};
export const fakeTaskOpen2 = {
id: '1', name: 'FakeOpenTask2', description: null, category: null,
assignee: { id: 1, email: 'fake-open-email@dom.com', firstName: 'firstName', lastName: 'lastName' },
created: '2017-07-15T11:19:17.440+0000',
dueDate: null,
endDate: null
};
id: '1',
name: 'FakeOpenTask2',
description: null,
category: null,
assignee: { id: 1, email: 'fake-open-email@dom.com', firstName: 'firstName', lastName: 'lastName' },
created: '2017-07-15T11:19:17.440+0000',
dueDate: null,
endDate: null
};
export const fakeTaskCompleted1 = {
id: '1', name: 'FakeCompletedTaskName1', description: null, category: null,
assignee: { id: 1, email: 'fake-completed-email@dom.com', firstName: 'firstName', lastName: 'lastName' },
created: '2016-07-15T11:19:17.440+0000',
dueDate: null,
endDate: '2016-11-03T15:25:42.749+0000'
};
id: '1',
name: 'FakeCompletedTaskName1',
description: null,
category: null,
assignee: { id: 1, email: 'fake-completed-email@dom.com', firstName: 'firstName', lastName: 'lastName' },
created: '2016-07-15T11:19:17.440+0000',
dueDate: null,
endDate: '2016-11-03T15:25:42.749+0000'
};
export const fakeTaskCompleted2 = {
id: '1', name: 'FakeCompletedTaskName2', description: null, category: null,
assignee: fakeUser1,
created: null,
dueDate: null,
endDate: '2016-11-03T15:25:42.749+0000'
};
id: '1',
name: 'FakeCompletedTaskName2',
description: null,
category: null,
assignee: fakeUser1,
created: null,
dueDate: null,
endDate: '2016-11-03T15:25:42.749+0000'
};
export const fakeOpenTaskList = new TaskListModel({
size: 2,

@ -15,15 +15,8 @@
* limitations under the License.
*/
import {
Component, EventEmitter, Input, OnChanges, OnInit,
Output, SimpleChanges, ViewChild, ViewEncapsulation, OnDestroy
} from '@angular/core';
import {
AppConfigService,
AppConfigValues,
FormValues
} from '@alfresco/adf-core';
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild, ViewEncapsulation, OnDestroy } from '@angular/core';
import { AppConfigService, AppConfigValues, FormValues } from '@alfresco/adf-core';
import { AppsProcessService } from '../../app-list/services/apps-process.service';
import { ProcessInstanceVariable } from '../models/process-instance-variable.model';
import { ProcessDefinitionRepresentation } from './../models/process-definition.model';
@ -35,7 +28,7 @@ import { map, takeUntil } from 'rxjs/operators';
import { MatAutocompleteTrigger } from '@angular/material/autocomplete';
import { MatSelectChange } from '@angular/material/select';
import { StartFormComponent } from '../../form';
import { MinimalNode, RelatedContentRepresentation } from '@alfresco/js-api';
import { Node, RelatedContentRepresentation } from '@alfresco/js-api';
import { AppDefinitionRepresentationModel } from '../../task-list';
import { ProcessNamePipe } from '../../pipes/process-name.pipe';
import { ActivitiContentService } from '../../form/services/activiti-alfresco.service';
@ -48,7 +41,6 @@ const MAX_LENGTH = 255;
encapsulation: ViewEncapsulation.None
})
export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestroy {
/** (optional) Limit the list of processes that can be started to those
* contained in the specified app.
*/
@ -130,24 +122,28 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
movedNodeToPS: FormValues;
private onDestroy$ = new Subject<boolean>();
constructor(private activitiProcess: ProcessService,
private activitiContentService: ActivitiContentService,
private appsProcessService: AppsProcessService,
private appConfig: AppConfigService,
private processNamePipe: ProcessNamePipe) {
}
constructor(
private activitiProcess: ProcessService,
private activitiContentService: ActivitiContentService,
private appsProcessService: AppsProcessService,
private appConfig: AppConfigService,
private processNamePipe: ProcessNamePipe
) {}
ngOnInit() {
this.processNameInput = new UntypedFormControl('', [Validators.required, Validators.maxLength(this.maxProcessNameLength), Validators.pattern('^[^\\s]+(\\s+[^\\s]+)*$')]);
this.processNameInput = new UntypedFormControl('', [
Validators.required,
Validators.maxLength(this.maxProcessNameLength),
Validators.pattern('^[^\\s]+(\\s+[^\\s]+)*$')
]);
this.processDefinitionInput = new UntypedFormControl();
this.load();
this.filteredProcessesDefinitions$ = this.processDefinitionInput.valueChanges
.pipe(
map((value) => this._filter(value)),
takeUntil(this.onDestroy$)
);
this.filteredProcessesDefinitions$ = this.processDefinitionInput.valueChanges.pipe(
map((value) => this._filter(value)),
takeUntil(this.onDestroy$)
);
this.activitiContentService.getAlfrescoRepositories().subscribe((repoList) => {
if (repoList && repoList[0]) {
@ -199,34 +195,40 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
this.isProcessDefinitionsLoading = true;
this.resetSelectedProcessDefinition();
this.activitiProcess.getProcessDefinitions(appId).pipe(
map((processDefinitionRepresentations: ProcessDefinitionRepresentation[]) => {
let currentProcessDef: ProcessDefinitionRepresentation;
this.activitiProcess
.getProcessDefinitions(appId)
.pipe(
map((processDefinitionRepresentations: ProcessDefinitionRepresentation[]) => {
let currentProcessDef: ProcessDefinitionRepresentation;
if (processDefinitionRepresentations.length === 1) {
currentProcessDef = processDefinitionRepresentations[0];
}
if (this.processDefinitionName) {
const filteredProcessDefinition = processDefinitionRepresentations.find((processDefinition) => processDefinition.name === this.processDefinitionName);
if (filteredProcessDefinition) {
currentProcessDef = filteredProcessDefinition;
if (processDefinitionRepresentations.length === 1) {
currentProcessDef = processDefinitionRepresentations[0];
}
}
return { currentProcessDef, processDefinitionRepresentations };
})
).subscribe(
(filteredProcessDefinitions) => {
this.processDefinitions = filteredProcessDefinitions.processDefinitionRepresentations;
this.processDefinitionSelectionChanged(filteredProcessDefinitions.currentProcessDef);
this.processDefinitionInput.setValue(this.selectedProcessDef ? this.selectedProcessDef.name : '');
this.isProcessDefinitionsLoading = false;
},
(error) => {
this.isProcessDefinitionsLoading = false;
this.error.emit(error);
});
if (this.processDefinitionName) {
const filteredProcessDefinition = processDefinitionRepresentations.find(
(processDefinition) => processDefinition.name === this.processDefinitionName
);
if (filteredProcessDefinition) {
currentProcessDef = filteredProcessDefinition;
}
}
return { currentProcessDef, processDefinitionRepresentations };
})
)
.subscribe(
(filteredProcessDefinitions) => {
this.processDefinitions = filteredProcessDefinitions.processDefinitionRepresentations;
this.processDefinitionSelectionChanged(filteredProcessDefinitions.currentProcessDef);
this.processDefinitionInput.setValue(this.selectedProcessDef ? this.selectedProcessDef.name : '');
this.isProcessDefinitionsLoading = false;
},
(error) => {
this.isProcessDefinitionsLoading = false;
this.error.emit(error);
}
);
}
filterProcessDefinitionByName() {
@ -244,7 +246,8 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
this.isAppsLoading = true;
this.appsProcessService
.getDeployedApplications()
.pipe(map((response: AppDefinitionRepresentationModel[]) => {
.pipe(
map((response: AppDefinitionRepresentationModel[]) => {
const applications = this.removeDefaultApps(response);
let currentApplication: AppDefinitionRepresentationModel;
@ -252,7 +255,7 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
currentApplication = applications[0];
}
const filteredApp = applications.find( app => app.id === +this.appId );
const filteredApp = applications.find((app) => app.id === +this.appId);
if (filteredApp) {
currentApplication = filteredApp;
@ -261,7 +264,8 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
return { currentApplication, applications };
})
)
.subscribe((filteredApps) => {
.subscribe(
(filteredApps) => {
this.applications = filteredApps.applications;
this.selectedApplication = filteredApps.currentApplication;
this.applicationSelection.emit(this.selectedApplication);
@ -274,7 +278,6 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
this.error.emit(err);
}
);
}
loadProcessDefinitionsBasedOnSelectedApp() {
@ -328,10 +331,11 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
for (const key in this.values) {
if (this.values.hasOwnProperty(key)) {
const currentValue = Array.isArray(this.values[key]) ? this.values[key] : [this.values[key]];
const contents = currentValue.filter((value: any) => value && value.isFile)
.map((content: MinimalNode) => this.activitiContentService.applyAlfrescoNode(content, null, accountIdentifier));
const contents = currentValue
.filter((value: any) => value && value.isFile)
.map((content: Node) => this.activitiContentService.applyAlfrescoNode(content, null, accountIdentifier));
forkJoin(contents).subscribe((res: RelatedContentRepresentation[]) => {
this.movedNodeToPS = { [key]: [...res]};
this.movedNodeToPS = { [key]: [...res] };
});
}
}
@ -435,7 +439,7 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
return !!(this.selectedApplication && this.selectedApplication.id);
}
private removeDefaultApps(apps: AppDefinitionRepresentationModel []): AppDefinitionRepresentationModel[] {
private removeDefaultApps(apps: AppDefinitionRepresentationModel[]): AppDefinitionRepresentationModel[] {
return apps.filter((app) => app.id);
}
@ -466,8 +470,11 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
}
private isProcessDefinitionChanged(changes: SimpleChanges) {
return changes['processDefinitionName'] && changes['processDefinitionName'].currentValue &&
changes['processDefinitionName'].currentValue !== changes['processDefinitionName'].previousValue;
return (
changes['processDefinitionName'] &&
changes['processDefinitionName'].currentValue &&
changes['processDefinitionName'].currentValue !== changes['processDefinitionName'].previousValue
);
}
private _filter(value: string): ProcessDefinitionRepresentation[] {

@ -22,8 +22,8 @@
"types": ["jasmine", "node", "jasminewd2"],
"lib": ["es2018", "esnext.array", "esnext.asynciterable", "dom"],
"paths": {
"@alfresco/adf-content-services": ["lib/content-services"],
"@alfresco/adf-core": ["lib/core"],
"@alfresco/adf-content-services": ["lib/content-services/src/public-api.ts"],
"@alfresco/adf-core": ["lib/core/src/public-api.ts"],
"@alfresco/adf-core/*": ["lib/core/*/public-api.ts"],
"@alfresco/adf-core/api": ["lib/core/api/src/index.ts"],
"@alfresco/adf-core/auth": ["lib/core/auth/src/index.ts"],