[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
This commit is contained in:
Cilibiu Bogdan
2020-04-15 12:44:26 +01:00
committed by GitHub
parent 6e33766fc4
commit 88f8b4065e
4 changed files with 199 additions and 107 deletions
+156 -84
View File
@@ -40,11 +40,11 @@ describe('NodeTemplateService', () => {
let alfrescoApiService: AlfrescoApiService; let alfrescoApiService: AlfrescoApiService;
let nodeTemplateService: NodeTemplateService; let nodeTemplateService: NodeTemplateService;
const fileTemplateConfig = { const fileTemplateConfig = {
relativePath: 'relative-path/parent-file-templates', primaryPathName: 'parent-file-templates',
selectionType: 'file' selectionType: 'file'
}; };
const folderTemplateConfig = { const folderTemplateConfig = {
relativePath: 'relative-path/parent-folder-templates', primaryPathName: 'parent-folder-templates',
selectionType: 'folder' selectionType: 'folder'
}; };
@@ -63,30 +63,38 @@ describe('NodeTemplateService', () => {
nodeTemplateService = TestBed.get(NodeTemplateService); nodeTemplateService = TestBed.get(NodeTemplateService);
}); });
it('should open dialog with parent node `id` as data property', () => { it('should open dialog with parent node `id` as data property', fakeAsync(() => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes, of({ list: { entries: [{ entry: { id: 'parent-node-id' } }] } })
'getNodeInfo' );
).and.returnValue(of({ id: 'parent-node-id' }));
spyOn(dialog, 'open'); spyOn(dialog, 'open');
nodeTemplateService.selectTemplateDialog(fileTemplateConfig); nodeTemplateService.selectTemplateDialog(fileTemplateConfig);
tick();
expect(dialog.open['calls'].argsFor(0)[1].data).toEqual( expect(dialog.open['calls'].argsFor(0)[1].data).toEqual(
jasmine.objectContaining({ currentFolderId: 'parent-node-id' }) jasmine.objectContaining({ currentFolderId: 'parent-node-id' })
); );
}); }));
it('should remove parents for templates node breadcrumb path', () => { it('should remove parents path for templates breadcrumb', fakeAsync(() => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes,
'getNodeInfo'
).and.returnValue(
of({ of({
id: 'parent-node-id', list: {
path: { entries: [
elements: [], {
name: '/Company Home/Data Dictionary' 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({ .data.breadcrumbTransform({
name: 'Node Templates', name: 'Node Templates',
path: { path: {
elements: [{ name: 'Company Home' }, { name: 'Data Dictionary' }], elements: [
{ id: 'id1', name: 'Company Home' },
{ id: 'id2', name: 'Data Dictionary' }
],
name: '/Company Home/Data Dictionary' name: '/Company Home/Data Dictionary'
} }
}); });
expect(breadcrumb.path.elements).toEqual([]); 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(() => { it('should raise an error when getNodeInfo fails', fakeAsync(() => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes,
'getNodeInfo'
).and.returnValue(
Promise.reject({ Promise.reject({
message: `{ "error": { "statusCode": 404 } } ` message: `{ "error": { "statusCode": 404 } } `
}) })
@@ -127,15 +179,20 @@ describe('NodeTemplateService', () => {
})); }));
it('should return true if row is not a `link` nodeType', () => { it('should return true if row is not a `link` nodeType', () => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes,
'getNodeInfo'
).and.returnValue(
of({ of({
id: 'templates-folder-id', list: {
path: { entries: [
elements: [], {
name: '/Company Home/Data Dictionary' 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', () => { it('should return false if row is a `filelink` nodeType', () => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes,
'getNodeInfo'
).and.returnValue(
of({ of({
id: 'templates-folder-id', list: {
path: { entries: [
elements: [], {
name: '/Company Home/Data Dictionary' 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', () => { it('should return false if row is a `folderlink` nodeType', () => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes,
'getNodeInfo'
).and.returnValue(
of({ of({
id: 'templates-folder-id', list: {
path: { entries: [
elements: [], {
name: '/Company Home/Data Dictionary' entry: {
id: 'templates-folder-id',
path: {
elements: [{}, {}],
name: '/Company Home/Data Dictionary'
}
}
}
]
} }
}) })
); );
@@ -200,10 +267,9 @@ describe('NodeTemplateService', () => {
describe('File templates', () => { describe('File templates', () => {
it('should return false if selected node is not a file', () => { it('should return false if selected node is not a file', () => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes, of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } })
'getNodeInfo' );
).and.returnValue(of({ id: 'templates-folder-id' }));
spyOn(dialog, 'open'); spyOn(dialog, 'open');
nodeTemplateService.selectTemplateDialog(fileTemplateConfig); nodeTemplateService.selectTemplateDialog(fileTemplateConfig);
@@ -213,17 +279,17 @@ describe('NodeTemplateService', () => {
.data.isSelectionValid({ .data.isSelectionValid({
name: 'some-folder-template', name: 'some-folder-template',
isFile: false, isFile: false,
isFolder: true isFolder: true,
path: { elements: [{}, {}] }
}); });
expect(isSelectionValid).toBe(false); expect(isSelectionValid).toBe(false);
}); });
it('should return true if selected node is a template file', () => { it('should return true if selected node is a template file', () => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes, of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } })
'getNodeInfo' );
).and.returnValue(of({ id: 'templates-folder-id' }));
spyOn(dialog, 'open'); spyOn(dialog, 'open');
nodeTemplateService.selectTemplateDialog(fileTemplateConfig); nodeTemplateService.selectTemplateDialog(fileTemplateConfig);
@@ -233,17 +299,17 @@ describe('NodeTemplateService', () => {
.data.isSelectionValid({ .data.isSelectionValid({
name: 'some-file-template', name: 'some-file-template',
isFile: true, isFile: true,
isFolder: false isFolder: false,
path: { elements: [{}, {}] }
}); });
expect(isSelectionValid).toBe(true); expect(isSelectionValid).toBe(true);
}); });
it('should set dialog title for file templates', () => { it('should set dialog title for file templates', () => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes, of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } })
'getNodeInfo' );
).and.returnValue(of({ id: 'templates-folder-id' }));
spyOn(dialog, 'open'); spyOn(dialog, 'open');
nodeTemplateService.selectTemplateDialog(fileTemplateConfig); nodeTemplateService.selectTemplateDialog(fileTemplateConfig);
@@ -256,10 +322,9 @@ describe('NodeTemplateService', () => {
describe('Folder templates', () => { describe('Folder templates', () => {
it('should return false if selected node is not a folder', () => { it('should return false if selected node is not a folder', () => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes, of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } })
'getNodeInfo' );
).and.returnValue(of({ id: 'templates-folder-id' }));
spyOn(dialog, 'open'); spyOn(dialog, 'open');
nodeTemplateService.selectTemplateDialog(folderTemplateConfig); nodeTemplateService.selectTemplateDialog(folderTemplateConfig);
@@ -269,17 +334,17 @@ describe('NodeTemplateService', () => {
.data.isSelectionValid({ .data.isSelectionValid({
name: 'some-file-template', name: 'some-file-template',
isFile: true, isFile: true,
isFolder: false isFolder: false,
path: { elements: [{}, {}] }
}); });
expect(isSelectionValid).toBe(false); expect(isSelectionValid).toBe(false);
}); });
it('should return false if current node is the parent folder', () => { it('should return false if current node is the parent folder', fakeAsync(() => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes, of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } })
'getNodeInfo' );
).and.returnValue(of({ id: 'templates-folder-id' }));
spyOn(dialog, 'open'); spyOn(dialog, 'open');
nodeTemplateService.selectTemplateDialog(folderTemplateConfig); nodeTemplateService.selectTemplateDialog(folderTemplateConfig);
@@ -289,37 +354,44 @@ describe('NodeTemplateService', () => {
.data.isSelectionValid({ .data.isSelectionValid({
name: 'parent-folder-templates', name: 'parent-folder-templates',
isFile: false, isFile: false,
isFolder: true isFolder: true,
path: { elements: [] }
}); });
expect(isSelectionValid).toBe(false); expect(isSelectionValid).toBe(false);
}); }));
it('should return true if selected node is a folder template', () => { it('should return true if selected node is a folder template', fakeAsync(() => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes, of({
'getNodeInfo' list: {
).and.returnValue(of({ id: 'templates-folder-id' })); entries: [
{ entry: { id: 'templates-folder-id', path: { elements: [] } } }
]
}
})
);
spyOn(dialog, 'open'); spyOn(dialog, 'open');
nodeTemplateService.selectTemplateDialog(folderTemplateConfig); nodeTemplateService.selectTemplateDialog(folderTemplateConfig);
tick();
const isSelectionValid = dialog.open['calls'] const isSelectionValid = dialog.open['calls']
.argsFor(0)[1] .argsFor(0)[1]
.data.isSelectionValid({ .data.isSelectionValid({
name: 'some-folder-template', name: 'some-folder-template',
isFile: false, isFile: false,
isFolder: true isFolder: true,
path: { elements: [{}, {}] }
}); });
expect(isSelectionValid).toBe(true); expect(isSelectionValid).toBe(true);
}); }));
it('should set dialog title for folder templates', () => { it('should set dialog title for folder templates', () => {
spyOn( spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(
alfrescoApiService.getInstance().nodes, of({ list: { entries: [{ entry: { id: 'templates-folder-id' } }] } })
'getNodeInfo' );
).and.returnValue(of({ id: 'templates-folder-id' }));
spyOn(dialog, 'open'); spyOn(dialog, 'open');
nodeTemplateService.selectTemplateDialog(folderTemplateConfig); nodeTemplateService.selectTemplateDialog(folderTemplateConfig);
+39 -19
View File
@@ -24,10 +24,20 @@
*/ */
import { Injectable } from '@angular/core'; 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 { CreateFromTemplateDialogComponent } from '../dialogs/node-template/create-from-template.dialog';
import { Subject, from, of } from 'rxjs'; 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 { AlfrescoApiService, TranslationService } from '@alfresco/adf-core';
import { switchMap, catchError } from 'rxjs/operators'; import { switchMap, catchError } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
@@ -39,7 +49,7 @@ import {
} from '@alfresco/adf-content-services'; } from '@alfresco/adf-content-services';
export interface TemplateDialogConfig { export interface TemplateDialogConfig {
relativePath: string; primaryPathName: string;
selectionType: string; selectionType: string;
} }
@@ -48,6 +58,7 @@ export interface TemplateDialogConfig {
}) })
export class NodeTemplateService { export class NodeTemplateService {
private currentTemplateConfig: TemplateDialogConfig = null; private currentTemplateConfig: TemplateDialogConfig = null;
private rootNode: ResultNode;
constructor( constructor(
private store: Store<AppStore>, private store: Store<AppStore>,
@@ -78,14 +89,21 @@ export class NodeTemplateService {
rowFilter: this.rowFilter.bind(this) rowFilter: this.rowFilter.bind(this)
}; };
from( const query = {
this.alfrescoApiService.getInstance().nodes.getNodeInfo('-root-', { query: {
relativePath: config.relativePath query: `PATH:"//${config.primaryPathName}"`,
}) language: 'afts'
) },
include: ['path', 'properties', 'allowableOperations', 'permissions']
};
from(this.alfrescoApiService.searchApi.search(query))
.pipe( .pipe(
switchMap(node => { switchMap(response => {
data.currentFolderId = node.id; const entry = response.list.entries[0].entry;
this.rootNode = entry;
data.currentFolderId = entry.id;
return this.dialog return this.dialog
.open(ContentNodeSelectorComponent, <MatDialogConfig>{ .open(ContentNodeSelectorComponent, <MatDialogConfig>{
data, data,
@@ -121,20 +139,13 @@ export class NodeTemplateService {
private transformNode(node: MinimalNode): MinimalNode { private transformNode(node: MinimalNode): MinimalNode {
if (node && node.path && node.path && node.path.elements instanceof Array) { if (node && node.path && node.path && node.path.elements instanceof Array) {
let { node.path.elements = this.getPathElements(node);
path: { elements: elementsPath = [] }
} = node;
elementsPath = elementsPath.filter(
path => path.name !== 'Company Home' && path.name !== 'Data Dictionary'
);
node.path.elements = elementsPath;
} }
return node; return node;
} }
private isSelectionValid(node: Node): boolean { private isSelectionValid(node: Node): boolean {
if (node.name === this.currentTemplateConfig.relativePath.split('/')[1]) { if (!node.path.elements.length) {
return false; return false;
} }
@@ -167,4 +178,13 @@ export class NodeTemplateService {
node.nodeType !== 'app:filelink' && node.nodeType !== 'app:folderlink' 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
)
);
}
} }
@@ -66,12 +66,12 @@ describe('TemplateEffects', () => {
} }
}; };
const fileTemplateConfig = { const fileTemplateConfig = {
relativePath: 'Data Dictionary/Node Templates', primaryPathName: 'app:node_templates',
selectionType: 'file' selectionType: 'file'
}; };
const folderTemplateConfig = { const folderTemplateConfig = {
relativePath: 'Data Dictionary/Space Templates', primaryPathName: 'app:space_templates',
selectionType: 'folder' selectionType: 'folder'
}; };
+2 -2
View File
@@ -63,7 +63,7 @@ export class TemplateEffects {
ofType<FileFromTemplate>(TemplateActionTypes.FileFromTemplate), ofType<FileFromTemplate>(TemplateActionTypes.FileFromTemplate),
map(() => { map(() => {
this.openDialog({ this.openDialog({
relativePath: 'Data Dictionary/Node Templates', primaryPathName: 'app:node_templates',
selectionType: 'file' selectionType: 'file'
}); });
}) })
@@ -74,7 +74,7 @@ export class TemplateEffects {
ofType<FolderFromTemplate>(TemplateActionTypes.FolderFromTemplate), ofType<FolderFromTemplate>(TemplateActionTypes.FolderFromTemplate),
map(() => map(() =>
this.openDialog({ this.openDialog({
relativePath: 'Data Dictionary/Space Templates', primaryPathName: 'app:space_templates',
selectionType: 'folder' selectionType: 'folder'
}) })
) )