From 79424ac10803816d4b5273a72e970c9d033301eb Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Fri, 11 Oct 2019 14:52:41 +0200 Subject: [PATCH] refactor community list datasource --- .../CommunityListDataSource.ts | 221 +++++++++--------- .../CommunityListService.ts | 19 +- .../community-list-page.component.scss | 0 .../community-list-page.component.ts | 1 + .../community-list.component.html | 2 +- .../community-list.component.scss | 0 .../community-list.component.ts | 5 +- 7 files changed, 133 insertions(+), 115 deletions(-) create mode 100644 src/app/community-list-page/community-list-page.component.scss create mode 100644 src/app/community-list-page/community-list/community-list.component.scss diff --git a/src/app/community-list-page/CommunityListDataSource.ts b/src/app/community-list-page/CommunityListDataSource.ts index f5dfa6606a..a3ef907e6c 100644 --- a/src/app/community-list-page/CommunityListDataSource.ts +++ b/src/app/community-list-page/CommunityListDataSource.ts @@ -1,118 +1,131 @@ -import {CommunityListService} from './CommunityListService'; -import {CollectionViewer, DataSource} from '@angular/cdk/typings/collections'; -import {BehaviorSubject, Observable, of} from 'rxjs'; -import {catchError, filter, finalize, map, take, tap} from 'rxjs/operators'; -import {Community} from '../core/shared/community.model'; -import {Collection} from '../core/shared/collection.model'; -import {hasValue, isEmpty} from '../shared/empty.util'; -import {RemoteData} from '../core/data/remote-data'; -import {PaginatedList} from '../core/data/paginated-list'; +import { combineLatest as observableCombineLatest } from 'rxjs/internal/observable/combineLatest'; +import { PaginatedList } from '../core/data/paginated-list'; +import { RemoteData } from '../core/data/remote-data'; +import { hasValue, isNotEmpty } from '../shared/empty.util'; +import { CommunityListService } from './CommunityListService'; +import { CollectionViewer, DataSource } from '@angular/cdk/typings/collections'; +import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; +import { + catchError, + filter, + finalize, + map, + switchMap, + take, +} from 'rxjs/operators'; +import { Community } from '../core/shared/community.model'; +import { Collection } from '../core/shared/collection.model'; export interface FlatNode { - expandable: boolean; - name: string; - handle: string; - level: number; - isExpanded?: boolean; - parent?: FlatNode; - community: Community; + isExpandable: boolean; + name: string; + id: string; + level: number; + isExpanded?: boolean; + parent?: FlatNode; + payload: Community | Collection; } +const combineAndFlatten = (obsList: Array>) => + observableCombineLatest(...obsList).pipe( + map((matrix: FlatNode[][]) => + matrix.reduce((combinedList, currentList: FlatNode[]) => [...combinedList, ...currentList])) + ); + +const toFlatNode = ( + c: Community | Collection, + level: number, + isExpanded: boolean, + parent?: FlatNode +): FlatNode => ({ + isExpandable: c instanceof Community, + name: c.name, + id: c.id, + level: level, + isExpanded, + parent, + payload: c, +}); + export class CommunityListDataSource implements DataSource { - private communityListSubject = new BehaviorSubject([]); - private loadingSubject = new BehaviorSubject(false); + private communityList$ = new BehaviorSubject([]); + private loading$ = new BehaviorSubject(false); - public loading$ = this.loadingSubject.asObservable(); + constructor(private communityListService: CommunityListService) { + } - constructor(private communityListService: CommunityListService) { + connect(collectionViewer: CollectionViewer): Observable { + return this.communityList$.asObservable(); + } + + disconnect(collectionViewer: CollectionViewer): void { + this.communityList$.complete(); + this.loading$.complete(); + } + + loadCommunities(expandedNodes: FlatNode[]): void { + this.loading$.next(true); + + this.communityListService.communities$ + .pipe( + take(1), + switchMap((result: Community[]) => { + return this.transformListOfCommunities(result, 0, null, expandedNodes); + }), + catchError(() => observableOf([])), + finalize(() => this.loading$.next(false)), + ).subscribe((flatNodes: FlatNode[]) => this.communityList$.next(flatNodes)); + }; + + private transformListOfCommunities(listOfCommunities: Community[], + level: number, + parent: FlatNode, + expandedNodes: FlatNode[]): Observable { + if (isNotEmpty(listOfCommunities)) { + const obsList = listOfCommunities + .map((community: Community) => + this.transformCommunity(community, level, parent, expandedNodes)); + + return combineAndFlatten(obsList); + } else { + return observableOf([]); + } + } + + private transformCommunity(community: Community, level: number, parent: FlatNode, expandedNodes: FlatNode[]): Observable { + let isExpanded = false; + if (isNotEmpty(expandedNodes)) { + isExpanded = hasValue(expandedNodes.find((node) => (node.id === community.id))); } - connect(collectionViewer: CollectionViewer): Observable { - return this.communityListSubject.asObservable(); + const communityFlatNode = toFlatNode(community, level, isExpanded, parent); + + let obsList = [observableOf([communityFlatNode])]; + + if (isExpanded) { + const subCommunityNodes$ = community.subcommunities.pipe( + filter((rd: RemoteData>) => rd.hasSucceeded), + take(1), + switchMap((rd: RemoteData>) => + this.transformListOfCommunities(rd.payload.page, level + 1, communityFlatNode, expandedNodes)) + ); + + obsList = [...obsList, subCommunityNodes$]; + + const collectionNodes$ = community.collections.pipe( + filter((rd: RemoteData>) => rd.hasSucceeded), + take(1), + map((rd: RemoteData>) => + rd.payload.page + .map((collection: Collection) => toFlatNode(collection, level + 1, false, parent)) + ) + ); + + obsList = [...obsList, collectionNodes$]; } - disconnect(collectionViewer: CollectionViewer): void { - this.communityListSubject.complete(); - this.loadingSubject.complete(); - } - - loadCommunities(expandedNodes: FlatNode[]) { - this.loadingSubject.next(true); - - this.communityListService.getCommunityList() - .pipe( - filter((rd: RemoteData>) => rd.hasSucceeded), - take(1), - finalize(() => this.loadingSubject.next(false)), - ) - .subscribe((result) => { - const communities = result.payload.page; - const flatNodes = this.transformListOfCommunities(communities, -1, [], null, expandedNodes); - this.communityListSubject.next(flatNodes) - }); - }; - - transformListOfCommunities(listOfCommunities: Community[], - level: number, - flatNodes: FlatNode[], - parent: FlatNode, - expandedNodes: FlatNode[]): FlatNode[] { - level++; - if (hasValue(listOfCommunities)) { - for (const community of listOfCommunities) { - let expanded = false; - if (hasValue(expandedNodes)) { - const expandedNodesFound = expandedNodes.filter((node) => (node.handle === community.handle)); - expanded = (expandedNodesFound.length > 0); - } - const communityFlatNode: FlatNode = { - expandable: true, - name: community.name, - handle: community.handle, - level: level, - isExpanded: expanded, - parent: parent, - community: community, - } - flatNodes.push(communityFlatNode); - if (expanded) { - let subcoms: Community[] = []; - community.subcommunities.pipe( - tap((v) => console.log('subcom tap', v)), - filter((rd: RemoteData>) => rd.hasSucceeded), - take(1),) - .subscribe((results) => { - subcoms = results.payload.page; - if (!isEmpty(subcoms)) { - this.transformListOfCommunities(subcoms, level, flatNodes, communityFlatNode, expandedNodes); - } - }); - let coll: Collection[] = []; - community.collections.pipe( - tap((v) => console.log('col tap ' ,v)), - filter((rd: RemoteData>) => rd.hasSucceeded), - take(1), - ) - .subscribe((results) => { - coll = results.payload.page; - for (const collection of coll) { - const collectionFlatNode: FlatNode = { - expandable: false, - name: collection.name, - handle: collection.handle, - level: level, - isExpanded: false, - parent: parent, - community: community, - } - flatNodes.push(collectionFlatNode); - } - }); - } - } - } - return flatNodes; - } + return combineAndFlatten(obsList); + } } diff --git a/src/app/community-list-page/CommunityListService.ts b/src/app/community-list-page/CommunityListService.ts index 34f80b9aae..a00f2716f5 100644 --- a/src/app/community-list-page/CommunityListService.ts +++ b/src/app/community-list-page/CommunityListService.ts @@ -1,16 +1,15 @@ import {Injectable} from '@angular/core'; -import {Observable} from 'rxjs'; +import {Observable, of} from 'rxjs'; import {CommunityDataService} from '../core/data/community-data.service'; import {PaginationComponentOptions} from '../shared/pagination/pagination-component-options.model'; import {SortDirection, SortOptions} from '../core/cache/models/sort-options.model'; +import { map, take, tap } from 'rxjs/operators'; import {Community} from '../core/shared/community.model'; -import {RemoteData} from '../core/data/remote-data'; -import {PaginatedList} from '../core/data/paginated-list'; @Injectable() export class CommunityListService { - communities: Community[]; + communities$: Observable; config: PaginationComponentOptions; sortConfig: SortOptions; @@ -18,17 +17,21 @@ export class CommunityListService { constructor(private cds: CommunityDataService) { this.config = new PaginationComponentOptions(); this.config.id = 'top-level-pagination'; - this.config.pageSize = 100; + this.config.pageSize = 10; this.config.currentPage = 1; this.sortConfig = new SortOptions('dc.title', SortDirection.ASC); + this.initTopCommunityList() } - public getCommunityList(): Observable>> { - return this.cds.findTop({ + private initTopCommunityList(): void { + this.communities$ = this.cds.findTop({ currentPage: this.config.currentPage, elementsPerPage: this.config.pageSize, sort: { field: this.sortConfig.field, direction: this.sortConfig.direction } - }); + }).pipe( + take(1), + map((results) => results.payload.page), + ); } } diff --git a/src/app/community-list-page/community-list-page.component.scss b/src/app/community-list-page/community-list-page.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/community-list-page/community-list-page.component.ts b/src/app/community-list-page/community-list-page.component.ts index fcf531e3b8..76fc96dcbe 100644 --- a/src/app/community-list-page/community-list-page.component.ts +++ b/src/app/community-list-page/community-list-page.component.ts @@ -3,6 +3,7 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'ds-community-list-page', templateUrl: './community-list-page.component.html', + styleUrls: ['./community-list-page.component.scss'] }) export class CommunityListPageComponent implements OnInit { diff --git a/src/app/community-list-page/community-list/community-list.component.html b/src/app/community-list-page/community-list/community-list.component.html index eedf20b5e3..55dc738ce6 100644 --- a/src/app/community-list-page/community-list/community-list.component.html +++ b/src/app/community-list-page/community-list/community-list.component.html @@ -15,7 +15,7 @@ diff --git a/src/app/community-list-page/community-list/community-list.component.scss b/src/app/community-list-page/community-list/community-list.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/community-list-page/community-list/community-list.component.ts b/src/app/community-list-page/community-list/community-list.component.ts index d6389b6a38..714024ee56 100644 --- a/src/app/community-list-page/community-list/community-list.component.ts +++ b/src/app/community-list-page/community-list/community-list.component.ts @@ -6,13 +6,14 @@ import {FlatTreeControl} from '@angular/cdk/tree'; @Component({ selector: 'ds-community-list', templateUrl: './community-list.component.html', + styleUrls: ['./community-list.component.scss'] }) export class CommunityListComponent implements OnInit { private expandedNodes: FlatNode[] = []; treeControl = new FlatTreeControl( - (node) => node.level, (node) => node.expandable + (node) => node.level, (node) => node.isExpandable ); dataSource: CommunityListDataSource; @@ -24,7 +25,7 @@ export class CommunityListComponent implements OnInit { this.dataSource.loadCommunities(null); } - hasChild = (_: number, node: FlatNode) => node.expandable; + hasChild = (_: number, node: FlatNode) => node.isExpandable; shouldRender(node: FlatNode) { const parent = node.parent;