Skip to content

Commit 734c837

Browse files
FrancescoMolinaroatarix83
authored andcommitted
Merged in task/ux-plus-2023_02_x/UXP-242 (pull request #40)
Task/ux plus 2023 02 x/UXP-242 Approved-by: Giuseppe Digilio
2 parents 7292f14 + 92581bf commit 734c837

7 files changed

Lines changed: 83 additions & 39 deletions

File tree

src/app/cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/hierarchy/hierarchy.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ <h4 class="modal-title border-bottom mb-3" *ngIf="vocabularyHeader">{{'vocabular
77
[enabledSearch]="false"
88
[publicModeOnly]="true"
99
[isRelationComponent]="true"
10+
[loadAllNodes]="true"
1011
></ds-vocabulary-treeview>
1112
</div>

src/app/shared/form/vocabulary-treeview-modal/vocabulary-treeview-modal.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ <h4 class="modal-title">{{'vocabulary-treeview.header' | translate}}</h4>
1111
[preloadLevel]="preloadLevel"
1212
[selectedItems]="selectedItems"
1313
[multiSelect]="multiSelect"
14+
[loadAllNodes]="true"
1415
(select)="onSelect($event)">
1516
</ds-vocabulary-treeview>
1617
</div>

src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<h2 *ngIf="!(loading | async) && dataSource.data.length === 0" class="h4 text-center text-muted mt-4" >
2424
<span>{{'vocabulary-treeview.search.no-result' | translate}}</span>
2525
</h2>
26-
<cdk-tree [dataSource]="dataSource" [treeControl]="treeControl">
26+
<cdk-tree *ngIf="!(loading | async) && dataSource.data.length !== 0" [dataSource]="dataSource" [treeControl]="treeControl">
2727
<!-- Leaf node -->
2828
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding class="d-flex">
2929
<span aria-hidden="true" type="button" class="btn btn-default px-2 mr-1" cdkTreeNodeToggle>

src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ describe('VocabularyTreeviewComponent test suite', () => {
146146
comp.selectedItems = [currentValue];
147147
fixture.detectChanges();
148148
expect(comp.dataSource.data).toEqual([]);
149-
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', false, false);
149+
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', false, false, false);
150150
});
151151

152152
it('should should init component properly with init value as VocabularyEntry', () => {
@@ -158,7 +158,7 @@ describe('VocabularyTreeviewComponent test suite', () => {
158158
comp.selectedItems = [currentValue];
159159
fixture.detectChanges();
160160
expect(comp.dataSource.data).toEqual([]);
161-
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', false, false);
161+
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', false, false, false);
162162
});
163163

164164
it('should should init component properly with init value as VocabularyEntryDetail', () => {
@@ -168,7 +168,7 @@ describe('VocabularyTreeviewComponent test suite', () => {
168168
comp.selectedItems = [currentValue];
169169
fixture.detectChanges();
170170
expect(comp.dataSource.data).toEqual([]);
171-
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', false, false);
171+
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', false, false, false);
172172
});
173173

174174
it('should should init component properly with init value as VocabularyEntry and publicModeOnly enabled', () => {
@@ -181,7 +181,7 @@ describe('VocabularyTreeviewComponent test suite', () => {
181181
comp.selectedItems = [currentValue];
182182
fixture.detectChanges();
183183
expect(comp.dataSource.data).toEqual([]);
184-
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', true, false);
184+
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID', true, false, false);
185185
});
186186

187187
it('should call loadMore function', () => {
@@ -201,7 +201,7 @@ describe('VocabularyTreeviewComponent test suite', () => {
201201
const node = new TreeviewFlatNode(item);
202202
comp.loadChildren(node);
203203
fixture.detectChanges();
204-
expect(vocabularyTreeviewServiceStub.loadMore).toHaveBeenCalledWith(node.item, [], true);
204+
expect(vocabularyTreeviewServiceStub.loadMore).toHaveBeenCalledWith(node.item, [], true, false);
205205
});
206206

207207
it('should emit proper FormFieldMetadataValueObject when VocabularyEntryDetail has authority', () => {

src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
7373
*/
7474
@Input() isRelationComponent = false;
7575

76+
/**
77+
* Whether to load all available nodes
78+
*/
79+
@Input() loadAllNodes = false;
80+
7681
/**
7782
* A map containing the current node showed by the tree
7883
*/
@@ -233,7 +238,7 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
233238
this.loading = this.vocabularyTreeviewService.isLoading();
234239

235240
const entryId: string = (this.selectedItems?.length > 0) ? this.getEntryId(this.selectedItems[0]) : null;
236-
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.getSelectedEntryIds(), entryId, this.publicModeOnly, this.isRelationComponent);
241+
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.getSelectedEntryIds(), entryId, this.publicModeOnly, this.isRelationComponent, this.loadAllNodes);
237242
}
238243

239244
/**
@@ -257,7 +262,7 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
257262
* @param node The TreeviewFlatNode for which to load children nodes
258263
*/
259264
loadChildren(node: TreeviewFlatNode) {
260-
this.vocabularyTreeviewService.loadMore(node.item, this.getSelectedEntryIds(), true);
265+
this.vocabularyTreeviewService.loadMore(node.item, this.getSelectedEntryIds(), true, this.loadAllNodes);
261266
}
262267

263268
/**
@@ -363,7 +368,7 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
363368
this.selectedItems = [];
364369
this.searchText = '';
365370
this.vocabularyTreeviewService.cleanTree();
366-
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.getSelectedEntryIds(), null);
371+
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.getSelectedEntryIds(), null, null, this.isRelationComponent);
367372
}
368373
}
369374
}

src/app/shared/form/vocabulary-treeview/vocabulary-treeview.service.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ describe('VocabularyTreeviewService test suite', () => {
272272
scheduler.schedule(() => service.initialize(vocabularyOptions, pageInfo, [child.id], child.id, false, true));
273273
scheduler.flush();
274274

275-
expect(serviceAsAny.retrieveNodesTreeByTopParentEntry).toHaveBeenCalledWith(child.otherInformation.parent, pageInfo, [child.id]);
275+
expect(serviceAsAny.retrieveNodesTreeByTopParentEntry).toHaveBeenCalledWith(child.otherInformation.parent, pageInfo, [child.id], false);
276276
});
277277
});
278278

src/app/shared/form/vocabulary-treeview/vocabulary-treeview.service.ts

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { RemoteData } from 'src/app/core/data/remote-data';
22
import { Injectable } from '@angular/core';
33

4-
import { BehaviorSubject, combineLatest, Observable, of as observableOf } from 'rxjs';
5-
import { map, merge, mergeMap, scan } from 'rxjs/operators';
4+
import { BehaviorSubject, combineLatest, EMPTY, Observable, of as observableOf } from 'rxjs';
5+
import { expand, map, merge, mergeMap, scan } from 'rxjs/operators';
66
import findIndex from 'lodash/findIndex';
77

88
import { LOAD_MORE_NODE, LOAD_MORE_ROOT_NODE, TreeviewFlatNode, TreeviewNode } from './vocabulary-treeview-node.model';
@@ -104,8 +104,9 @@ export class VocabularyTreeviewService {
104104
* @param initValueId The entry id of the node to mark as selected, if any
105105
* @param publicModeOnly Whether the tree is used in a public view
106106
* @param isRelationComponent Whether the tree is used as relation component
107+
* @param loadAll
107108
*/
108-
initialize(options: VocabularyOptions, pageInfo: PageInfo, selectedItems: string[], initValueId?: string, publicModeOnly = false, isRelationComponent = false): void {
109+
initialize(options: VocabularyOptions, pageInfo: PageInfo, selectedItems: string[], initValueId?: string, publicModeOnly = false, isRelationComponent = false, loadAll = false): void {
109110
this.loading.next(true);
110111
this.vocabularyOptions = options;
111112
this.vocabularyName = options.name;
@@ -116,8 +117,8 @@ export class VocabularyTreeviewService {
116117
if (hasValue(hierarchy) && hierarchy.length > 0) {
117118
this.initValueHierarchy = hierarchy;
118119
isRelationComponent ?
119-
this.retrieveNodesTreeByTopParentEntry(hierarchy[0], pageInfo, selectedItems) :
120-
this.retrieveTopNodes(pageInfo, [], selectedItems, publicModeOnly ? hierarchy : null);
120+
this.retrieveNodesTreeByTopParentEntry(hierarchy[0], pageInfo, selectedItems, loadAll) :
121+
this.retrieveTopNodes(pageInfo, [], selectedItems, publicModeOnly ? hierarchy : null, loadAll);
121122
} else {
122123
this.loading.next(false);
123124
}
@@ -150,22 +151,25 @@ export class VocabularyTreeviewService {
150151
* @param item
151152
* @param selectedItems
152153
* @param onlyFirstTime
154+
* @param loadAll
153155
*/
154-
loadMore(item: VocabularyEntryDetail, selectedItems: string[], onlyFirstTime = false) {
156+
loadMore(item: VocabularyEntryDetail, selectedItems: string[], onlyFirstTime = false, loadAll = false) {
155157
if (!this.nodeMap.has(item.otherInformation.id)) {
156158
return;
157159
}
158160
const parent: TreeviewNode = this.nodeMap.get(item.otherInformation.id)!;
159161
const children = this.nodeMap.get(item.otherInformation.id)!.children || [];
160-
this.getChildrenNodesByParent(item.otherInformation.id, parent.pageInfo).subscribe((list: PaginatedList<VocabularyEntryDetail>) => {
161-
162-
if (onlyFirstTime && parent.children!.length > 0) {
162+
this.getChildrenNodesByParent(item.otherInformation.id, parent.pageInfo, (loadAll && selectedItems.length > 0)).subscribe((list: PaginatedList<VocabularyEntryDetail>) => {
163+
if (onlyFirstTime && parent.children!.length > 0 && !loadAll) {
163164
return;
164165
}
165166

166167
const newNodes: TreeviewNode[] = list.page.map((entry) => this._generateNode(entry, selectedItems));
167168
if (newNodes.length > 0) {
168-
children.pop();
169+
if (!loadAll) {
170+
//remove load more button
171+
children.pop();
172+
}
169173
children.push(...newNodes);
170174
}
171175

@@ -175,11 +179,15 @@ export class VocabularyTreeviewService {
175179
currentPage: list.pageInfo.currentPage + 1
176180
});
177181
parent.updatePageInfo(newPageInfo);
182+
parent.childrenChange.next(children);
178183

179-
// Need a new load more node
180-
children.push(new TreeviewNode(LOAD_MORE_NODE, false, newPageInfo, item));
184+
if (!(loadAll && selectedItems.length > 0)) {
185+
// if not all loaded add a load more button
186+
children.push(new TreeviewNode(LOAD_MORE_NODE, false, newPageInfo, item));
187+
}
188+
} else {
189+
parent.childrenChange.next(children);
181190
}
182-
parent.childrenChange.next(children);
183191
this.dataChange.next(this.dataChange.value);
184192
});
185193

@@ -289,14 +297,35 @@ export class VocabularyTreeviewService {
289297
* Return the vocabulary entry's children
290298
* @param parentId The node id
291299
* @param pageInfo The {@link PageInfo} object
300+
* @param loadAll
301+
* @param selectedItem
292302
* @return Observable<PaginatedList<VocabularyEntryDetail>>
293303
*/
294-
private getChildrenNodesByParent(parentId: string, pageInfo: PageInfo): Observable<PaginatedList<VocabularyEntryDetail>> {
304+
private getChildrenNodesByParent(parentId: string, pageInfo: PageInfo, loadAll = false): Observable<PaginatedList<VocabularyEntryDetail>> {
295305
return this.vocabularyService.getEntryDetailChildren(parentId, this.vocabularyName, pageInfo).pipe(
296-
getFirstSucceededRemoteDataPayload()
306+
getFirstSucceededRemoteDataPayload(),
307+
).pipe(
308+
expand(res => this.getPaginatedChildren(res, parentId, loadAll))
297309
);
298310
}
299311

312+
/**
313+
* Get children recursively in expand to load all children
314+
* @param res
315+
* @param parentId
316+
* @param loadAll
317+
* @private
318+
*/
319+
private getPaginatedChildren(res: PaginatedList<VocabularyEntryDetail>, parentId: string, loadAll: boolean): Observable<PaginatedList<VocabularyEntryDetail>> {
320+
if (res.pageInfo.currentPage + 1 <= res.pageInfo.totalPages && loadAll) {
321+
const newPageInfo = Object.assign({}, res.pageInfo, {currentPage: res.pageInfo.currentPage + 1});
322+
return this.vocabularyService.getEntryDetailChildren(parentId, this.vocabularyName, newPageInfo).pipe(
323+
getFirstSucceededRemoteDataPayload()
324+
);
325+
}
326+
return EMPTY;
327+
}
328+
300329
/**
301330
* Return the vocabulary entry's parent
302331
* @param entryId The entry id
@@ -331,8 +360,9 @@ export class VocabularyTreeviewService {
331360
* @param nodes The top level nodes already loaded, if any
332361
* @param selectedItems The currently selected items
333362
* @param hierarchyToLimit If given the top nodes included will be only the one related to the hierarchy
363+
* @param loadAll
334364
*/
335-
private retrieveTopNodes(pageInfo: PageInfo, nodes: TreeviewNode[], selectedItems: string[], hierarchyToLimit?: string[]): void {
365+
private retrieveTopNodes(pageInfo: PageInfo, nodes: TreeviewNode[], selectedItems: string[], hierarchyToLimit?: string[], loadAll = false): void {
336366
this.vocabularyService.searchTopEntries(this.vocabularyName, pageInfo).pipe(
337367
getFirstSucceededRemoteDataPayload()
338368
).subscribe((list: PaginatedList<VocabularyEntryDetail>) => {
@@ -344,15 +374,20 @@ export class VocabularyTreeviewService {
344374
nodes.push(...newNodes);
345375
}
346376

347-
348377
if ((list.pageInfo.currentPage + 1) <= list.pageInfo.totalPages) {
349-
// Need a new load more node
350378
const newPageInfo: PageInfo = Object.assign(new PageInfo(), list.pageInfo, {
351379
currentPage: list.pageInfo.currentPage + 1
352380
});
353-
const loadMoreNode = new TreeviewNode(LOAD_MORE_ROOT_NODE, false, newPageInfo);
354-
loadMoreNode.updatePageInfo(newPageInfo);
355-
nodes.push(loadMoreNode);
381+
382+
if (loadAll) {
383+
// loop over pages until we load all of them
384+
this.retrieveTopNodes(newPageInfo, nodes, selectedItems, hierarchyToLimit);
385+
return;
386+
} else {
387+
const loadMoreNode = new TreeviewNode(LOAD_MORE_ROOT_NODE, false, newPageInfo);
388+
loadMoreNode.updatePageInfo(newPageInfo);
389+
nodes.push(loadMoreNode);
390+
}
356391
}
357392
this.loading.next(false);
358393
// Notify the change.
@@ -365,23 +400,23 @@ export class VocabularyTreeviewService {
365400
* @param entry The root node to use to start building the tree
366401
* @param pageInfo The {@link PageInfo} object
367402
* @param selectedItems The currently selected items
403+
* @param loadAll
368404
*/
369-
private retrieveNodesTreeByTopParentEntry(entry: string, pageInfo: PageInfo, selectedItems: string[]): void {
370-
const nodes = [];
405+
private retrieveNodesTreeByTopParentEntry(entry: string, pageInfo: PageInfo, selectedItems: string[], loadAll = false): void {
371406
const rootNode$ = this.getById(entry);
372407
let tempList;
373408

374409
combineLatest([
375410
rootNode$,
376-
this.getChildrenNodesByParent(entry, pageInfo)
411+
this.getChildrenNodesByParent(entry, pageInfo, loadAll)
377412
]).pipe(
378413
mergeMap(([rootNode, list]) => {
379414
tempList = list;
380415
let newPageInfo: PageInfo;
381416

382417
const childNodes: TreeviewNode[] = list.page.map((entryDetail: VocabularyEntryDetail) => this._generateNode(entryDetail, selectedItems));
383418

384-
if ((tempList.pageInfo.currentPage + 1) <= tempList.pageInfo.totalPages) {
419+
if ((tempList.pageInfo.currentPage + 1) <= tempList.pageInfo.totalPages && !loadAll) {
385420
// Need a new load more node
386421
newPageInfo = Object.assign(new PageInfo(), tempList.pageInfo, {
387422
currentPage: tempList.pageInfo.currentPage + 1
@@ -398,11 +433,13 @@ export class VocabularyTreeviewService {
398433
);
399434
})
400435
).subscribe(hierarchy => {
401-
nodes.push(hierarchy);
402-
403-
this.loading.next(false);
436+
// Loading stops if we reach the end of the list or if we are done with the first loading and don't need to load all.
437+
// Major or equal because rest seems bugged and return total pages 0 if there is only 1 element
438+
if ((tempList.pageInfo.currentPage >= tempList.pageInfo.totalPages && loadAll) || !loadAll) {
439+
this.loading.next(false);
440+
}
404441
// Notify the change.
405-
this.dataChange.next(nodes);
442+
this.dataChange.next([hierarchy]);
406443

407444
});
408445

0 commit comments

Comments
 (0)