Skip to content

Commit c0b7dd9

Browse files
committed
feat(dot-browsing): Enhance tree structure with parent reference and update tests
## Summary This commit introduces a parent reference in the tree structure for better data management and updates related tests to ensure functionality. ## Changes Made ### Models - Added `parent` property to `CustomTreeNode` in `dot-browser-selector.model.ts`. ### Store - Updated `HostFolderFiledStore` to utilize the new `CustomTreeNode` structure in `host-folder-field.store.ts`. ### Service - Modified `DotBrowsingService` to include the parent reference in the tree response in `dot-browsing.service.ts`. ### Tests - Expanded test cases in `dot-browsing.service.spec.ts` to validate the presence of the parent reference in tree structures for both single and multi-level paths. ## Technical Details The addition of the parent reference allows consumers of the tree structure to access the parent folder's hostname directly, improving the usability of the data model. ## Testing - [x] Unit tests added/updated to cover new functionality. - [x] Manual testing performed to verify tree structure integrity and parent reference accessibility.
1 parent 2446f2c commit c0b7dd9

File tree

4 files changed

+132
-14
lines changed

4 files changed

+132
-14
lines changed

core-web/libs/dotcms-models/src/lib/dot-browser-selector.model.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { TreeNode } from 'primeng/api';
22

3+
import { DotFolder } from './dot-folder.model';
4+
35
export type TreeNodeData = {
46
type: 'site' | 'folder';
57
path: string;
@@ -14,6 +16,7 @@ export type TreeNodeSelectItem = TreeNodeSelectEvent<TreeNodeData>;
1416
export type CustomTreeNode = {
1517
node: null | TreeNodeItem;
1618
tree: {
19+
parent?: DotFolder;
1720
path: string;
1821
folders: TreeNodeItem[];
1922
} | null;

core-web/libs/edit-content/src/lib/fields/dot-edit-content-host-folder-field/store/host-folder-field.store.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import { tapResponse } from '@ngrx/operators';
2-
import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
2+
import { patchState, signalStore, withComputed, withMethods, withState } from '@ngrx/signals';
33
import { rxMethod } from '@ngrx/signals/rxjs-interop';
44
import { of, pipe } from 'rxjs';
55

66
import { computed, inject } from '@angular/core';
77

8-
import { tap, exhaustMap, switchMap, map, filter } from 'rxjs/operators';
8+
import { exhaustMap, filter, map, switchMap, tap } from 'rxjs/operators';
99

10-
import { ComponentStatus, TreeNodeItem, TreeNodeSelectItem } from '@dotcms/dotcms-models';
10+
import {
11+
ComponentStatus,
12+
CustomTreeNode,
13+
TreeNodeItem,
14+
TreeNodeSelectItem
15+
} from '@dotcms/dotcms-models';
1116
import { DotBrowsingService } from '@dotcms/ui';
1217

1318
export const PEER_PAGE_LIMIT = 7000;
@@ -132,7 +137,7 @@ export const HostFolderFiledStore = signalStore(
132137
const hasPaths = path.includes('/');
133138

134139
if (!hasPaths) {
135-
const response = {
140+
const response: CustomTreeNode = {
136141
node: sites.find((item) => item.data.hostname === path),
137142
tree: null
138143
};

core-web/libs/ui/src/lib/services/dot-browsing/dot-browsing.service.spec.ts

Lines changed: 111 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import {
66
} from '@ngneat/spectator/jest';
77
import { of, throwError } from 'rxjs';
88

9-
import { DotSiteService, DotFolderService } from '@dotcms/data-access';
9+
import { DotFolderService, DotSiteService } from '@dotcms/data-access';
1010
import {
11-
DotFolder,
12-
SiteEntity,
11+
ContentByFolderParams,
1312
DotCMSContentlet,
14-
ContentByFolderParams
13+
DotFolder,
14+
SiteEntity
1515
} from '@dotcms/dotcms-models';
16-
import { createFakeSite, createFakeFolder, createFakeContentlet } from '@dotcms/utils-testing';
16+
import { createFakeContentlet, createFakeFolder, createFakeSite } from '@dotcms/utils-testing';
1717

1818
import { DotBrowsingService } from './dot-browsing.service';
1919

@@ -410,6 +410,112 @@ describe('DotBrowsingService', () => {
410410
}
411411
});
412412
});
413+
414+
it('should always return tree with defined parent and hostName for single level path', (done) => {
415+
const path = 'example.com';
416+
const rootParent = createFakeFolder({
417+
id: 'root',
418+
hostName: 'example.com',
419+
path: '/',
420+
addChildrenAllowed: true
421+
});
422+
423+
const rootFolders: DotFolder[] = [rootParent];
424+
425+
dotFolderService.getFolders.mockReturnValue(of(rootFolders));
426+
427+
spectator.service.buildTreeByPaths(path).subscribe((result) => {
428+
expect(result.tree).toBeDefined();
429+
expect(result.tree?.parent).toBeDefined();
430+
expect(result.tree?.parent?.hostName).toBe('example.com');
431+
expect(result.tree?.path).toBe('/');
432+
// Consumer (host-folder-field.store) can safely use tree.parent.hostName
433+
expect(() => {
434+
const hostName = result.tree?.parent?.hostName;
435+
return hostName;
436+
}).not.toThrow();
437+
done();
438+
});
439+
});
440+
441+
it('should always return tree with defined parent and hostName for multi level path (regression: tree.parent.hostName in host-folder-field.store)', (done) => {
442+
const path = 'demo.com/level1/level2';
443+
444+
const level2Parent = createFakeFolder({
445+
id: 'parent-level2',
446+
hostName: 'demo.com',
447+
path: '/level1/level2',
448+
addChildrenAllowed: true
449+
});
450+
451+
const level2Folders: DotFolder[] = [
452+
level2Parent,
453+
createFakeFolder({
454+
id: 'child-level2',
455+
hostName: 'demo.com',
456+
path: '/level1/level2/child',
457+
addChildrenAllowed: true
458+
})
459+
];
460+
461+
const level1Folders: DotFolder[] = [
462+
createFakeFolder({
463+
id: 'parent-level1',
464+
hostName: 'demo.com',
465+
path: '/level1',
466+
addChildrenAllowed: true
467+
}),
468+
createFakeFolder({
469+
id: 'parent-level2',
470+
hostName: 'demo.com',
471+
path: '/level1/level2',
472+
addChildrenAllowed: true
473+
})
474+
];
475+
476+
const rootFolders: DotFolder[] = [
477+
createFakeFolder({
478+
id: 'root',
479+
hostName: 'demo.com',
480+
path: '/',
481+
addChildrenAllowed: true
482+
}),
483+
createFakeFolder({
484+
id: 'parent-level1',
485+
hostName: 'demo.com',
486+
path: '/level1',
487+
addChildrenAllowed: true
488+
})
489+
];
490+
491+
dotFolderService.getFolders.mockImplementation((requestedPath: string) => {
492+
if (requestedPath === '//demo.com/level1/level2/') {
493+
return of(level2Folders);
494+
}
495+
if (requestedPath === '//demo.com/level1/') {
496+
return of(level1Folders);
497+
}
498+
if (requestedPath === '//demo.com/') {
499+
return of(rootFolders);
500+
}
501+
return of([]);
502+
});
503+
504+
spectator.service.buildTreeByPaths(path).subscribe((result) => {
505+
expect(result.tree).toBeDefined();
506+
expect(result.tree?.parent).toBeDefined();
507+
expect(result.tree?.parent?.hostName).toBeDefined();
508+
expect(result.tree?.parent?.hostName).toBe('demo.com');
509+
// Simulates host-folder-field.store: item.data.hostname === tree.parent.hostName
510+
expect(() => {
511+
const tree = result.tree;
512+
if (tree) {
513+
return tree.parent?.hostName;
514+
}
515+
}).not.toThrow();
516+
done();
517+
});
518+
});
413519
});
414520

415521
describe('getCurrentSiteAsTreeNodeItem', () => {

core-web/libs/ui/src/lib/services/dot-browsing/dot-browsing.service.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import { Injectable, inject } from '@angular/core';
44

55
import { filter, map } from 'rxjs/operators';
66

7-
import { DotSiteService, DotFolderService } from '@dotcms/data-access';
7+
import { DotFolderService, DotSiteService } from '@dotcms/data-access';
88
import {
9-
DotFolder,
10-
TreeNodeItem,
9+
ContentByFolderParams,
1110
CustomTreeNode,
12-
ContentByFolderParams
11+
DotFolder,
12+
TreeNodeItem
1313
} from '@dotcms/dotcms-models';
1414

1515
/**
@@ -142,7 +142,11 @@ export class DotBrowsingService {
142142
}
143143
}
144144

145-
rta.tree = { path: node.parent.path, folders: node.folders };
145+
rta.tree = {
146+
path: node.parent.path,
147+
folders: node.folders,
148+
parent: node.parent
149+
};
146150

147151
return rta;
148152
},

0 commit comments

Comments
 (0)