mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-17 15:03:07 +00:00
refactor community list datasource
This commit is contained in:

committed by
Marie Verdonck

parent
8e0280cb5a
commit
79424ac108
@@ -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<Observable<FlatNode[]>>) =>
|
||||
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<FlatNode> {
|
||||
|
||||
private communityListSubject = new BehaviorSubject<FlatNode[]>([]);
|
||||
private loadingSubject = new BehaviorSubject<boolean>(false);
|
||||
private communityList$ = new BehaviorSubject<FlatNode[]>([]);
|
||||
private loading$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
public loading$ = this.loadingSubject.asObservable();
|
||||
constructor(private communityListService: CommunityListService) {
|
||||
}
|
||||
|
||||
constructor(private communityListService: CommunityListService) {
|
||||
connect(collectionViewer: CollectionViewer): Observable<FlatNode[]> {
|
||||
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<FlatNode[]> {
|
||||
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<FlatNode[]> {
|
||||
let isExpanded = false;
|
||||
if (isNotEmpty(expandedNodes)) {
|
||||
isExpanded = hasValue(expandedNodes.find((node) => (node.id === community.id)));
|
||||
}
|
||||
|
||||
connect(collectionViewer: CollectionViewer): Observable<FlatNode[]> {
|
||||
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<PaginatedList<Community>>) => rd.hasSucceeded),
|
||||
take(1),
|
||||
switchMap((rd: RemoteData<PaginatedList<Community>>) =>
|
||||
this.transformListOfCommunities(rd.payload.page, level + 1, communityFlatNode, expandedNodes))
|
||||
);
|
||||
|
||||
obsList = [...obsList, subCommunityNodes$];
|
||||
|
||||
const collectionNodes$ = community.collections.pipe(
|
||||
filter((rd: RemoteData<PaginatedList<Collection>>) => rd.hasSucceeded),
|
||||
take(1),
|
||||
map((rd: RemoteData<PaginatedList<Collection>>) =>
|
||||
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<PaginatedList<Community>>) => 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<PaginatedList<Community>>) => 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<PaginatedList<Collection>>) => 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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<Community[]>;
|
||||
|
||||
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<RemoteData<PaginatedList<Community>>> {
|
||||
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),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
||||
|
@@ -15,7 +15,7 @@
|
||||
<button type="button" class="btn btn-default" cdkTreeNodeToggle
|
||||
[attr.aria-label]="'toggle ' + node.name"
|
||||
(click)="toggleExpanded(node)"
|
||||
[style.visibility]="node.expandable ? 'visible' : 'hidden'">
|
||||
[style.visibility]="node.isExpandable ? 'visible' : 'hidden'">
|
||||
<span class="{{treeControl.isExpanded(node) ? 'fa fa-chevron-down' : 'fa fa-chevron-right'}}" aria-hidden="true">
|
||||
</span>
|
||||
</button>
|
||||
|
@@ -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<FlatNode>(
|
||||
(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;
|
||||
|
Reference in New Issue
Block a user