From 88f8b4065ed91d31c6a880d67faf8c396513dbea Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 15 Apr 2020 14:44:26 +0300 Subject: [PATCH] [ACA-3043] Create From Template - relativePath not working when ACS installation language is different (#1411) * use primary path to get node information * breadcrumb transform based on paths intersection * update tests --- .../services/node-template.service.spec.ts | 240 ++++++++++++------ src/app/services/node-template.service.ts | 58 +++-- .../store/effects/template.effects.spec.ts | 4 +- src/app/store/effects/template.effects.ts | 4 +- 4 files changed, 199 insertions(+), 107 deletions(-) diff --git a/src/app/services/node-template.service.spec.ts b/src/app/services/node-template.service.spec.ts index 7233c6941..751a269b7 100644 --- a/src/app/services/node-template.service.spec.ts +++ b/src/app/services/node-template.service.spec.ts @@ -40,11 +40,11 @@ describe('NodeTemplateService', () => { let alfrescoApiService: AlfrescoApiService; let nodeTemplateService: NodeTemplateService; const fileTemplateConfig = { - relativePath: 'relative-path/parent-file-templates', + primaryPathName: 'parent-file-templates', selectionType: 'file' }; const folderTemplateConfig = { - relativePath: 'relative-path/parent-folder-templates', + primaryPathName: 'parent-folder-templates', selectionType: 'folder' }; @@ -63,30 +63,38 @@ describe('NodeTemplateService', () => { nodeTemplateService = TestBed.get(NodeTemplateService); }); - it('should open dialog with parent node `id` as data property', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'parent-node-id' })); + it('should open dialog with parent node `id` as data property', fakeAsync(() => { + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( + of({ list: { entries: [{ entry: { id: 'parent-node-id' } }] } }) + ); spyOn(dialog, 'open'); nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + tick(); expect(dialog.open['calls'].argsFor(0)[1].data).toEqual( jasmine.objectContaining({ currentFolderId: 'parent-node-id' }) ); - }); + })); - it('should remove parents for templates node breadcrumb path', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue( + it('should remove parents path for templates breadcrumb', fakeAsync(() => { + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( of({ - id: 'parent-node-id', - path: { - elements: [], - name: '/Company Home/Data Dictionary' + list: { + entries: [ + { + entry: { + id: 'parent-node-id', + path: { + elements: [ + { id: 'id1', name: 'Company Home' }, + { id: 'id2', name: 'Data Dictionary' } + ], + name: '/Company Home/Data Dictionary' + } + } + } + ] } }) ); @@ -99,19 +107,63 @@ describe('NodeTemplateService', () => { .data.breadcrumbTransform({ name: 'Node Templates', path: { - elements: [{ name: 'Company Home' }, { name: 'Data Dictionary' }], + elements: [ + { id: 'id1', name: 'Company Home' }, + { id: 'id2', name: 'Data Dictionary' } + ], name: '/Company Home/Data Dictionary' } }); expect(breadcrumb.path.elements).toEqual([]); - }); + })); + + it('should set template folder path as root for breadcrumb', fakeAsync(() => { + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( + of({ + list: { + entries: [ + { + entry: { + id: 'parent-node-id', + path: { + elements: [ + { id: 'id1', name: 'Company Home' }, + { id: 'id2', name: 'Data Dictionary' } + ], + name: '/Company Home/Data Dictionary' + } + } + } + ] + } + }) + ); + spyOn(dialog, 'open'); + + nodeTemplateService.selectTemplateDialog(fileTemplateConfig); + + const breadcrumb = dialog.open['calls'] + .argsFor(0)[1] + .data.breadcrumbTransform({ + name: 'Node Templates', + path: { + elements: [ + { id: 'id1', name: 'Company Home' }, + { id: 'id2', name: 'Data Dictionary' }, + { id: 'id3', name: 'Templates' } + ], + name: '/Company Home/Data Dictionary/Templates' + } + }); + + expect(breadcrumb.path.elements).toEqual([ + { id: 'id3', name: 'Templates' } + ]); + })); it('should raise an error when getNodeInfo fails', fakeAsync(() => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue( + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( Promise.reject({ message: `{ "error": { "statusCode": 404 } } ` }) @@ -127,15 +179,20 @@ describe('NodeTemplateService', () => { })); it('should return true if row is not a `link` nodeType', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue( + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( of({ - id: 'templates-folder-id', - path: { - elements: [], - name: '/Company Home/Data Dictionary' + list: { + entries: [ + { + entry: { + id: 'templates-folder-id', + path: { + elements: [{}, {}], + name: '/Company Home/Data Dictionary' + } + } + } + ] } }) ); @@ -151,15 +208,20 @@ describe('NodeTemplateService', () => { }); it('should return false if row is a `filelink` nodeType', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue( + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( of({ - id: 'templates-folder-id', - path: { - elements: [], - name: '/Company Home/Data Dictionary' + list: { + entries: [ + { + entry: { + id: 'templates-folder-id', + path: { + elements: [{}, {}], + name: '/Company Home/Data Dictionary' + } + } + } + ] } }) ); @@ -175,15 +237,20 @@ describe('NodeTemplateService', () => { }); it('should return false if row is a `folderlink` nodeType', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue( + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( of({ - id: 'templates-folder-id', - path: { - elements: [], - name: '/Company Home/Data Dictionary' + list: { + entries: [ + { + entry: { + id: 'templates-folder-id', + path: { + elements: [{}, {}], + name: '/Company Home/Data Dictionary' + } + } + } + ] } }) ); @@ -200,10 +267,9 @@ describe('NodeTemplateService', () => { describe('File templates', () => { it('should return false if selected node is not a file', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( + of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } }) + ); spyOn(dialog, 'open'); nodeTemplateService.selectTemplateDialog(fileTemplateConfig); @@ -213,17 +279,17 @@ describe('NodeTemplateService', () => { .data.isSelectionValid({ name: 'some-folder-template', isFile: false, - isFolder: true + isFolder: true, + path: { elements: [{}, {}] } }); expect(isSelectionValid).toBe(false); }); it('should return true if selected node is a template file', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( + of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } }) + ); spyOn(dialog, 'open'); nodeTemplateService.selectTemplateDialog(fileTemplateConfig); @@ -233,17 +299,17 @@ describe('NodeTemplateService', () => { .data.isSelectionValid({ name: 'some-file-template', isFile: true, - isFolder: false + isFolder: false, + path: { elements: [{}, {}] } }); expect(isSelectionValid).toBe(true); }); it('should set dialog title for file templates', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( + of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } }) + ); spyOn(dialog, 'open'); nodeTemplateService.selectTemplateDialog(fileTemplateConfig); @@ -256,10 +322,9 @@ describe('NodeTemplateService', () => { describe('Folder templates', () => { it('should return false if selected node is not a folder', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( + of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } }) + ); spyOn(dialog, 'open'); nodeTemplateService.selectTemplateDialog(folderTemplateConfig); @@ -269,17 +334,17 @@ describe('NodeTemplateService', () => { .data.isSelectionValid({ name: 'some-file-template', isFile: true, - isFolder: false + isFolder: false, + path: { elements: [{}, {}] } }); expect(isSelectionValid).toBe(false); }); - it('should return false if current node is the parent folder', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); + it('should return false if current node is the parent folder', fakeAsync(() => { + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( + of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } }) + ); spyOn(dialog, 'open'); nodeTemplateService.selectTemplateDialog(folderTemplateConfig); @@ -289,37 +354,44 @@ describe('NodeTemplateService', () => { .data.isSelectionValid({ name: 'parent-folder-templates', isFile: false, - isFolder: true + isFolder: true, + path: { elements: [] } }); expect(isSelectionValid).toBe(false); - }); + })); - it('should return true if selected node is a folder template', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); + it('should return true if selected node is a folder template', fakeAsync(() => { + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( + of({ + list: { + entries: [ + { entry: { id: 'templates-folder-id', path: { elements: [] } } } + ] + } + }) + ); spyOn(dialog, 'open'); nodeTemplateService.selectTemplateDialog(folderTemplateConfig); + tick(); const isSelectionValid = dialog.open['calls'] .argsFor(0)[1] .data.isSelectionValid({ name: 'some-folder-template', isFile: false, - isFolder: true + isFolder: true, + path: { elements: [{}, {}] } }); expect(isSelectionValid).toBe(true); - }); + })); it('should set dialog title for folder templates', () => { - spyOn( - alfrescoApiService.getInstance().nodes, - 'getNodeInfo' - ).and.returnValue(of({ id: 'templates-folder-id' })); + spyOn(alfrescoApiService.searchApi, 'search').and.returnValue( + of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } }) + ); spyOn(dialog, 'open'); nodeTemplateService.selectTemplateDialog(folderTemplateConfig); diff --git a/src/app/services/node-template.service.ts b/src/app/services/node-template.service.ts index 8633d5093..274ae13d5 100644 --- a/src/app/services/node-template.service.ts +++ b/src/app/services/node-template.service.ts @@ -24,10 +24,20 @@ */ import { Injectable } from '@angular/core'; -import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material'; +import { + MatDialog, + MatDialogConfig, + MatDialogRef +} from '@angular/material/dialog'; import { CreateFromTemplateDialogComponent } from '../dialogs/node-template/create-from-template.dialog'; import { Subject, from, of } from 'rxjs'; -import { Node, MinimalNode, MinimalNodeEntryEntity } from '@alfresco/js-api'; +import { + Node, + MinimalNode, + MinimalNodeEntryEntity, + ResultNode, + PathElement +} from '@alfresco/js-api'; import { AlfrescoApiService, TranslationService } from '@alfresco/adf-core'; import { switchMap, catchError } from 'rxjs/operators'; import { Store } from '@ngrx/store'; @@ -39,7 +49,7 @@ import { } from '@alfresco/adf-content-services'; export interface TemplateDialogConfig { - relativePath: string; + primaryPathName: string; selectionType: string; } @@ -48,6 +58,7 @@ export interface TemplateDialogConfig { }) export class NodeTemplateService { private currentTemplateConfig: TemplateDialogConfig = null; + private rootNode: ResultNode; constructor( private store: Store, @@ -78,14 +89,21 @@ export class NodeTemplateService { rowFilter: this.rowFilter.bind(this) }; - from( - this.alfrescoApiService.getInstance().nodes.getNodeInfo('-root-', { - relativePath: config.relativePath - }) - ) + const query = { + query: { + query: `PATH:"//${config.primaryPathName}"`, + language: 'afts' + }, + include: ['path', 'properties', 'allowableOperations', 'permissions'] + }; + + from(this.alfrescoApiService.searchApi.search(query)) .pipe( - switchMap(node => { - data.currentFolderId = node.id; + switchMap(response => { + const entry = response.list.entries[0].entry; + this.rootNode = entry; + data.currentFolderId = entry.id; + return this.dialog .open(ContentNodeSelectorComponent, { data, @@ -121,20 +139,13 @@ export class NodeTemplateService { private transformNode(node: MinimalNode): MinimalNode { if (node && node.path && node.path && node.path.elements instanceof Array) { - let { - path: { elements: elementsPath = [] } - } = node; - elementsPath = elementsPath.filter( - path => path.name !== 'Company Home' && path.name !== 'Data Dictionary' - ); - node.path.elements = elementsPath; + node.path.elements = this.getPathElements(node); } - return node; } private isSelectionValid(node: Node): boolean { - if (node.name === this.currentTemplateConfig.relativePath.split('/')[1]) { + if (!node.path.elements.length) { return false; } @@ -167,4 +178,13 @@ export class NodeTemplateService { node.nodeType !== 'app:filelink' && node.nodeType !== 'app:folderlink' ); } + + private getPathElements(node: Node): PathElement[] { + return node.path.elements.filter( + pathElement => + !this.rootNode.path.elements.some( + rootPathElement => pathElement.id === rootPathElement.id + ) + ); + } } diff --git a/src/app/store/effects/template.effects.spec.ts b/src/app/store/effects/template.effects.spec.ts index e0d522d00..28deb86e9 100644 --- a/src/app/store/effects/template.effects.spec.ts +++ b/src/app/store/effects/template.effects.spec.ts @@ -66,12 +66,12 @@ describe('TemplateEffects', () => { } }; const fileTemplateConfig = { - relativePath: 'Data Dictionary/Node Templates', + primaryPathName: 'app:node_templates', selectionType: 'file' }; const folderTemplateConfig = { - relativePath: 'Data Dictionary/Space Templates', + primaryPathName: 'app:space_templates', selectionType: 'folder' }; diff --git a/src/app/store/effects/template.effects.ts b/src/app/store/effects/template.effects.ts index ab6a778de..917162d9a 100644 --- a/src/app/store/effects/template.effects.ts +++ b/src/app/store/effects/template.effects.ts @@ -63,7 +63,7 @@ export class TemplateEffects { ofType(TemplateActionTypes.FileFromTemplate), map(() => { this.openDialog({ - relativePath: 'Data Dictionary/Node Templates', + primaryPathName: 'app:node_templates', selectionType: 'file' }); }) @@ -74,7 +74,7 @@ export class TemplateEffects { ofType(TemplateActionTypes.FolderFromTemplate), map(() => this.openDialog({ - relativePath: 'Data Dictionary/Space Templates', + primaryPathName: 'app:space_templates', selectionType: 'folder' }) )