70599: Improvements comcol tree

This commit is contained in:
Marie Verdonck
2020-05-03 01:53:46 +02:00
parent bb4aedc472
commit b1e44a7fa5
4 changed files with 60 additions and 89 deletions

View File

@@ -1,3 +1,4 @@
import { FindListOptions } from '../core/data/request.models';
import { CommunityListService, FlatNode } from './community-list-service'; import { CommunityListService, FlatNode } from './community-list-service';
import { CollectionViewer, DataSource } from '@angular/cdk/typings/collections'; import { CollectionViewer, DataSource } from '@angular/cdk/typings/collections';
import { BehaviorSubject, Observable, } from 'rxjs'; import { BehaviorSubject, Observable, } from 'rxjs';
@@ -21,10 +22,10 @@ export class CommunityListDatasource implements DataSource<FlatNode> {
return this.communityList$.asObservable(); return this.communityList$.asObservable();
} }
loadCommunities(expandedNodes: FlatNode[]) { loadCommunities(findOptions: FindListOptions, expandedNodes: FlatNode[]) {
this.loading$.next(true); this.loading$.next(true);
this.communityListService.loadCommunities(expandedNodes).pipe( this.communityListService.loadCommunities(findOptions, expandedNodes).pipe(
take(1), take(1),
finalize(() => this.loading$.next(false)), finalize(() => this.loading$.next(false)),
).subscribe((flatNodes: FlatNode[]) => { ).subscribe((flatNodes: FlatNode[]) => {

View File

@@ -4,11 +4,12 @@ import { combineLatest as observableCombineLatest } from 'rxjs/internal/observab
import { Observable, of as observableOf } from 'rxjs'; import { Observable, of as observableOf } from 'rxjs';
import { AppState } from '../app.reducer'; import { AppState } from '../app.reducer';
import { CommunityDataService } from '../core/data/community-data.service'; import { CommunityDataService } from '../core/data/community-data.service';
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; import { FindListOptions } from '../core/data/request.models';
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; import { map, flatMap } from 'rxjs/operators';
import { catchError, filter, map, switchMap, take } from 'rxjs/operators';
import { Community } from '../core/shared/community.model'; import { Community } from '../core/shared/community.model';
import { Collection } from '../core/shared/collection.model'; import { Collection } from '../core/shared/collection.model';
import { getSucceededRemoteData } from '../core/shared/operators';
import { PageInfo } from '../core/shared/page-info.model';
import { hasValue, isNotEmpty } from '../shared/empty.util'; import { hasValue, isNotEmpty } from '../shared/empty.util';
import { RemoteData } from '../core/data/remote-data'; import { RemoteData } from '../core/data/remote-data';
import { PaginatedList } from '../core/data/paginated-list'; import { PaginatedList } from '../core/data/paginated-list';
@@ -46,8 +47,7 @@ export class ShowMoreFlatNode {
// Helper method to combine an flatten an array of observables of flatNode arrays // Helper method to combine an flatten an array of observables of flatNode arrays
export const combineAndFlatten = (obsList: Array<Observable<FlatNode[]>>): Observable<FlatNode[]> => export const combineAndFlatten = (obsList: Array<Observable<FlatNode[]>>): Observable<FlatNode[]> =>
observableCombineLatest(...obsList).pipe( observableCombineLatest(...obsList).pipe(
map((matrix: FlatNode[][]) => map((matrix: any[][]) => [].concat(...matrix))
matrix.reduce((combinedList, currentList: FlatNode[]) => [...combinedList, ...currentList]))
); );
/** /**
@@ -99,6 +99,8 @@ const communityListStateSelector = (state: AppState) => state.communityList;
const expandedNodesSelector = createSelector(communityListStateSelector, (communityList: CommunityListState) => communityList.expandedNodes); const expandedNodesSelector = createSelector(communityListStateSelector, (communityList: CommunityListState) => communityList.expandedNodes);
const loadingNodeSelector = createSelector(communityListStateSelector, (communityList: CommunityListState) => communityList.loadingNode); const loadingNodeSelector = createSelector(communityListStateSelector, (communityList: CommunityListState) => communityList.loadingNode);
export const MAX_COMCOLS_PER_PAGE = 2;
/** /**
* Service class for the community list, responsible for the creating of the flat list used by communityList dataSource * Service class for the community list, responsible for the creating of the flat list used by communityList dataSource
* and connection to the store to retrieve and save the state of the community list * and connection to the store to retrieve and save the state of the community list
@@ -107,26 +109,8 @@ const loadingNodeSelector = createSelector(communityListStateSelector, (communit
@Injectable() @Injectable()
export class CommunityListService { export class CommunityListService {
// page-limited list of top-level communities
payloads$: Array<Observable<PaginatedList<Community>>>;
topCommunitiesConfig: PaginationComponentOptions;
topCommunitiesSortConfig: SortOptions;
maxSubCommunitiesPerPage: number;
maxCollectionsPerPage: number;
constructor(private communityDataService: CommunityDataService, private collectionDataService: CollectionDataService, constructor(private communityDataService: CommunityDataService, private collectionDataService: CollectionDataService,
private store: Store<any>) { private store: Store<any>) {
this.topCommunitiesConfig = new PaginationComponentOptions();
this.topCommunitiesConfig.id = 'top-level-pagination';
this.topCommunitiesConfig.pageSize = 10;
this.topCommunitiesConfig.currentPage = 1;
this.topCommunitiesSortConfig = new SortOptions('dc.title', SortDirection.ASC);
this.initTopCommunityList();
this.maxSubCommunitiesPerPage = 3;
this.maxCollectionsPerPage = 3;
} }
saveCommunityListStateToStore(expandedNodes: FlatNode[], loadingNode: FlatNode): void { saveCommunityListStateToStore(expandedNodes: FlatNode[], loadingNode: FlatNode): void {
@@ -141,57 +125,46 @@ export class CommunityListService {
return this.store.select(loadingNodeSelector); return this.store.select(loadingNodeSelector);
} }
/**
* Increases the payload so it contains the next page of top level communities
*/
getNextPageTopCommunities(): void {
this.topCommunitiesConfig.currentPage = this.topCommunitiesConfig.currentPage + 1;
this.payloads$ = [...this.payloads$, this.communityDataService.findTop({
currentPage: this.topCommunitiesConfig.currentPage,
elementsPerPage: this.topCommunitiesConfig.pageSize,
sort: {
field: this.topCommunitiesSortConfig.field,
direction: this.topCommunitiesSortConfig.direction
}
}).pipe(
take(1),
map((results) => results.payload),
)];
}
/** /**
* Gets all top communities, limited by page, and transforms this in a list of flatNodes. * Gets all top communities, limited by page, and transforms this in a list of flatNodes.
* @param expandedNodes List of expanded nodes; if a node is not expanded its subCommunities and collections need * @param expandedNodes List of expanded nodes; if a node is not expanded its subCommunities and collections need
* not be added to the list * not be added to the list
*/ */
loadCommunities(expandedNodes: FlatNode[]): Observable<FlatNode[]> { loadCommunities(findOptions: FindListOptions, expandedNodes: FlatNode[]): Observable<FlatNode[]> {
const res = this.payloads$.map((payload) => { const currentPage = findOptions.currentPage;
return payload.pipe( const topCommunities = [];
take(1), for (let i = 1; i <= currentPage; i++) {
switchMap((result: PaginatedList<Community>) => { const pagination: FindListOptions = Object.assign({}, findOptions, { currentPage: i });
return this.transformListOfCommunities(result, 0, null, expandedNodes); topCommunities.push(this.getTopCommunities(pagination));
}), }
catchError(() => observableOf([])), const topComs$ = observableCombineLatest(...topCommunities).pipe(
); map((coms: Array<PaginatedList<Community>>) => {
}); const newPages: Community[][] = coms.map((unit: PaginatedList<Community>) => unit.page);
return combineAndFlatten(res); const newPage: Community[] = [].concat(...newPages);
let newPageInfo = new PageInfo();
if (coms && coms.length > 0) {
newPageInfo = Object.assign({}, coms[0].pageInfo, { currentPage })
}
return new PaginatedList(newPageInfo, newPage);
})
);
return topComs$.pipe(flatMap((topComs: PaginatedList<Community>) => this.transformListOfCommunities(topComs, 0, null, expandedNodes)));
}; };
/** /**
* Puts the initial top level communities in a list to be called upon * Puts the initial top level communities in a list to be called upon
*/ */
private initTopCommunityList(): void { private getTopCommunities(options: FindListOptions): Observable<PaginatedList<Community>> {
this.payloads$ = [this.communityDataService.findTop({ return this.communityDataService.findTop({
currentPage: this.topCommunitiesConfig.currentPage, currentPage: options.currentPage,
elementsPerPage: this.topCommunitiesConfig.pageSize, elementsPerPage: MAX_COMCOLS_PER_PAGE,
sort: { sort: {
field: this.topCommunitiesSortConfig.field, field: options.sort.field,
direction: this.topCommunitiesSortConfig.direction direction: options.sort.direction
} }
}).pipe( }).pipe(
take(1),
map((results) => results.payload), map((results) => results.payload),
)]; );
} }
/** /**
@@ -206,16 +179,15 @@ export class CommunityListService {
parent: FlatNode, parent: FlatNode,
expandedNodes: FlatNode[]): Observable<FlatNode[]> { expandedNodes: FlatNode[]): Observable<FlatNode[]> {
if (isNotEmpty(listOfPaginatedCommunities.page)) { if (isNotEmpty(listOfPaginatedCommunities.page)) {
let currentPage = this.topCommunitiesConfig.currentPage; let currentPage = listOfPaginatedCommunities.currentPage;
if (isNotEmpty(parent)) { if (isNotEmpty(parent)) {
currentPage = expandedNodes.find((node: FlatNode) => node.id === parent.id).currentCommunityPage; currentPage = expandedNodes.find((node: FlatNode) => node.id === parent.id).currentCommunityPage;
} }
const isNotAllCommunities = (listOfPaginatedCommunities.totalElements > (listOfPaginatedCommunities.elementsPerPage * currentPage));
let obsList = listOfPaginatedCommunities.page let obsList = listOfPaginatedCommunities.page
.map((community: Community) => { .map((community: Community) => {
return this.transformCommunity(community, level, parent, expandedNodes) return this.transformCommunity(community, level, parent, expandedNodes)
}); });
if (isNotAllCommunities && listOfPaginatedCommunities.currentPage > currentPage) { if (currentPage < listOfPaginatedCommunities.totalPages && currentPage === listOfPaginatedCommunities.currentPage) {
obsList = [...obsList, observableOf([showMoreFlatNode('community', level, parent)])]; obsList = [...obsList, observableOf([showMoreFlatNode('community', level, parent)])];
} }
@@ -252,13 +224,12 @@ export class CommunityListService {
let subcoms = []; let subcoms = [];
for (let i = 1; i <= currentCommunityPage; i++) { for (let i = 1; i <= currentCommunityPage; i++) {
const nextSetOfSubcommunitiesPage = this.communityDataService.findByParent(community.uuid, { const nextSetOfSubcommunitiesPage = this.communityDataService.findByParent(community.uuid, {
elementsPerPage: this.maxSubCommunitiesPerPage, elementsPerPage: MAX_COMCOLS_PER_PAGE,
currentPage: i currentPage: i
}) })
.pipe( .pipe(
filter((rd: RemoteData<PaginatedList<Community>>) => rd.hasSucceeded), getSucceededRemoteData(),
take(1), flatMap((rd: RemoteData<PaginatedList<Community>>) =>
switchMap((rd: RemoteData<PaginatedList<Community>>) =>
this.transformListOfCommunities(rd.payload, level + 1, communityFlatNode, expandedNodes)) this.transformListOfCommunities(rd.payload, level + 1, communityFlatNode, expandedNodes))
); );
@@ -271,16 +242,15 @@ export class CommunityListService {
let collections = []; let collections = [];
for (let i = 1; i <= currentCollectionPage; i++) { for (let i = 1; i <= currentCollectionPage; i++) {
const nextSetOfCollectionsPage = this.collectionDataService.findByParent(community.uuid, { const nextSetOfCollectionsPage = this.collectionDataService.findByParent(community.uuid, {
elementsPerPage: this.maxCollectionsPerPage, elementsPerPage: MAX_COMCOLS_PER_PAGE,
currentPage: i currentPage: i
}) })
.pipe( .pipe(
filter((rd: RemoteData<PaginatedList<Collection>>) => rd.hasSucceeded), getSucceededRemoteData(),
take(1),
map((rd: RemoteData<PaginatedList<Collection>>) => { map((rd: RemoteData<PaginatedList<Collection>>) => {
let nodes = rd.payload.page let nodes = rd.payload.page
.map((collection: Collection) => toFlatNode(collection, observableOf(false), level + 1, false, communityFlatNode)); .map((collection: Collection) => toFlatNode(collection, observableOf(false), level + 1, false, communityFlatNode));
if ((rd.payload.elementsPerPage * currentCollectionPage) < rd.payload.totalElements && rd.payload.currentPage > currentCollectionPage) { if (currentCollectionPage < rd.payload.totalPages && currentCollectionPage === rd.payload.currentPage) {
nodes = [...nodes, showMoreFlatNode('collection', level + 1, communityFlatNode)]; nodes = [...nodes, showMoreFlatNode('collection', level + 1, communityFlatNode)];
} }
return nodes; return nodes;
@@ -305,21 +275,18 @@ export class CommunityListService {
let hasColls$: Observable<boolean>; let hasColls$: Observable<boolean>;
hasSubcoms$ = this.communityDataService.findByParent(community.uuid, { elementsPerPage: 1 }) hasSubcoms$ = this.communityDataService.findByParent(community.uuid, { elementsPerPage: 1 })
.pipe( .pipe(
filter((rd: RemoteData<PaginatedList<Community>>) => rd.hasSucceeded), getSucceededRemoteData(),
take(1),
map((results) => results.payload.totalElements > 0), map((results) => results.payload.totalElements > 0),
); );
hasColls$ = this.collectionDataService.findByParent(community.uuid, { elementsPerPage: 1 }) hasColls$ = this.collectionDataService.findByParent(community.uuid, { elementsPerPage: 1 })
.pipe( .pipe(
filter((rd: RemoteData<PaginatedList<Collection>>) => rd.hasSucceeded), getSucceededRemoteData(),
take(1),
map((results) => results.payload.totalElements > 0), map((results) => results.payload.totalElements > 0),
); );
let hasChildren$: Observable<boolean>; let hasChildren$: Observable<boolean>;
hasChildren$ = observableCombineLatest(hasSubcoms$, hasColls$).pipe( hasChildren$ = observableCombineLatest(hasSubcoms$, hasColls$).pipe(
take(1),
map(([hasSubcoms, hasColls]: [boolean, boolean]) => { map(([hasSubcoms, hasColls]: [boolean, boolean]) => {
if (hasSubcoms || hasColls) { if (hasSubcoms || hasColls) {
return true; return true;

View File

@@ -1,5 +1,7 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { FindListOptions } from '../../core/data/request.models';
import { CommunityListService, FlatNode } from '../community-list-service'; import { CommunityListService, FlatNode } from '../community-list-service';
import { CommunityListDatasource } from '../community-list-datasource'; import { CommunityListDatasource } from '../community-list-datasource';
import { FlatTreeControl } from '@angular/cdk/tree'; import { FlatTreeControl } from '@angular/cdk/tree';
@@ -27,7 +29,13 @@ export class CommunityListComponent implements OnInit, OnDestroy {
dataSource: CommunityListDatasource; dataSource: CommunityListDatasource;
paginationConfig: FindListOptions;
constructor(private communityListService: CommunityListService) { constructor(private communityListService: CommunityListService) {
this.paginationConfig = new FindListOptions();
this.paginationConfig.elementsPerPage = 2;
this.paginationConfig.currentPage = 1;
this.paginationConfig.sort = new SortOptions('dc.title', SortDirection.ASC);
} }
ngOnInit() { ngOnInit() {
@@ -37,7 +45,7 @@ export class CommunityListComponent implements OnInit, OnDestroy {
}); });
this.communityListService.getExpandedNodesFromStore().pipe(take(1)).subscribe((result) => { this.communityListService.getExpandedNodesFromStore().pipe(take(1)).subscribe((result) => {
this.expandedNodes = [...result]; this.expandedNodes = [...result];
this.dataSource.loadCommunities(this.expandedNodes); this.dataSource.loadCommunities(this.paginationConfig, this.expandedNodes);
}); });
} }
@@ -74,7 +82,7 @@ export class CommunityListComponent implements OnInit, OnDestroy {
node.currentCommunityPage = 1; node.currentCommunityPage = 1;
} }
} }
this.dataSource.loadCommunities(this.expandedNodes); this.dataSource.loadCommunities(this.paginationConfig, this.expandedNodes);
} }
/** /**
@@ -94,10 +102,10 @@ export class CommunityListComponent implements OnInit, OnDestroy {
const parentNodeInExpandedNodes = this.expandedNodes.find((node2: FlatNode) => node.parent.id === node2.id); const parentNodeInExpandedNodes = this.expandedNodes.find((node2: FlatNode) => node.parent.id === node2.id);
parentNodeInExpandedNodes.currentCommunityPage++; parentNodeInExpandedNodes.currentCommunityPage++;
} }
this.dataSource.loadCommunities(this.expandedNodes); this.dataSource.loadCommunities(this.paginationConfig, this.expandedNodes);
} else { } else {
this.communityListService.getNextPageTopCommunities(); this.paginationConfig.currentPage++;
this.dataSource.loadCommunities(this.expandedNodes); this.dataSource.loadCommunities(this.paginationConfig, this.expandedNodes);
} }
} }

View File

@@ -150,12 +150,7 @@ export class RemoteDataBuildService {
filterSuccessfulResponses(), filterSuccessfulResponses(),
map((response: DSOSuccessResponse) => { map((response: DSOSuccessResponse) => {
if (hasValue((response as DSOSuccessResponse).pageInfo)) { if (hasValue((response as DSOSuccessResponse).pageInfo)) {
const resPageInfo = (response as DSOSuccessResponse).pageInfo; return (response as DSOSuccessResponse).pageInfo;
if (isNotEmpty(resPageInfo) && resPageInfo.currentPage >= 0) {
return Object.assign({}, resPageInfo, { currentPage: resPageInfo.currentPage + 1 });
} else {
return resPageInfo;
}
} }
}) })
); );