68346: PaginatedDragAndDropBitstreamList component and refactoring item-edit-bitstream-bundle using this new component ; removed pagination-drag-and-drop

This commit is contained in:
Kristof De Langhe
2020-02-06 16:57:17 +01:00
parent 90f8bf42a1
commit 5e93a89678
10 changed files with 207 additions and 170 deletions

View File

@@ -27,6 +27,7 @@ import { ItemEditBitstreamBundleComponent } from './item-bitstreams/item-edit-bi
import { BundleDataService } from '../../core/data/bundle-data.service';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { ItemEditBitstreamDragHandleComponent } from './item-bitstreams/item-edit-bitstream-drag-handle/item-edit-bitstream-drag-handle.component';
import { PaginatedDragAndDropBitstreamListComponent } from './item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component';
/**
* Module that contains all components related to the Edit Item page administrator functionality
@@ -57,6 +58,7 @@ import { ItemEditBitstreamDragHandleComponent } from './item-bitstreams/item-edi
EditInPlaceFieldComponent,
ItemEditBitstreamComponent,
ItemEditBitstreamBundleComponent,
PaginatedDragAndDropBitstreamListComponent,
EditInPlaceFieldComponent,
EditRelationshipComponent,
EditRelationshipListComponent,

View File

@@ -17,29 +17,5 @@
</div>
</div>
</div>
<ds-pagination-drag-and-drop [paginationOptions]="bitstreamsOptions"
[paginatedList]="(bitstreamsRD$ | async)?.payload"
[hideGear]="true"
[hidePaginationDetail]="true"
[disableRouteParameterUpdate]="true"
(pageChange)="switchPage($event)">
<div [id]="bundle.id" class="bundle-bitstreams-list"
[ngClass]="{'mb-3': (bitstreamsRD$ | async)?.payload?.totalElements > batchSize}"
*ngVar="((updates$ | async) | dsObjectValues) as updateValues" cdkDropList (cdkDropListDropped)="drop($event)">
<div class="row bitstream-row" *ngFor="let updateValue of updateValues" cdkDrag
[ngClass]="{
'table-warning': updateValue.changeType === 0,
'table-danger': updateValue.changeType === 2,
'table-success': updateValue.changeType === 1,
'bg-white': updateValue.changeType === undefined
}">
<ds-item-edit-bitstream [fieldUpdate]="updateValue"
[bundleUrl]="bundle.self">
<div class="d-flex align-items-center" slot="drag-handle" cdkDragHandle>
<ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle>
</div>
</ds-item-edit-bitstream>
</div>
</div>
</ds-pagination-drag-and-drop>
<ds-paginated-drag-and-drop-bitstream-list [bundle]="bundle"></ds-paginated-drag-and-drop-bitstream-list>
</ng-template>

View File

@@ -7,7 +7,7 @@ import { toBitstreamsArray } from '../../../../core/shared/item-bitstreams-utils
import { map, switchMap, take, tap } from 'rxjs/operators';
import { Bitstream } from '../../../../core/shared/bitstream.model';
import { Item } from '../../../../core/shared/item.model';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { CdkDragDrop, CdkDragStart } from '@angular/cdk/drag-drop';
import { RemoteData } from '../../../../core/data/remote-data';
import { PaginatedList } from '../../../../core/data/paginated-list';
import { BundleDataService } from '../../../../core/data/bundle-data.service';
@@ -42,85 +42,10 @@ export class ItemEditBitstreamBundleComponent implements OnInit {
*/
@Input() item: Item;
/**
* The bitstreams within this bundle retrieved from the REST API
*/
bitstreamsRD$: Observable<RemoteData<PaginatedList<Bitstream>>>;
/**
* The updates to the current bundle
*/
updates$: Observable<FieldUpdates>;
/**
* The amount of one bitstreams one "batch" resembles
* The user is able to increase the amount of bitstreams displayed per bundle by this batch size until all are shown
*/
batchSize = 2;
/**
* The page options to use for fetching the bitstreams
*/
bitstreamsOptions = Object.assign(new PaginationComponentOptions(),{
id: 'bitstreams-pagination-options',
currentPage: 1,
pageSize: this.batchSize
});
/**
* The current page we're displaying for this bundle
*/
currentPage$ = new BehaviorSubject<number>(1);
/**
* A list of pages that have been initialized in the field-update store
*/
initializedPages: number[] = [];
constructor(private objectUpdatesService: ObjectUpdatesService,
private bundleService: BundleDataService,
private viewContainerRef: ViewContainerRef) {
constructor(private viewContainerRef: ViewContainerRef) {
}
ngOnInit(): void {
this.bitstreamsRD$ = this.currentPage$.pipe(
switchMap((page: number) => this.bundleService.getBitstreams(this.bundle.id,
new PaginatedSearchOptions({pagination: Object.assign({}, this.bitstreamsOptions, { currentPage: page })})))
);
this.updates$ = this.bitstreamsRD$.pipe(
toBitstreamsArray(),
tap((bitstreams: Bitstream[]) => {
// Pages in the field-update store are indexed starting at 0 (because they're stored in an array of pages)
const updatesPage = this.currentPage$.value - 1;
if (isEmpty(this.initializedPages)) {
// No updates have been initialized yet for this bundle, initialize the first page
this.objectUpdatesService.initializeWithCustomOrder(this.bundle.self, bitstreams, new Date(), this.batchSize, updatesPage);
this.initializedPages.push(updatesPage);
} else if (this.initializedPages.indexOf(updatesPage) < 0) {
// Updates were initialized for this bundle, but not the page we're on. Add the current page to the field-update store for this bundle
this.objectUpdatesService.addPageToCustomOrder(this.bundle.self, bitstreams, updatesPage);
this.initializedPages.push(updatesPage);
}
}),
switchMap((bitstreams: Bitstream[]) => this.objectUpdatesService.getFieldUpdatesByCustomOrder(this.bundle.self, bitstreams, this.currentPage$.value - 1))
);
this.viewContainerRef.createEmbeddedView(this.bundleView);
}
/**
* Update the current page
* @param page
*/
switchPage(page: number) {
this.currentPage$.next(page);
}
/**
* A bitstream was moved, send updates to the store
* @param event
*/
drop(event: CdkDragDrop<any>) {
this.objectUpdatesService.saveMoveFieldUpdate(this.bundle.self, event.previousIndex, event.currentIndex, this.currentPage$.value - 1, this.currentPage$.value - 1);
}
}

View File

@@ -0,0 +1,28 @@
<ds-pagination *ngIf="(objectsRD$ | async)?.payload"
[hideGear]="true"
[hidePagerWhenSinglePage]="true"
[hidePaginationDetail]="true"
[paginationOptions]="options"
[pageInfoState]="(objectsRD$ | async)?.payload"
[collectionSize]="(objectsRD$ | async)?.payload?.totalElements"
[disableRouteParameterUpdate]="true"
(pageChange)="switchPage($event)">
<div [id]="bundle.id" class="bundle-bitstreams-list"
[ngClass]="{'mb-3': (objectsRD$ | async)?.payload?.totalElements > pageSize}"
*ngVar="((updates$ | async) | dsObjectValues) as updateValues" cdkDropList (cdkDropListDropped)="drop($event)">
<div class="row bitstream-row" *ngFor="let updateValue of updateValues" cdkDrag (cdkDragStarted)="dragStarted($event)"
[ngClass]="{
'table-warning': updateValue.changeType === 0,
'table-danger': updateValue.changeType === 2,
'table-success': updateValue.changeType === 1,
'bg-white': updateValue.changeType === undefined
}">
<ds-item-edit-bitstream [fieldUpdate]="updateValue"
[bundleUrl]="bundle.self">
<div class="d-flex align-items-center" slot="drag-handle" cdkDragHandle>
<ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle>
</div>
</ds-item-edit-bitstream>
</div>
</div>
</ds-pagination>

View File

@@ -0,0 +1,40 @@
import { AbstractPaginatedDragAndDropListComponent } from '../../../../../shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component';
import { Component, Input, OnInit } from '@angular/core';
import { Bundle } from '../../../../../core/shared/bundle.model';
import { Bitstream } from '../../../../../core/shared/bitstream.model';
import { ObjectUpdatesService } from '../../../../../core/data/object-updates/object-updates.service';
import { BundleDataService } from '../../../../../core/data/bundle-data.service';
import { switchMap } from 'rxjs/operators';
import { PaginatedSearchOptions } from '../../../../../shared/search/paginated-search-options.model';
@Component({
selector: 'ds-paginated-drag-and-drop-bitstream-list',
styleUrls: ['../../item-bitstreams.component.scss'],
templateUrl: './paginated-drag-and-drop-bitstream-list.component.html',
})
export class PaginatedDragAndDropBitstreamListComponent extends AbstractPaginatedDragAndDropListComponent<Bitstream> implements OnInit {
/**
* The bundle to display bitstreams for
*/
@Input() bundle: Bundle;
constructor(protected objectUpdatesService: ObjectUpdatesService,
protected bundleService: BundleDataService) {
super(objectUpdatesService);
}
ngOnInit() {
super.ngOnInit();
}
initializeObjectsRD(): void {
this.objectsRD$ = this.currentPage$.pipe(
switchMap((page: number) => this.bundleService.getBitstreams(this.bundle.id,
new PaginatedSearchOptions({pagination: Object.assign({}, this.options, { currentPage: page })})))
);
}
initializeURL(): void {
this.url = this.bundle.self;
}
}

View File

@@ -137,3 +137,13 @@ export const getFirstSucceededRemoteDataPayload = () =>
hasValueOperator(),
take(1)
);
/**
* Operator for turning the current page of bitstreams into an array
*/
export const paginatedListToArray = () =>
<T extends DSpaceObject>(source: Observable<RemoteData<PaginatedList<T>>>): Observable<T[]> =>
source.pipe(
hasValueOperator(),
map((objectRD: RemoteData<PaginatedList<T>>) => objectRD.payload.page.filter((object: T) => hasValue(object)))
);

View File

@@ -0,0 +1,124 @@
import { FieldUpdates } from '../../core/data/object-updates/object-updates.reducer';
import { Observable } from 'rxjs/internal/Observable';
import { RemoteData } from '../../core/data/remote-data';
import { PaginatedList } from '../../core/data/paginated-list';
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { ObjectUpdatesService } from '../../core/data/object-updates/object-updates.service';
import { switchMap, tap } from 'rxjs/operators';
import { Bitstream } from '../../core/shared/bitstream.model';
import { isEmpty } from '../empty.util';
import { paginatedListToArray } from '../../core/shared/operators';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { CdkDragDrop, CdkDragStart } from '@angular/cdk/drag-drop';
export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpaceObject> {
/**
* The URL to use for accessing the object updates from this list
*/
url: string;
/**
* The objects to retrieve data for and transform into field updates
*/
objectsRD$: Observable<RemoteData<PaginatedList<T>>>;
/**
* The updates to the current list
*/
updates$: Observable<FieldUpdates>;
/**
* The amount of objects to display per page
*/
pageSize = 2;
/**
* The page options to use for fetching the objects
* Start at page 1 and always use the set page size
*/
options = Object.assign(new PaginationComponentOptions(),{
id: 'paginated-drag-and-drop-options',
currentPage: 1,
pageSize: this.pageSize
});
/**
* The current page being displayed
*/
currentPage$ = new BehaviorSubject<number>(1);
/**
* The last page we were on when we started dragging an item
* This is used to keep track of the original page the drag started from
*/
lastPage$ = new BehaviorSubject<number>(1);
/**
* A list of pages that have been initialized in the field-update store
*/
initializedPages: number[] = [];
protected constructor(protected objectUpdatesService: ObjectUpdatesService) {
}
ngOnInit() {
this.initializeObjectsRD();
this.initializeURL();
this.initializeUpdates();
}
/**
* Overwrite this method to define how the list of objects is initialized and updated
*/
abstract initializeObjectsRD(): void;
/**
* Overwrite this method to define how the URL is set
*/
abstract initializeURL(): void;
/**
* Initialize the field-updates in the store
* This method ensures (new) pages displayed are automatically added to the field-update store when the objectsRD updates
*/
initializeUpdates(): void {
this.updates$ = this.objectsRD$.pipe(
paginatedListToArray(),
tap((objects: DSpaceObject[]) => {
// Pages in the field-update store are indexed starting at 0 (because they're stored in an array of pages)
const updatesPage = this.currentPage$.value - 1;
if (isEmpty(this.initializedPages)) {
// No updates have been initialized yet for this list, initialize the first page
this.objectUpdatesService.initializeWithCustomOrder(this.url, objects, new Date(), this.pageSize, updatesPage);
this.initializedPages.push(updatesPage);
} else if (this.initializedPages.indexOf(updatesPage) < 0) {
// Updates were initialized for this list, but not the page we're on. Add the current page to the field-update store for this list
this.objectUpdatesService.addPageToCustomOrder(this.url, objects, updatesPage);
this.initializedPages.push(updatesPage);
}
}),
switchMap((bitstreams: Bitstream[]) => this.objectUpdatesService.getFieldUpdatesByCustomOrder(this.url, bitstreams, this.currentPage$.value - 1))
);
}
/**
* Update the current page
* @param page
*/
switchPage(page: number) {
this.currentPage$.next(page);
}
/**
* A bitstream was moved, send updates to the store
* @param event
*/
drop(event: CdkDragDrop<any>) {
this.objectUpdatesService.saveMoveFieldUpdate(this.url, event.previousIndex, event.currentIndex, this.lastPage$.value - 1, this.currentPage$.value - 1);
}
dragStarted(event: CdkDragStart) {
this.lastPage$.next(this.currentPage$.value);
}
}

View File

@@ -1,11 +0,0 @@
<ds-pagination *ngIf="paginatedList"
[hideGear]="hideGear"
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
[hidePaginationDetail]="hidePaginationDetail"
[paginationOptions]="paginationOptions"
[pageInfoState]="paginatedList"
[collectionSize]="paginatedList?.totalElements"
[disableRouteParameterUpdate]="disableRouteParameterUpdate"
(pageChange)="switchPage($event)">
<ng-content></ng-content>
</ds-pagination>

View File

@@ -1,55 +0,0 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
import { PaginatedList } from '../../core/data/paginated-list';
@Component({
selector: 'ds-pagination-drag-and-drop',
templateUrl: './pagination-drag-and-drop.component.html',
})
export class PaginationDragAndDropComponent {
/**
* Configuration for the NgbPagination component.
*/
@Input() paginationOptions: PaginationComponentOptions;
/**
* The paginated list being displayed
*/
@Input() paginatedList: PaginatedList<any>;
/**
* Option for hiding the pagination detail
*/
@Input() public hidePaginationDetail = false;
/**
* Option for hiding the gear
*/
@Input() public hideGear = false;
/**
* Option for hiding the pager when there is less than 2 pages
*/
@Input() public hidePagerWhenSinglePage = true;
/**
* Option for disabling updating and reading route parameters on pagination changes
* In other words, changing pagination won't add or update the url parameters on the current page, and the url
* parameters won't affect the pagination of this component
*/
@Input() public disableRouteParameterUpdate = false;
/**
* An event fired when the page is changed.
* Event's payload equals to the newly selected page.
*/
@Output() pageChange: EventEmitter<number> = new EventEmitter<number>();
/**
* Switch to a different page
* @param page Page to switch to
*/
switchPage(page: number) {
this.pageChange.emit(page);
}
}

View File

@@ -178,7 +178,6 @@ import { ImportableListItemControlComponent } from './object-collection/shared/i
import { DragDropModule } from '@angular/cdk/drag-drop';
import { ExistingMetadataListElementComponent } from './form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component';
import { CustomSwitchComponent } from './form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.component';
import { PaginationDragAndDropComponent } from './pagination-drag-and-drop/pagination-drag-and-drop.component';
const MODULES = [
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
@@ -264,7 +263,6 @@ const COMPONENTS = [
AbstractListableElementComponent,
ObjectCollectionComponent,
PaginationComponent,
PaginationDragAndDropComponent,
SearchFormComponent,
PageWithSidebarComponent,
SidebarDropdownComponent,